<commit_before>// Load Modules

var MongoDB = require('mongodb');
var Hoek = require('hoek');
var Boom = require('boom');

// Declare internals

var internals = {
    collectionNames: ['client',
                       'invite',
                       'grant',
                       'project', 'project.sort',
                       'suggestion',
                       'task', 'task.details', 'task.sort',
                       'tip',
                       'user', 'user.exclude', 'user.last', 'user.storage']
};

module.exports = internals.Db = function (options) {

    this._vault = options.vault.database;
    this._client = new MongoDB.Db(options.config.database.db, new MongoDB.Server(options.config.database.host, options.config.database.port, {}), { strict: true });
    this._collections = {};

    this.Long = this._client.bson_serializer.Long;
    this.ObjectID = this._client.bson_serializer.ObjectID;
};

internals.Db.prototype.initialize = function (arg1, arg2) {        // [isNew,] callback

    var self = this;

    var isNew = (arg2 ? arg1 : false);
    var callback = (arg2 || arg1);

    this._client.open(function (err, client) {

        if (err) {
            return callback('Database connection error: ' + JSON.stringify(err));
        }

        if (!self._vault.username) {
            return self.initCollection(0, isNew, callback);
        }

        self._client.authenticate(self._vault.username, self._vault.password, function (err, result) {

            if (err) {
                return callback('Database authentication error: ' + JSON.stringify(err));
            }

            if (!result) {
                return callback('Database authentication failed');
            }

            return self.initCollection(0, isNew, callback);
        });
    });

    // TODO: find a way to close the connection
};

internals.Db.prototype.initCollection = function (i, isNew, callback) {

    var self = this;

    var next = function (err, collection) {

        if (err) {
            return callback('Failed opening collection: ' + internals.collectionNames[i] + ' due to: ' + err);
        }

        self._collections[internals.collectionNames[i]] = collection;
        self.initCollection(i + 1, isNew, callback);
    };

    if (i >= internals.collectionNames.length) {
        return callback(null);
    }

    if (isNew) {
        return this._client.createCollection(internals.collectionNames[i], next);
    }

    return this._client.collection(internals.collectionNames[i], next);
};

// Get entire collection

internals.Db.prototype.all = function (collectionName, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'all'));
    }

    collection.find(function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'all'));
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'all'));
            }

            self._normalize(results);
            return callback(null, results);
        });
    });
};

// Get document by id

internals.Db.prototype.get = function (collectionName, id, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'get', id));
    }

    var dbId = this._getDbId(id);
    if (!dbId) {
        return callback(null, null);
    }

    collection.findOne(dbId, function (err, result) {

        if (err) {
            return callback(internals.error(err, collectionName, 'get', id));
        }

        self._normalize(result);
        return callback(null, result);
    });
};

// Get multiple documents by id list

internals.Db.prototype.getMany = function (collectionName, ids, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'getMany', ids), ids);
    }

    var notFound = [];
    var criteria = { _id: {} };
    criteria._id.$in = [];
    for (var i = 0, il = ids.length; i < il; ++i) {
        var dbId = this._getDbId(ids[i]);
        if (dbId) {
            criteria._id.$in.push(dbId);
        }
        else {
            notFound.push(ids[i]);
        }
    }

    if (criteria._id.$in.length <= 0) {
        return callback(null, [], ids);
    }

    collection.find(criteria, function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'getMany', ids), ids);
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'getMany', ids), ids);
            }

            if (results.length <= 0) {
                return callback(null, [], ids);
            }

            self._normalize(results);

            // Sort based on requested ids

            var map = {};
            for (i = 0, il = results.length; i < il; ++i) {
                map[results[i]._id] = results[i];
            }

            var items = [];
            for (i = 0, il = ids.length; i < il; ++i) {
                if (map[ids[i]]) {
                    items.push(map[ids[i]]);
                }
                else {
                    notFound.push(ids[i]);
                }
            }

            return callback(null, items, notFound);
        });
    });
};

// Query documents by criteria

internals.Db.prototype.query = function (collectionName, criteria, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'query', criteria));
    }

    this._idifyString(criteria);
    collection.find(criteria, function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'query', criteria));
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'query', criteria));
            }

            self._normalize(results);
            return callback(null, results);
        });
    });
};

// Query for a single (unique) documents by criteria

internals.Db.prototype.queryUnique = function (collectionName, criteria, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'queryUnique', criteria));
    }

    this._idifyString(criteria);
    collection.find(criteria, function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'queryUnique', criteria));
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'queryUnique', criteria));
            }

            if (!results) {
                return callback(internals.error('Null result array', collectionName, 'queryUnique', criteria));
            }

            if (results.length <= 0) {
                return callback(null, null);
            }

            if (results.length !== 1) {
                return callback(internals.error('Found multiple results for unique criteria', collectionName, 'queryUnique', criteria));
            }

            var result = results[0];
            self._normalize(result);
            return callback(null, result);
        });
    });
};

// Count documents by criteria

internals.Db.prototype.count = function (collectionName, criteria, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'count', criteria));
    }

    this._idifyString(criteria);
    collection.count(criteria, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'count', criteria));
        }

        return callback(null, count);
    });
};

// Save new documents (one or many)

internals.Db.prototype.insert = function (collectionName, items, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'insert', items));
    }

    var now = Date.now();

    if (items instanceof Array) {
        for (var i = 0, il = items.length; i < il; ++i) {
            items[i].created = now;
            items[i].modified = now;
        }
    }
    else {
        items.created = now;
        items.modified = now;
    }

    this._idifyString(items);
    collection.insert(items, function (err, results) {

        if (err) {
            return callback(internals.error(err, collectionName, 'insert', items));
        }

        if (!results ||
            results.length <= 0) {

            return callback(internals.error('No database insert output', collectionName, 'insert', items));
        }

        self._normalize(results);
        return callback(null, results);
    });
};

// Replace a single existing document

internals.Db.prototype.replace = function (collectionName, item, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'replace', item));
    }

    var now = Date.now();
    if (item.created === undefined) {

        item.created = now;
    }

    item.modified = now;

    this._idifyString(item);
    collection.update({ _id: item._id }, item, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'replace', item));
        }

        if (!count) {
            return callback(internals.error('No document found to replace', collectionName, 'replace', item));
        }

        return callback(null);
    });
};

// Update a single existing document

internals.Db.prototype.update = function (collectionName, id, changes, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'update', [id, changes]));
    }

    changes = changes || {};
    changes.$set = changes.$set || {};

    var now = Date.now();
    changes.$set.modified = now;

    var dbId = this._getDbId(id);
    if (!dbId) {
        return callback(internals.error('Invalid id', collectionName, 'update', [id, changes]));
    }

    collection.update({ _id: dbId }, changes, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'update', [id, changes]));
        }

        if (!count) {
            return callback(internals.error('No document found to update', collectionName, 'update', [id, changes]));
        }

        return callback(null);
    });
};

// Update any existing document matching criteria

internals.Db.prototype.updateCriteria = function (collectionName, id, itemCriteria, changes, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'updateCriteria', [id, itemCriteria, changes]));
    }

    changes = changes || {};
    changes.$set = changes.$set || {};

    var now = Date.now();
    changes.$set.modified = now;

    var isValid = true;

    // Add id to criteria if present

    var options = {};

    if (id) {
        var dbId = this._getDbId(id);
        if (dbId) {
            itemCriteria._id = dbId;
        }
        else {
            isValid = false;
        }
    }
    else {
        options.multi = true;
    }

    if (!isValid) {
        return callback(internals.error('Invalid id', collectionName, 'updateCriteria', [id, itemCriteria, changes, options]));
    }

    collection.update(itemCriteria, changes, options, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'updateCriteria', [id, itemCriteria, changes, options]));
        }

        if (!id) {
            return callback(null);
        }

        if (!count) {
            return callback(internals.error('No document found to update', collectionName, 'updateCriteria', [id, itemCriteria, changes, options]));
        }

        return callback(null);
    });
};

// Remove item

internals.Db.prototype.remove = function (collectionName, id, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'remove', id));
    }

    var dbId = new this.ObjectID(id);
    collection.remove({ _id: dbId }, function (err, collection) {

        if (err) {
            return callback(internals.error(err, collectionName, 'remove', id));
        }

        return callback(null);
    });
};

// Remove criteria

internals.Db.prototype.removeCriteria = function (collectionName, criteria, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'remove', id));
    }

    this._idifyString(criteria);
    collection.remove(criteria, function (err, collection) {

        if (err) {
            return callback(internals.error(err, collectionName, 'remove', id));
        }

        return callback(null);
    });
};

// Remove multiple items

internals.Db.prototype.removeMany = function (collectionName, ids, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'remove', ids));
    }

    var criteria = { _id: {} };
    criteria._id.$in = [];
    for (var i = 0, il = ids.length; i < il; ++i) {
        var dbId = this._getDbId(ids[i]);
        if (dbId) {
            criteria._id.$in.push(dbId);
        }
    }

    if (criteria._id.$in.length <= 0) {
        return callback(internals.error('Invalid ids', collectionName, 'remove', ids));
    }

    collection.remove(criteria, function (err, collection) {

        if (err) {
            return callback(internals.error(err, collectionName, 'remove', ids));
        }

        return callback(null);
    });
};

// Convert object into update changes

internals.Db.prototype.toChanges = function (item) {

    var changes = {};

    if (item &&
        item instanceof Object &&
        item instanceof Array === false) {

        changes.$set = {};

        for (var i in item) {
            if (item.hasOwnProperty(i)) {
                changes.$set[i] = item[i];
            }
        }
    }

    return changes;
};

// Get unique identifier

internals.Db.prototype.generateId = function () {

    var id = new this.ObjectID();
    return id.toString();
};

// Encode key

internals.Db.prototype.encodeKey = function (value) {

    return value.replace(/%/g, '%25').replace(/\./g, '%2E').replace(/^\$/, '%24');
};

// Decode key

internals.Db.prototype.decodeKey = function (value) {

    return decodeURIComponent(value);
};

// Remove db specific id object type

internals.Db.prototype._normalize = function (obj) {

    if (obj !== null) {
        for (var i in obj) {
            if (obj.hasOwnProperty(i)) {
                if (obj[i] instanceof this.Long) {
                    obj[i] = obj[i].toNumber();
                }
                else if (obj[i] instanceof this.ObjectID) {
                    obj[i] = obj[i].toString();
                }
                else if (obj[i] && typeof obj[i] === 'object') {
                    this._normalize(obj[i]);
                }
            }
        }
    }
};

// Changed id into db specific object type

internals.Db.prototype._idifyString = function (items) {

    if (items) {
        if (items instanceof Array) {
            for (var i = 0, il = items.length; i < il; ++i) {
                if (items[i]._id) {
                    items[i]._id = new this.ObjectID(items[i]._id);
                }
            }
        }
        else {
            if (items._id) {
                items._id = new this.ObjectID(items._id);
            }
        }
    }
};

// Get DB id

internals.Db.prototype._getDbId = function (id) {

    if (/^[0-9a-fA-F]{24}$/.test(id)) {
        return new this.ObjectID(id);
    }
    else {
        return null;
    }
};

// Construct error artifact

internals.error = function (error, collection, action, input) {

    return Boom.internal('Database error', { error: error, collection: collection, action: action, input: input });
};

<commit_msg>vault rewrite<commit_after>// Load Modules

var MongoDB = require('mongodb');
var Hoek = require('hoek');
var Boom = require('boom');

// Declare internals

var internals = {
    collectionNames: ['client',
                       'invite',
                       'grant',
                       'project', 'project.sort',
                       'suggestion',
                       'task', 'task.details', 'task.sort',
                       'tip',
                       'user', 'user.exclude', 'user.last', 'user.storage']
};

module.exports = internals.Db = function (options) {

    this._settings = options.config;
    this._client = new MongoDB.Db(options.config.database.db, new MongoDB.Server(options.config.database.host, options.config.database.port, {}), { strict: true });
    this._collections = {};

    this.Long = this._client.bson_serializer.Long;
    this.ObjectID = this._client.bson_serializer.ObjectID;
};

internals.Db.prototype.initialize = function (arg1, arg2) {        // [isNew,] callback

    var self = this;

    var isNew = (arg2 ? arg1 : false);
    var callback = (arg2 || arg1);

    this._client.open(function (err, client) {

        if (err) {
            return callback('Database connection error: ' + JSON.stringify(err));
        }

        if (!self._settings.database.username) {
            return self.initCollection(0, isNew, callback);
        }

        self._client.authenticate(self._settings.database.username, self._settings.database.password, function (err, result) {

            if (err) {
                return callback('Database authentication error: ' + JSON.stringify(err));
            }

            if (!result) {
                return callback('Database authentication failed');
            }

            return self.initCollection(0, isNew, callback);
        });
    });

    // TODO: find a way to close the connection
};

internals.Db.prototype.initCollection = function (i, isNew, callback) {

    var self = this;

    var next = function (err, collection) {

        if (err) {
            return callback('Failed opening collection: ' + internals.collectionNames[i] + ' due to: ' + err);
        }

        self._collections[internals.collectionNames[i]] = collection;
        self.initCollection(i + 1, isNew, callback);
    };

    if (i >= internals.collectionNames.length) {
        return callback(null);
    }

    if (isNew) {
        return this._client.createCollection(internals.collectionNames[i], next);
    }

    return this._client.collection(internals.collectionNames[i], next);
};

// Get entire collection

internals.Db.prototype.all = function (collectionName, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'all'));
    }

    collection.find(function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'all'));
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'all'));
            }

            self._normalize(results);
            return callback(null, results);
        });
    });
};

// Get document by id

internals.Db.prototype.get = function (collectionName, id, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'get', id));
    }

    var dbId = this._getDbId(id);
    if (!dbId) {
        return callback(null, null);
    }

    collection.findOne(dbId, function (err, result) {

        if (err) {
            return callback(internals.error(err, collectionName, 'get', id));
        }

        self._normalize(result);
        return callback(null, result);
    });
};

// Get multiple documents by id list

internals.Db.prototype.getMany = function (collectionName, ids, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'getMany', ids), ids);
    }

    var notFound = [];
    var criteria = { _id: {} };
    criteria._id.$in = [];
    for (var i = 0, il = ids.length; i < il; ++i) {
        var dbId = this._getDbId(ids[i]);
        if (dbId) {
            criteria._id.$in.push(dbId);
        }
        else {
            notFound.push(ids[i]);
        }
    }

    if (criteria._id.$in.length <= 0) {
        return callback(null, [], ids);
    }

    collection.find(criteria, function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'getMany', ids), ids);
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'getMany', ids), ids);
            }

            if (results.length <= 0) {
                return callback(null, [], ids);
            }

            self._normalize(results);

            // Sort based on requested ids

            var map = {};
            for (i = 0, il = results.length; i < il; ++i) {
                map[results[i]._id] = results[i];
            }

            var items = [];
            for (i = 0, il = ids.length; i < il; ++i) {
                if (map[ids[i]]) {
                    items.push(map[ids[i]]);
                }
                else {
                    notFound.push(ids[i]);
                }
            }

            return callback(null, items, notFound);
        });
    });
};

// Query documents by criteria

internals.Db.prototype.query = function (collectionName, criteria, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'query', criteria));
    }

    this._idifyString(criteria);
    collection.find(criteria, function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'query', criteria));
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'query', criteria));
            }

            self._normalize(results);
            return callback(null, results);
        });
    });
};

// Query for a single (unique) documents by criteria

internals.Db.prototype.queryUnique = function (collectionName, criteria, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'queryUnique', criteria));
    }

    this._idifyString(criteria);
    collection.find(criteria, function (err, cursor) {

        if (err) {
            return callback(internals.error(err, collectionName, 'queryUnique', criteria));
        }

        cursor.toArray(function (err, results) {

            if (err) {
                return callback(internals.error(err, collectionName, 'queryUnique', criteria));
            }

            if (!results) {
                return callback(internals.error('Null result array', collectionName, 'queryUnique', criteria));
            }

            if (results.length <= 0) {
                return callback(null, null);
            }

            if (results.length !== 1) {
                return callback(internals.error('Found multiple results for unique criteria', collectionName, 'queryUnique', criteria));
            }

            var result = results[0];
            self._normalize(result);
            return callback(null, result);
        });
    });
};

// Count documents by criteria

internals.Db.prototype.count = function (collectionName, criteria, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'count', criteria));
    }

    this._idifyString(criteria);
    collection.count(criteria, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'count', criteria));
        }

        return callback(null, count);
    });
};

// Save new documents (one or many)

internals.Db.prototype.insert = function (collectionName, items, callback) {

    var self = this;

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'insert', items));
    }

    var now = Date.now();

    if (items instanceof Array) {
        for (var i = 0, il = items.length; i < il; ++i) {
            items[i].created = now;
            items[i].modified = now;
        }
    }
    else {
        items.created = now;
        items.modified = now;
    }

    this._idifyString(items);
    collection.insert(items, function (err, results) {

        if (err) {
            return callback(internals.error(err, collectionName, 'insert', items));
        }

        if (!results ||
            results.length <= 0) {

            return callback(internals.error('No database insert output', collectionName, 'insert', items));
        }

        self._normalize(results);
        return callback(null, results);
    });
};

// Replace a single existing document

internals.Db.prototype.replace = function (collectionName, item, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'replace', item));
    }

    var now = Date.now();
    if (item.created === undefined) {

        item.created = now;
    }

    item.modified = now;

    this._idifyString(item);
    collection.update({ _id: item._id }, item, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'replace', item));
        }

        if (!count) {
            return callback(internals.error('No document found to replace', collectionName, 'replace', item));
        }

        return callback(null);
    });
};

// Update a single existing document

internals.Db.prototype.update = function (collectionName, id, changes, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'update', [id, changes]));
    }

    changes = changes || {};
    changes.$set = changes.$set || {};

    var now = Date.now();
    changes.$set.modified = now;

    var dbId = this._getDbId(id);
    if (!dbId) {
        return callback(internals.error('Invalid id', collectionName, 'update', [id, changes]));
    }

    collection.update({ _id: dbId }, changes, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'update', [id, changes]));
        }

        if (!count) {
            return callback(internals.error('No document found to update', collectionName, 'update', [id, changes]));
        }

        return callback(null);
    });
};

// Update any existing document matching criteria

internals.Db.prototype.updateCriteria = function (collectionName, id, itemCriteria, changes, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'updateCriteria', [id, itemCriteria, changes]));
    }

    changes = changes || {};
    changes.$set = changes.$set || {};

    var now = Date.now();
    changes.$set.modified = now;

    var isValid = true;

    // Add id to criteria if present

    var options = {};

    if (id) {
        var dbId = this._getDbId(id);
        if (dbId) {
            itemCriteria._id = dbId;
        }
        else {
            isValid = false;
        }
    }
    else {
        options.multi = true;
    }

    if (!isValid) {
        return callback(internals.error('Invalid id', collectionName, 'updateCriteria', [id, itemCriteria, changes, options]));
    }

    collection.update(itemCriteria, changes, options, function (err, count) {

        if (err) {
            return callback(internals.error(err, collectionName, 'updateCriteria', [id, itemCriteria, changes, options]));
        }

        if (!id) {
            return callback(null);
        }

        if (!count) {
            return callback(internals.error('No document found to update', collectionName, 'updateCriteria', [id, itemCriteria, changes, options]));
        }

        return callback(null);
    });
};

// Remove item

internals.Db.prototype.remove = function (collectionName, id, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'remove', id));
    }

    var dbId = new this.ObjectID(id);
    collection.remove({ _id: dbId }, function (err, collection) {

        if (err) {
            return callback(internals.error(err, collectionName, 'remove', id));
        }

        return callback(null);
    });
};

// Remove criteria

internals.Db.prototype.removeCriteria = function (collectionName, criteria, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'remove', id));
    }

    this._idifyString(criteria);
    collection.remove(criteria, function (err, collection) {

        if (err) {
            return callback(internals.error(err, collectionName, 'remove', id));
        }

        return callback(null);
    });
};

// Remove multiple items

internals.Db.prototype.removeMany = function (collectionName, ids, callback) {

    var collection = this._collections[collectionName];
    if (!collection) {
        return callback(internals.error('Collection not found', collectionName, 'remove', ids));
    }

    var criteria = { _id: {} };
    criteria._id.$in = [];
    for (var i = 0, il = ids.length; i < il; ++i) {
        var dbId = this._getDbId(ids[i]);
        if (dbId) {
            criteria._id.$in.push(dbId);
        }
    }

    if (criteria._id.$in.length <= 0) {
        return callback(internals.error('Invalid ids', collectionName, 'remove', ids));
    }

    collection.remove(criteria, function (err, collection) {

        if (err) {
            return callback(internals.error(err, collectionName, 'remove', ids));
        }

        return callback(null);
    });
};

// Convert object into update changes

internals.Db.prototype.toChanges = function (item) {

    var changes = {};

    if (item &&
        item instanceof Object &&
        item instanceof Array === false) {

        changes.$set = {};

        for (var i in item) {
            if (item.hasOwnProperty(i)) {
                changes.$set[i] = item[i];
            }
        }
    }

    return changes;
};

// Get unique identifier

internals.Db.prototype.generateId = function () {

    var id = new this.ObjectID();
    return id.toString();
};

// Encode key

internals.Db.prototype.encodeKey = function (value) {

    return value.replace(/%/g, '%25').replace(/\./g, '%2E').replace(/^\$/, '%24');
};

// Decode key

internals.Db.prototype.decodeKey = function (value) {

    return decodeURIComponent(value);
};

// Remove db specific id object type

internals.Db.prototype._normalize = function (obj) {

    if (obj !== null) {
        for (var i in obj) {
            if (obj.hasOwnProperty(i)) {
                if (obj[i] instanceof this.Long) {
                    obj[i] = obj[i].toNumber();
                }
                else if (obj[i] instanceof this.ObjectID) {
                    obj[i] = obj[i].toString();
                }
                else if (obj[i] && typeof obj[i] === 'object') {
                    this._normalize(obj[i]);
                }
            }
        }
    }
};

// Changed id into db specific object type

internals.Db.prototype._idifyString = function (items) {

    if (items) {
        if (items instanceof Array) {
            for (var i = 0, il = items.length; i < il; ++i) {
                if (items[i]._id) {
                    items[i]._id = new this.ObjectID(items[i]._id);
                }
            }
        }
        else {
            if (items._id) {
                items._id = new this.ObjectID(items._id);
            }
        }
    }
};

// Get DB id

internals.Db.prototype._getDbId = function (id) {

    if (/^[0-9a-fA-F]{24}$/.test(id)) {
        return new this.ObjectID(id);
    }
    else {
        return null;
    }
};

// Construct error artifact

internals.error = function (error, collection, action, input) {

    return Boom.internal('Database error', { error: error, collection: collection, action: action, input: input });
};

<|endoftext|>


<commit_before>import Sequelize from 'sequelize';

const env = process.env.NODE_ENV || 'dev';
let db;

// when hosted by Heroku, use postgresql
if (process.env.DATABASE_URL) {
  db = new Sequelize(process.env.DATABASE_URL, {
    dialect:  'postgres',
    isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED,
    logging: env === 'dev' ? console.log : false,
  });

// devs use sqlite on local machines
} else if (env === 'dev') {
  db = new Sequelize('bridge-club', null, null, {
    dialect: 'sqlite',
    storage: './bridge-club.sqlite',
    isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED,
    logging: env === 'dev' ? console.log : false,
  });
}

if (!db) {
    throw new Error('Cannot determine database for the environment');
}

module.exports = db;
<commit_msg>chore(database): createdAt and updatedAt are not needed<commit_after>import Sequelize from 'sequelize';

const env = process.env.NODE_ENV || 'dev';
let db;

// when hosted by Heroku, use postgresql
if (process.env.DATABASE_URL) {
  db = new Sequelize(process.env.DATABASE_URL, {
    dialect:  'postgres',
    isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED,
    logging: env === 'dev' ? console.log : false,
    define: {
      timestamps: false
    },
  });

// devs use sqlite on local machines
} else if (env === 'dev') {
  db = new Sequelize('bridge-club', null, null, {
    dialect: 'sqlite',
    storage: './bridge-club.sqlite',
    isolationLevel: Sequelize.Transaction.ISOLATION_LEVELS.READ_UNCOMMITTED,
    logging: env === 'dev' ? console.log : false,
    define: {
      timestamps: false
    },
  });
}

if (!db) {
    throw new Error('Cannot determine database for the environment');
}

module.exports = db;
<|endoftext|>


<commit_before>module.exports = df;
df.pingVersion = pingVersion;
df.apps = apps;
df.logs = logs;

df.usage = "\nfhc df ping"
  + "\nfhc df version"
  + "\nfhc df apps"
  + "\nfhc df logs <app id>"
  + "\nfhc df start <app id>"
  + "\nfhc df stop <app id>"
  + "\nfhc df delete <app id>"
  + "\nfhc df act <app id> <server function> <params>"
  + "\nfhc df url <app id> (returns the full DynoFarm url given an appId)";

var log = require("./utils/log");
var hash = require("./utils/hash");
var fhc = require("./fhc");
var util = require('util');
var output = require("./utils/output");
var request = require('request');
var common = require('./common.js');
var Table = require('cli-table');
var ini = require('./utils/ini');

// main DynoFarm entry point
function df (args, cb) {
  var action = args.shift();
  switch (action) {
    case "ping": return pingVersion("ping", cb);
    case "version": return pingVersion("version", cb);
    case "apps": case "ls": return apps(cb);
    case "logs":  {
      if (args.length != 1) return unknown("logs", cb);
      else return logs(args[0], cb);
    };
    case "stop":  {
      if (args.length != 1) return unknown("stop", cb);
      else return stop(args[0], cb);
    };
    case "start":  {
      if (args.length != 1) return unknown("start", cb);
      else return start(args[0], cb);
    };
    case "restart":  {
      if (args.length != 1) return unknown("restart", cb);
      else return restart(args[0], cb);
    };
    case "url":  {
      if (args.length != 1) return unknown("url", cb);
      else return url(args[0], cb);
    };
    case "act": {
      if (args.length < 2) return unknown("act", cb);
      return act(args[0], args[1], args[2], cb);
    };
    case "delete":  {
      if (args.length != 1) return unknown("delete", cb);
      else return deleteApp(args[0], cb);
    };
    default: return unknown(action, cb);
  }
};

// gets the app endpoint from the dftarget
function getAppUrl(appId){
  var appName = common.getAppName(appId);
  var df = fhc.config.get("dynofarm");
  var uri = require('url').parse(df);

  // replace 'api' with the modified appId to get our enpoint
  var port = uri.port ? ":" +  uri.port : "";
  var url = uri.protocol + "//" + appName + "." + uri.hostname + port;
  url = url.replace(/\.api\./g, '.');

  return url;
}

// our 'act' function
function act(appId, funct, params, cb) {
  var data = {};
  if (params) data = JSON.parse(params);
  log.silly(data, "df act params");

  // firgure out our app endpoint
  var appUrl = getAppUrl(appId);
  log.verbose('' + appUrl, "App endpoint");
  log.verbose('' + funct, "Calling DF function");

  // post to /cloud
  request({uri: appUrl + "/cloud/" + funct, method: 'POST', json: data}, function (err, response, body) {
    log.silly(response);
    return cb(nullToUndefined(err), body);
  });
};

// ping
function pingVersion (pingVersion, cb) {
  request(getDynoFarmUrl() + "sys/info/" + pingVersion, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// put our apps into table format..
function createTableForApps(apps) {
  // calculate widths
  var maxTitle=5, maxName=4, maxUser=5, maxPort=5, maxState=5, maxUrl=3;

  for (var a in apps) {
    var app = apps[a];

    if(common.strlen(app.title) > maxTitle) maxTitle = common.strlen(app.title);
    if(common.strlen(app.appname) > maxName) maxName = common.strlen(app.appname);
    if(common.strlen(app.url) > maxUrl) maxUrl = common.strlen(app.url);
    if(common.strlen(app.email) > maxUser) maxUser = common.strlen(app.email);
    if(common.strlen(app.port) > maxPort) maxPort = common.strlen(app.port);
    if(common.strlen(app.state) > maxState) maxState = common.strlen(app.state);
  }

  // create our table
  df.table = new Table({
    head: ['Title', 'Name', 'Url', 'Email', 'Port', 'State'],
    colWidths: [maxTitle+2 , maxName+2, maxUrl+2, maxUser+2, maxPort+2, maxState+2],
    style: common.style()
  });

  // populate our table
  for (var a in apps) {
    var app = apps[a];
    df.table.push([app.title, app.appname, app.url, app.email, app.port || '-', app.state]);
  }
}

// DynoFarm apps
function apps (cb) {
  request(getDynoFarmUrl() + "apps", function (err, response, body) {
    if (err) return cb(nullToUndefined(err));
    var apps;
    try{
      apps = JSON.parse(body);
    } catch (x) {
      return cb("Error parsing apps: " + util.inspect(x));
    }

    if(ini.get('table') === true) {
      createTableForApps(apps);
    }

    return cb(undefined, apps);
  });
};

// DynoFarm logs
function logs(appId, cb) {
  request(getDynoFarmUrl() + "logs/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Stop app
function stop(appId, cb) {
  request(getDynoFarmUrl() + "stop/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Start app
function start(appId, cb) {
  request(getDynoFarmUrl() + "start/" + appId, function (err, response, body) {
    if(err) return cb(err);

    var app;
    try{
      app = JSON.parse(body);
    } catch (x) {
      log.error("Error parsing: " + body);
      return cb(x);
    }

    if(ini.get('table') === true) {
      df.table = common.createObjectTable(app);
    }

    return cb(nullToUndefined(err), app);
  });
};

// Restart app
function restart(appId, cb) {
  request(getDynoFarmUrl() + "restart/" + appId, function (err, response, body) {
    if(err) return cb(err);
    if(response.statusCode !== 200) return cb("Bad response: " + response.statusCode + " " + body);
    var app;
    try{
      app = JSON.parse(body);
    } catch (x) {
      return cb("Error parsing app: " + util.inspect(body) + " error: " + util.inspect(x));
    }

    if(ini.get('table') === true) {
      df.table = common.createObjectTable(app);
    }

    return cb(nullToUndefined(err), app);
  });
};

// Given an app id, returns its DynoFarm endpoint
function url(appId, cb) {
  var appName = common.getAppName(appId);
  var url = getAppUrl(appId);
  return cb(undefined, {name: appName, url:url});
};

function unknown (action, cb) {
  var msg = action ? "Wrong arguments for or unknown action: " + action + "\n" : "";
  msg += "Usage:\n" + df.usage;
  cb(msg);
};

// get our DF endpoint
function getDynoFarmUrl () {
  var r = fhc.config.get("dynofarm");
  if (!r) {
    return new Error("Must define DynoFarm URLs before accessing FeedHenry DynoFarm Server.")
  }
  if (r.substr(-1) !== "/") r += "/";
  fhc.config.set("dynofarm", r);
  return r;
};

// Annoyingly, 'request' returns nulls, the rest of FHC uses undefined, so return undefined to keep
// things consistent.
function nullToUndefined(err) {
  return err == null? undefined: err;
}

// delete an app
function deleteApp(appId, cb) {
  request({url: getDynoFarmUrl() + "delete/" + appId, method: 'POST'}, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// bash completion
df.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;
  if (argv[1] !== "df") argv.unshift("df");
  if (argv.length === 2) {
    var cmds = ["apps", "logs", "start", "stop", "delete", "act", "url", "version"];
    return cb(null, cmds);
  }

  var action = argv[2];
  switch (action) {
    // todo: complete with valid values, if possible.
    case "apps":
    case "logs":
    case "start":
    case "delete":
    case "act":
    case "url":
    case "version":
      return cb(null, Object.keys(types));
    default: return cb(null, []);
  }
};
<commit_msg>fhc df delete now deletes multiple apps<commit_after>module.exports = df;
df.pingVersion = pingVersion;
df.apps = apps;
df.logs = logs;

df.usage = "\nfhc df ping"
  + "\nfhc df version"
  + "\nfhc df apps"
  + "\nfhc df logs <app id>"
  + "\nfhc df start <app id>"
  + "\nfhc df stop <app id>"
  + "\nfhc df delete <app id>"
  + "\nfhc df act <app id> <server function> <params>"
  + "\nfhc df url <app id> (returns the full DynoFarm url given an appId)";

var log = require("./utils/log");
var hash = require("./utils/hash");
var fhc = require("./fhc");
var util = require('util');
var output = require("./utils/output");
var request = require('request');
var common = require('./common.js');
var Table = require('cli-table');
var ini = require('./utils/ini');
var async = require('async');

// main DynoFarm entry point
function df (args, cb) {
  var action = args.shift();
  switch (action) {
    case "ping": return pingVersion("ping", cb);
    case "version": return pingVersion("version", cb);
    case "apps": case "ls": return apps(cb);
    case "logs":  {
      if (args.length != 1) return unknown("logs", cb);
      else return logs(args[0], cb);
    };
    case "stop":  {
      if (args.length != 1) return unknown("stop", cb);
      else return stop(args[0], cb);
    };
    case "start":  {
      if (args.length != 1) return unknown("start", cb);
      else return start(args[0], cb);
    };
    case "restart":  {
      if (args.length != 1) return unknown("restart", cb);
      else return restart(args[0], cb);
    };
    case "url":  {
      if (args.length != 1) return unknown("url", cb);
      else return url(args[0], cb);
    };
    case "act": {
      if (args.length < 2) return unknown("act", cb);
      return act(args[0], args[1], args[2], cb);
    };
    case "delete":  {
      if (args.length < 1) return unknown("delete", cb);
      else return deleteApps(args, cb);
    };
    default: return unknown(action, cb);
  }
};

// gets the app endpoint from the dftarget
function getAppUrl(appId){
  var appName = common.getAppName(appId);
  var df = fhc.config.get("dynofarm");
  var uri = require('url').parse(df);

  // replace 'api' with the modified appId to get our enpoint
  var port = uri.port ? ":" +  uri.port : "";
  var url = uri.protocol + "//" + appName + "." + uri.hostname + port;
  url = url.replace(/\.api\./g, '.');

  return url;
}

// our 'act' function
function act(appId, funct, params, cb) {
  var data = {};
  if (params) data = JSON.parse(params);
  log.silly(data, "df act params");

  // firgure out our app endpoint
  var appUrl = getAppUrl(appId);
  log.verbose('' + appUrl, "App endpoint");
  log.verbose('' + funct, "Calling DF function");

  // post to /cloud
  request({uri: appUrl + "/cloud/" + funct, method: 'POST', json: data}, function (err, response, body) {
    log.silly(response);
    return cb(nullToUndefined(err), body);
  });
};

// ping
function pingVersion (pingVersion, cb) {
  request(getDynoFarmUrl() + "sys/info/" + pingVersion, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// put our apps into table format..
function createTableForApps(apps) {
  // calculate widths
  var maxTitle=5, maxName=4, maxUser=5, maxPort=5, maxState=5, maxUrl=3;

  for (var a in apps) {
    var app = apps[a];

    if(common.strlen(app.title) > maxTitle) maxTitle = common.strlen(app.title);
    if(common.strlen(app.appname) > maxName) maxName = common.strlen(app.appname);
    if(common.strlen(app.url) > maxUrl) maxUrl = common.strlen(app.url);
    if(common.strlen(app.email) > maxUser) maxUser = common.strlen(app.email);
    if(common.strlen(app.port) > maxPort) maxPort = common.strlen(app.port);
    if(common.strlen(app.state) > maxState) maxState = common.strlen(app.state);
  }

  // create our table
  df.table = new Table({
    head: ['Title', 'Name', 'Url', 'Email', 'Port', 'State'],
    colWidths: [maxTitle+2 , maxName+2, maxUrl+2, maxUser+2, maxPort+2, maxState+2],
    style: common.style()
  });

  // populate our table
  for (var a in apps) {
    var app = apps[a];
    df.table.push([app.title, app.appname, app.url, app.email, app.port || '-', app.state]);
  }
}

// DynoFarm apps
function apps (cb) {
  request(getDynoFarmUrl() + "apps", function (err, response, body) {
    if (err) return cb(nullToUndefined(err));
    var apps;
    try{
      apps = JSON.parse(body);
    } catch (x) {
      return cb("Error parsing apps: " + util.inspect(x, true, null) + " body: " + util.inspect(body));
    }

    if(ini.get('table') === true) {
      createTableForApps(apps);
    }

    return cb(undefined, apps);
  });
};

// DynoFarm logs
function logs(appId, cb) {
  request(getDynoFarmUrl() + "logs/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Stop app
function stop(appId, cb) {
  request(getDynoFarmUrl() + "stop/" + appId, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

// Start app
function start(appId, cb) {
  request(getDynoFarmUrl() + "start/" + appId, function (err, response, body) {
    if(err) return cb(err);

    var app;
    try{
      app = JSON.parse(body);
    } catch (x) {
      log.error("Error parsing: " + body);
      return cb(x);
    }

    if(ini.get('table') === true) {
      df.table = common.createObjectTable(app);
    }

    return cb(nullToUndefined(err), app);
  });
};

// Restart app
function restart(appId, cb) {
  request(getDynoFarmUrl() + "restart/" + appId, function (err, response, body) {
    if(err) return cb(err);
    if(response.statusCode !== 200) return cb("Bad response: " + response.statusCode + " " + body);
    var app;
    try{
      app = JSON.parse(body);
    } catch (x) {
      return cb("Error parsing app: " + util.inspect(body) + " error: " + util.inspect(x));
    }

    if(ini.get('table') === true) {
      df.table = common.createObjectTable(app);
    }

    return cb(nullToUndefined(err), app);
  });
};

// Given an app id, returns its DynoFarm endpoint
function url(appId, cb) {
  var appName = common.getAppName(appId);
  var url = getAppUrl(appId);
  return cb(undefined, {name: appName, url:url});
};

function unknown (action, cb) {
  var msg = action ? "Wrong arguments for or unknown action: " + action + "\n" : "";
  msg += "Usage:\n" + df.usage;
  cb(msg);
};

// get our DF endpoint
function getDynoFarmUrl () {
  var r = fhc.config.get("dynofarm");
  if (!r) {
    return new Error("Must define DynoFarm URLs before accessing FeedHenry DynoFarm Server.")
  }
  if (r.substr(-1) !== "/") r += "/";
  fhc.config.set("dynofarm", r);
  return r;
};

// Annoyingly, 'request' returns nulls, the rest of FHC uses undefined, so return undefined to keep
// things consistent.
function nullToUndefined(err) {
  return err == null? undefined: err;
}

// delete an app
function deleteApp(appId, cb) {
  request({url: getDynoFarmUrl() + "delete/" + appId, method: 'POST'}, function (err, response, body) {
    return cb(nullToUndefined(err), body);
  });
};

function deleteApps(apps, cb) {
  async.map(apps, deleteApp, cb);
};

// bash completion
df.completion = function (opts, cb) {
  var argv = opts.conf.argv.remain;
  if (argv[1] !== "df") argv.unshift("df");
  if (argv.length === 2) {
    var cmds = ["apps", "logs", "start", "stop", "delete", "act", "url", "version"];
    return cb(null, cmds);
  }

  var action = argv[2];
  switch (action) {
    // todo: complete with valid values, if possible.
    case "apps":
    case "logs":
    case "start":
    case "delete":
    case "act":
    case "url":
    case "version":
      return cb(null, Object.keys(types));
    default: return cb(null, []);
  }
};
<|endoftext|>


<commit_before>var git = require('nodegit');
var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.bold.green;
var notice = chalk.bold.yellow;
var error = chalk.bold.red;
var underline = chalk.underline;

exports.getCurrentRepo = function() {
	return git.Repository.open("./");
};

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) == 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✓] Initialized existing Git repository.'));
		}
	});
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✓] Added everything!'));
};

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		this.addAll();
		exec('git commit -m "' + message + '"');

		console.log(success('[✓] Commited!'));
		console.log('\nMessage: "' + underline(message) + '"');
	}
};

exports.push = function() {
	exec('git push', function(error, stdout, stderr) {
		if (stdout.substring(0, 10) == 'Everything') {
			console.log(notice('[~] Everything already pushed.'));
		} else if (stdout.substring(0, 8) == 'Counting') {
			console.log(success('[✓] Pushed!'));
		} else {
			console.log(error('[!] Could not push commits.'))
		}
	});
};
<commit_msg>Fixed error output formatting.<commit_after>var git = require('nodegit');
var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.bold.green;
var notice = chalk.bold.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.getCurrentRepo = function() {
	return git.Repository.open("./");
};

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) == 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✓] Initialized existing Git repository.'));
		}
	});
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✓] Added everything!'));
};

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		this.addAll();
		exec('git commit -m "' + message + '"');

		console.log(success('[✓] Commited!'));
		console.log('\nMessage: "' + underline(message) + '"');
	}
};

exports.push = function() {
	exec('git push', function(error, stdout, stderr) {
		if (stdout.substring(0, 10) == 'Everything') {
			console.log(notice('[~] Everything already pushed.'));
		} else if (stdout.substring(0, 8) == 'Counting') {
			console.log(success('[✓] Pushed!'));
		} else {
			console.log(whoops('[!] Could not push commits.'));
		}
	});
};
<|endoftext|>


<commit_before>var git = require('nodegit');
var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.green;
var notice = chalk.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.getCurrentRepo = function() {
	return git.Repository.open("./");
};

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) == 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✔] Initialized existing Git repository.'));
		}
	});
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✔] Added everything!'));
};

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		this.addAll();

		exec('git commit -m "' + message + '"', function(error, stdout, stderr) {
			if (stdout.substring(0, 1) == '[') {
				console.log(success('[✔] Commited!'));

				console.log();
				console.log('"' + underline(message) + '"');
			} else if (stdout.substring(0, 2) == 'On') {
				console.log(notice('[~] Everything already committed.'));
			} else {
				console.log(whoops('[✖] Could not commit changes.'));
			}
		});
	}
};

exports.push = function() {
	this.addAll();
	exec('git push', function(error, stdout, stderr) {
		if (stderr.substring(0, 10) == 'Everything') {
			console.log(notice('[~] All commits already pushed.'));
		} else if (stderr.substring(0, 2) == 'To') {
			console.log(success('[✔] Pushed!'));
		} else {
			console.log(whoops('[✖] Could not push commits.'));
		}
	});
};

exports.status = function() {
	exec('git status', function(error, stdout, stderr) {
		var status = stdout.split('\n');

		// Branch.
		console.log(chalk.dim('branch  ') + chalk.gray.dim(' | ') + success(status[0].split(' ')[2]));

		// Position in branch.
		var position;
		switch (status[1].split(' ')[3]) {
			case 'behind':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits behind')  + notice(' (fetch or pull)');
				break;

			case 'up-to-date':
				position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				break;

			case 'ahead':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits ahead') + notice(' (push commits)');
				break;

			default:
				position = 'position' + chalk.gray.dim(' | ') + whoops('diverged');
		}
		console.log(position);
	});
};

// https://gist.github.com/textarcana/1306223
exports.log = function() {
	exec('git log --pretty=format:\'{%n  "commit": "%H",%n  "author": "%an <%ae>",%n  "date": "%ad",%n  "message": "%f"%n},\' $@ | perl -pe \'BEGIN{print "["}; END{print "]\n"}\' | perl -pe \'s/},]/}]/\'', function(error, stdout, stderr) {
		var log = JSON.parse(stdout);
		log.reverse(); // Show newest at the bottom.

		for (var i = 0; i < log.length; i++) {
			console.log(); // New line between each commit.

			console.log(chalk.yellow('[' + log[i].commit + ']'));

			var author = {
				name: log[i].author.split('<')[0].trim(),
				email: '<' + log[i].author.split('<')[1]
			};

			console.log('|- ' + chalk.gray(author.name) + " " + chalk.gray.dim(author.email));
			console.log('|- ' + chalk.gray.dim(log[i].date));
			console.log('|- ' + chalk.green(log[i].message.split('-').join(' ')));
		}
	});
};
<commit_msg>Added staging and commits to status shortcut.<commit_after>var git = require('nodegit');
var exec = require('child_process').exec;
var chalk = require('chalk');

// Output styling.
var success = chalk.green;
var notice = chalk.yellow;
var whoops = chalk.bold.red; // Can't name error as exec uses error in callback.
var underline = chalk.underline;

exports.getCurrentRepo = function() {
	return git.Repository.open("./");
};

exports.init = function() {
	exec('git init', function(error, stdout, stderr) {
		if (stdout.substring(0, 13) == 'Reinitialized') {
			console.log(notice('[~] Reinitialized existing Git repository.'));
		} else {
			console.log(success('[✔] Initialized existing Git repository.'));
		}
	});
};

exports.addAll = function() {
	exec('git add -A');

	console.log(success('[✔] Added everything!'));
};

exports.commit = function(message) {
	// No commit message.
	if (message === '') {
		console.log(notice('[~] You must enter a commit message.'));
	} else {
		this.addAll();

		exec('git commit -m "' + message + '"', function(error, stdout, stderr) {
			if (stdout.substring(0, 1) == '[') {
				console.log(success('[✔] Commited!'));

				console.log();
				console.log('"' + underline(message) + '"');
			} else if (stdout.substring(0, 2) == 'On') {
				console.log(notice('[~] Everything already committed.'));
			} else {
				console.log(whoops('[✖] Could not commit changes.'));
			}
		});
	}
};

exports.push = function() {
	this.addAll();
	exec('git push', function(error, stdout, stderr) {
		if (stderr.substring(0, 10) == 'Everything') {
			console.log(notice('[~] All commits already pushed.'));
		} else if (stderr.substring(0, 2) == 'To') {
			console.log(success('[✔] Pushed!'));
		} else {
			console.log(whoops('[✖] Could not push commits.'));
		}
	});
};

exports.status = function() {
	exec('git status', function(error, stdout, stderr) {
		var status = stdout.split('\n');

		// Branch.
		console.log(chalk.dim('branch  ') + chalk.gray.dim(' | ') + success(status[0].split(' ')[2]));

		// Position in branch.
		var position;
		switch (status[1].split(' ')[3]) {
			case 'behind':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits behind (fetch or pull)');
				break;

			case 'up-to-date':
				position = chalk.dim('position') + chalk.gray.dim(' | ') + success('up-to-date');
				break;

			case 'ahead':
				position = 'position' + chalk.gray.dim(' | ') + notice(status[1].split(' ')[7] + ' commits ahead (push commits)');
				break;

			default:
				position = 'position' + chalk.gray.dim(' | ') + whoops('diverged');
		}
		console.log(position);

		// Staging and commits.
		var staging;
		if (status[3] == 'Changes not staged for commit:') {
			staging = 'staging ' + chalk.gray.dim(' | ') + notice('not all changes staged (add all changes)');
		} else {
			staging = chalk.dim('staging ') + chalk.gray.dim(' | ') + success('all changes staged');
		}

		console.log(staging);

		var commits;
		if (status[3] == 'Changes to be committed:') {
			commits = 'commits ' + chalk.gray.dim(' | ') + notice('not all changes committed (commit all changes)');
		} else {
			commits = chalk.dim('commits ') + chalk.gray.dim(' | ') + success('all changes committed');
		}

		console.log(commits);
	});
};

// https://gist.github.com/textarcana/1306223
exports.log = function() {
	exec('git log --pretty=format:\'{%n  "commit": "%H",%n  "author": "%an <%ae>",%n  "date": "%ad",%n  "message": "%f"%n},\' $@ | perl -pe \'BEGIN{print "["}; END{print "]\n"}\' | perl -pe \'s/},]/}]/\'', function(error, stdout, stderr) {
		var log = JSON.parse(stdout);
		log.reverse(); // Show newest at the bottom.

		for (var i = 0; i < log.length; i++) {
			console.log(); // New line between each commit.

			console.log(chalk.yellow('[' + log[i].commit + ']'));

			var author = {
				name: log[i].author.split('<')[0].trim(),
				email: '<' + log[i].author.split('<')[1]
			};

			console.log('|- ' + chalk.gray(author.name) + " " + chalk.gray.dim(author.email));
			console.log('|- ' + chalk.gray.dim(log[i].date));
			console.log('|- ' + chalk.green(log[i].message.split('-').join(' ')));
		}
	});
};
<|endoftext|>


<commit_before>(function (window) {
    'use strict';

    var storageTypes = {
        localStorage: window.localStorage,
        sessionStorage: window.sessionStorage
    };

    // LS error messages
    var errorMessages = {
        doesNotExist: {
            message: 'Endpoint does not exist'
        },
        typeError: {
            message: 'Function is missing a parameter, or first parameter type incorrect'
        }
    };

    /**
     * main constructor
     *
     * @param {Object} settings
     * @return {this}
     * @public
     */

    var LS = function LS (settings) {
        var currentDate = new Date().getTime(),
            self = this,
            mergedSettings,

            promise = new Promise(function (resolve, reject) {

                // merge default settings with custom settings
                mergedSettings = LS.mergedSettings = Object.assign(
                    {}, LS.defaultSettings, settings
                );

                // configure storage type
                LS.storageType =
                    storageTypes[mergedSettings.storageType] ||
                    LS.defaultSettings.storageType;

                if (mergedSettings.endpoint) {

                    // if local storage exists return self
                    if (self.check()) {

                        // remove expired storage
                        if (mergedSettings.expires !== undefined) {
                            if (currentDate > (LS.storageItem.dateCreated + mergedSettings.expires)) {
                                self.remove();
                            }
                        }

                        resolve(self);
                    }
                } else {
                    reject(Error('init error: ' + errorMessages.typeError.message));
                }
            });

        promise.then(function (instance) {
            return instance;
        });

        promise.catch(function (err) {
            return err;
        });
    };

    // instance properties
    LS.defaultSettings = {
        storageType: storageTypes.localStorage,
        endpoint: undefined,
        expires: undefined
    };

    LS.mergedSettings = {};
    LS.storageType = null;
    LS.storageItem = {};

    /**
     * set local storage and instance data
     *
     * @param {Object} data
     * @param {Function} fn (response)
     * @return {promise}
     * @public
     */

    LS.prototype.set = function (data, fn) {

        var promise = new Promise(function (resolve, reject) {
            if (data && typeof data !== 'function') {
                LS.storageItem.endpoint = LS.mergedSettings.endpoint;
                LS.storageItem.data = data;
                LS.storageItem.dateCreated = new Date().getTime();

                LS.storageType[LS.mergedSettings.endpoint] = JSON.stringify(LS.storageItem);

                resolve(LS.storageItem.data);
            } else {
                reject(Error('set error: ' + errorMessages.typeError.message));
            }
        });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    /**
     * get local storage data and provide object to client with optional callback
     *
     * @param {Function} fn (response)
     * @return {promise}
     * @public
     */

    LS.prototype.get = LS.prototype.find = function (fn) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (self.check()) {
                    LS.storageItem = JSON.parse(LS.storageType[LS.mergedSettings.endpoint]);

                    resolve(LS.storageItem.data);
                } else {
                    resolve({
                        error: {
                            message: 'get error: ' + errorMessages.doesNotExist.message
                        }
                    })
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    /**
     * convenience function
     * get local storage data and provide object to client
     *
     * @return {Object}
     * @public
     */

    LS.prototype.$get = function () {
        var storageItem = JSON.parse(LS.storageType[LS.mergedSettings.endpoint]);

        if (this.check()) {
            return storageItem.data;
        } else {
            return {
                error: {
                    message: 'get error: ' + errorMessages.doesNotExist.message
                }
            };
        }
    };

    /**
     * check if local storage data exists
     *
     * @return {Boolean}
     * @public
     */

    LS.prototype.check = function () {
        return LS.storageType[LS.mergedSettings.endpoint] !== undefined;
    };

    /**
     * clear local storage and instance data with optional callback
     *
     * @param {Function} fn (response)
     * @return {promise}
     * @public
     */

    LS.prototype.remove = LS.prototype.delete = function (fn) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (self.check()) {

                    // remove local storage
                    LS.storageType.removeItem(LS.mergedSettings.endpoint);

                    // reset storageItem object
                    LS.storageItem = {};

                    resolve(self);
                } else {
                    resolve({
                        error: {
                            message: 'remove error: ' + errorMessages.doesNotExist.message
                        }
                    });
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    /**
     * update local storage data with optional callback
     *
     * @param {Function} fn (response)
     * @param {Boolean} bool
     * @return {promise}
     * @public
     */

    LS.prototype.update = LS.prototype.save = function (fn, bool) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (self.check() && LS.storageItem.endpoint) {

                    // if user provides true for update dateCreated
                    if (fn && bool && typeof bool === 'boolean' || !bool && fn && typeof fn === 'boolean') {
                        LS.storageItem.dateCreated = new Date().getTime();
                    }

                    // update local storage object
                    LS.storageType[LS.mergedSettings.endpoint] = JSON.stringify(LS.storageItem);

                    resolve(LS.storageItem.data);
                } else {
                    reject(Error('update error: ' + errorMessages.doesNotExist.message));
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    // Object.assign shim
    if (typeof Object.assign != 'function') {
        (function () {
            Object.assign = function (target) {
                if (target === undefined || target === null) {
                    throw new TypeError('Cannot convert undefined or null to object');
                }

                var output = Object(target);

                for (var index = 1; index < arguments.length; index++) {
                    var source = arguments[index];

                    if (source !== undefined && source !== null) {
                        for (var nextKey in source) {
                            if (source.hasOwnProperty(nextKey)) {
                                output[nextKey] = source[nextKey];
                            }
                        }
                    }
                }

                return output;
            };
        })();
    }

    // globalize LS object/constructor
    window.LS = LS;

})(window);
<commit_msg>refactoring<commit_after>(function (window) {
    'use strict';

    var storageTypes = {
        localStorage: window.localStorage,
        sessionStorage: window.sessionStorage
    };

    // LS error messages
    var errorMessages = {
        doesNotExist: {
            message: 'Endpoint does not exist'
        },
        typeError: {
            message: 'Function is missing a parameter, or first parameter type incorrect'
        }
    };

    /**
     * main constructor
     *
     * @param {Object} settings
     * @return {this}
     * @public
     */

    var LS = function LS (settings) {
        var currentDate = new Date().getTime(),
            self = this,

            promise = new Promise(function (resolve, reject) {

                // merge default settings with custom settings
                self.settings = Object.assign(
                    {}, LS.defaultSettings, settings
                );

                // configure storage type
                self.settings.storageType =
                    storageTypes[self.settings.storageType] ||
                    LS.defaultSettings.storageType;

                if (self.settings.endpoint) {

                    // if local storage exists return self
                    if (self.check()) {

                        // remove expired storage
                        if (self.settings.expires !== undefined) {
                            if (currentDate > (this.storageItem.dateCreated + self.settings.expires)) {
                                self.remove();
                            }
                        }

                        resolve(self);
                    }
                } else {
                    reject(Error('init error: ' + errorMessages.typeError.message));
                }
            });

        promise.then(function (instance) {
            return instance;
        });

        promise.catch(function (err) {
            return err;
        });
    };

    // instance properties
    LS.defaultSettings = {
        storageType: storageTypes.localStorage,
        endpoint: undefined,
        expires: undefined
    };

    /**
     * set local storage and instance data
     *
     * @param {Object} data
     * @param {Function} fn (response)
     * @return {promise}
     * @public
     */

    LS.prototype.set = function (data, fn) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (data && typeof data !== 'function') {
                    self.storageItem = {};
                    self.storageItem.endpoint = self.settings.endpoint;
                    self.storageItem.data = data;
                    self.storageItem.dateCreated = new Date().getTime();

                    self.settings.storageType[self.settings.endpoint] = JSON.stringify(self.storageItem);

                    resolve(self.storageItem.data);
                } else {
                    reject(Error('set error: ' + errorMessages.typeError.message));
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    /**
     * get local storage data and provide object to client with optional callback
     *
     * @param {Function} fn (response)
     * @return {promise}
     * @public
     */

    LS.prototype.get = LS.prototype.find = function (fn) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (self.check()) {
                    self.storageItem = JSON.parse(self.settings.storageType[self.settings.endpoint]);

                    resolve(self.storageItem.data);
                } else {
                    resolve({
                        error: {
                            message: 'get error: ' + errorMessages.doesNotExist.message
                        }
                    })
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    /**
     * convenience function
     * get local storage data and provide object to client
     *
     * @return {Object}
     * @public
     */

    LS.prototype.$get = function () {
        var storageItem = JSON.parse(this.settings.storageType[this.settings.endpoint]);

        if (this.check()) {
            return storageItem.data;
        } else {
            return {
                error: {
                    message: 'get error: ' + errorMessages.doesNotExist.message
                }
            };
        }
    };

    /**
     * check if local storage data exists
     *
     * @return {Boolean}
     * @public
     */

    LS.prototype.check = function () {
        return this.settings.storageType[this.settings.endpoint] !== undefined;
    };

    /**
     * clear local storage and instance data with optional callback
     *
     * @param {Function} fn (response)
     * @return {promise}
     * @public
     */

    LS.prototype.remove = LS.prototype.delete = function (fn) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (self.check()) {

                    // remove local storage
                    self.settings.storageType.removeItem(self.settings.endpoint);

                    self.storageItem = {};

                    resolve(self);
                } else {
                    resolve({
                        error: {
                            message: 'remove error: ' + errorMessages.doesNotExist.message
                        }
                    });
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    /**
     * update local storage data with optional callback
     *
     * @param {Function} fn (response)
     * @param {Boolean} bool
     * @return {promise}
     * @public
     */

    LS.prototype.update = LS.prototype.save = function (fn, bool) {

        var self = this,
            promise = new Promise(function (resolve, reject) {
                if (self.check() && self.storageItem.endpoint) {

                    // if user provides true for update dateCreated
                    if (fn && bool && typeof bool === 'boolean' || !bool && fn && typeof fn === 'boolean') {
                        self.storageItem.dateCreated = new Date().getTime();
                    }

                    self.settings.storageType[self.settings.endpoint] = JSON.stringify(self.storageItem);

                    resolve(self.storageItem.data);
                } else {
                    reject(Error('update error: ' + errorMessages.doesNotExist.message));
                }
            });

        if (fn && typeof fn === 'function') {
            promise.then(function (response) {
                fn(response);
            });
        }

        return promise;
    };

    // Object.assign shim
    if (typeof Object.assign != 'function') {
        (function () {
            Object.assign = function (target) {
                if (target === undefined || target === null) {
                    throw new TypeError('Cannot convert undefined or null to object');
                }

                var output = Object(target);

                for (var index = 1; index < arguments.length; index++) {
                    var source = arguments[index];

                    if (source !== undefined && source !== null) {
                        for (var nextKey in source) {
                            if (source.hasOwnProperty(nextKey)) {
                                output[nextKey] = source[nextKey];
                            }
                        }
                    }
                }

                return output;
            };
        })();
    }

    // globalize LS object/constructor
    window.LS = LS;

})(window);
<|endoftext|>


<commit_before>/*
 *  Ni - a minimalistic Node framework that makes setting up an MVC project
 *  a breeze. Inspired by CodeIgniter.
 *
 *  Since Ni is fully contained in a Node module, you can use it with Connect
 *  and your own choice of template engine, database, static file server, etc.
 *  No frills, no restrictions, no worries.
 */

/*
 *  Module dependencies
 */

var fs = require('fs'),
    Step = require('step');

/*
 *  Ni object
 */

var Ni = function() {
    var Ni = this;

    /*
     *  Registry for custom configuration variables.
     */

    this.config = {};

    /*
     *  Tells Ni what root directory to look into.
     *
     *  Call this function before calling boot.
     */

    this.setRoot = function(__root) {
        this.__root = __root;
    }

    /*
     *  Loads controllers, models, views, templates and helpers from the root
     *  directory, and makes them all available to the Ni object.
     */

    this.boot = function(callbackDone) {
        Step(
                function bootStrapEverything() {
                    bootStrapControllers(Ni.__root, this.parallel());
                    bootStrapModels(Ni.__root, this.parallel());
                    bootStrapViews(Ni.__root, this.parallel());
                    bootStrapLibraries(Ni.__root, this.parallel());
                },
                function buildNi(err, controllers, models, views, libraries) {
                    if (err) throw err;
                    Ni.controllers = controllers;
                    Ni.models = models;
                    Ni.views = views;
                    Ni.libraries = libraries;
                    callbackDone();
                }
            );
    }

    /*
     *  Provides router for Connect to automatically call the correct controller
     *  functions with the correct arguments based on the URL. If the controller
     *  or action is not found, it calls next() in the Connect list.
     *
     *  Add this to your Connect call as: Ni.router
     */

    this.router = function(req, res, next) {
        parsedUrl = require('url').parse(req.url, true);
        pathArr = parsedUrl.pathname.split('/');
        res.Ni = { view: true };

        var controller;
        if (pathArr[1]) {
            controller = Ni.controllers[pathArr[1]];
            if (controller) {
                res.Ni.controller = controller;
                var fn;
                if (pathArr[2]) {
                    res.Ni.action = pathArr[2];
                    fn = controller[pathArr[2]];
                }
                else {
                    res.Ni.action = 'index';
                    fn = controller.index;
                }

                if (fn) {
                    var args = pathArr.slice(3);
                    args.unshift(next);
                    args.unshift(res);
                    args.unshift(req);
                    fn.apply(null, args);
                }
                else {
                    next();
                }
            }
            else {
                next();
            }
        }
        else {
            controller = Ni.controllers.home;
            if (controller && controller.index) {
                res.Ni.controller = 'home';
                res.Ni.action = 'index';
                controller.index(req, res, next);
            }
            else {
                next();
            }
        }
    }

    this.view = function (renderer) {
      if (typeof(renderer) === 'function') {
        console.log('setting up route handler for views');
        return function (req, res, next) {
          if (res.Ni.view && typeof(res.Ni.action) !== 'undefined') {
            renderer(req, res, next, res.Ni.controller + '/' + res.Ni.action);
          }
        }
      } else {
        throw new Error('Ni.view expects a function as the first argument');
      }
    }
};

/* Helper functions
*******************************************************************************/

/*
 *  Loads controllers.
 */

function bootStrapControllers(__root, callback) {
    bootStrapModules(__root + '/controllers', function(err, controllers) {
        if (err) throw err;
        callback(null, controllers);
    });
}

/*
 *  Loads models.
 */

function bootStrapModels(__root, callback) {
    bootStrapModules(__root + '/models', function(err, models) {
        if (err) throw err;
        callback(null, models);
    });
}

/*
 *  Loads views.
 */

function bootStrapViews(__root, callback) {
    var __views = __root + '/views';
    var views = {};

    loadFilesFromDir(__views, function(dir, file, name) {
        var view = {};
        view.path = dir + '/' + file;
        fs.readFile(view.path, 'utf-8', function(err, data) {
            view.template = data;
            views[name] = view;
        });
    }, function(err) {
        if (err) throw err;
        callback(null, views);
    });
}

/*
 *  Loads libraries.
 */

function bootStrapLibraries(__root, callback) {
    bootStrapModules(__root + '/libraries', function(err, libraries) {
        if (err) throw err;
        callback(null, libraries);
    });
}

/*
 *  Loads anything that is represented as a Node.js module.
 *  This includes controllers, models, libraries and helpers.
 */

function bootStrapModules(__root, callback) {
    var __modules = __root;
    var modules = {};

    loadFilesFromDir(__modules, function(dir, file, name) {
        var name = file.split('.')[0];
        modules[name] = require(dir + '/' + file);
    }, function(err) {
        if (err) callback(err);
        else callback(null, modules);
    });
}

/*
 *  Loads files from given directory and calls the given function on them.
 */

function loadFilesFromDir(dir, fnOnFile, callbackDone) {
    fs.readdir(dir, function(err, files){
        if (err || !files) callbackDone(null);
        else {
            Step(
                function readFiles() {
                    if (files.length > 0) {
                        var group = this.group();
                        files.forEach(function (file){
                            var name = file.split('.')[0];

                            fnOnFile(dir, file, name);
                            group()();
                        });
                    }
                    else {
                        return null;
                    }
                },
                function finish(err) {
                    if (err) callbackDone(err);
                    callbackDone(null);
                }
            );
        }
    });
}

/*
 *  Exports the Ni object to Node.js.
 */

module.exports = new Ni();<commit_msg>Add missing next() call.<commit_after>/*
 *  Ni - a minimalistic Node framework that makes setting up an MVC project
 *  a breeze. Inspired by CodeIgniter.
 *
 *  Since Ni is fully contained in a Node module, you can use it with Connect
 *  and your own choice of template engine, database, static file server, etc.
 *  No frills, no restrictions, no worries.
 */

/*
 *  Module dependencies
 */

var fs = require('fs'),
    Step = require('step');

/*
 *  Ni object
 */

var Ni = function() {
    var Ni = this;

    /*
     *  Registry for custom configuration variables.
     */

    this.config = {};

    /*
     *  Tells Ni what root directory to look into.
     *
     *  Call this function before calling boot.
     */

    this.setRoot = function(__root) {
        this.__root = __root;
    }

    /*
     *  Loads controllers, models, views, templates and helpers from the root
     *  directory, and makes them all available to the Ni object.
     */

    this.boot = function(callbackDone) {
        Step(
                function bootStrapEverything() {
                    bootStrapControllers(Ni.__root, this.parallel());
                    bootStrapModels(Ni.__root, this.parallel());
                    bootStrapViews(Ni.__root, this.parallel());
                    bootStrapLibraries(Ni.__root, this.parallel());
                },
                function buildNi(err, controllers, models, views, libraries) {
                    if (err) throw err;
                    Ni.controllers = controllers;
                    Ni.models = models;
                    Ni.views = views;
                    Ni.libraries = libraries;
                    callbackDone();
                }
            );
    }

    /*
     *  Provides router for Connect to automatically call the correct controller
     *  functions with the correct arguments based on the URL. If the controller
     *  or action is not found, it calls next() in the Connect list.
     *
     *  Add this to your Connect call as: Ni.router
     */

    this.router = function(req, res, next) {
        parsedUrl = require('url').parse(req.url, true);
        pathArr = parsedUrl.pathname.split('/');
        res.Ni = { view: true };

        var controller;
        if (pathArr[1]) {
            controller = Ni.controllers[pathArr[1]];
            if (controller) {
                res.Ni.controller = controller;
                var fn;
                if (pathArr[2]) {
                    res.Ni.action = pathArr[2];
                    fn = controller[pathArr[2]];
                }
                else {
                    res.Ni.action = 'index';
                    fn = controller.index;
                }

                if (fn) {
                    var args = pathArr.slice(3);
                    args.unshift(next);
                    args.unshift(res);
                    args.unshift(req);
                    fn.apply(null, args);
                }
                else {
                    next();
                }
            }
            else {
                next();
            }
        }
        else {
            controller = Ni.controllers.home;
            if (controller && controller.index) {
                res.Ni.controller = 'home';
                res.Ni.action = 'index';
                controller.index(req, res, next);
            }
            else {
                next();
            }
        }
    }

    this.view = function (renderer) {
      if (typeof(renderer) === 'function') {
        console.log('setting up route handler for views');
        return function (req, res, next) {
          if (res.Ni.view && typeof(res.Ni.action) !== 'undefined') {
            renderer(req, res, next, res.Ni.controller + '/' + res.Ni.action);
          } else {
            next();
          }
        }
      } else {
        throw new Error('Ni.view expects a function as the first argument');
      }
    }
};

/* Helper functions
*******************************************************************************/

/*
 *  Loads controllers.
 */

function bootStrapControllers(__root, callback) {
    bootStrapModules(__root + '/controllers', function(err, controllers) {
        if (err) throw err;
        callback(null, controllers);
    });
}

/*
 *  Loads models.
 */

function bootStrapModels(__root, callback) {
    bootStrapModules(__root + '/models', function(err, models) {
        if (err) throw err;
        callback(null, models);
    });
}

/*
 *  Loads views.
 */

function bootStrapViews(__root, callback) {
    var __views = __root + '/views';
    var views = {};

    loadFilesFromDir(__views, function(dir, file, name) {
        var view = {};
        view.path = dir + '/' + file;
        fs.readFile(view.path, 'utf-8', function(err, data) {
            view.template = data;
            views[name] = view;
        });
    }, function(err) {
        if (err) throw err;
        callback(null, views);
    });
}

/*
 *  Loads libraries.
 */

function bootStrapLibraries(__root, callback) {
    bootStrapModules(__root + '/libraries', function(err, libraries) {
        if (err) throw err;
        callback(null, libraries);
    });
}

/*
 *  Loads anything that is represented as a Node.js module.
 *  This includes controllers, models, libraries and helpers.
 */

function bootStrapModules(__root, callback) {
    var __modules = __root;
    var modules = {};

    loadFilesFromDir(__modules, function(dir, file, name) {
        var name = file.split('.')[0];
        modules[name] = require(dir + '/' + file);
    }, function(err) {
        if (err) callback(err);
        else callback(null, modules);
    });
}

/*
 *  Loads files from given directory and calls the given function on them.
 */

function loadFilesFromDir(dir, fnOnFile, callbackDone) {
    fs.readdir(dir, function(err, files){
        if (err || !files) callbackDone(null);
        else {
            Step(
                function readFiles() {
                    if (files.length > 0) {
                        var group = this.group();
                        files.forEach(function (file){
                            var name = file.split('.')[0];

                            fnOnFile(dir, file, name);
                            group()();
                        });
                    }
                    else {
                        return null;
                    }
                },
                function finish(err) {
                    if (err) callbackDone(err);
                    callbackDone(null);
                }
            );
        }
    });
}

/*
 *  Exports the Ni object to Node.js.
 */

module.exports = new Ni();<|endoftext|>


<commit_before>'use strict';

var Bluebird = require('./bluebird-fresh.js'),
    printRejectionReason = require('./bluebird-captured-trace-fresh.js').possiblyUnhandledRejection,
    _ = require('lodash');

// Load Request freshly - so that users can require an unaltered request instance!
var request = (function () {

    function clearCache() {
        _(require.cache).keys().forEach(function (key) {
            delete require.cache[key];
        });
    }

    var temp = _.assign({}, require.cache);
    clearCache();

    var freshRequest = require('request');

    clearCache();
    _.assign(require.cache, temp);

    return freshRequest;

})();

function ownCallback(err, httpResponse, body) {

    /* jshint validthis:true */
    var self = this;

    var origCallbackThrewException = false, thrownException;

    if (_.isFunction(self._rp_callbackOrig)) {
        try {
            self._rp_callbackOrig.apply(self, arguments);
        } catch (e) {
            origCallbackThrewException = true;
            thrownException = e;
        }
    }

    if (err) {
        self._rp_reject({
            error: err,
            options: self._rp_options,
            response: httpResponse
        });
    } else if (self._rp_options.simple && !(/^2/.test('' + httpResponse.statusCode))) {
        self._rp_reject({
            error: body,
            options: self._rp_options,
            response: httpResponse,
            statusCode: httpResponse.statusCode
        });
    } else {
        if (_.isFunction(self._rp_options.transform)) {
            try {
                self._rp_resolve(self._rp_options.transform(body, httpResponse));
            } catch (e) {
                self._rp_reject(e);
            }
        } else if (self._rp_options.resolveWithFullResponse) {
            self._rp_resolve(httpResponse);
        } else {
            self._rp_resolve(body);
        }
    }

    if (origCallbackThrewException) {
        throw thrownException;
    }

    // Mimic original behavior of errors emitted by request with no error listener registered
    if (err && _.isFunction(self._rp_callbackOrig) === false && self._rp_promise_in_use !== true && self.listeners('error').length === 1) {
        throw err;
    }

}

var originalInit = request.Request.prototype.init;

request.Request.prototype.init = function (options) {

    var self = this;

    // Init may be called again - currently in case of redirects
    if (_.isPlainObject(options) && self._callback === undefined && self._rp_promise === undefined) {

        self._rp_promise = new Bluebird(function (resolve, reject) {
            self._rp_resolve = resolve;
            self._rp_reject = reject;
        });
        self._rp_promise._rp_in_use = false;

        self._rp_callbackOrig = self.callback;
        self.callback = ownCallback;

        if (_.isString(options.method)) {
            options.method = options.method.toUpperCase();
        }

        self._rp_options = options;
        self._rp_options.simple = options.simple === false ? false : true;
        self._rp_options.resolveWithFullResponse = options.resolveWithFullResponse === true ? true : false;

    }

    return originalInit.apply(self, arguments);

};

function markPromiseInUse(requestInstance) {
    requestInstance._rp_promise_in_use = true;
    requestInstance._rp_promise._rp_in_use = true;
}

request.Request.prototype.then = function (onFulfilled, onRejected) {
    markPromiseInUse(this);
    return this._rp_promise.then.apply(this._rp_promise, arguments);
};

request.Request.prototype.catch = function (onRejected) {
    markPromiseInUse(this);
    return this._rp_promise.catch.apply(this._rp_promise, arguments);
};

Bluebird.onPossiblyUnhandledRejection(function (reason, promise) {
    // For whatever reason we don't see _rp_in_use here at all after then is called. --> We compare to false instead of true.
    if (promise._rp_in_use !== false) {
        printRejectionReason(reason);
    }
    // else: The user did not call .then(...)
    // --> We need to assume that this request is processed with a callback or a pipe etc.
});

module.exports = request;
<commit_msg>Added .promise() and function names for inspection<commit_after>'use strict';

var Bluebird = require('./bluebird-fresh.js'),
    printRejectionReason = require('./bluebird-captured-trace-fresh.js').possiblyUnhandledRejection,
    _ = require('lodash');

// Load Request freshly - so that users can require an unaltered request instance!
var request = (function () {

    function clearCache() {
        _(require.cache).keys().forEach(function (key) {
            delete require.cache[key];
        });
    }

    var temp = _.assign({}, require.cache);
    clearCache();

    var freshRequest = require('request');

    clearCache();
    _.assign(require.cache, temp);

    return freshRequest;

})();

function ownCallback(err, httpResponse, body) {

    /* jshint validthis:true */
    var self = this;

    var origCallbackThrewException = false, thrownException;

    if (_.isFunction(self._rp_callbackOrig)) {
        try {
            self._rp_callbackOrig.apply(self, arguments);
        } catch (e) {
            origCallbackThrewException = true;
            thrownException = e;
        }
    }

    if (err) {
        self._rp_reject({
            error: err,
            options: self._rp_options,
            response: httpResponse
        });
    } else if (self._rp_options.simple && !(/^2/.test('' + httpResponse.statusCode))) {
        self._rp_reject({
            error: body,
            options: self._rp_options,
            response: httpResponse,
            statusCode: httpResponse.statusCode
        });
    } else {
        if (_.isFunction(self._rp_options.transform)) {
            try {
                self._rp_resolve(self._rp_options.transform(body, httpResponse));
            } catch (e) {
                self._rp_reject(e);
            }
        } else if (self._rp_options.resolveWithFullResponse) {
            self._rp_resolve(httpResponse);
        } else {
            self._rp_resolve(body);
        }
    }

    if (origCallbackThrewException) {
        throw thrownException;
    }

    // Mimic original behavior of errors emitted by request with no error listener registered
    if (err && _.isFunction(self._rp_callbackOrig) === false && self._rp_promise_in_use !== true && self.listeners('error').length === 1) {
        throw err;
    }

}

var originalInit = request.Request.prototype.init;

request.Request.prototype.init = function (options) {

    var self = this;

    // Init may be called again - currently in case of redirects
    if (_.isPlainObject(options) && self._callback === undefined && self._rp_promise === undefined) {

        self._rp_promise = new Bluebird(function (resolve, reject) {
            self._rp_resolve = resolve;
            self._rp_reject = reject;
        });
        self._rp_promise._rp_in_use = false;

        self._rp_callbackOrig = self.callback;
        self.callback = ownCallback;

        if (_.isString(options.method)) {
            options.method = options.method.toUpperCase();
        }

        self._rp_options = options;
        self._rp_options.simple = options.simple === false ? false : true;
        self._rp_options.resolveWithFullResponse = options.resolveWithFullResponse === true ? true : false;

    }

    return originalInit.apply(self, arguments);

};

function markPromiseInUse(requestInstance) {
    requestInstance._rp_promise_in_use = true;
    requestInstance._rp_promise._rp_in_use = true;
}

request.Request.prototype.then = function RP$then(onFulfilled, onRejected) {
    markPromiseInUse(this);
    return this._rp_promise.then.apply(this._rp_promise, arguments);
};

request.Request.prototype.catch = function RP$catch(onRejected) {
    markPromiseInUse(this);
    return this._rp_promise.catch.apply(this._rp_promise, arguments);
};

request.Request.prototype.promise = function RP$promise() {
    markPromiseInUse(this);
    return this._rp_promise;
};

Bluebird.onPossiblyUnhandledRejection(function (reason, promise) {
    // For whatever reason we don't see _rp_in_use here at all after then is called. --> We compare to false instead of true.
    if (promise._rp_in_use !== false) {
        printRejectionReason(reason);
    }
    // else: The user did not call .then(...)
    // --> We need to assume that this request is processed with a callback or a pipe etc.
});

module.exports = request;
<|endoftext|>