server: add base path management (closes #290589)

update url path asset so that it is possible to serve mosaic from demo.logilab.fr/mosaic

authorAdrien Di Mascio <Adrien.DiMascio@logilab.fr>
changeset02ae766a6e8b
branchdefault
phasedraft
hiddenyes
parent revision#0ad9e966770f Added tag mosaic-version-0.1.0 for changeset 331ceaee160f
child revision<not specified>
files modified by this revision
mosaicserver/config.js
mosaicserver/lib.js
mosaicserver/prod_server.js
mosaicserver/routes.js
mosaicserver/test/test_lib.js
mosaicserver/views/layout.jade
portfolios/_template.html
# HG changeset patch
# User Adrien Di Mascio <Adrien.DiMascio@logilab.fr>
# Date 1428662426 -7200
# Fri Apr 10 12:40:26 2015 +0200
# Node ID 02ae766a6e8b9d562865edf1bbfd79a52f2257f6
# Parent 0ad9e966770f9610ffe8f227e03d7a0b31f284c0
server: add base path management (closes #290589)

update url path asset so that it is possible to serve mosaic from
demo.logilab.fr/mosaic

diff --git a/mosaicserver/config.js b/mosaicserver/config.js
@@ -0,0 +1,12 @@
1 +'use strict';
2 +
3 +module.exports = {
4 +    port: 8080,
5 +    basePath: '',
6 +
7 +    set: function set(key, value) {
8 +        if (value !== undefined) {
9 +            this[key] = value;
10 +        }
11 +    }
12 +};
diff --git a/mosaicserver/lib.js b/mosaicserver/lib.js
@@ -0,0 +1,15 @@
13 +// lib module
14 +
15 +// contains utility functions for mosaicserver
16 +
17 +'use strict';
18 +
19 +function instantiateTemplate(content, context) {
20 +    // substitute {{var}} in `content` with corresponding
21 +    // value in `context`
22 +    return content.replace(/\{\{(.+?)\}\}/g, function($0, $1) {
23 +        return $1 in context ? context[$1] : $0;
24 +    });
25 +}
26 +
27 +exports.instantiateTemplate = instantiateTemplate;
diff --git a/mosaicserver/prod_server.js b/mosaicserver/prod_server.js
@@ -2,26 +2,26 @@
28 
29 
30  var app = require('./app');
31  var http = require('http');
32  var program = require('commander');
33 -
34 -var defaultOpts = {
35 -    port: 8080
36 -};
37 +var config = require('./config');
38 
39  program
40      .version(require('../package.json').version)
41      .usage('[options]')
42      .option('-p, --port <int>',
43              'port number to start the server on (default to ' +
44 -            defaultOpts.port + ')');
45 +            config.port + ')')
46 +    .option('--base-path <base-path>',
47 +            'relative path from hostname (default to "")');
48 
49  program.parse(process.argv);
50 
51  var server = http.createServer(app);
52 
53 -app.set('port', program.port || defaultOpts.port);
54 +config.set('port', program.port);
55 +config.set('basePath', program.basePath);
56 
57 -server.listen(app.get('port'), function() {
58 -    console.log('server started on port', app.get('port'));
59 +server.listen(config.port, function() {
60 +    console.log('server started on port', config.port);
61  });
diff --git a/mosaicserver/routes.js b/mosaicserver/routes.js
@@ -3,10 +3,13 @@
62  var path = require('path');
63 
64  var express = require('express');
65  var router = express.Router();
66 
67 +var config = require('./config'),
68 +    lib = require('./lib');
69 +
70 
71  /* GET home page. */
72  router.get('/', function(req, res, next) {
73      res.render('index', {
74          title: 'Mosaic Server'
@@ -24,29 +27,32 @@
75              res.status(200).send('ok');
76          }
77      });
78  });
79 
80 +var templateContent = fs.readFileSync(path.join(__dirname, '/../portfolios/_template.html')).toString();
81 +
82  router.post('/newportfolio', function(req, res, next) {
83      var slug = req.body.name.replace(/[ \/]/g, '_'), // XXX sanitize
84          filename = path.join(__dirname, '/../portfolios/' + slug + '.html'),
85          template = path.join(__dirname, '/../portfolios/_template.html');
86 
87      fs.exists(filename, function(exists) {
88          if (exists) {
89              res.redirect('/' + slug);
90          } else {
91 -            var istream = fs.createReadStream(template),
92 -                ostream = fs.createWriteStream(filename);
93 -            ostream.on('finish', function() {
94 -                res.redirect('/' + slug);
95 +            var context = {basePath: config.basePath,
96 +                           name: slug},
97 +                content = lib.instantiateTemplate(templateContent, context);
98 +            fs.writeFile(filename, content, function(err) {
99 +                if (err) {
100 +                    res.status(500).send('could not create resource');
101 +                    next();
102 +                } else {
103 +                    res.redirect('/' + slug);
104 +                }
105              });
106 -            ostream.on('error', function () {
107 -                res.status(500).send('could not create resource');
108 -                next();
109 -            });
110 -            istream.pipe(ostream);
111          }
112      });
113  });
114 
115  router.get('/:slug', function(req, res, next) {
diff --git a/mosaicserver/test/test_lib.js b/mosaicserver/test/test_lib.js
@@ -0,0 +1,33 @@
116 +/* global describe, it */
117 +'use strict';
118 +
119 +var assert = require('assert');
120 +var lib = require('../lib');
121 +
122 +describe('lib module tests', function () {
123 +
124 +    it('should substitute variables', function () {
125 +        var result = lib.instantiateTemplate('{{foo}}', {foo: 'hello'});
126 +        assert.strictEqual(result, 'hello');
127 +    });
128 +
129 +    it('should substitute same variable multiple values', function () {
130 +        var result = lib.instantiateTemplate('{{foo}} - {{foo}}',
131 +                                             {foo: 'hello'});
132 +        assert.strictEqual(result, 'hello - hello');
133 +    });
134 +
135 +    it('should substitute multiple variables', function () {
136 +        var result = lib.instantiateTemplate('{{foo}} {{bar}}',
137 +                                             {foo: 'hello',
138 +                                              bar: 'world'});
139 +        assert.strictEqual(result, 'hello world');
140 +    });
141 +
142 +    it('should ignore unknown variables', function () {
143 +        var result = lib.instantiateTemplate('{{foo}} {{bar}}',
144 +                                             {foo: 'hello'});
145 +        assert.strictEqual(result, 'hello {{bar}}');
146 +    });
147 +
148 +});
diff --git a/mosaicserver/views/layout.jade b/mosaicserver/views/layout.jade
@@ -1,10 +1,10 @@
149  doctype html
150  html
151    head
152      title= title
153 -    link(rel='stylesheet', href='/vendor.css')
154 +    link(rel='stylesheet', href='vendor.css')
155    body
156      div(class='container')
157        block content
158 -    script(src='/vendor.js')
159 +    script(src='vendor.js')
160 
diff --git a/portfolios/_template.html b/portfolios/_template.html
@@ -1,27 +1,27 @@
161  <!doctype html>
162  <html lang="en">
163    <head>
164      <meta charset="UTF-8"/>
165      <title>Portfolio {{name}}</title>
166 -    <script src="/babel-browser-polyfill.js"></script>
167 -    <link rel="stylesheet" href="/vendor.css"/>
168 -    <link rel="stylesheet" href="/app.css"/>
169 -    <script src="/vendor.js"></script>
170 +    <script src="{{basePath}}/babel-browser-polyfill.js"></script>
171 +    <link rel="stylesheet" href="{{basePath}}/vendor.css"/>
172 +    <link rel="stylesheet" href="{{basePath}}/app.css"/>
173 +    <script src="{{basePath}}/vendor.js"></script>
174      <!--
175          app.js contains require and registry module definition,
176          it must be inserted _before_ any plugins
177        -->
178 -    <script src="/app.js"></script>
179 -    <link rel="import" href="/components/xmosaicframe/xmosaicframe.html" />
180 -    <link rel="import" href="/components/neotableview/neotableview.html" />
181 -    <link rel="import" href="/components/neolistview/neolistview.html" />
182 -    <link rel="import" href="/components/sparqltableview/sparqltableview.html" />
183 -    <link rel="import" href="/components/cwtableview/cwtableview.html" />
184 -    <link rel="import" href="/components/markdown-editable/markdown-editable.html" />
185 -    <link rel="import" href="/components/pdfview/pdfview.html" />
186 -    <link rel="import" href="/components/plainview/plainview.html" />
187 +    <script src="{{basePath}}/app.js"></script>
188 +    <link rel="import" href="{{basePath}}/components/xmosaicframe/xmosaicframe.html" />
189 +    <link rel="import" href="{{basePath}}/components/neotableview/neotableview.html" />
190 +    <link rel="import" href="{{basePath}}/components/neolistview/neolistview.html" />
191 +    <link rel="import" href="{{basePath}}/components/sparqltableview/sparqltableview.html" />
192 +    <link rel="import" href="{{basePath}}/components/cwtableview/cwtableview.html" />
193 +    <link rel="import" href="{{basePath}}/components/markdown-editable/markdown-editable.html" />
194 +    <link rel="import" href="{{basePath}}/components/pdfview/pdfview.html" />
195 +    <link rel="import" href="{{basePath}}/components/plainview/plainview.html" />
196    </head>
197    <body>
198      <div class="container">
199        <x-markdown-editable>###Edit me</x-markdown-editable>
200