summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/explorer.js93
-rw-r--r--package.json6
-rw-r--r--public/stylesheets/style.css23
-rw-r--r--routes/index.js36
-rw-r--r--views/data.jade19
5 files changed, 137 insertions, 40 deletions
diff --git a/lib/explorer.js b/lib/explorer.js
new file mode 100644
index 0000000..57f5f64
--- /dev/null
+++ b/lib/explorer.js
@@ -0,0 +1,93 @@
+var http = require('http');
+var nodemailer = require('nodemailer');
+var url = require('url')
+
+var mailTransport
+if(process.env.SMTP_HOST) {
+ mailTransport = nodemailer.createTransport('SMTP', {
+ host: process.env.SMTP_HOST,
+ name: process.env.SMTP_NAME,
+ debug: process.env.SMTP_DEBUG === 'true',
+ auth: {
+ user: process.env.SMTP_AUTH_USER,
+ pass: process.env.SMTP_AUTH_PASS,
+ }
+ });
+}
+
+function fetchCollection(u, cb) {
+ var options = url.parse(u);
+ options.headers = {
+ accept: 'application/vnd.collection+json'
+ };
+ var start = new Date();
+ var req = http.get(options, function(res) {
+ res.setEncoding('utf8');
+ var body = '';
+ res.on('data', function (chunk) {
+ body += chunk;
+ });
+ res.on('end', function () {
+ var result = {
+ req: {
+ uri: options.uri,
+ headers: options.headers,
+ },
+ res: {
+ status: '',
+ statusCode: res.statusCode,
+ time: (new Date().getTime() - start.getTime()),
+ headers: res.headers,
+ },
+ body: body
+ };
+ sendMail(undefined, result);
+ cb(undefined, result);
+ });
+ }).on('error', function() {
+ cb('Unable to fetch ' + u);
+ sendMail('Unable to fetch ' + u);
+ });
+}
+
+function sendMail(err, result) {
+ if(!mailTransport) {
+ return;
+ }
+
+ if(err) {
+ }
+ else {
+ mailTransport.sendMail({
+ from: process.env.SMTP_FROM,
+ to: process.env.SMTP_TO,
+ subject: 'explorer',
+ attachments: [
+ {
+ fileName: 'request.json',
+ contents: JSON.stringify(result.req),
+ contentType: 'application/json',
+ },
+ {
+ fileName: 'response-meta.json',
+ contents: JSON.stringify(result.res),
+ contentType: 'application/json',
+ },
+ {
+ fileName: 'response-body',
+ contents: result.body,
+ contentType: result.res.headers['content-type']
+ }
+ ]
+ }, function(error, responseStatus) {
+ if(!error){
+ console.log('Message sent: ' + responseStatus.message);
+ }
+ else {
+ console.warn('Message not sent: ' + error);
+ }
+ });
+ }
+}
+
+module.exports.fetchCollection = fetchCollection;
diff --git a/package.json b/package.json
index f8a0fcc..420f4f3 100644
--- a/package.json
+++ b/package.json
@@ -3,12 +3,13 @@
"version": "0.0.1",
"private": true,
"scripts": {
- "start": "node app"
+ "test": "./node_modules/.bin/mocha"
},
"dependencies": {
"collection_json": "git+http://trygvis.dyndns.org/~trygvis/git/2012/06/collection_json.js.git",
"express": "3.0.0beta4",
"jade": "~0.26.3",
+ "nodemailer": "~0.3.21",
"underscore": "~1.3.3"
},
"devDependencies": {
@@ -17,8 +18,5 @@
"engines": {
"node": "0.6.x",
"npm": "1.1.x"
- },
- "scripts": {
- "test": "./node_modules/.bin/mocha"
}
}
diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css
index 9096f12..09dd30c 100644
--- a/public/stylesheets/style.css
+++ b/public/stylesheets/style.css
@@ -23,6 +23,9 @@
}
}
+/**
+ * Forms
+ */
table.cj-form th {
text-align: right;
min-width: 300px;
@@ -37,3 +40,23 @@ table.cj-form tbody td,
table.cj-form tbody input {
width: 100%;
}
+
+/**
+ * Item's data table
+ */
+table.data-table {
+ margin-top: 1em;
+ margin-bottom: 1em;
+}
+
+table.data-table th {
+ text-align: right;
+ padding-right: 1em;
+ font-weight: bold;
+ min-width: 120px;
+}
+
+table.data-table th,
+table.data-table td {
+ vertical-align: top;
+}
diff --git a/routes/index.js b/routes/index.js
index 702ec0f..fff06b6 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -1,4 +1,5 @@
var collection_json = require('collection_json')
+ , explorer = require('../lib/explorer.js')
, http = require('http')
, url = require('url')
, util = require('util')
@@ -162,16 +163,16 @@ exports.render = function(req, res) {
var u = url.parse(req.query.url, true);
var params = extractParams(req.query);
u.query = _.extend({}, u.query, params);
- fetchCollection(url.format(u), function(err, httpResponse) {
+ explorer.fetchCollection(url.format(u), function(err, result) {
if(err) {
- sendErr(req, res, err, httpResponse);
+ sendErr(req, res, err, result);
return;
}
var parsedBody;
try {
- parsedBody = JSON.parse(httpResponse.body);
+ parsedBody = JSON.parse(result.body);
} catch(e) {
- sendErr(req, res, 'Unable to parse JSON: ' + e, httpResponse);
+ sendErr(req, res, 'Unable to parse JSON: ' + e, result);
return;
}
res.render('data', {
@@ -179,33 +180,10 @@ exports.render = function(req, res) {
url: req.query.url, referer: req.query.referer,
params: params,
root: collection_json.fromObject(parsedBody),
- httpResponse: httpResponse,
+ httpResponse: result.res,
parsedBody: parsedBody,
- rawBody: httpResponse.body
+ rawBody: result.body
});
});
};
-function fetchCollection(u, cb) {
- var options = url.parse(u);
- options.headers = {
- accept: 'application/vnd.collection+json'
- };
- var req = http.get(options, function(res) {
- res.setEncoding('utf8');
- var body = '';
- res.on('data', function (chunk) {
- body += chunk;
- });
- res.on('end', function () {
- cb(undefined, {
- statusCode: res.statusCode,
- status: '',
- headers: res.headers,
- body: body
- });
- });
- }).on('error', function() {
- cb('Unable to fetch ' + u);
- });
-}
diff --git a/views/data.jade b/views/data.jade
index 9dd54e4..203353f 100644
--- a/views/data.jade
+++ b/views/data.jade
@@ -121,9 +121,11 @@ block items
|
a(class='btn btn-danger btn-mini', href=urlgenerator.delete(url, item.href)) Delete
- dl
- dt href
- dd: div: mixin href(item.href)
+ div(class='fluid-row')
+ div(class='span12')
+ dl
+ dt href
+ dd: div: mixin href(item.href)
if item.links.length > 0
h3 Item Links
@@ -132,10 +134,13 @@ block items
block link
h3 Data
- dl(class='dl-horizontal')
- each data in item.data
- dt #{data.name}
- dd #{data.value}
+ div(class='fluid-row')
+ div(class='span12')
+ table.data-table
+ each data in item.data
+ tr
+ th #{data.name}
+ td #{data.value}
block items_links