Implement MongoDB client

This commit is contained in:
Tankred Hase 2016-05-25 16:13:49 +02:00
parent 7f629aec13
commit ce2b24d83d
9 changed files with 378 additions and 1 deletions

3
.gitignore vendored
View File

@ -1,3 +1,6 @@
.DS_Store
credentials.json
# Logs
logs
*.log

4
.jscsrc Normal file
View File

@ -0,0 +1,4 @@
{
"disallowTrailingWhitespace": true,
"validateIndentation": 2
}

25
.jshintrc Normal file
View File

@ -0,0 +1,25 @@
{
"strict": true,
"node": true,
"nonew": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"newcap": true,
"regexp": true,
"evil": true,
"eqnull": true,
"expr": true,
"undef": true,
"unused": true,
"esnext": true,
"globals": {
"describe" : true,
"it" : true,
"before" : true,
"beforeEach" : true,
"after" : true,
"afterEach" : true
}
}

17
.travis.yml Normal file
View File

@ -0,0 +1,17 @@
sudo: false
language: node_js
node_js:
- "4"
- "5"
- "6"
before_script:
- npm install -g grunt-cli
- sleep 15
- mongo test_db --eval 'db.addUser("travis", "test");'
notifications:
email:
- build@mailvelope.com
services:
- mongodb
env:
- MONGO_URI=127.0.0.1:27017/test_db MONGO_USER=travis MONGO_PASS=test

43
Gruntfile.js Normal file
View File

@ -0,0 +1,43 @@
'use strict';
module.exports = function(grunt) {
grunt.initConfig({
jshint: {
all: ['*.js', 'src/**/*.js', 'test/**/*.js'],
options: {
jshintrc: '.jshintrc'
}
},
jscs: {
src: ['*.js', 'src/**/*.js', 'test/**/*.js'],
options: {
config: ".jscsrc",
esnext: true, // If you use ES6 http://jscs.info/overview.html#esnext
verbose: true, // If you need output with rule names http://jscs.info/overview.html#verbose
}
},
mochaTest: {
test: {
options: {
reporter: 'spec'
},
src: [
'test/unit/*.js',
'test/integration/*.js',
]
}
}
});
// Load the plugin(s)
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-jscs');
grunt.loadNpmTasks('grunt-mocha-test');
// Default task(s).
grunt.registerTask('test', ['jshint', 'jscs', 'mochaTest']);
};

View File

@ -1,2 +1,4 @@
# keyserver
Mailvelope Keyserver [![Build Status](https://travis-ci.org/mailvelope/keyserver.svg?branch=master)](https://travis-ci.org/mailvelope/keyserver)
==============
A simple OpenPGP public key server

28
package.json Normal file
View File

@ -0,0 +1,28 @@
{
"name": "mailvelope-keyserver",
"version": "0.0.1",
"license": "AGPL-3.0",
"repository": {
"type": "git",
"url": "https://github.com/mailvelope/keyserver.git"
},
"engines": {
"node": ">=4"
},
"scripts": {
"test": "grunt test"
},
"dependencies": {
"mongodb": "^2.1.20"
},
"devDependencies": {
"chai": "^3.5.0",
"co-mocha": "^1.1.2",
"grunt": "^1.0.1",
"grunt-contrib-jshint": "^1.0.0",
"grunt-jscs": "^2.8.0",
"grunt-mocha-test": "^0.12.7",
"mocha": "^2.5.3",
"sinon": "^1.17.4"
}
}

124
src/dao/mongo.js Normal file
View File

@ -0,0 +1,124 @@
/**
* Mailvelope - secure email with OpenPGP encryption for Webmail
* Copyright (C) 2016 Mailvelope GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License version 3
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
'use strict';
const MongoClient = require('mongodb').MongoClient;
/**
* A simple wrapper around the official MongoDB client.
*/
class Mongo {
/**
* Create an instance of the MongoDB client.
* @param {String} options.uri The mongodb uri
* @param {String} options.user The databse user
* @param {String} options.password The database user's password
* @param {String} options.type (optional) The default collection type to use e.g. 'publickey'
* @return {undefined}
*/
constructor(options) {
this._uri = 'mongodb://' + options.user + ':' + options.password + '@' + options.uri;
this._type = options.type;
}
/**
* Initializes the database client by connecting to the MongoDB.
* @return {undefined}
*/
*connect() {
this._db = yield MongoClient.connect(this._uri);
}
/**
* Cleanup by closing the connection to the database.
* @return {undefined}
*/
disconnect() {
return this._db.close();
}
/**
* Inserts a single document.
* @param {Object} document Inserts a single documents
* @param {String} type (optional) The collection to use e.g. 'publickey'
* @return {Object} The operation result
*/
create(document, type) {
let col = this._db.collection(type || this._type);
return col.insertOne(document);
}
/**
* Update a single document.
* @param {Object} query The query e.g. { _id:'0' }
* @param {Object} diff The attributes to change/set e.g. { foo:'bar' }
* @param {String} type (optional) The collection to use e.g. 'publickey'
* @return {Object} The operation result
*/
update(query, diff, type) {
let col = this._db.collection(type || this._type);
return col.updateOne(query, { $set:diff });
}
/**
* Read a single document.
* @param {Object} query The query e.g. { _id:'0' }
* @param {String} type (optional) The collection to use e.g. 'publickey'
* @return {Object} The document object
*/
get(query, type) {
let col = this._db.collection(type || this._type);
return col.findOne(query);
}
/**
* Read multiple documents at once.
* @param {Object} query The query e.g. { foo:'bar' }
* @param {String} type (optional) The collection to use e.g. 'publickey'
* @return {Array} An array of document objects
*/
list(query, type) {
let col = this._db.collection(type || this._type);
return col.find(query).toArray();
}
/**
* Delete a single document.
* @param {Object} query The query e.g. { _id:'0' }
* @param {String} type (optional) The collection to use e.g. 'publickey'
* @return {Object} The document object
*/
remove(query, type) {
let col = this._db.collection(type || this._type);
return col.deleteOne(query);
}
/**
* Clear all documents of a collection.
* @param {String} type (optional) The collection to use e.g. 'publickey'
* @return {Object} The operation result
*/
clear(type) {
let col = this._db.collection(type || this._type);
return col.deleteMany({});
}
}
module.exports = Mongo;

View File

@ -0,0 +1,131 @@
'use strict';
require('co-mocha')(require('mocha')); // monkey patch mocha for generators
const Mongo = require('../../src/dao/mongo'),
expect = require('chai').expect,
fs = require('fs');
describe('Mongo Integration Tests', function() {
this.timeout(20000);
const defaultType = 'apple';
const secondaryType = 'orange';
let mongo;
before(function *() {
let credentials;
try {
credentials = JSON.parse(fs.readFileSync(__dirname + '/../../credentials.json'));
} catch(e) {}
mongo = new Mongo({
uri: process.env.MONGO_URI || credentials.mongoUri,
user: process.env.MONGO_USER || credentials.mongoUser,
password: process.env.MONGO_PASS || credentials.mongoPass,
type: defaultType
});
yield mongo.connect();
});
beforeEach(function *() {
yield mongo.clear();
yield mongo.clear(secondaryType);
});
afterEach(function() {});
after(function *() {
yield mongo.clear();
yield mongo.clear(secondaryType);
yield mongo.disconnect();
});
describe("create", function() {
it('should insert a document', function *() {
let r = yield mongo.create({ _id:'0' });
expect(r.insertedCount).to.equal(1);
});
it('should insert a document with a type', function *() {
let r = yield mongo.create({ _id:'0' });
expect(r.insertedCount).to.equal(1);
r = yield mongo.create({ _id:'0' }, secondaryType);
expect(r.insertedCount).to.equal(1);
});
it('should fail if two with the same ID are inserted', function *() {
let r = yield mongo.create({ _id:'0' });
expect(r.insertedCount).to.equal(1);
try {
r = yield mongo.create({ _id:'0' });
} catch(e) {
expect(e.message).to.match(/duplicate/);
}
});
});
describe("update", function() {
it('should update a document', function *() {
let r = yield mongo.create({ _id:'0' });
r = yield mongo.update({ _id:'0' }, { foo:'bar' });
expect(r.modifiedCount).to.equal(1);
r = yield mongo.get({ _id:'0' });
expect(r.foo).to.equal('bar');
});
it('should update a document with a type', function *() {
let r = yield mongo.create({ _id:'0' }, secondaryType);
r = yield mongo.update({ _id:'0' }, { foo:'bar' }, secondaryType);
expect(r.modifiedCount).to.equal(1);
r = yield mongo.get({ _id:'0' }, secondaryType);
expect(r.foo).to.equal('bar');
});
});
describe("get", function() {
it('should get a document', function *() {
let r = yield mongo.create({ _id:'0' });
r = yield mongo.get({ _id:'0' });
expect(r).to.exist;
});
it('should get a document with a type', function *() {
let r = yield mongo.create({ _id:'0' }, secondaryType);
r = yield mongo.get({ _id:'0' }, secondaryType);
expect(r).to.exist;
});
});
describe("list", function() {
it('should list documents', function *() {
let r = yield mongo.create({ _id:'0', foo:'bar' });
r = yield mongo.create({ _id:'1', foo:'bar' });
r = yield mongo.list({ foo:'bar' });
expect(r).to.deep.equal([{ _id:'0', foo:'bar' }, { _id:'1', foo:'bar' }]);
});
it('should list documents with a type', function *() {
let r = yield mongo.create({ _id:'0', foo:'bar' }, secondaryType);
r = yield mongo.create({ _id:'1', foo:'bar' }, secondaryType);
r = yield mongo.list({ foo:'bar' }, secondaryType);
expect(r).to.deep.equal([{ _id:'0', foo:'bar' }, { _id:'1', foo:'bar' }]);
});
});
describe("remove", function() {
it('should remove a document', function *() {
let r = yield mongo.create({ _id:'0' });
r = yield mongo.remove({ _id:'0' });
r = yield mongo.get({ _id:'0' });
expect(r).to.not.exist;
});
it('should remove a document with a type', function *() {
let r = yield mongo.create({ _id:'0' }, secondaryType);
r = yield mongo.remove({ _id:'0' }, secondaryType);
r = yield mongo.get({ _id:'0' }, secondaryType);
expect(r).to.not.exist;
});
});
});