mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
Bookshelf provider abstraction and tests
This commit is contained in:
parent
503e9fb391
commit
242367e228
14 changed files with 313 additions and 106 deletions
|
@ -61,7 +61,7 @@
|
|||
connection: {
|
||||
filename: './core/shared/data/testdb.db'
|
||||
},
|
||||
debug: true
|
||||
debug: false
|
||||
},
|
||||
|
||||
staging: {},
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
/** TODO potentially use req.acceptedLanguages rather than the default
|
||||
* TODO handle loading language file for frontend on frontend request etc
|
||||
* TODO switch this mess to be promise driven */
|
||||
fs.stat(langFilePath, function (error, stat) {
|
||||
fs.stat(langFilePath, function (error) {
|
||||
if (error) {
|
||||
console.log('No language file found for language ' + lang + '. Defaulting to en');
|
||||
lang = 'en';
|
||||
|
|
|
@ -69,7 +69,14 @@
|
|||
});
|
||||
};
|
||||
|
||||
down = function () {};
|
||||
down = function () {
|
||||
|
||||
return when.all([
|
||||
knex.Schema.dropTableIfExists("posts"),
|
||||
knex.Schema.dropTableIfExists("users"),
|
||||
knex.Schema.dropTableIfExists("settings")
|
||||
]);
|
||||
};
|
||||
|
||||
exports.up = up;
|
||||
exports.down = down;
|
||||
|
|
72
core/shared/models/dataProvider.bookshelf.base.js
Normal file
72
core/shared/models/dataProvider.bookshelf.base.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* The base class for interacting with bookshelf models/collections.
|
||||
* Provides naive implementations of CRUD/BREAD operations.
|
||||
*/
|
||||
var BookshelfBase = function (model, collection) {
|
||||
this.model = model;
|
||||
this.collection = collection;
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive find all
|
||||
* @param args
|
||||
* @param callback
|
||||
*/
|
||||
BookshelfBase.prototype.findAll = function (args, callback) {
|
||||
args = args || {};
|
||||
this.collection.forge().fetch().then(function (results) {
|
||||
callback(null, results);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive find one where args match
|
||||
* @param args
|
||||
* @param callback
|
||||
*/
|
||||
BookshelfBase.prototype.findOne = function (args, callback) {
|
||||
this.model.forge(args).fetch().then(function (result) {
|
||||
callback(null, result);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive add
|
||||
* @param newObj
|
||||
* @param callback
|
||||
*/
|
||||
BookshelfBase.prototype.add = function (newObj, callback) {
|
||||
this.model.forge(newObj).save().then(function (createdObj) {
|
||||
callback(null, createdObj);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive edit
|
||||
* @param editedObj
|
||||
* @param callback
|
||||
*/
|
||||
BookshelfBase.prototype.edit = function (editedObj, callback) {
|
||||
this.model.forge({id: editedObj.id}).fetch().then(function (foundObj) {
|
||||
foundObj.set(editedObj).save().then(function (updatedObj) {
|
||||
callback(null, updatedObj);
|
||||
}, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive destroy
|
||||
* @param _identifier
|
||||
* @param callback
|
||||
*/
|
||||
BookshelfBase.prototype.destroy = function (_identifier, callback) {
|
||||
this.model.forge({id: _identifier}).destroy().then(function () {
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = BookshelfBase;
|
||||
}());
|
|
@ -7,8 +7,8 @@
|
|||
"use strict";
|
||||
|
||||
var knex = require('./knex_init'),
|
||||
models = require('./models'),
|
||||
bcrypt = require('bcrypt'),
|
||||
PostsProvider = require('./dataProvider.bookshelf.posts'),
|
||||
UsersProvider = require('./dataProvider.bookshelf.users'),
|
||||
DataProvider,
|
||||
instance;
|
||||
|
||||
|
@ -17,7 +17,7 @@
|
|||
instance = this;
|
||||
knex.Schema.hasTable('posts').then(null, function () {
|
||||
// Simple boostraping of the data model for now.
|
||||
require('./../data/migration/001').up().then(function () {
|
||||
require('../data/migration/001').up().then(function () {
|
||||
console.log('all done....');
|
||||
});
|
||||
});
|
||||
|
@ -26,102 +26,8 @@
|
|||
return instance;
|
||||
};
|
||||
|
||||
DataProvider.prototype.posts = function () { };
|
||||
DataProvider.prototype.users = function () { };
|
||||
|
||||
/**
|
||||
* Naive find all
|
||||
* @param args
|
||||
* @param callback
|
||||
*/
|
||||
DataProvider.prototype.posts.findAll = function (args, callback) {
|
||||
models.Posts.forge().fetch().then(function (posts) {
|
||||
callback(null, posts);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive find one where args match
|
||||
* @param args
|
||||
* @param callback
|
||||
*/
|
||||
DataProvider.prototype.posts.findOne = function (args, callback) {
|
||||
models.Post.forge(args).fetch().then(function (post) {
|
||||
callback(null, post);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive add
|
||||
* @param _post
|
||||
* @param callback
|
||||
*/
|
||||
DataProvider.prototype.posts.add = function (_post, callback) {
|
||||
console.log(_post);
|
||||
models.Post.forge(_post).save().then(function (post) {
|
||||
callback(null, post);
|
||||
}, callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive edit
|
||||
* @param _post
|
||||
* @param callback
|
||||
*/
|
||||
DataProvider.prototype.posts.edit = function (_post, callback) {
|
||||
models.Post.forge({id: _post.id}).fetch().then(function (post) {
|
||||
post.set(_post).save().then(function (post) {
|
||||
callback(null, post);
|
||||
}, callback);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
DataProvider.prototype.posts.destroy = function (_identifier, callback) {
|
||||
models.Post.forge({id: _identifier}).destroy().then(function () {
|
||||
callback(null);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Naive user add
|
||||
* @param _user
|
||||
* @param callback
|
||||
*
|
||||
* Could probably do with some refactoring, but it works right now.
|
||||
*/
|
||||
DataProvider.prototype.users.add = function (_user, callback) {
|
||||
console.log('outside of forge', _user);
|
||||
bcrypt.genSalt(10, function (err, salt) {
|
||||
bcrypt.hash(_user.password, salt, function (err, hash) {
|
||||
var test = {
|
||||
"password": hash,
|
||||
"email_address": _user.email
|
||||
};
|
||||
new models.User(test).save().then(function (user) {
|
||||
console.log('within the forge for the user bit', user);
|
||||
callback(null, user);
|
||||
}, callback);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
DataProvider.prototype.users.check = function (_userdata, callback) {
|
||||
var test = {
|
||||
email_address: _userdata.email
|
||||
};
|
||||
models.User.forge(test).fetch().then(function (user) {
|
||||
var _user;
|
||||
bcrypt.compare(_userdata.pw, user.attributes.password, function (err, res) {
|
||||
if (res) {
|
||||
_user = user;
|
||||
} else {
|
||||
_user = false;
|
||||
}
|
||||
callback(null, _user);
|
||||
});
|
||||
});
|
||||
};
|
||||
DataProvider.prototype.posts = new PostsProvider();
|
||||
DataProvider.prototype.users = new UsersProvider();
|
||||
|
||||
module.exports = DataProvider;
|
||||
}());
|
20
core/shared/models/dataProvider.bookshelf.posts.js
Normal file
20
core/shared/models/dataProvider.bookshelf.posts.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
(function() {
|
||||
"use strict";
|
||||
|
||||
var util = require('util'),
|
||||
|
||||
models = require('./models'),
|
||||
BaseProvider = require('./dataProvider.bookshelf.base'),
|
||||
PostsProvider;
|
||||
|
||||
/**
|
||||
* The Posts data provider implementation for Bookshelf.
|
||||
*/
|
||||
PostsProvider = function () {
|
||||
BaseProvider.call(this, models.Post, models.Posts);
|
||||
};
|
||||
|
||||
util.inherits(PostsProvider, BaseProvider);
|
||||
|
||||
module.exports = PostsProvider;
|
||||
}());
|
86
core/shared/models/dataProvider.bookshelf.users.js
Normal file
86
core/shared/models/dataProvider.bookshelf.users.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
(function() {
|
||||
"use strict";
|
||||
|
||||
var util = require('util'),
|
||||
_ = require('underscore'),
|
||||
bcrypt = require('bcrypt'),
|
||||
models = require('./models.js'),
|
||||
BaseProvider = require('./dataProvider.bookshelf.base.js'),
|
||||
UsersProvider;
|
||||
|
||||
/**
|
||||
* The Users data provider implementation for Bookshelf.
|
||||
*/
|
||||
UsersProvider = function () {
|
||||
BaseProvider.call(this, models.User, models.Users);
|
||||
};
|
||||
|
||||
util.inherits(UsersProvider, BaseProvider);
|
||||
|
||||
/**
|
||||
* Naive user add
|
||||
* @param _user
|
||||
* @param callback
|
||||
*
|
||||
* Hashes the password provided before saving to the database.
|
||||
*/
|
||||
UsersProvider.prototype.add = function (_user, callback) {
|
||||
var self = this,
|
||||
// Clone the _user so we don't expose the hashed password unnecessarily
|
||||
userData = _.extend({}, _user);
|
||||
|
||||
this._hashPassword(userData.password, function (err, hash) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
userData.password = hash;
|
||||
|
||||
BaseProvider.prototype.add.call(self, userData, function (err, createdUser) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, createdUser);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
UsersProvider.prototype._hashPassword = function (password, callback) {
|
||||
bcrypt.genSalt(10, function (err, salt) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
bcrypt.hash(password, salt, function (err, hash) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
|
||||
callback(null, hash);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
UsersProvider.prototype.check = function (_userdata, callback) {
|
||||
var test = {
|
||||
email_address: _userdata.email
|
||||
};
|
||||
models.User.forge(test).fetch().then(function (user) {
|
||||
var _user;
|
||||
bcrypt.compare(_userdata.pw, user.attributes.password, function (err, res) {
|
||||
if (err) {
|
||||
return callback(err);
|
||||
}
|
||||
if (res) {
|
||||
_user = user;
|
||||
} else {
|
||||
_user = false;
|
||||
}
|
||||
callback(null, _user);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = UsersProvider;
|
||||
}());
|
|
@ -46,7 +46,9 @@
|
|||
|
||||
/* Lets bootstrap with dummy data */
|
||||
d = new DataProvider();
|
||||
d.globals.save(blogData, function (error, globals) {});
|
||||
d.globals.save(blogData, function (error) {
|
||||
if (error) { throw error; }
|
||||
});
|
||||
|
||||
module.exports = DataProvider;
|
||||
}());
|
|
@ -2,9 +2,10 @@
|
|||
(function () {
|
||||
"use strict";
|
||||
|
||||
var knex = require('knex');
|
||||
var knex = require('knex'),
|
||||
config = require('../../../config');
|
||||
|
||||
knex.Initialize(require('../../../config').database[process.env.NODE_ENV || 'development']);
|
||||
knex.Initialize(config.database[process.env.NODE_ENV || 'development']);
|
||||
|
||||
module.exports = knex;
|
||||
}());
|
|
@ -12,6 +12,7 @@
|
|||
Post,
|
||||
Posts,
|
||||
User,
|
||||
Users,
|
||||
Setting;
|
||||
|
||||
Post = Bookshelf.Model.extend({
|
||||
|
@ -67,6 +68,12 @@
|
|||
}
|
||||
});
|
||||
|
||||
Users = Bookshelf.Collection.extend({
|
||||
|
||||
model: User
|
||||
|
||||
});
|
||||
|
||||
Setting = Bookshelf.Model.extend({
|
||||
|
||||
tableName: 'settings'
|
||||
|
@ -77,6 +84,7 @@
|
|||
Post: Post,
|
||||
Posts: Posts,
|
||||
User: User,
|
||||
Users: Users,
|
||||
Setting: Setting
|
||||
};
|
||||
}());
|
42
core/test/ghost/api_posts_spec.js
Normal file
42
core/test/ghost/api_posts_spec.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
/*globals describe, beforeEach, it*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var should = require('should'),
|
||||
helpers = require('./helpers'),
|
||||
PostProvider = require('../../shared/models/dataProvider.bookshelf.posts');
|
||||
|
||||
describe("dataProvider.bookshelf", function () {
|
||||
describe('PostsProvider', function () {
|
||||
|
||||
var posts;
|
||||
|
||||
beforeEach(function (done) {
|
||||
helpers.resetData().then(function () {
|
||||
posts = new PostProvider();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can create', function (done) {
|
||||
var newPost = {
|
||||
title: 'Test Title 1',
|
||||
content: 'Test Content 1'
|
||||
};
|
||||
|
||||
posts.add(newPost, function (err, createdPost) {
|
||||
if (err) { throw err; }
|
||||
|
||||
should.exist(createdPost);
|
||||
|
||||
createdPost.attributes.title.should.equal(newPost.title, "title is correct");
|
||||
createdPost.attributes.content.should.equal(newPost.content, "content is correct");
|
||||
createdPost.attributes.slug.should.equal(newPost.title.toLowerCase().replace(/ /g, '-'), 'slug is correct');
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}());
|
44
core/test/ghost/api_users_spec.js
Normal file
44
core/test/ghost/api_users_spec.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*globals describe, beforeEach, it*/
|
||||
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
var should = require('should'),
|
||||
helpers = require('./helpers'),
|
||||
UserProvider = require('../../shared/models/dataProvider.bookshelf.users');
|
||||
|
||||
describe('dataProvider.bookshelf', function () {
|
||||
describe('UsersProvider', function () {
|
||||
|
||||
var users;
|
||||
|
||||
beforeEach(function (done) {
|
||||
helpers.resetData().then(function () {
|
||||
users = new UserProvider();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('can create', function(done) {
|
||||
var userData = {
|
||||
password: 'testpass1',
|
||||
email_address: "test@test1.com"
|
||||
};
|
||||
|
||||
users.add(userData, function(err, createdUser) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
should.exist(createdUser);
|
||||
|
||||
createdUser.attributes.password.should.not.equal(userData.password, "password was hashed");
|
||||
createdUser.attributes.email_address.should.eql(userData.email_address, "email address corred");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
}());
|
18
core/test/ghost/helpers.js
Normal file
18
core/test/ghost/helpers.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
(function() {
|
||||
"use strict";
|
||||
|
||||
var migrations = {
|
||||
one: require("../../shared/data/migration/001")
|
||||
},
|
||||
helpers;
|
||||
|
||||
helpers = {
|
||||
resetData: function () {
|
||||
return migrations.one.down().then(function () {
|
||||
return migrations.one.up();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = helpers;
|
||||
}());
|
|
@ -26,6 +26,7 @@
|
|||
"grunt-contrib-nodeunit": "0.1.x",
|
||||
"grunt-contrib-compass": "0.2.x",
|
||||
"nodeunit": "0.8.x",
|
||||
"grunt-jslint": "0.2.x"
|
||||
"grunt-jslint": "0.2.x",
|
||||
"should": "~1.2.2"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue