Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'release/v0.3.0'

  • Loading branch information...
commit a0599d4807a4d60d4b1c6b60a9500578aafa2015 2 parents 48f7f52 + 308bec9
@andzdroid authored
View
171 app.js
@@ -6,8 +6,8 @@ var express = require('express')
, routes = require('./routes')
, http = require('http');
-//TODO: remove underscore.js from dependencies or is it more often
-_ = require('underscore');
+var _ = require('underscore');
+var utils = require('./utils');
var mongodb = require('mongodb');
//var cons = require('consolidate');
@@ -15,12 +15,6 @@ var swig = require('swig');
var swig_filters = require('./filters');
var app = express();
-var config = require('./config');
-var host = config.mongodb.host || 'localhost';
-var port = config.mongodb.port || mongodb.Connection.DEFAULT_PORT;
-var db = new mongodb.Db(config.mongodb.database, new mongodb.Server(host, port, {auto_reconnect: true}));
-
-
//Set up swig
swig.init({
root: __dirname + '/views',
@@ -61,46 +55,169 @@ app.configure('development', function(){
app.use(express.errorHandler());
});
-//View helper, sets local variables used in templates
-app.locals.use(function(req, res) {
- res.locals.base_href = config.site.base_url;
- res.locals.collections = app.set('collections');
- res.locals.database = config.mongodb.database;
-});
+
+//Set up database stuff
+var config = require('./config');
+var host = config.mongodb.host || 'localhost';
+var port = config.mongodb.port || mongodb.Connection.DEFAULT_PORT;
+var db = new mongodb.Db('local', new mongodb.Server(host, port, {auto_reconnect: true}));
+
+
+var connections = {};
+var databases = [];
+var collections = {};
+var adminDb;
+var mainConn; //main db connection
+
+
+
+//Update the collections list
+var updateCollections = function(db, db_name, callback) {
+ db.collectionNames(function (err, result) {
+ var names = [];
+
+ for (var r in result) {
+ names.push(utils.parseCollectionName(result[r].name));
+ }
+
+ collections[db_name] = names.sort();
+
+ if (callback) {
+ callback(err);
+ }
+ });
+};
+
+//Update database list
+var updateDatabases = function(admin) {
+ admin.listDatabases(function(err, dbs) {
+ if (err) {
+ //TODO: handle error
+ console.error(err);
+ }
+
+ for (var key in dbs.databases) {
+ var db_name = dbs.databases[key]['name'];
+
+ //'local' is special database, ignore it
+ if (db_name == 'local') {
+ continue;
+ }
+
+ connections[db_name] = mainConn.db(db_name);
+ databases.push(db_name);
+
+ updateCollections(connections[db_name], db_name);
+ }
+
+ //Sort database names
+ databases = databases.sort();
+ });
+};
//Connect to mongodb database
db.open(function(err, db) {
if (!err) {
console.log('Database connected!');
- app.set('db', db);
- db.collectionNames(function(err, names) {
- app.set('collections', _.sortBy(names, 'name'));
+ mainConn = db;
+
+ //get admin instance
+ db.admin(function(err, a) {
+ adminDb = a;
+
+ if (config.mongodb.username.length == 0) {
+ console.log('Admin DB connected');
+ updateDatabases(adminDb);
+ } else {
+ //auth details were supplied, authenticate admin account with them
+ adminDb.authenticate(config.mongodb.username, config.mongodb.password, function(err, result) {
+ if (err) {
+ //TODO: handle error
+ console.error(err);
+ }
+
+ console.log('Admin DB connected');
+ updateDatabases(adminDb);
+ });
+ }
});
} else {
throw err;
}
});
+//View helper, sets local variables used in templates
+app.locals.use(function(req, res) {
+ res.locals.base_href = config.site.base_url;
+ res.locals.databases = databases;
+ res.locals.collections = collections;
+});
+
+
+//route param pre-conditions
+app.param('database', function(req, res, next, id) {
+ //Make sure database exists
+ if (!_.include(databases, id)) {
+ //TODO: handle error
+ return next('Error!');
+ }
+
+ req.db_name = id;
+ res.locals.db_name = id;
+
+ if (connections[id] !== undefined) {
+ req.db = connections[id];
+ } else {
+ connections[id] = mainConn.db(id);
+ req.db = connections[id];
+ }
+
+ next();
+});
+
+//:collection param MUST be preceded by a :database param
+app.param('collection', function(req, res, next, id) {
+ //Make sure collection exists
+ if (!_.include(collections[req.db_name], id)) {
+ //TODO: handle error
+ return next('Error!');
+ }
+
+ req.collection_name = id;
+ res.locals.collection_name = id;
+
+ connections[req.db_name].collection(id, function(err, coll) {
+ if (err) {
+ //TODO: handle error
+ return next('Error!');
+ }
+
+ req.collection = coll;
+
+ next();
+ });
+});
+
+
//mongodb middleware
var middleware = function(req, res, next) {
- req.db = app.set('db');
- req.collections = app.set('collections');
- req.database = config.mongodb.database;
+ req.adminDb = adminDb;
+ req.databases = databases; //List of database names
+ req.collections = collections; //List of collection names in all databases
+
+ //Allow page handlers to request an update for collection list
+ req.updateCollections = updateCollections;
- req.updateCollections = function(collections) {
- app.set('collections', _.sortBy(collections, 'name'));
- };
next();
};
//Routes
app.get('/', middleware, routes.index);
-app.post('/', middleware, routes.createCollection);
-//TODO: Use route param pre-conditions to automatically assign collection name variables to request
-app.get('/db/:collection', middleware, routes.collection);
-app.del('/db/:collection', middleware, routes.deleteCollection);
+//app.post('/db/:database', middleware, routes.createCollection);
+app.get('/db/:database/:collection', middleware, routes.viewCollection);
+app.del('/db/:database/:collection', middleware, routes.deleteCollection);
app.listen(config.site.port || 80);
View
5 config.js
@@ -2,7 +2,10 @@ module.exports = {
mongodb: {
server: 'localhost',
port: 27017,
- database: 'test'
+ //username and password must be for admin account
+ //leave it empty if no admin account
+ username: '',
+ password: ''
},
site: {
//base_url: the URL that mongo express will be located at
View
2  package.json
@@ -2,7 +2,7 @@
"author": "Chun-hao Hu <hu.chunhao@gmail.com> (http://blog.huchunhao.com)",
"name": "mongo-express",
"description": "Web-based admin interface for MongoDB",
- "version": "0.2.3",
+ "version": "0.3.0",
"repository": {
"type": "git",
"url": "git://github.com/andzdroid/mongo-express.git"
View
87 routes/collection.js
@@ -2,80 +2,32 @@ var utils = require('../utils');
//view all entries in a collection
-exports.collection = function(req, res, next) {
- var db = req.db;
- var collection_name = req.params.collection;
-
- var getCollection = function() {
- //remove database prefix from collection name
- var coll_name = utils.parseCollectionName(collection_name);
-
- //get collection
- db.collection(coll_name, function(err, collection) {
- if (err) {
- //TODO: handle error
- console.error(err);
- }
+exports.viewCollection = function(req, res, next) {
+ var query_options = {
+ limit: 20,
+ skip: 0
+ };
- var query_options = {
- limit: 20,
- skip: 0
+ req.collection.find({}, query_options).toArray(function(err, items) {
+ req.collection.stats(function(err, stats) {
+ var ctx = {
+ title: 'Viewing Collection: ' + req.collection_name,
+ documents: items,
+ stats: stats
};
- //get documents from the collection
- collection.find({}, query_options).toArray(function(err, items) {
- collection.stats(function(err, stats) {
- var ctx = {
- title: 'Viewing Collection: ' + collection_name,
- collection: collection_name,
- documents: items,
- stats: stats
- };
-
- res.render('collection', ctx);
- });
- });
+ res.render('collection', ctx);
});
- };
-
- //Check if collection name is in list of collections
- for (var key in req.collections) {
- if (req.collections[key].name == collection_name) {
- return getCollection();
- }
- }
-
- var found = false;
- //Check if collection is in db
- db.collectionNames(function(err, names) {
- if (err) {
- //TODO: handle error
- console.error(err);
- }
+ });
+};
- for (var key in names) {
- if (names[key].name == collection_name) {
- req.updateCollections(names);
- getCollection();
- found = true;
- return;
- }
- }
- if (found === false) {
- //TODO: show error page for non-existent collection
- next();
- }
- });
+exports.addCollection = function(req, res, next) {
};
exports.deleteCollection = function(req, res, next) {
- var db = req.db;
- var collection = req.params.collection;
- var collection_name = utils.parseCollectionName(collection);
-
- db.dropCollection(collection_name, function(err, result) {
+ req.collection.drop(function(err, result) {
if (err) {
//TODO: handle error
console.error(err);
@@ -83,16 +35,13 @@ exports.deleteCollection = function(req, res, next) {
//If delete was successful, result === true
- //Update list of collections
- db.collectionNames(function(err, names) {
+ req.updateCollections(req.db, req.db_name, function(err) {
if (err) {
//TODO: handle error
console.error(err);
}
- req.updateCollections(names);
-
- res.redirect('/');
+ res.redirect('/db/' + req.db_name);
});
});
};
View
28 routes/index.js
@@ -1,27 +1,23 @@
//Add routes from other files
var coll = require('./collection');
-exports.collection = coll.collection;
+exports.viewCollection = coll.viewCollection;
+exports.addCollection = coll.addCollection;
exports.deleteCollection = coll.deleteCollection;
//Homepage route
exports.index = function(req, res){
- var db = req.db;
+ req.adminDb.serverStatus(function(err, info) {
+ if (err) {
+ //TODO: handle error
+ console.error(err);
+ }
- //TODO: add possibility to add admin credentials to config and authenticate as admin
- db.admin(function(err, admin) {
- admin.serverStatus(function(err, info) {
- if (err) {
- //TODO: handle error
- console.error(err);
- }
-
- var ctx = {
- title: 'Mongo Express',
- info: info
- };
- res.render('index', ctx);
- });
+ var ctx = {
+ title: 'Mongo Express',
+ info: info
+ };
+ res.render('index', ctx);
});
};
View
6 views/collection.html
@@ -1,6 +1,6 @@
{% extends 'layout.html' %}
-{% block title %}{{ collection }}{% endblock %}
+{% block title %}{{ collection_name }}{% endblock %}
{% block content %}
@@ -11,7 +11,7 @@
{% else %}
{% for document in documents %}
<pre class="prettyprint">{{ document|json }}</pre>
- <!--<a href="db/{{ collection }}/{{ document._id }}">Edit</a>-->
+ <!--<a href="db/{{ db_name }}/{{ collection_name }}/{{ document._id }}">Edit</a>-->
{% endfor %}
{% endif %}
@@ -37,7 +37,7 @@
#}
<h2>Delete Collection</h2>
-<form method="POST" action="db/{{ collection }}" class="well">
+<form method="POST" action="db/{{ db_name }}/{{ collection_name }}" class="well">
<input type="hidden" name="_method" value="delete">
<p>Are you sure you want to delete this collection? All documents will be deleted.</p>
<button type="submit" class="btn btn-danger btn-large">
View
25 views/layout.html
@@ -43,9 +43,24 @@
<div class="span3">
<div class="well sidebar-nav">
<ul class="nav nav-list">
- <li class="nav-header">Collections</li>
- {% for collection in collections %}
- <li><a href="db/{{ collection.name }}">{{ collection.name }}</a></li>
+ {% for db in databases %}
+ <li class="nav-header" onclick="$('#toggle_{{ db }}').collapse('toggle')">
+ {{ db }}
+ <i class="icon-chevron-down pull-right"></i>
+ </li>
+ <li><a href="db/{{ db }}"><i class="icon-book"></i> View Database</a></li>
+ <ul class="unstyled collapse nav nav-list
+ {%- if db == db_name %} in{% endif -%}
+ " id="toggle_{{ db }}">
+ {% for collection_db in collections -%}
+ {% if loop.key == db -%}
+ {% for collection in collection_db -%}
+ <li><a href="db/{{ db }}/{{ collection }}"><i class="icon-folder-open"></i> {{ collection }}</a></li>
+ {%- endfor %}
+ {%- endif %}
+ {%- endfor %}
+ </ul>
+ <li class="divider"></li>
{% endfor %}
</ul>
</div>
@@ -63,5 +78,9 @@
</div>
</div>
+
+<script src="javascripts/jquery-1.7.2.min.js"></script>
+<script src="javascripts/bootstrap.min.js"></script>
+
</body>
</html>
Please sign in to comment.
Something went wrong with that request. Please try again.