better separation, minor fixes

This commit is contained in:
AJ ONeal 2015-01-13 14:50:17 -07:00
parent e5867b00a5
commit cfa1688085
8 changed files with 286 additions and 162 deletions

63
bin/deardesi.js Normal file
View File

@ -0,0 +1,63 @@
'use strict';
var PromiseA = require('bluebird')
, fs = PromiseA.promisifyAll(require('fs'))
, path = require('path')
, cli = require('cli')
;
cli.parse({
blog: ['b', 'Where your blog is, i.e. ~/path/to/blog', 'string', './']
//, output: ['o', 'name of output directory within ~/path/to/blog', 'string', './compiled']
});
function serve(blogdir) {
var http = require('http')
//, https = require('https')
, app = require('../server').create({ blogdir: blogdir })
, server
;
server = http.createServer(app).listen(65080, function () {
console.log("Listening from " + blogdir);
console.log("Listening on http://local.dear.desi:" + server.address().port);
});
//secureServer = https.createServer(app).listen(65043);
}
cli.main(function (args, options) {
var command = args[0]
, blogdir = options.blog
;
if (!blogdir) {
blogdir = path.resolve('./');
}
if (!fs.existsSync(path.join(options.blog, 'site.yml'))) {
console.error("Usage: deardesi [serve|init|post] -b ~/path/to/blog");
console.error("(if ~/path/to/blog doesn't yet exist or doesn't have config.yml, site.yml, etc, "
+ "try `deardesi init -b ~/path/to/blog'");
process.exit(1);
return;
}
if ('init' === command) {
console.error("`init' not yet implemented");
process.exit(1);
return;
}
else if ('post' === command) {
console.error("`post' not yet implemented");
process.exit(1);
return;
}
else if ('serve' === command) {
serve(blogdir);
return;
}
else {
console.error("Usage: deardesi [serve|init|post] -b ~/path/to/blog");
return;
}
});

View File

@ -1,13 +1,22 @@
angular.module('myApp.services', []). angular.module('myApp.services', []).
factory('Desirae', ['$q', function($q) { factory('Desirae', ['$q', '$http', function ($q, $http) {
var Desi = window.Desi || require('./deardesi').Desi var Desi = window.Desi || require('./deardesi').Desi
, desi = {} , desi = {/*TODO api_base: '/api'*/}
, fsapi = window.fsapi , fsapi = window.fsapi
; ;
function getBlogdir () {
return $http.get('/api/fs/rootdir').then(function (resp) {
desi.blogdir = resp.data;
return resp.data;
});
}
getBlogdir();
return { return {
reset: function () { reset: function () {
desi = {}; desi = {};
return getBlogdir();
} }
, toDesiDate: Desi.toLocaleDate , toDesiDate: Desi.toLocaleDate
, meta: function () { , meta: function () {

@ -1 +1 @@
Subproject commit 3235b6c182a6cff73fc3a2482b347979ad126b01 Subproject commit 4b7106363794014edd7575a6892fae98c5f83d70

134
desirae-http-api.js Normal file
View File

@ -0,0 +1,134 @@
'use strict';
var fsapi = require('./desirae/lib/fsapi').fsapi
, path = require('path')
;
module.exports.create = function (options) {
var restful = {}
;
//
// Required for desirae
//
restful.walk = function (req, res, next) {
if (!(/^GET$/i.test(req.method) || /^GET$/i.test(req.query._method))) {
next();
return;
}
var opts = {}
, dirnames = req.query.dir && [req.query.dir] || (req.query.dirs && req.query.dirs.split(/,/g)) || req.body.dirs
;
if (!dirnames || !dirnames.length) {
res.json({ error: "please specify GET w/ req.query.dir or POST w/ _method=GET&dirs=path/to/thing,..." });
return;
}
if (!dirnames.every(function (dirname) {
return 'string' === typeof dirname;
})) {
res.json({ error: "malformed request: " + JSON.stringify(dirnames) });
return;
}
/*
if (req.query.excludes) {
opts.excludes = req.query.excludes.split(',');
}
*/
if (req.query.extensions) {
opts.extensions = req.query.extensions.split(/,/g);
}
if ('true' === req.query.dotfiles) {
opts.dotfiles = true;
}
if ('false' === req.query.sha1sum) {
opts.sha1sum = false;
}
if ('true' === req.query.contents) {
opts.contents = true;
}
// TODO opts.contents?
fsapi.walk.walkDirs(options.blogdir, dirnames, opts).then(function (stats) {
if (!req.body.dirs && !req.query.dirs) {
res.json(stats[dirnames[0]]);
} else {
res.json(stats);
}
});
};
restful.getFiles = function (req, res, next) {
if (!(/^GET$/i.test(req.method) || /^GET$/i.test(req.query._method))) {
next();
return;
}
var filepaths = req.query.path && [req.query.path] || (req.query.paths && req.query.paths.split(/,/g)) || req.body.paths
;
if (!filepaths || !filepaths.length) {
res.json({ error: "please specify GET w/ req.query.path or POST _method=GET&paths=path/to/thing,..." });
return;
}
return fsapi.getfs(options.blogdir, filepaths).then(function (files) {
if (!req.body.paths && !req.query.paths) {
res.json(files[0]);
} else {
res.send(files);
}
});
};
restful.putFiles = function (req, res, next) {
if (!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))) {
next();
return;
}
var opts = {}
, files = req.body.files
;
if (!files || !files.length) {
res.json({ error: "please specify POST w/ req.body.files" });
return;
}
opts.tmpdir = options.tmpdir;
return fsapi.putfs(options.blogdir, files, opts).then(function (results) {
res.json(results);
});
};
restful.copy = function (req, res, next) {
if (!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))) {
next();
return;
}
var opts = {}
, files = req.body.files
;
if ('object' !== typeof files || !Object.keys(files).length) {
res.json({ error: "please specify POST w/ req.body.files" });
return;
}
return fsapi.copyfs(options.blogdir, files, opts).then(function (results) {
res.json(results);
});
};
//
// end Desirae API
//
return restful;
};

View File

@ -6,6 +6,9 @@
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1" "test": "echo \"Error: no test specified\" && exit 1"
}, },
"bin": {
"deardesi": "bin/deardesi.js"
},
"repository": { "repository": {
"type": "git", "type": "git",
"url": "https://github.com/DearDesi/deardesi.git" "url": "https://github.com/DearDesi/deardesi.git"
@ -35,6 +38,7 @@
"dependencies": { "dependencies": {
"bluebird": "^2.6.4", "bluebird": "^2.6.4",
"body-parser": "^1.10.1", "body-parser": "^1.10.1",
"cli": "^0.6.5",
"compression": "^1.3.0", "compression": "^1.3.0",
"connect": "^3.3.4", "connect": "^3.3.4",
"connect-query": "^0.2.0", "connect-query": "^0.2.0",

175
server.js
View File

@ -1,173 +1,66 @@
'use strict'; 'use strict';
require('require-yaml'); module.exports.create = function (options) {
var connect = require('connect')
var connect = require('connect')
//, PromiseA = require('bluebird').Promise
, query = require('connect-query') , query = require('connect-query')
, bodyParser = require('body-parser') , bodyParser = require('body-parser')
, serveStatic = require('serve-static') , serveStatic = require('serve-static')
, send = require('connect-send-json') , send = require('connect-send-json')
, app = connect()
, fsapi = require('./desirae/lib/fsapi')
, walk = require('./desirae/lib/fsapi').walk
, getfs = require('./desirae/lib/fsapi').getfs
, putfs = require('./desirae/lib/fsapi').putfs
, blogdir = process.argv[2]
, port = process.argv[3] || '65080'
, path = require('path') , path = require('path')
//, config = require(path.join('./', blogdir, 'config.yml'))
, app = connect()
, restful = require('./desirae-http-api').create(options)
; ;
if (!blogdir) { app
console.error("Usage: deardesi ~/path/to/blog");
process.exit(1);
return;
}
app
.use(send.json()) .use(send.json())
.use(query()) .use(query())
.use(bodyParser.json({ limit: 10 * 1024 * 1024 })) // 10mb .use(bodyParser.json({ limit: 10 * 1024 * 1024 })) // 10mb
.use(require('compression')()) .use(require('compression')())
.use('/api/fs/walk', function (req, res, next) {
if (!(/^GET$/i.test(req.method) || /^GET$/i.test(req.query._method))) {
next();
return;
}
var opts = {}
, dirnames = req.query.dir && [req.query.dir] || (req.query.dirs && req.query.dirs.split(/,/g)) || req.body.dirs
; ;
if (!dirnames || !dirnames.length) { //
res.json({ error: "please specify GET w/ req.query.dir or POST w/ _method=GET&dirs=path/to/thing,..." }); // Keeping the API *required* by desirae super minimal
return; // so that it can be implemented easily in any language
} //
app
if (!dirnames.every(function (dirname) { .use('/api/fs/static', serveStatic(options.blogdir))
return 'string' === typeof dirname; .use('/api/fs/walk', restful.walk)
})) { .use('/api/fs/files', restful.getFiles)
res.json({ error: "malformed request: " + JSON.stringify(dirnames) }); .use('/api/fs/files', restful.putFiles)
return; .use('/api/fs/copy', restful.copy)
}
/*
if (req.query.excludes) {
opts.excludes = req.query.excludes.split(',');
}
*/
if (req.query.extensions) {
opts.extensions = req.query.extensions.split(/,/g);
}
if ('true' === req.query.dotfiles) {
opts.dotfiles = true;
}
if ('false' === req.query.sha1sum) {
opts.sha1sum = false;
}
if ('true' === req.query.contents) {
opts.contents = true;
}
// TODO opts.contents?
walk.walkDirs(blogdir, dirnames, opts).then(function (stats) {
if (!req.body.dirs && !req.query.dirs) {
res.json(stats[dirnames[0]]);
} else {
res.json(stats);
}
});
})
.use('/api/fs/files', function (req, res, next) {
if (!(/^GET$/i.test(req.method) || /^GET$/i.test(req.query._method))) {
next();
return;
}
var filepaths = req.query.path && [req.query.path] || (req.query.paths && req.query.paths.split(/,/g)) || req.body.paths
; ;
// end Desirae API
if (!filepaths || !filepaths.length) { if (options.tmpdir) {
res.json({ error: "please specify GET w/ req.query.path or POST _method=GET&paths=path/to/thing,..." }); app.use(serveStatic(options.tmpdir));
return;
} }
return getfs(blogdir, filepaths).then(function (files) { // this is used by DearDesi, but not required for desirae
if (!req.body.paths && !req.query.paths) { app
res.json(files[0]); .use('/api/fs/rootdir', function (req, res) {
} else { var pathname = path.resolve(options.blogdir)
res.send(files);
}
});
})
.use('/api/fs/files', function (req, res, next) {
if (!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))) {
next();
return;
}
var opts = {}
, files = req.body.files
;
if (!files || !files.length) {
res.json({ error: "please specify POST w/ req.body.files" });
return;
}
return putfs(blogdir, files, opts).then(function (results) {
res.json(results);
});
})
.use('/api/fs/copy', function (req, res, next) {
if (!(/^POST|PUT$/i.test(req.method) || /^POST|PUT$/i.test(req.query._method))) {
next();
return;
}
var opts = {}
, files = req.body.files
;
if ('object' !== typeof files || !Object.keys(files).length) {
res.json({ error: "please specify POST w/ req.body.files" });
return;
}
return fsapi.copyfs(blogdir, files, opts).then(function (results) {
res.json(results);
});
})
.use('/api/fs', function (req, res) {
var pathname = path.resolve(blogdir)
; ;
res.json({ res.json({
path: pathname path: pathname
, name: path.basename(pathname) , name: path.basename(pathname)
, relativePath: path.dirname(pathname) , relativePath: path.dirname(pathname)
//, cwd: path.resolve()
//, patharg: blogdir
}); });
return; return;
}) })
.use('/api/fs/static', serveStatic(blogdir))
.use(serveStatic('./'))
.use('/compiled_dev', serveStatic(path.join(blogdir, '/compiled_dev')))
// TODO
//.use(serveStatic(tmpdir))
; ;
module.exports = app; app
// the AngularJS App
.use(serveStatic(__dirname))
// TODO change file requests to '/blog'
//.use(serveStatic(options.blogdir))
.use('/blog', serveStatic(options.blogdir))
.use('/compiled_dev', serveStatic(path.join(options.blogdir, '/compiled_dev')))
//.use('/compiled', serveStatic(path.join(options.blogdir, '/compiled')))
;
require('http').createServer().on('request', app).listen(port, function () { return app;
console.log('listening from ' + blogdir + ' http://local.dear.desi:' + port); };
});

View File

@ -3,7 +3,7 @@
<div class="row"> <div class="row">
<div class="page-header"> <div class="page-header">
<h1>Write a Post</h1> <h1>Write a Post</h1>
<h3><span ng-bind="Post.selected.abspath" ></span></h3> <h3><span ng-bind="Post.selected.post.yml.permalink" ></span></h3>
</div> </div>
</div> </div>
@ -105,6 +105,22 @@
</div> </div>
</div> </div>
<div class="form-group">
<label for="inputPostAbsPath" class="col-lg-2 control-label">URL</label>
<div class="col-lg-10">
<input
required="required"
disabled
ng-model="Post.selected.url"
ng-change="Post.onChange()"
type="text"
class="form-control"
id="inputPostAbsPath"
placeholder="i.e. https://blog.me.co/posts/my-first-post/"
>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label for="inputPostAbsPath" class="col-lg-2 control-label">Filepath</label> <label for="inputPostAbsPath" class="col-lg-2 control-label">Filepath</label>
<div class="col-lg-10"> <div class="col-lg-10">

View File

@ -88,6 +88,8 @@ angular.module('myApp.post', ['ngRoute'])
if (!/\.html?$/.test(selected.path)) { if (!/\.html?$/.test(selected.path)) {
selected.path = window.path.join(selected.path, 'index.html'); selected.path = window.path.join(selected.path, 'index.html');
} }
selected.url = window.path.join(scope.site.base_url + window.path.join(scope.site.base_path, post.yml.permalink));
selected.abspath = window.path.join(scope.blogdir, selected.path); selected.abspath = window.path.join(scope.blogdir, selected.path);
}; };
scope.onFrontmatterChange = function () { scope.onFrontmatterChange = function () {
@ -107,10 +109,13 @@ angular.module('myApp.post', ['ngRoute'])
scope.selected.post.yml = data; scope.selected.post.yml = data;
post = scope.selected.post; post = scope.selected.post;
scope.selected.path = window.path.join((scope.selected.collection || 'posts'), window.path.basename(post.yml.permalink)); scope.selected.path = window.path.join((scope.selected.collection || 'posts'), window.path.basename(post.yml.permalink));
if (!/\.html?$/.test(scope.selected.path)) { if (!/\.html?$/.test(window.path.basename(post.yml.permalink))) {
scope.selected.path = window.path.join(scope.selected.path, 'index.html'); scope.selected.path = window.path.join(scope.selected.path.replace(/\.w+$/, ''), 'index.html');
} }
scope.selected.url = window.path.join(scope.site.base_url + window.path.join(scope.site.base_path, post.yml.permalink));
scope.selected.abspath = window.path.join(scope.blogdir, scope.selected.path);
} catch(e) { } catch(e) {
console.error(e); console.error(e);
console.error('ignoring update that created parse error'); console.error('ignoring update that created parse error');