git-gallery
Version:
A gallery app for showing work based on Git commits.
226 lines (194 loc) • 6.29 kB
JavaScript
const express = require('express');
const router = express.Router({mergeParams: true});
const fs = require("fs");
const path = require('path');
const parseUrl = require('parseurl');
const multer = require('multer');
const mime = require('mime');
const debug = require('debug')('git-gallery');
const gallery = require('./gallery.js');
const commitsDB = require('../lib/commitsDB');
const pagesDB = require('../lib/pagesDB');
const fsUtils = require('../lib/fsUtils');
const repoUtils = require('../lib/repoUtils');
const galleryRoot = fsUtils.galleryRoot;
function multerDestination(req, file) {
return path.join(galleryRoot, req.body.commitId);
}
function multerFilename(dir, name, ext) {
let fn = name + ext;
let p = path.join(dir, fn);
if (fsUtils.pathExists(p)) {
// add a number after the name so the name doesn't conflict with an already existing file
let number = 1;
do {
number++;
fn = name + number + ext;
p = path.join(dir, fn);
} while (fsUtils.pathExists(p));
}
return fn;
}
var storage = multer.diskStorage({
destination: function (req, file, cb) {
// console.log('multer request: %s %s %s' + req.method, req.url, req.path);
let d = multerDestination(req, file);
// console.log('multer destination: ' + d);
cb(null, d);
},
filename: function (req, file, cb) {
let name = file.originalname;
let ext = '.' + mime.getExtension(file.mimetype);
if (mime.getType(name) == file.mimetype) {
ext = path.extname(name);
name = name.substring(0, name.length - ext.length)
}
let dir = multerDestination(req, file);
let fn = multerFilename(dir, name, ext);
cb(null, fn);
}
});
var upload = multer({ storage: storage });
router.use(function(req, res, next) {
console.log('pagesRouter: %s %s %s', req.method, req.url, req.path);
next();
});
var repo = require('./repo');
router.use('/repo', repo.router);
router.get('/thumbnail', thumbnailRequest);
router.get('/', pageRequest);
router.get('/index.html', pageRequest);
router.post('/commitcurrent', commitCurrent);
function pageRequest(req, res, next) {
let commitId = req.params.commitRef;
switch (commitId) {
case 'workdir':
// Shouldn't happen -- probably means the requested working dir file doesn't exist
return res.send('');
case 'current':
case 'CURRENT':
// case 'current.html':
return getCurrent(req, res, next);
case 'HEAD':
debug('HEAD request');
return repoUtils.getHeadCommit().then(head => {
debug('HEAD = ' + head);
return handlePageRequest(head.sha(), req, res, next); });
default:
return handlePageRequest(commitId, req, res, next);
}
}
function handlePageRequest(commitId, req, res, next) {
createPageRenderData(commitId)
.then(data => {
data.editable = true;
res.render('page.hbs', data);
})
.catch(error => res.sendStatus(404));
}
router.get('/*', function(req, res, next) {
let pn = parseUrl(req).pathname;
let f = path.join(req.params.commitRef, pn);
let root = '.gitGallery';
// console.log("pathname: " + pn);
// console.log('root resolved: ' + path.resolve(root));
// console.log('req url: ' + req.url);
// console.log('commitRef: ' + req.params.commitRef);
// console.log('Sending file: ' + f);
res.sendFile(f, {root: root});
});
router.post('/editpage', function(req, res, next) {
let commitId = req.params.commitRef;
if (commitId === 'HEAD') {
return repoUtils.getHeadCommit().then(head => { editPage(head.sha(), req, res); });
} else {
return editPage(commitId, req, res);
}
});
function editPage(commitId, req, res) {
debug('Edit page: name=' + req.body.name + ' => value=' + req.body.value);
let page = pagesDB.getPage(commitId);
if (req.body.name.startsWith('caption/')) {
let imgSrc = req.body.name.substring(8);
let caption = null;
for (img of page.images) {
if (img.src === imgSrc) {
img.caption = req.body.value;
break;
}
}
} else {
page[req.body.name] = req.body.value;
}
res.sendStatus(200);
}
router.post('/addimage', upload.single('file'), function(req, res, next) {
if (req.params.commitRef === 'HEAD') {
return repoUtils.getHeadCommit().then(head => { addImage(head.sha(), req, res); });
} else {
return addImage(req.params.commitRef, req, res);
}
});
function addImage(commitId, req, res) {
let page = pagesDB.getPage(commitId);
page.images.push({ 'src': req.file.filename, 'caption': '' });
res.sendStatus(200);
}
function thumbnailRequest(req, res, next) {
let page = pagesDB.getPage(req.params.commitRef);
if (!page) {
return res.sendStatus(404);
} else if (!page.images || page.images.length < 1) {
return res.redirect('/images/1x1.png');
} else {
let image = page.images[0];
let thumb = req.query.thumb || '200x200';
return res.redirect(image.src + '?thumb=' + thumb);
}
}
function getCurrent(req, res, next) {
return repoUtils.repoStatus().then(status => {
if (status.isClean) {
return repoUtils.getHeadCommit().then(head => {
let page = pagesDB.getPage(head.sha());
status.pageExists = !!page;
status.page = page;
return status;
});
} else {
return Promise.resolve(status);
}
}).then(status => res.render('current', status));
}
function commitCurrent(req, res, next) {
let message = req.body.message || '';
return repoUtils.commitAllChanges(message).then(() => {
return res.redirect('/current/');
})
}
/** Data that can be sent to the page template including commit and page info. */
function createPageRenderData(commitId) {
let page = pagesDB.getPage(commitId);
return commitsDB.getCommit(commitId).then(commit => {
let data = {
"commitId": commitId,
"galleryData": gallery.getGalleryData(),
"commit": commit,
"page": page,
"isHead": commitId === 'HEAD',
"showImages": true
};
return data;
}).then(data => {
if (data.isHead) {
return repoUtils.headStatus().then(headStatus => {
data.isClean = headStatus.isClean;
data.isDetached = headStatus.isDetached;
return data;
});
}
return data;
});
}
exports.router = router;
exports.createPageRenderData = createPageRenderData;