/* global __dirname */ /* jshint strict:false */ "use strict"; var express = require('express'); var bodyParser = require('body-parser'); var slug = require('slug'); var beautify = require('json-beautify'); var _ = require('lodash'); var path = require('path'); var Mustache = require('mustache'); var app = express(); var fs = require('fs'); var Promise = require('bluebird'); Promise.promisifyAll(fs); var sandboxTpml = fs.readFileSync(__dirname + '/html/template.mustache.html').toString(); var exampleTmpl = require('./lib/exampleTmpl.json'); var repoTmpl = require('./lib/repoTmpl.json'); var ExampleStore = require('./lib/ExampleStore'); var isTesting = process.env.NODE_ENV === 'testing'; var examplesDir = ! isTesting ? __dirname + '/exemples' : __dirname + '/test/integration/test-examples'; var exStore = new ExampleStore(examplesDir); var { readFileAsync, readFilesAsync } = require('./lib/fsio'); var { getAcceptLanguage, getIndexBare, // getIndexTest, getIndexRepo, getIndexExample } = require('./lib/indexHandlers')(exStore, examplesDir, isTesting); var { // getIndexBare, getPartsRepo, getPartsExample } = require('./lib/partHandlers')(exStore, examplesDir); /** * Initialize example store */ exStore.init(); // .then(() => console.log(exStore.getMenu())); /** * Initialize Express app: * - root folder as static * - body parsers * - browser language detection middleware */ app.use(express.static(__dirname)); app.use(bodyParser.json()); app.use(bodyParser.urlencoded({ extended: true })); app.use(getAcceptLanguage); function addExample(slug, title) { return fs.writeFileAsync(examplesJSON, beautify(examples, null, 2, 100)); } function readConfigJson(exampleSlug) { console.log(exampleSlug); return require('./exemples/jquery/' + exampleSlug + '/config.json'); } function mapObjToArray(obj, key, value) { var arr = []; for(var p in obj) { arr.push({ [key]: p, [value]: obj[p] }); } return arr; } /** * Get repo parts */ app.get('/parts/:repoSlug', getPartsRepo); /** * Get example parts */ app.get('/parts/:repoSlug/:exampleSlug', getPartsExample); /** * Index page: render with only repo list in menu */ app.get('/', getIndexBare); /** * Index page: render for tests */ // if(isTesting) { // app.get('/test', getIndexTest); // } /** * Repo page: render with repo list and selected repo's example list in menu */ app.get('/:repoSlug', getIndexRepo); /** * Example page: render with repo list and selected repo's example list in menu, * and the editor with the selected example */ app.get('/:repoSlug/:exampleSlug', getIndexExample); function checkRepoExists(req, res, next) { const { repoSlug } = req.params; console.log('### checkRepoExists', repoSlug); // Get repo from store req.repo = exStore.getRepo(repoSlug); if(! req.repo) { res.status(404).send("Repo " + repoSlug + "not found"); } next(); } /** * Create a new repo */ app.post('/repos', function(req, res) { // Check for title and extract params if(! req.body || ! req.body.title) { res.status(400).send('Le titre ne peut pas être vide !'); } const { title } = req.body; const repoSlug = slug(title.toLowerCase()); const existingRepo = exStore.getRepo(repoSlug); // Prevent duplicate title if(existingRepo) { return res.status(409).send("La collection '" + title + "' existe déjà !"); } // Prepare config var config = Object.assign({ title }, repoTmpl); exStore.addRepository(repoSlug, config) .then(repo => res.json(config)); }); /** * Create a new example for specified repo */ app.post('/:repoSlug/examples', checkRepoExists, function(req, res) { // Check for title and extract params if(! req.body || ! req.body.title) { res.status(400).send('Le titre ne peut pas être vide !'); } const { title } = req.body; const { repoSlug } = req.params; // Prevent duplicate title var existingTitle = _.find(req.repo.examples, { title: title }); if(existingTitle) { return res.status(409).send("L'exemple '" + title + "' existe déjà !"); } var exampleSlug = slug(req.body.title.toLowerCase()); // Prepare config var config = Object.assign({ slug: exampleSlug, title, category: req.repo.defaultCategory }, exampleTmpl); // Prepare files to write var targetDir = examplesDir + '/' + repoSlug + '/' + exampleSlug; var files = mapObjToArray({ 'example.html': '\n', 'script.js': '// ' + title, 'config.json': beautify(config, null, 2, 100) }, 'file', 'content'); fs.mkdirAsync(targetDir) .then(() => Promise.map( files, ({ file, content }) => fs.writeFileAsync(targetDir + '/' + file, content) )) .then(files => req.repo.examples.push(config)) .then(() => res.json(config)); } ); app.get('/examples/:repoSlug/:slug', checkRepoExists, function(req, res) { const { repoSlug, slug } = req.params; var example = _.find(req.repo.examples, { slug }); const { title, html, js, css, libsCss, libsJs } = example; console.log(example, title, html, js, css, libsCss, libsJs); readFileAsync(__dirname + '/exemples/' + repoSlug + '/' + slug + '/example.html') .then(body => Mustache.render(sandboxTpml, { body, repoSlug, slug, title, js, css, libsCss, libsJs }) ) .then(html => res.send(html)); } ); app.get('/menu', (rea, res) => { res.send(exStore.getMenu()); }); app.get('/list/:repoPath', function(req, res) { const { repoPath } = req.params; const repo = exStore.getList(repoPath); if(! repo) { return res.status(404).send('Repo ' + repoPath + ' not found'); } console.log('found repo', repo); const data = repo.examples.map(e => ( { slug: e.slug, title: e.title } )); res.json(data); }); app.put('/examples/:slug', function(req, res) { var slug = req.params.slug; var existing = _.find(examples, { slug: slug }); if(! existing) { res.status(404).send("L'exemple avec l'identifiant '" + slug + "' est introuvable !"); } var targetDir = __dirname + '/exemples/' + slug; if(req.body.html) { fs.writeFileSync(targetDir + '/contenu.html', req.body.html); } if(req.body.javascript) { fs.writeFileSync(targetDir + '/script.js', req.body.javascript); } var theDate = new Date(); console.log(theDate.getHours() + ':' + theDate.getMinutes() + " - Sauvegarde de l'exemple '" + existing.title + " effectuée'"); res.json({ success: true }); }); module.exports = app;