diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..8568ba9
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,2 @@
+.git
+node_modules
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f0103aa
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+npm-debug.log
+node_modules
+.idea
+.dockerrun.sh
+.vscode
\ No newline at end of file
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..b26bd55
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,17 @@
+FROM node:4.4.1-slim
+MAINTAINER Rob Humphris
+
+# Copy the source to the Docker's usr directory
+COPY . /usr/src/app
+
+# Set the working directory accordingly
+WORKDIR /usr/src/app
+
+#Run npm install
+RUN npm install
+
+#Expose node port
+EXPOSE 3000
+
+#Start mongo and node
+CMD node appAcra.js
\ No newline at end of file
diff --git a/README.md b/README.md
index 6f29856..525be15 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,15 @@
- ACRA Node Server (v. 0.0.3)
+ ACRA Node Server (v. 0.0.4)
================
Server [ACRA](http://acra.ch/) for [Node.js](http://nodejs.org/) with data base [Mongodb](http://www.mongodb.org/)
Save all the crash reports in your own server.
+### version 0.0.4
+* Updated to work with Express 4.x
+* Updated to work with newer MongoDB
+
+
### version 0.0.3
* Statistics by android version.
* Statistics by date error.
@@ -15,14 +20,12 @@ Save all the crash reports in your own server.
Technologies Used
------------
-
Server = [node.js, express, ejs, mongodb, emailjs, node-properties-parser, colors, moment, async]
Client = [bootstrap, jquery, tablesorter, jqplot]
Installation
------------
-
1. Download and unzip (or git clone) into a directory.
2. Run "$ npm install"
3. Configure /acra_server.properties with mongodb, port web, user and password access and email credentials.
@@ -31,7 +34,6 @@ Installation
Philosophy
------------
-
* Build a Server to replace Google Docs.
* Write using modern tecnologies as Node.js and Mongodb.
* Simple configuration with a only one properties file.
@@ -39,7 +41,6 @@ Philosophy
Features
------------
-
* Basic front end web pages.
* Send emails when receive ACRA report.
* Login system to protect access.
@@ -145,7 +146,6 @@ date_format=YYYY-MM-DD hh:mm:ss
```
## Configuration Mongodb
-
Automatic configuration:
* Creation of DB automatic
@@ -153,7 +153,6 @@ Automatic configuration:
* Independent collections by App
## Access server
-
* http://my_server:port_server (and login)
diff --git a/acra_server.properties b/acra_server.properties
index 0f8a8c0..d8c57d9 100644
--- a/acra_server.properties
+++ b/acra_server.properties
@@ -13,19 +13,20 @@ secret = b29a25fe160453b475d4243d12yrty342345752eeaa5bc
# port mongodb
mongodb_port = 27017
# Ip mongodb
-mongodb_ip = localhost
+#mongodb_ip = localhost
+mongodb_ip = db.checkit-develop.elektron-dev.com
# Name Data base
name_database = acraloggerdb
# CONFIGURATION MAIL
# yes or no if want send email if acra error recive
-send_mail = yes
+send_mail = no
# config connection email server
user_mail= your_email@gmail.com
password_mail = password_mail_gmail
-host =smtp.gmail.com
+host = smtp.gmail.com
ssl = true
# config email
diff --git a/appAcra.js b/appAcra.js
index f58597f..c3c8cbe 100644
--- a/appAcra.js
+++ b/appAcra.js
@@ -1,55 +1,85 @@
var express = require('express');
var colors = require('colors');
var prop = require('./properties.js');
-var logger = require('./logger');
+var logger = require('morgan');
+var acraLogger = require('./logger.js');
+var bodyParser = require('body-parser');
+var cookieParser = require('cookie-parser')
+var favicon = require('serve-favicon');
+var session = require('express-session');
+var basicAuth = require('basic-auth');
+//function control errors
+function clientErrorHandler(err, req, res, next) {
+ console.log('client error handler found in ip:'+req.ip, err);
+ res.sendStatus(500);
+ res.render('error', {locals: {"error":err} });
+}
var app = express();
-
-app.configure(function () {
- app.use(express.logger('default')); /* 'default', 'short', 'tiny', 'dev' */
- app.use(express.bodyParser());
-});
-
app.use(express.static(__dirname + '/public'));
-app.use(express.favicon());
-app.use(express.cookieParser());
-app.use(express.cookieSession({
- key:prop.key,
- secret :prop.secret,
- cookie:{ path: '/', httpOnly: true, maxAge: null }
-}));
-
+app.use(favicon(__dirname + '/public/favicon.ico'));
+app.use(cookieParser());
app.use(clientErrorHandler);
-app.use( express.bodyParser());
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
-app.use(app.router);
+app.use(logger('dev'));
+app.use(bodyParser.json());
+function auth (req, res, next) {
+ function unauthorized(res) {
+ res.set('WWW-Authenticate', 'Basic realm=Authorization Required');
+ return res.sendStatus(401);
+ };
+ var user = basicAuth(req);
-//function control errors
-function clientErrorHandler(err, req, res, next) {
- console.log('client error handler found in ip:'+req.ip, err);
- res.status(500);
- res.render('error', {locals: {"error":err} });
-}
+ if (!user || !user.name || !user.pass) {
+ return unauthorized(res);
+ };
+
+ if (user.name === prop.username && user.pass === prop.password) {
+ return next();
+ } else {
+ return unauthorized(res);
+ };
+};
-var basicAuth = express.basicAuth(function(username, password) {
- return (username == prop.username && password == prop.password);
-}, 'Restrict area, please identify');
-
//Mobile without auth
-app.post('/logs/:appid', logger.addLog);
+app.post('/logs/:appid', acraLogger.addLog);
+app.put('/logs/:appid', acraLogger.addLog);
+
//Administration with auth
-app.get('/logs/:appid/:id', basicAuth, logger.findByIdDetail);
-app.get('/logsexport/:appid/:id', basicAuth, logger.findByIdDetailExport);
-app.get('/logs/:appid', basicAuth, logger.findAll);
-app.get('/logsexport/:appid', basicAuth, logger.findAllExport);
-app.get('/mobiles', basicAuth, logger.findAllCollections);
-app.get('/logs/:appid/:id/delete', basicAuth, logger.deleteLog);
-app.get('/logout', logger.logout);
+app.get('/logs/:appid/:id', auth, acraLogger.findByIdDetail);
+app.get('/logsexport/:appid/:id', auth, acraLogger.findByIdDetailExport);
+app.get('/logs/:appid', auth, acraLogger.findAll);
+app.get('/logsexport/:appid', auth, acraLogger.findAllExport);
+app.get('/mobiles', auth, acraLogger.findAllCollections);
+app.get('/logs/:appid/:id/delete', auth, acraLogger.deleteLog);
+app.get('/logout', acraLogger.logout);
+
+prop.loadProperties(() => {
+ acraLogger.open(prop, function(err) {
+ app.use(session({
+ secret: prop.secret,
+ resave: false,
+ saveUninitialized: false,
+ cookie: { path: '/', httpOnly: true, secure: true, maxAge: null }
+ }));
+ console.log("------------------".yellow);
+ app.listen(prop.portWeb);
+ console.log('Listening on port '.yellow+prop.portWeb.red);
+ });
+});
+
+
+
+
+
+
+
+
-console.log("------------------".yellow);
-app.listen(prop.portWeb);
-console.log('Listening on port '.yellow+prop.portWeb.red);
+
+
+
diff --git a/dockerrun.sh b/dockerrun.sh
new file mode 100644
index 0000000..fd3f094
--- /dev/null
+++ b/dockerrun.sh
@@ -0,0 +1 @@
+docker run -d --name acra-node-server --link mongo:mongodb elektron/acra-node-server
\ No newline at end of file
diff --git a/email.js b/email.js
index e2bbbf1..93b5953 100644
--- a/email.js
+++ b/email.js
@@ -8,7 +8,7 @@ var server = email.server.connect({
ssl: prop.ssl
});
-exports.send = function send (mobile,log) {
+exports.send = function send(mobile,log) {
if (prop.send_mail == 'yes') {
console.log('Send email with error model:'+log.PHONE_MODEL);
// send the message and get a callback with an error or details of the message that was sent
@@ -24,7 +24,10 @@ exports.send = function send (mobile,log) {
to: prop.to,
cc: "",
subject: prop.subject+ " from Mobile "+mobile
- }, function(err, message) { console.log(err || message); });
+ }, (err, message) =>
+ {
+ console.log(err || message);
+ });
}
}
diff --git a/logger.js b/logger.js
index 99aa00f..ff72ca8 100644
--- a/logger.js
+++ b/logger.js
@@ -1,44 +1,45 @@
var mongo = require('mongodb');
-var prop = require('./properties.js');
var email = require('./email.js');
var moment = require('moment');
var async = require('async');
var ejs = require('ejs');
-var DB_NAME = prop.name_database;
-
-var Server = mongo.Server,
- Db = mongo.Db,
- BSON = mongo.BSONPure;
-
-var server = new Server(prop.mongodbIp, prop.mongodbPort, {auto_reconnect: true, safe:false,journal:true});
-var db= new Db(DB_NAME, server);
-
-db.open(function(err, db) {
- if(!err) {
- console.log("Connected to data base ".yellow+DB_NAME.red);
- console.log("------------------".yellow);
- }
-});
+var l = {
+ server: null,
+ db: null,
+ prop: null,
+ open: function(p, cb) {
+ l.prop = p;
+ l.server = new mongo.Server(l.prop.mongodbIp, l.prop.mongodbPort, {auto_reconnect: true, safe:false,journal:true});
+ l.db = new mongo.Db(l.prop.name_database, l.server);
+ l.db.open(function(err, db) {
+ if(!err) {
+ console.log("Connected to data base ".yellow+l.prop.name_database.red);
+ console.log("------------------".yellow);
+ }
+ cb(err);
+ });
+ }
+};
//Export detail log of app in json format
-exports.findByIdDetailExport = function(req, res) {
+l.findByIdDetailExport = function(req, res) {
var appid = req.params.appid;
var id = req.params.id;
console.log("findByIdDetailExport.appid:"+appid);
console.log("findByIdDetailExport.id:"+id);
- db.collection(appid, function(err, collection) {
- collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
+ l.db.collection(appid, function(err, collection) {
+ collection.findOne({'_id':new mongo.BSONPure.ObjectID(id)}, function(err, item) {
res.send(item);
});
});
};
//Export all logs of app in json format
-exports.findAllExport = function(req, res) {
+l.findAllExport = function(req, res) {
var appid = req.params.appid;
console.log("findAllExport.appid:"+appid);
- db.collection(appid, function(err, collection) {
+ l.db.collection(appid, function(err, collection) {
collection.find().toArray(function(err, items) {
res.send(items);
});
@@ -46,89 +47,71 @@ exports.findAllExport = function(req, res) {
};
// VIEW - /views/detail.ejs
-exports.findByIdDetail = function(req, res) {
+l.findByIdDetail = function(req, res) {
var appid = req.params.appid;
var id = req.params.id;
console.log("findByIdDetail.appid:"+appid);
console.log("findByIdDetail.id:"+id);
- db.collection(appid, function(err, collection) {
- collection.findOne({'_id':new BSON.ObjectID(id)}, function(err, item) {
- res.render('detail', {locals: {"log":item,"appid":appid,"id":id} });
+ l.db.collection(appid, function(err, collection) {
+ collection.findOne({'_id':new mongo.BSONPure.ObjectID(id)}, function(err, item) {
+ res.render('detail', {log: item, appid: appid, id: id});
});
});
};
// VIEW - /views/listLogs.ejs
-exports.findAll = function(req, res) {
+l.findAll = function(req, res) {
var appid = req.params.appid;
console.log("findAll.appid:"+appid);
loadListLogs(appid,res);
};
// VIEW - /views/listMobiles.ejs
-exports.findAllCollections = function(req, res) {
- console.log("findAllCollections");
- db.collectionNames(function(err, names){
- res.render('listApps', {locals: {"list":names,"dbname":prop.name_database}});
- });
+l.findAllCollections = function(req, res) {
+ console.log("findAllCollections");
+ l.db.listCollections().toArray(function(err, names) {
+ res.render('listApps', { list: names, dbname: l.prop.name_database });
+ });
};
// VIEW - /views/delete.ejs
-exports.deleteLog = function(req, res) {
+l.deleteLog = function(req, res) {
var appid = req.params.appid;
var id = req.params.id;
console.log("deleteLog.appid:"+appid);
console.log("deleteLog.id:"+id);
- db.collection(appid, function(err, collection) {
- collection.remove({'_id':new BSON.ObjectID(id)}, {safe:true}, function(err, result) {
- res.render('delete', {locals: {"appid":appid,"err":err}});
+ l.db.collection(appid, function(err, collection) {
+ collection.remove({'_id':new mongo.BSONPure.ObjectID(id)}, {safe:true}, function(err, result) {
+ res.render('delete', {appid: appid, err: err});
});
});
}
// IMPORTANT - Method without security access
// Method to add info from mobile
-exports.addLog = function(req, res) {
+l.addLog = function(req, res) {
var appid = req.params.appid;
var log = req.body;
console.log("addLog.appid:"+appid);
- db.collection(appid, function(err, collection) {
+ l.db.collection(appid, function(err, collection) {
collection.insert(log, {safe:true}, function(err, result) {
if (err) {
console.log("Add log error:"+err);
res.send({'error':'An error has occurred'});
} else {
- console.log("addLog:OK save");
- //format date text to date format
- //to aggregate dates
- formatDate(result,collection);
- //After insert send email
- email.send(appid,log);
+ console.log("addLog:OK save");
+ email.send(appid, log);
res.send(result[0]);
}
});
});
}
-function formatDate(toSave,collection) {
- var doc = toSave[0];
- doc.USER_CRASH_DATE = new Date(doc.USER_CRASH_DATE);
- collection.update({_id:doc._id }, {
- $set: { 'USER_CRASH_DATE': doc.USER_CRASH_DATE },
- }, function(err) {
- if (!err) {
- console.log("Error:"+err);
- } else {
- console.log("Modify date format");
- }
- });
-}
-
//Logout and delete cookie
-exports.logout = function (req, res) {
+l.logout = function (req, res) {
console.log("logout");
req.session = null;
- res.clearCookie(prop.key);
+ res.clearCookie(l.prop.key);
res.redirect('/index.html');
}
@@ -138,7 +121,7 @@ function loadListLogs(appid,res) {
var resultSearch = {};
async.parallel([
function(callback) {
- db.collection(appid, function(err, collection) {
+ l.db.collection(appid, function(err, collection) {
collection.aggregate([
{ $group : { _id : {android :"$ANDROID_VERSION"} , number : { $sum : 1 } } },
{ $sort : { number : -1 } },
@@ -149,7 +132,7 @@ function loadListLogs(appid,res) {
});
});
}, function(callback) {
- db.collection(appid, function(err, collection) {
+ l.db.collection(appid, function(err, collection) {
collection.aggregate([
{ $group : { _id : {movile :"$PHONE_MODEL"} , number : { $sum : 1 } } },
{ $sort : { number : -1 } },
@@ -161,7 +144,7 @@ function loadListLogs(appid,res) {
});
},
function(callback) {
- db.collection(appid, function(err, collection) {
+ l.db.collection(appid, function(err, collection) {
collection.aggregate([
{ $group : { _id : {year:{$year :"$USER_CRASH_DATE"},month:{$month :"$USER_CRASH_DATE"}} , number : { $sum : 1 } } },
{ $sort : { _id : -1 } },
@@ -173,11 +156,11 @@ function loadListLogs(appid,res) {
});
},
function(callback) {
- db.collection(appid, function(err, collection) {
+ l.db.collection(appid, function(err, collection) {
collection.find().toArray(function(err, items) {
for (var i = 0; i < items.length; i++) {
if (items[i].USER_APP_START_DATE.length > 0 ) {
- items[i].USER_APP_START_DATE = moment(items[i].USER_APP_START_DATE).format(prop.date_format);
+ items[i].USER_APP_START_DATE = moment(items[i].USER_APP_START_DATE).format(l.prop.date_format);
}
}
resultSearch.logs = items;
@@ -186,7 +169,8 @@ function loadListLogs(appid,res) {
});
}
], function(err) {
- res.render('listLogs', {locals: {"list":resultSearch.logs,"mobiles":resultSearch.agg_phone,"android":resultSearch.android,"dates":resultSearch.dates,"appid":appid} });
+ res.render('listLogs', {list: resultSearch.logs, mobiles: resultSearch.agg_phone, android: resultSearch.android, dates: resultSearch.dates, appid: appid});
});
}
+module.exports = l;
\ No newline at end of file
diff --git a/package.json b/package.json
index 6cf872e..808bae5 100644
--- a/package.json
+++ b/package.json
@@ -1,18 +1,33 @@
{
- "name": "acra_server_log",
+ "name": "acra-node-server",
"description": "Acra Server with nodejs and mongodb",
"author": "Diego Martin MorenoACRA Node Server
- © 2013 Sinclinal.com - Version 0.0.3 + © 2013 Sinclinal.com - Version 0.0.4