Skip to content
Permalink
Browse files

Implements Models & Data API for Apps

closes #2138
- Adds new models for AppField and AppSetting
- Removed permitted attributes from App model (handled by base)
- Added reference from Post to AppFields
- Added fixture data to DataGenerator
- Added integration tests for Apps, AppSettings, AppFields
- Added import for Apps
- Added app_fields to default fixtures
  • Loading branch information...
halfdan authored and sebgie committed Feb 24, 2014
1 parent 7b003be commit 41cef386bcba98db6a613e0830d848e9bb2c2f47
@@ -12,7 +12,8 @@ Importer000 = function () {
this.importFrom = {
'000': this.basicImport,
'001': this.basicImport,
'002': this.basicImport
'002': this.basicImport,
'003': this.basicImport
};
};

@@ -35,6 +36,7 @@ Importer000.prototype.canImport = function (data) {


function stripProperties(properties, data) {
data = _.clone(data, true);
_.each(data, function (obj) {
_.each(properties, function (property) {
delete obj[property];
@@ -125,6 +127,47 @@ function importSettings(ops, tableData, transaction) {
.otherwise(function (error) { return when.reject(error); }));
}

function importApps(ops, tableData, transaction) {
tableData = stripProperties(['id'], tableData);
_.each(tableData, function (app) {
// Avoid duplicates
ops.push(models.App.findOne({name: app.name}, {transacting: transaction}).then(function (_app) {
if (!_app) {
return models.App.add(app, {transacting: transaction})
// add pass-through error handling so that bluebird doesn't think we've dropped it
.otherwise(function (error) { return when.reject(error); });
}
return when.resolve(_app);
}));
});
}
/*
function importAppSettings(ops, tableData, transaction) {
var appsData = tableData.apps,
appSettingsData = tableData.app_settings,
appName;
appSettingsData = stripProperties(['id'], appSettingsData);
_.each(appSettingsData, function (appSetting) {
// Find app to attach settings to
appName = _.find(appsData, function (app) {
return app.id === appSetting.app_id;
}).name;
ops.push(models.App.findOne({name: appName}, {transacting: transaction}).then(function (_app) {
if (_app) {
// Fix app_id
appSetting.app_id = _app.id;
return models.AppSetting.add(appSetting, {transacting: transaction})
// add pass-through error handling so that bluebird doesn't think we've dropped it
.otherwise(function (error) { return when.reject(error); });
}
// Gracefully ignore missing apps
return when.resolve(_app);
}));
});
}
*/
// No data needs modifying, we just import whatever tables are available
Importer000.prototype.basicImport = function (data) {
var ops = [],
@@ -153,6 +196,20 @@ Importer000.prototype.basicImport = function (data) {
importSettings(ops, tableData.settings, t);
}

if (tableData.apps && tableData.apps.length) {
importApps(ops, tableData.apps, t);

// ToDo: This is rather complicated
// Only import settings if there are apps defined
//if (tableData.app_settings && tableData.app_settings.length) {
// importAppSettings(ops, _.pick(tableData, 'apps', 'app_settings'), t);
//}

//if (tableData.app_fields && tableData.app_fields.length) {
// importAppFields(ops, _.pick(tableData, 'apps', 'posts', 'app_fields'), t);
//}
}

/** do nothing with these tables, the data shouldn't have changed from the fixtures
* permissions
* roles
@@ -0,0 +1,8 @@
var Importer000 = require('./000');

module.exports = {
Importer003: Importer000,
importData: function (data) {
return new Importer000.importData(data);
}
};
@@ -1,19 +1,22 @@
var ghostBookshelf = require('./base'),
AppSetting = require('./appSetting'),
App,
Apps;

App = ghostBookshelf.Model.extend({
tableName: 'apps',

permittedAttributes: ['id', 'uuid', 'name', 'created_at', 'created_by', 'updated_at', 'updated_by'],

validate: function () {
ghostBookshelf.validator.check(this.get('name'), "App name cannot be blank").notEmpty();
},

permissions: function () {
// Have to use the require here because of circular dependencies
return this.belongsToMany(require('./permission').Permission, 'permissions_apps');
},

settings: function () {
return this.belongsToMany(AppSetting, 'app_settings');
}
});

@@ -0,0 +1,32 @@
var ghostBookshelf = require('./base'),
Post = require('./post').Post,
AppField,
AppFields;

AppField = ghostBookshelf.Model.extend({
tableName: 'app_fields',

validate: function () {
ghostBookshelf.validator.check(this.get('key'), 'Key cannot be blank').notEmpty();
ghostBookshelf.validator.check(this.get('key'), 'Key maximum length is 150 characters.').len(0, 150);
ghostBookshelf.validator.check(this.get('app_id'), 'App cannot be blank').notEmpty();
ghostBookshelf.validator.check(this.get('type'), 'Type maximum length is 150 characters.').len(0, 150);
ghostBookshelf.validator.check(this.get('relatable_id'), 'Relatable id cannot be blank').notEmpty();
ghostBookshelf.validator.check(this.get('relatable_type'), 'Relatable type cannot be blank').notEmpty();

return true;
},

post: function () {
return this.morphOne(Post, 'relatable');
}
});

AppFields = ghostBookshelf.Collection.extend({
model: AppField
});

module.exports = {
AppField: AppField,
AppFields: AppFields
};
@@ -0,0 +1,30 @@
var ghostBookshelf = require('./base'),
App = require('./app'),
AppSetting,
AppSettings;

AppSetting = ghostBookshelf.Model.extend({
tableName: 'app_settings',

validate: function () {
ghostBookshelf.validator.check(this.get('key'), 'Key cannot be blank').notEmpty();
ghostBookshelf.validator.check(this.get('key'), 'Key maximum length is 150 characters.').len(0, 150);
ghostBookshelf.validator.check(this.get('app_id'), 'App cannot be blank').notEmpty();
ghostBookshelf.validator.check(this.get('type'), 'Type maximum length is 150 characters.').len(0, 150);

return true;
},

app: function () {
return this.belongsTo(App);
}
});

AppSettings = ghostBookshelf.Collection.extend({
model: AppSetting
});

module.exports = {
AppSetting: AppSetting,
AppSettings: AppSettings
};
@@ -12,6 +12,8 @@ module.exports = {
Base: require('./base'),
Session: require('./session').Session,
App: require('./app').App,
AppField: require('./appField').AppField,
AppSetting: require('./appSetting').AppSetting,

init: function () {
return migrations.init();
@@ -1,6 +1,4 @@
var ghostBookshelf = require('./base'),
_ = require('lodash'),
when = require('when'),
User = require('./user').User,
Role = require('./role').Role,
App = require('./app').App,
@@ -5,6 +5,7 @@ var _ = require('lodash'),
Showdown = require('showdown'),
ghostgfm = require('../../shared/lib/showdown/extensions/ghostgfm'),
converter = new Showdown.converter({extensions: [ghostgfm]}),
AppField = require('./appField').AppField,
User = require('./user').User,
Tag = require('./tag').Tag,
Tags = require('./tag').Tags,
@@ -198,6 +199,10 @@ Post = ghostBookshelf.Model.extend({

tags: function () {
return this.belongsToMany(Tag);
},

fields: function () {
return this.morphMany(AppField, 'relatable');
}

}, {
@@ -206,7 +211,8 @@ Post = ghostBookshelf.Model.extend({
// Extends base model findAll to eager-fetch author and user relationships.
findAll: function (options) {
options = options || {};
options.withRelated = [ 'author', 'tags' ];

options.withRelated = [ 'author', 'tags', 'fields' ];
return ghostBookshelf.Model.findAll.call(this, options);
},

@@ -223,7 +229,7 @@ Post = ghostBookshelf.Model.extend({
delete args.status;
}

options.withRelated = [ 'author', 'tags' ];
options.withRelated = [ 'author', 'tags', 'fields' ];
return ghostBookshelf.Model.findOne.call(this, args, options);
},

@@ -289,7 +295,7 @@ Post = ghostBookshelf.Model.extend({
}

// Fetch related models
opts.withRelated = [ 'author', 'tags' ];
opts.withRelated = [ 'author', 'tags', 'fields' ];

// If a query param for a tag is attached
// we need to fetch the tag model to find its id
@@ -1,5 +1,4 @@
var _ = require('lodash'),
when = require('when'),
Models = require('../models'),
errors = require('../errorHandling'),
User = Models.User,
@@ -0,0 +1,76 @@
/*globals describe, before, beforeEach, afterEach, it*/
var testUtils = require('../../utils'),
should = require('should'),
_ = require("lodash"),

// Stuff we are testing
Models = require('../../../server/models'),
knex = require('../../../server/models/base').knex;

describe('App Fields Model', function () {

var AppFieldsModel = Models.AppField;

before(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});

beforeEach(function (done) {
testUtils.initData()
.then(function () {
return testUtils.insertApps();
})
.then(function () {
done();
}, done);
});

afterEach(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});

after(function (done) {
testUtils.clearData().then(function () {
done();
}, done);
});

it('can browse', function (done) {
AppFieldsModel.browse().then(function (results) {

should.exist(results);

results.length.should.be.above(0);

done();
}).then(null, done);
});

it('can read', function (done) {
AppFieldsModel.read({id: 1}).then(function (foundAppField) {
should.exist(foundAppField);

done();
}).then(null, done);
});

it('can edit', function (done) {
AppFieldsModel.read({id: 1}).then(function (foundAppField) {
should.exist(foundAppField);

return foundAppField.set({value: "350"}).save();
}).then(function () {
return AppFieldsModel.read({id: 1});
}).then(function (updatedAppField) {
should.exist(updatedAppField);

updatedAppField.get("value").should.equal("350");

done();
}).then(null, done);
});
});

0 comments on commit 41cef38

Please sign in to comment.
You can’t perform that action at this time.