[TIC-UI] add the filedownload feature
authorHee Kyoung, Oh <heekyoung.oh@samsung.com>
Sat, 17 Dec 2016 09:10:23 +0000 (18:10 +0900)
committerHee Kyoung, Oh <heekyoung.oh@samsung.com>
Sat, 17 Dec 2016 09:10:23 +0000 (18:10 +0900)
- add the filedownload button
- add the file stats (size and update time)
- add the router
- changing the file name ws.filesystem.js to filesystem.js
- changing the file name ws.mic.js to mic.js

Change-Id: Id793c91c626a4f27cb0c763ecfad04a2851d63e8
Signed-off-by: Hee Kyoung, Oh <heekyoung.oh@samsung.com>
app.js
public/src/css/style.css
public/src/index.html
public/src/js/page/image.js
server/fs/filesystem.js [new file with mode: 0644]
server/fs/mic.js [new file with mode: 0644]
server/fs/ws.filesystem.js
server/routes/router.js [new file with mode: 0644]

diff --git a/app.js b/app.js
index 15ba9a5..4477913 100644 (file)
--- a/app.js
+++ b/app.js
@@ -6,7 +6,9 @@ var fs = require('fs');
 var express = require('express');
 var bodyParser = require('body-parser');
 
-var FileSystem = require('./server/fs/ws.filesystem');
+var FileSystem = require('./server/fs/filesystem');
+var Mic = require('./server/fs/mic');
+var Router = require('./server/routes/router');
 
 var app = express();
 var server = http.createServer(app);
@@ -20,15 +22,7 @@ app.use(bodyParser.json());
 app.use(bodyParser.urlencoded());
 
 app.use(express.static(path.join(__dirname, '/public/src'))); //module directory
-
-/**
- * TODO
- *
- * apply router
- *
- * var AppRouter = require('./routes');
- * app.use(mount('/', AppRouter));
- */
+app.use('/api', Router);
 
 server.listen(app.get('port'), process.env.IP || "0.0.0.0", function () {
     var addr = server.address();
@@ -60,6 +54,26 @@ io.on('connection', function (socket) {
         socket.emit('ws/fs/image/list/to', msgData);
     });
 
+    socket.on('ws/fs/image/add/from', function (data) {
+        console.log(data);
+        var msgData, ans;
+
+        msgData = {};
+
+        function sendMsg(msg) {
+            // send
+            socket.emit('ws/fs/image/add/to', msg);
+        }
+
+        // get the list of file
+        Mic.create(data, socket);
+    });
+
+    socket.on('ws/fs/image/download/from', function (data) {
+        console.log(data);
+
+    });
+
     socket.on('disconnect', function () {
         console.log('socket disconnect');
     });
index 04af47a..0739b02 100644 (file)
@@ -141,6 +141,45 @@ html {
     position: relative;
     overflow: auto;
 }
+#tic-image-list {
+    margin-top: 3px;
+}
+
+.image-list-time {
+    padding-left: 10px;
+}
+
+.image-item {
+    overflow: hidden;
+    text-overflow: ellipsis;
+}
+
+.infobox {
+    padding: 20px;
+    margin: 20px 0;
+    border: 1px solid #eee;
+    border-radius: 3px;
+    margin-top: 3px;
+    height: 25vh;
+    overflow: auto;
+    font-size: 14px;
+}
+
+.infoboxheader {
+    padding-left: 15px;
+    border: 1px solid #eee;
+    border-left-width: 5px;
+    border-radius: 3px;
+    margin-top: -5px;
+    height: 5vh;
+    overflow: hidden;
+    text-overflow: ellipsis;
+    border-left-color: #1b809e;
+}
+.infoboxheader h4 {
+    color: #1b809e;
+}
+
 @media (min-width: 992px) {
     #tic-image-summary {
         height: 70vh;
index e05f700..2583932 100644 (file)
                         <div class="panel panel-primary">
                             <div class="panel-heading">Image List</div>
                             <div class="panel-body">
-                                <h1>Image list and download</h1>
-                                <table id="tic-image-list"></table>
+                                <div class="infoboxheader">
+                                    <h4>create a image</h4>
+                                </div>
+                                <div class="infobox info" id="tic-image-new">
+                                    <div id="tic-image-new-log">
+                                    </div>
+                                </div>
+                                <div class="infoboxheader">
+                                    <h4>image list</h4>
+                                </div>
+                                <ul class="list-group" id="tic-image-list"></ul>
                             </div>
                         </div>
                     </div><!-- /End Image List Column -->
                 </div>
             </div><!-- /.container -->
+            <!-- modal -->
+            <div class="modal fade" id="confirmModalCreateImage" role="dialog">
+                <div class="modal-dialog modal-sm">
+                <div class="modal-content">
+                    <div class="modal-header">
+                        <button type="button" class="close" data-dismiss="modal">&times;</button>
+                        <h4 class="modal-title">Create a new Image</h4>
+                    </div>
+                    <div class="modal-body">
+                        <p>Are you sure ?</p>
+                    </div>
+                    <div class="modal-footer">
+                        <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
+                        <button type="button" class="btn btn-primary">Ok</button>
+                    </div>
+                </div>
+                </div>
+            </div>
         </section>
 
 
index 485c1ce..77c3136 100644 (file)
@@ -7,22 +7,28 @@ define([
 ) {
     'use strict';
 
-    var client;
+    // connected socket object
+    var client,
+
+        // the list of checked pakages
+        checkedPackagesList,
+
+        // template for the URL
+        URL_EXPORTS = '<%= protocol %>//<%= hostname %>:<%= port %>/exports',
+
+        // the path for ks
+        PATH_TIC_KS = '/tmp/tic/ks/',
+
+        // the path for images
+        PATH_TIC_IMAGES = '/tmp/tic/images/';
+
+
 
     function updateList(socket) {
-        /**
-         * FIXME
-         *
-         * changed to be set the path dynamically
-         */
         var msgData = {
-            path: './resource/images/'
+            path: PATH_TIC_IMAGES
         };
 
-        /**
-         * TODO
-         * checks
-         */
         client = socket;
 
         client.emit('ws/fs/image/list/from', msgData);
@@ -33,11 +39,39 @@ define([
             list = data.list;
             tableDomElem = $('#tic-image-list');
 
-            /**
-             * FIXME
-             */
             list.forEach(function (file) {
-                tableDomElem.append(file.name + ' (size:' + file.size + ')' + '</br>');
+                /**
+                 * @info
+                 *
+                 * file = {
+                 *  name: '',
+                 *  size: ''
+                 * }
+                 */
+                var liElem, aElem, spanElem, fileName, hrefPath;
+
+                fileName = file.name;
+
+                hrefPath = '/api/fs/download/' + fileName;
+
+                liElem = document.createElement('li');
+                liElem.innerText = fileName;
+                liElem.setAttribute('class', 'list-group-item image-item');
+
+                spanElem = document.createElement('span');
+                spanElem.innerText = '(' + file.size + 'B / ' + file.mtime + ')';
+                spanElem.setAttribute('class', 'image-list-time');
+
+                aElem = document.createElement('a');
+                aElem.innerText = 'Download';
+                aElem.setAttribute('class', 'badge');
+                aElem.setAttribute('href', hrefPath);
+                aElem.setAttribute('data-name', fileName);
+                aElem.setAttribute('download', 'download');
+
+                liElem.appendChild(spanElem);
+                liElem.appendChild(aElem);
+                tableDomElem.append(liElem);
             });
         });
 
@@ -49,12 +83,12 @@ define([
         var packageCount = $('#tic-image-package-count').empty();
         var packageList = $('#tic-image-package-list').empty();
 
-        var list = require('js/page/package').getCheckedPackages();
-        var count = _.size(list);
-        var imageSize = _.sumBy(list, function getImageSize(item) {
+        checkedPackagesList = require('js/page/package').getCheckedPackages();
+        var count = _.size(checkedPackagesList);
+        var imageSize = _.sumBy(checkedPackagesList, function getImageSize(item) {
             return _.toNumber(item.size);
         });
-        var imageInstalledSize = _.sumBy(list, function getImageInstalled(item) {
+        var imageInstalledSize = _.sumBy(checkedPackagesList, function getImageInstalled(item) {
             return _.toNumber(item.installed);
         });
 
@@ -67,16 +101,137 @@ define([
         if (_.isNumber(count)) {
             packageCount.html(count);
         }
-        if (!_.isEmpty(list)) {
-            packageList.html(_.orderBy(_.map(list, 'text')).join('<br>'));
+        if (!_.isEmpty(checkedPackagesList)) {
+            packageList.html(_.orderBy(_.map(checkedPackagesList, 'text')).join('<br>'));
         }
 
         $('#tic-image-create').prop('disabled', count === 0);
     }
 
+    function confirmCreateImage() {
+        var isOk;
+
+        $('#tic-image-create').prop('disabled', true);
+
+        // when packages are checked nothing
+        if (_.isEmpty(checkedPackagesList)) {
+            $('#tic-image-create').prop('disabled', true);
+            return;
+        }
+
+        function createImage(pathKsFile) {
+            /**
+             * TODO - checks the msgData
+             */
+            var msgData, tableDomElem;
+            msgData = {
+                pathKsFile: pathKsFile,
+                pathOutput: PATH_TIC_IMAGES
+            };
+
+            tableDomElem = $('#tic-image-new-log');
+
+            client.emit('ws/fs/image/add/from', msgData);
+
+            client.on('ws/fs/image/add/to', function (data) {
+                console.log(data);
+                var elem = document.createElement('p');
+                elem.innerText = data;
+                tableDomElem.append(elem);
+            });
+
+            // when finished
+            client.on('ws/fs/image/add/finished', function (data) {
+                $('#tic-image-create').prop('disabled', false);
+                $('#tic-image-new').empty();
+                updateList();
+            });
+        }
+
+        function getExportsUrl() {
+            return _.template(URL_EXPORTS)({
+                protocol: location.protocol,
+                hostname: location.hostname,
+                port: parseInt(location.port) + 1
+            });
+        }
+
+        function getKickstartRecipeFile() {
+            return new Promise(function (resolve, reject) {
+                var msgData = {
+                    recipe: {
+                        name: 'default'
+                    },
+                    packages: _.map(checkedPackagesList, 'name'),
+                    output: PATH_TIC_KS
+                };
+
+                console.log('url = ' + getExportsUrl());
+                console.log(msgData);
+
+                $.ajax({
+                    type: 'POST',
+                    contentType: 'text/plain',
+                    data: JSON.stringify(msgData),
+                    dataType: 'json',
+                    url: getExportsUrl(),
+                    success: function (res) {
+                        console.log(res);
+                        resolve(res.data);
+                    },
+                    error: function (err) {
+                        reject(err.responseText);
+                    }
+                });
+            });
+        }
+
+        /**
+         * FIXME
+         * using modal
+         *
+         * $('#confirmModalCreateImage').modal('show');
+         */
+        // confirm
+        isOk = window.confirm('Are you sure?');
+        if (isOk) {
+            getKickstartRecipeFile()
+                .then(createImage)
+                .catch(function (err) {
+                    console.log(err);
+                    Util.showLoadingDialog(false);
+                    Util.showAlertDialog('Failed to create a image.<br>Please check the ks file.');
+                });
+        } else {
+            $('#tic-image-create').prop('disabled', false);
+        }
+    }
+
+    /**
+     * Initiation for the all widgets
+     */
+    function _initWidgets() {
+        // button
+        $('#tic-image-create').prop('disabled', true);
+        $('#tic-image-create').click(confirmCreateImage);
+
+        /**
+         * FIXME
+         * chanage 'confirm' to 'modal'
+         *
+         * modal
+         *   $('#confirmModalCreateImage').modal({
+         *       keyboard: false,
+         *       backdrop: true
+         *   });
+         */
+
+    }
+
     function init() {
         console.log('image: init');
-        $('#tic-image-create').prop('disabled', true);
+
+        _initWidgets();
     }
 
     init();
@@ -87,6 +242,11 @@ define([
          * @method updateSummary
          */
         updateSummary: updateSummary,
+
+        /**
+         * Update list in image page
+         * @method updateList
+         */
         updateList: updateList
     }
 
diff --git a/server/fs/filesystem.js b/server/fs/filesystem.js
new file mode 100644 (file)
index 0000000..68cbf9e
--- /dev/null
@@ -0,0 +1,58 @@
+'use strict';
+/**
+ * using websocket
+ */
+
+var fs = require('fs');
+var path = require('path');
+
+var FileSystem = {};
+
+FileSystem.list = function (dirPath) {
+    console.log('filesystem.list called');
+    var results, info, list;
+
+    results = [];
+
+    if(!fs.existsSync(dirPath)) {
+        fs.mkdirSync(dirPath);
+    }
+
+    list = fs.readdirSync(dirPath);
+    list.forEach(function(file) {
+        var fileStat, filePath;
+
+        filePath = dirPath + file;
+
+        fileStat = fs.statSync(filePath);
+
+        if (fileStat && fileStat.isDirectory()) {
+            results = results.concat(FileSystem.list(filePath))
+        } else {
+            /**
+             * TODO
+             * to be extended .. 
+             */
+            info = {
+                name: file,
+                size: fileStat['size'],
+                atime: fileStat['atime'],
+                mtime: fileStat['mtime'],
+                ctime: fileStat['ctime'],
+                birthtime: fileStat['birthtime']
+            }
+            results.push(info);
+        }
+    });
+    return results;
+};
+
+FileSystem.remove = function () {
+    console.log('filesystem.remove called');
+};
+
+FileSystem.download = function () {
+    console.log('filesystem.download called');
+};
+
+module.exports = FileSystem;
\ No newline at end of file
diff --git a/server/fs/mic.js b/server/fs/mic.js
new file mode 100644 (file)
index 0000000..b95e0fa
--- /dev/null
@@ -0,0 +1,56 @@
+'use strict';
+/**
+ * using websocket
+ */
+
+var fs = require('fs');
+var path = require('path');
+var exec = require('child_process').exec;
+var util = require('util');
+
+var Mic = {};
+
+Mic.subprocess = function (processname, arg, cb) {
+    var p = exec(processname, arg);
+    p.on('exit', cb.exit);
+    p.stdout.on('data', cb.stdout || function (out) {
+        process.stdout.write(out);
+    });
+    p.stderr.on('data', cb.stderr || function (err) {
+        process.stdout.write(err);
+    });
+};
+
+Mic.create = function (paramObj, client) {
+    console.log('Mic.create called');
+    var micProcess, micProcessArgs, mic, child, stdoutPath, exitPath;
+
+    stdoutPath = 'ws/fs/image/add/to';
+    exitPath = 'ws/fs/image/add/finished';
+
+    micProcess = 'sudo mic cr loop ' + paramObj.pathKsFile;
+    micProcessArgs = [];
+    micProcessArgs.push(util.format('-A %s', 'x86_64'));
+    micProcessArgs.push(util.format('-o %s', paramObj.pathOutput));
+
+    function sendMsg(path, msg) {
+        client.emit(path, msg);
+    }
+
+    Mic.subprocess(micProcess, micProcessArgs, {
+        stdout: function (out) {
+            console.log('stdout' + out);
+            sendMsg(stdoutPath, 'stdout: ' + out);
+        },
+        stderr: function (out) {
+            console.log('stderr' + out);
+            sendMsg(stdoutPath, 'stderr: ' + out);
+        },
+        exit: function (out) {
+            console.log('exit: ' + out);
+            sendMsg(exitPath, 'exit: ' + out);
+        }
+    });
+};
+
+module.exports = Mic;
\ No newline at end of file
index 736f115..f4d79f6 100644 (file)
@@ -6,10 +6,15 @@ var path = require('path');
 var FileSystem = {};
 
 FileSystem.list = function (dirPath) {
+    console.log('FileSystem.list called');
     var results, info, list;
 
     results = [];
 
+    if(!fs.existsSync(dirPath)) {
+        fs.mkdirSync(dirPath);
+    }
+
     list = fs.readdirSync(dirPath);
     list.forEach(function(file) {
         var fileStat, filePath;
@@ -26,7 +31,7 @@ FileSystem.list = function (dirPath) {
              * to be extended .. 
              */
             info = {
-                name: filePath,
+                name: file,
                 size: fileStat['size']
             }
             results.push(info);
diff --git a/server/routes/router.js b/server/routes/router.js
new file mode 100644 (file)
index 0000000..a276618
--- /dev/null
@@ -0,0 +1,37 @@
+var express = require('express');
+var router = express.Router();
+var mime = require('mime');
+var fs = require('fs');
+var path = require('path');
+
+router.use(function timeLog(req, res, next) {
+    var time = new Date();
+    console.log('Time: ', time.toISOString());
+    next();
+});
+
+/**
+ * API
+ * 
+ * path : /api/fs/download
+ * request body : {
+ *      filename: 'filename.ks'
+ * }
+ */
+router.get('/fs/download/:filename', function (req, res) {
+    var fileName, filePath, fileOptions, fileMimetype, fileStream;
+    console.log('>> file download called');
+
+    fileName = req.params.filename;
+    filePath = '/tmp/tic/images/' + fileName;
+    fileMimetype = mime.lookup(filePath);
+    console.log('>> filename: ' + req.params.filename + ', mime: ' + fileMimetype);
+
+    res.setHeader('Content-disposition', 'attachment; filename=' + fileName);
+    res.setHeader('Content-type', fileMimetype);
+
+    fileStream = fs.createReadStream(filePath);
+    fileStream.pipe(res);
+});
+
+module.exports = router;
\ No newline at end of file