Pārlūkot izejas kodu

embed stringified example in HTML on server, WIP on file creation route handler

Benoît Hubert 8 gadi atpakaļ
vecāks
revīzija
530be59958
4 mainītis faili ar 64 papildinājumiem un 7 dzēšanām
  1. 4 3
      html/index.mustache.html
  2. 4 4
      js/ws-forms.js
  3. 2 0
      lib/indexHandlers.js
  4. 54 0
      sandboxApp.js

+ 4 - 3
html/index.mustache.html

@@ -93,8 +93,8 @@
             <li id="add-file"><button class="add-btn inline-block h-collapsed fast{{#repo}} in{{/repo}}">+</button>
                 <form class="inline-block h-collapsed">
                     <input type="text" name="title" class="input-xs input-light-border" value="" placeholder="{{_.fileNameWithExt}}" required />
-                    <button type="button" id="add-example-cancel" class="icon-cross rounded red"></button><!--
-                    --><button type="submit" id="add-example-save" class="icon-checkmark rounded green"></button>
+                    <button type="button" id="add-example-cancel" class="icon-cross"></button><!--
+                    --><button type="submit" id="add-example-save" class="icon-checkmark"></button>
                 </form></li>
             </ul>
             <div id="editor"></div>
@@ -166,7 +166,8 @@
 <script id="inline-js-data">
 window._ws = {
   files: {{{filesJSON}}},
-  repo: {{{repoJSON}}}
+  repo: {{{repoJSON}}},
+  example: {{{exampleJSON}}}
 };
 </script>
 <script src="/js/req-promise.js"></script>

+ 4 - 4
js/ws-forms.js

@@ -118,16 +118,16 @@
   makeFormView(
     'add-file',
     function(name) {
-      return rp.post('/' + _ws.repo.path + '/examples/file', { name: name });
+      return rp.post('/' + _ws.repo.path + '/examples/' + _ws.example.slug + '/file', { name: name });
     },
     {
       events: {
         'keyup input[name="title"]': function(e) {
           var filename = this.$input.val();
-          // console.log('filename', filename);
           var bits = filename.split('.');
           var lastIdx = bits.length - 1;
-          console.log(bits, bits.length, lastIdx, bits[lastIdx], typeof bits[lastIdx]);
+
+          // show warning if no extension has been provided
           if(bits.length < 2) {
             this.$input
             .removeClass('input-success input-error')
@@ -135,9 +135,9 @@
             this.cantSubmit = 'Impossible de valider: extension (.html/.js/.css) manquante';
             return;
           }
+          // show error if provided extension is invalid
           else {
             var ext = (bits[lastIdx]).toLowerCase();
-            console.log(ext);
             if( ['html', 'js', 'css'].indexOf( ext ) === -1 ) {
               this.$input
               .removeClass('input-success input-warning')

+ 2 - 0
lib/indexHandlers.js

@@ -47,6 +47,7 @@ module.exports = function(exStore, exDir, testMode) {
     let data = {
       menuRepo: exStore.getRepoMenu(),
       repoJSON: 'null',
+      exampleJSON: 'null',
       testMode,
       testRun: testMode && req.query.testing,
       appPath: req.path,
@@ -71,6 +72,7 @@ module.exports = function(exStore, exDir, testMode) {
     // Fetch example if needed
     if(withExample && data.repo) {
       data.example = _.find(data.repo.examples, { slug: exampleSlug });
+      data.exampleJSON = JSON.stringify(data.example);
       if(! data.example) {
         // return res.status(404).send('Example ' + req.params.repoSlug + '/' + req.params.exampleSlug + ' not found');
         data.errorMessage = translator.getOne(locale, "exampleNotFound", [repoSlug, exampleSlug]);

+ 54 - 0
sandboxApp.js

@@ -76,6 +76,25 @@ function mapObjToArray(obj, key, value) {
   return arr;
 }
 
+function checkBodyPropsExist(props) {
+  return function(req, res, next) {
+    if(! props) {
+      throw new Error('checkBodyPropsExist was called with empty props argument');
+    }
+    if(! req.body) {
+      return res.status(400).send('request doest not have a body: please set "content-type" header to "application/json"');
+    }
+    props = typeof props === 'string' ? [props] : props;
+    for(let p = 0 ; p < props.length ; p++) {
+      const prop = props[p];
+      if(! req.body[prop]) {
+        return res.status(400).send('request body doest not have a `' + prop + '` parameter: please provide it.');
+      }
+    }
+    next();
+  };
+}
+
 /**
  * Get repo parts
  */
@@ -151,6 +170,38 @@ app.post('/repos', function(req, res) {
 
 });
 
+app.post('/:repoSlug/examples/:exampleSlug/file',
+  checkRepoExists,
+  checkBodyPropsExist('name'),
+  function(req, res) {
+    const { name } = req.body;
+    const { repoSlug, exampleSlug } = req.params;
+    const re = /^[A-Za-z0-9_\-\.]+$/;
+    const targetDir = examplesDir + '/' + repoSlug + '/' + exampleSlug;
+    const fullPath = targetDir + '/' + name;
+    if(! re.test(name)) {
+      return res.status(400).json('Le paramètre `name` est incorrect: caractères autorisés: lettres, chiffres, _, - et .' );
+    }
+    fs.statAsync(fullPath)
+    // Invert the usual flow of a Promise. fs.stat() fails if file does not exist (which is what we want)
+    // Hence .catch() is a success handler and .then() an error handler (has to rethrow)
+    .catch(err => {
+      return fs.writeFileAsync(fullPath, '')
+      .then(() => res.json({
+        name,
+        path: fullPath
+      }));
+    })
+    .then(stats => {
+      throw new Error('Le fichier `' + name + '` existe déjà !');
+    })
+    .catch(err => {
+      const statusCode = err.message.startsWith('Le fichier') ? 409 : 500;
+      return res.status(statusCode).send(err.message);
+    });
+  }
+);
+
 /**
  * Create a new example for specified repo
  */
@@ -210,6 +261,9 @@ app.get('/examples/:repoSlug/:slug',
   }
 );
 
+
+
+
 app.get('/menu', (rea, res) => {
   res.send(exStore.getMenu());
 });