mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-03-25 02:31:59 -05:00
Merge pull request #6572 from ErisDS/data005-part1-fixpastfixtures
Data 005 - Part 1 - Fix Past Fixtures (refactor & test fixture migrations)
This commit is contained in:
commit
21770c53da
24 changed files with 1610 additions and 752 deletions
|
@ -0,0 +1,46 @@
|
|||
// Moves jQuery inclusion to code injection via ghost_foot
|
||||
var _ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
serverPath = '../../../../',
|
||||
config = require(serverPath + 'config'),
|
||||
models = require(serverPath + 'models'),
|
||||
notifications = require(serverPath + 'api/notifications'),
|
||||
i18n = require(serverPath + 'i18n'),
|
||||
|
||||
// These messages are shown in the admin UI, not the console, and should therefore be translated
|
||||
jquery = [
|
||||
i18n.t('notices.data.fixtures.canSafelyDelete'),
|
||||
'<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>\n\n'
|
||||
],
|
||||
privacyMessage = [
|
||||
i18n.t('notices.data.fixtures.jQueryRemoved'),
|
||||
i18n.t('notices.data.fixtures.canBeChanged')
|
||||
];
|
||||
|
||||
module.exports = function moveJQuery(options, logInfo) {
|
||||
var value;
|
||||
|
||||
return models.Settings.findOne('ghost_foot').then(function (setting) {
|
||||
if (setting) {
|
||||
value = setting.attributes.value;
|
||||
// Only add jQuery if it's not already in there
|
||||
if (value.indexOf(jquery.join('')) === -1) {
|
||||
logInfo('Adding jQuery link to ghost_foot');
|
||||
value = jquery.join('') + value;
|
||||
|
||||
return models.Settings.edit({key: 'ghost_foot', value: value}, options).then(function () {
|
||||
if (_.isEmpty(config.privacy)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
logInfo(privacyMessage.join(' ').replace(/<\/?strong>/g, ''));
|
||||
return notifications.add({
|
||||
notifications: [{
|
||||
type: 'info',
|
||||
message: privacyMessage.join(' ')
|
||||
}]
|
||||
}, options);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
// Update the `isPrivate` setting, so that it has a type of `private` rather than `blog`
|
||||
var models = require('../../../../models'),
|
||||
Promise = require('bluebird');
|
||||
|
||||
module.exports = function updatePrivateSetting(options, logInfo) {
|
||||
return models.Settings.findOne('isPrivate').then(function (setting) {
|
||||
if (setting) {
|
||||
logInfo('Update isPrivate setting');
|
||||
return models.Settings.edit({key: 'isPrivate', type: 'private'}, options);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,13 @@
|
|||
// Update the `password` setting, so that it has a type of `private` rather than `blog`
|
||||
var models = require('../../../../models'),
|
||||
Promise = require('bluebird');
|
||||
|
||||
module.exports = function updatePasswordSetting(options, logInfo) {
|
||||
return models.Settings.findOne('password').then(function (setting) {
|
||||
if (setting) {
|
||||
logInfo('Update password setting');
|
||||
return models.Settings.edit({key: 'password', type: 'private'}, options);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
// Update the `ghost-admin` client so that it has a proper secret
|
||||
var models = require('../../../../models'),
|
||||
_ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
crypto = require('crypto'),
|
||||
|
||||
adminClient = require('../fixtures').models.Client[0];
|
||||
|
||||
module.exports = function updateGhostAdminClient(options, logInfo) {
|
||||
// ghost-admin should already exist from 003 version
|
||||
return models.Client.findOne({slug: adminClient.slug}).then(function (client) {
|
||||
if (client) {
|
||||
logInfo('Update ghost-admin client fixture');
|
||||
return models.Client.edit(
|
||||
_.extend({}, adminClient, {secret: crypto.randomBytes(6).toString('hex')}),
|
||||
_.extend({}, options, {id: client.id})
|
||||
);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,15 @@
|
|||
// Create a new `ghost-frontend` client for use in themes
|
||||
var models = require('../../../../models'),
|
||||
Promise = require('bluebird'),
|
||||
|
||||
frontendClient = require('../fixtures').models.Client[1];
|
||||
|
||||
module.exports = function addGhostFrontendClient(options, logInfo) {
|
||||
return models.Client.findOne({slug: frontendClient.slug}).then(function (client) {
|
||||
if (!client) {
|
||||
logInfo('Add ghost-frontend client fixture');
|
||||
return models.Client.add(frontendClient, options);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
// Clean tags which start with commas, the only illegal char in tags
|
||||
var models = require('../../../../models'),
|
||||
Promise = require('bluebird');
|
||||
|
||||
module.exports = function cleanBrokenTags(options, logInfo) {
|
||||
return models.Tag.findAll(options).then(function (tags) {
|
||||
var tagOps = [];
|
||||
if (tags) {
|
||||
tags.each(function (tag) {
|
||||
var name = tag.get('name'),
|
||||
updated = name.replace(/^(,+)/, '').trim();
|
||||
|
||||
// If we've ended up with an empty string, default to just 'tag'
|
||||
updated = updated === '' ? 'tag' : updated;
|
||||
|
||||
if (name !== updated) {
|
||||
tagOps.push(tag.save({name: updated}, options));
|
||||
}
|
||||
});
|
||||
if (tagOps.length > 0) {
|
||||
logInfo('Cleaning ' + tagOps.length + ' malformed tags');
|
||||
return Promise.all(tagOps);
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
|
@ -0,0 +1,39 @@
|
|||
// Add a new order value to posts_tags based on the existing info
|
||||
var models = require('../../../../models'),
|
||||
_ = require('lodash'),
|
||||
sequence = require('../../../../utils/sequence');
|
||||
|
||||
module.exports = function addPostTagOrder(options, logInfo) {
|
||||
var tagOps = [];
|
||||
logInfo('Collecting data on tag order for posts...');
|
||||
return models.Post.findAll(_.extend({}, options)).then(function (posts) {
|
||||
if (posts) {
|
||||
return posts.mapThen(function (post) {
|
||||
return post.load(['tags']);
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}).then(function (posts) {
|
||||
_.each(posts, function (post) {
|
||||
var order = 0;
|
||||
post.related('tags').each(function (tag) {
|
||||
tagOps.push((function (order) {
|
||||
var sortOrder = order;
|
||||
return function () {
|
||||
return post.tags().updatePivot(
|
||||
{sort_order: sortOrder}, _.extend({}, options, {query: {where: {tag_id: tag.id}}})
|
||||
);
|
||||
};
|
||||
}(order)));
|
||||
order += 1;
|
||||
});
|
||||
});
|
||||
|
||||
if (tagOps.length > 0) {
|
||||
logInfo('Updating order on ' + tagOps.length + ' tag relationships (could take a while)...');
|
||||
return sequence(tagOps).then(function () {
|
||||
logInfo('Tag order successfully updated');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
|
@ -0,0 +1,27 @@
|
|||
// Adds a new draft post with information about the new design
|
||||
var models = require('../../../../models'),
|
||||
newPost = {
|
||||
title: 'You\'ve been upgraded to the latest version of Ghost',
|
||||
slug: 'ghost-0-7',
|
||||
markdown: 'You\'ve just upgraded to the latest version of Ghost and we\'ve made a few changes that you should probably know about!\n\n## Woah, why does everything look different?\n\nAfter two years and hundreds of thousands of users, we learned a great deal about what was (and wasn\'t) working in the old Ghost admin user interface. What you\'re looking at is Ghost\'s first major UI refresh, with a strong focus on being more usable and robust all round.\n\n\n\nThe main navigation menu, previously located at the top of your screen, has now moved over to the left. This makes it way easier to work with on mobile devices, and has the added benefit of providing ample space for upcoming features!\n\n## Lost and found: Your old posts\n\nFrom talking to many of you we understand that finding old posts in the admin area was a real pain; so we\'ve added a new magical search bar which lets you quickly find posts for editing, without having to scroll endlessly. Take it for a spin!\n\n\n\nQuestions? Comments? Send us a tweet [@TryGhost](https://twitter.com/tryghost)\n\nOh, and yes – you can safely delete this draft post!',
|
||||
image: null,
|
||||
featured: false,
|
||||
page: false,
|
||||
status: 'draft',
|
||||
language: 'en_US',
|
||||
meta_title: null,
|
||||
meta_description: null
|
||||
};
|
||||
|
||||
module.exports = function addNewPostFixture(options, logInfo) {
|
||||
return models.Post.findOne({slug: newPost.slug, status: 'all'}, options).then(function (post) {
|
||||
if (!post) {
|
||||
logInfo('Adding 0.7 upgrade post fixture');
|
||||
// Set the published_at timestamp, but keep the post as a draft so doesn't appear on the frontend
|
||||
// This is a hack to ensure that this post appears at the very top of the drafts list, because
|
||||
// unpublished posts always appear first
|
||||
newPost.published_at = Date.now();
|
||||
return models.Post.add(newPost, options);
|
||||
}
|
||||
});
|
||||
};
|
25
core/server/data/migration/fixtures/004/index.js
Normal file
25
core/server/data/migration/fixtures/004/index.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
module.exports = [
|
||||
// add jquery setting and privacy info
|
||||
require('./01-move-jquery-with-alert'),
|
||||
|
||||
// change `type` for protected blog `isPrivate` setting
|
||||
require('./02-update-private-setting-type'),
|
||||
|
||||
// change `type` for protected blog `password` setting
|
||||
require('./03-update-password-setting-type'),
|
||||
|
||||
// Update ghost-admin client fixture
|
||||
require('./04-update-ghost-admin-client'),
|
||||
|
||||
// add ghost-frontend client if missing
|
||||
require('./05-add-ghost-frontend-client'),
|
||||
|
||||
// clean up broken tags
|
||||
require('./06-clean-broken-tags'),
|
||||
|
||||
// Add post_tag order
|
||||
require('./07-add-post-tag-order'),
|
||||
|
||||
// Add a new draft post
|
||||
require('./08-add-post-fixture')
|
||||
];
|
|
@ -1,81 +1,269 @@
|
|||
{
|
||||
"users": [
|
||||
{
|
||||
"name": "Ghost Owner",
|
||||
"email": "ghost@ghost.org",
|
||||
"status": "inactive"
|
||||
}
|
||||
],
|
||||
"posts": [
|
||||
{
|
||||
"title": "Welcome to Ghost",
|
||||
"slug": "welcome-to-ghost",
|
||||
"markdown": "You're live! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. You can manage your content by signing in to the admin area at `<your blog URL>/ghost/`. When you arrive, you can select this post from a list on the left and see a preview of it on the right. Click the little pencil icon at the top of the preview to edit this post and read the next section!\n\n## Getting Started\n\nGhost uses something called Markdown for writing. Essentially, it's a shorthand way to manage your post formatting as you write!\n\nWriting in Markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use *shortcuts* to **style** your content. For example, a list:\n\n* Item number one\n* Item number two\n * A nested item\n* A final item\n\nor with numbers!\n\n1. Remember to buy some milk\n2. Drink the milk\n3. Tweet that I remembered to buy the milk, and drank it\n\n### Links\n\nWant to link to a source? No problem. If you paste in a URL, like http://ghost.org - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to [the Ghost website](http://ghost.org). Neat.\n\n### What about Images?\n\nImages work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:\n\n\n\nNot sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:\n\n![A bowl of bananas]\n\n\n### Quoting\n\nSometimes a link isn't enough, you want to quote someone on what they've said. Perhaps you've started using a new blogging platform and feel the sudden urge to share their slogan? A quote might be just the way to do it!\n\n> Ghost - Just a blogging platform\n\n### Working with Code\n\nGot a streak of geek? We've got you covered there, too. You can write inline `<code>` blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.\n\n .awesome-thing {\n display: block;\n width: 100%;\n }\n\n### Ready for a Break? \n\nThrow 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.\n\n---\n\n### Advanced Usage\n\nThere's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.\n\n<input type=\"text\" placeholder=\"I'm an input field!\" />\n\nThat should be enough to get you started. Have fun - and let us know what you think :)",
|
||||
"image": null,
|
||||
"featured": false,
|
||||
"page": false,
|
||||
"status": "published",
|
||||
"language": "en_US",
|
||||
"meta_title": null,
|
||||
"meta_description": null
|
||||
}
|
||||
],
|
||||
"models": {
|
||||
"Post": [
|
||||
{
|
||||
"title": "Welcome to Ghost",
|
||||
"slug": "welcome-to-ghost",
|
||||
"markdown": "You're live! Nice. We've put together a little post to introduce you to the Ghost editor and get you started. You can manage your content by signing in to the admin area at `<your blog URL>/ghost/`. When you arrive, you can select this post from a list on the left and see a preview of it on the right. Click the little pencil icon at the top of the preview to edit this post and read the next section!\n\n## Getting Started\n\nGhost uses something called Markdown for writing. Essentially, it's a shorthand way to manage your post formatting as you write!\n\nWriting in Markdown is really easy. In the left hand panel of Ghost, you simply write as you normally would. Where appropriate, you can use *shortcuts* to **style** your content. For example, a list:\n\n* Item number one\n* Item number two\n * A nested item\n* A final item\n\nor with numbers!\n\n1. Remember to buy some milk\n2. Drink the milk\n3. Tweet that I remembered to buy the milk, and drank it\n\n### Links\n\nWant to link to a source? No problem. If you paste in a URL, like http://ghost.org - it'll automatically be linked up. But if you want to customise your anchor text, you can do that too! Here's a link to [the Ghost website](http://ghost.org). Neat.\n\n### What about Images?\n\nImages work too! Already know the URL of the image you want to include in your article? Simply paste it in like this to make it show up:\n\n\n\nNot sure which image you want to use yet? That's ok too. Leave yourself a descriptive placeholder and keep writing. Come back later and drag and drop the image in to upload:\n\n![A bowl of bananas]\n\n\n### Quoting\n\nSometimes a link isn't enough, you want to quote someone on what they've said. Perhaps you've started using a new blogging platform and feel the sudden urge to share their slogan? A quote might be just the way to do it!\n\n> Ghost - Just a blogging platform\n\n### Working with Code\n\nGot a streak of geek? We've got you covered there, too. You can write inline `<code>` blocks really easily with back ticks. Want to show off something more comprehensive? 4 spaces of indentation gets you there.\n\n .awesome-thing {\n display: block;\n width: 100%;\n }\n\n### Ready for a Break? \n\nThrow 3 or more dashes down on any new line and you've got yourself a fancy new divider. Aw yeah.\n\n---\n\n### Advanced Usage\n\nThere's one fantastic secret about Markdown. If you want, you can write plain old HTML and it'll still work! Very flexible.\n\n<input type=\"text\" placeholder=\"I'm an input field!\" />\n\nThat should be enough to get you started. Have fun - and let us know what you think :)",
|
||||
"image": null,
|
||||
"featured": false,
|
||||
"page": false,
|
||||
"status": "published",
|
||||
"language": "en_US",
|
||||
"meta_title": null,
|
||||
"meta_description": null
|
||||
}
|
||||
],
|
||||
|
||||
"posts_0_7": [
|
||||
{
|
||||
"title": "You've been upgraded to the latest version of Ghost",
|
||||
"slug": "ghost-0-7",
|
||||
"markdown": "You've just upgraded to the latest version of Ghost and we've made a few changes that you should probably know about!\n\n## Woah, why does everything look different?\n\nAfter two years and hundreds of thousands of users, we learned a great deal about what was (and wasn't) working in the old Ghost admin user interface. What you're looking at is Ghost's first major UI refresh, with a strong focus on being more usable and robust all round.\n\n\n\nThe main navigation menu, previously located at the top of your screen, has now moved over to the left. This makes it way easier to work with on mobile devices, and has the added benefit of providing ample space for upcoming features!\n\n## Lost and found: Your old posts\n\nFrom talking to many of you we understand that finding old posts in the admin area was a real pain; so we've added a new magical search bar which lets you quickly find posts for editing, without having to scroll endlessly. Take it for a spin!\n\n\n\nQuestions? Comments? Send us a tweet [@TryGhost](https://twitter.com/tryghost)\n\nOh, and yes – you can safely delete this draft post!",
|
||||
"image": null,
|
||||
"featured": false,
|
||||
"page": false,
|
||||
"status": "draft",
|
||||
"language": "en_US",
|
||||
"meta_title": null,
|
||||
"meta_description": null
|
||||
}
|
||||
],
|
||||
"Tag": [
|
||||
{
|
||||
"name": "Getting Started",
|
||||
"slug": "getting-started",
|
||||
"description": null,
|
||||
"parent_id": null,
|
||||
"meta_title": null,
|
||||
"meta_description": null
|
||||
}
|
||||
],
|
||||
|
||||
"tags": [
|
||||
"Client": [
|
||||
{
|
||||
"name": "Ghost Admin",
|
||||
"slug": "ghost-admin",
|
||||
"status": "enabled"
|
||||
},
|
||||
{
|
||||
"name": "Ghost Frontend",
|
||||
"slug": "ghost-frontend",
|
||||
"status": "enabled"
|
||||
}
|
||||
],
|
||||
"Role": [
|
||||
{
|
||||
"name": "Administrator",
|
||||
"description": "Administrators"
|
||||
},
|
||||
{
|
||||
"name": "Editor",
|
||||
"description": "Editors"
|
||||
},
|
||||
{
|
||||
"name": "Author",
|
||||
"description": "Authors"
|
||||
},
|
||||
{
|
||||
"name": "Owner",
|
||||
"description": "Blog Owner"
|
||||
}
|
||||
],
|
||||
"Permission": [
|
||||
{
|
||||
"name": "Export database",
|
||||
"action_type": "exportContent",
|
||||
"object_type": "db"
|
||||
},
|
||||
{
|
||||
"name": "Import database",
|
||||
"action_type": "importContent",
|
||||
"object_type": "db"
|
||||
},
|
||||
{
|
||||
"name": "Delete all content",
|
||||
"action_type": "deleteAllContent",
|
||||
"object_type": "db"
|
||||
},
|
||||
{
|
||||
"name": "Send mail",
|
||||
"action_type": "send",
|
||||
"object_type": "mail"
|
||||
},
|
||||
{
|
||||
"name": "Browse notifications",
|
||||
"action_type": "browse",
|
||||
"object_type": "notification"
|
||||
},
|
||||
{
|
||||
"name": "Add notifications",
|
||||
"action_type": "add",
|
||||
"object_type": "notification"
|
||||
},
|
||||
{
|
||||
"name": "Delete notifications",
|
||||
"action_type": "destroy",
|
||||
"object_type": "notification"
|
||||
},
|
||||
{
|
||||
"name": "Browse posts",
|
||||
"action_type": "browse",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"name": "Read posts",
|
||||
"action_type": "read",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"name": "Edit posts",
|
||||
"action_type": "edit",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"name": "Add posts",
|
||||
"action_type": "add",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"name": "Delete posts",
|
||||
"action_type": "destroy",
|
||||
"object_type": "post"
|
||||
},
|
||||
{
|
||||
"name": "Browse settings",
|
||||
"action_type": "browse",
|
||||
"object_type": "setting"
|
||||
},
|
||||
{
|
||||
"name": "Read settings",
|
||||
"action_type": "read",
|
||||
"object_type": "setting"
|
||||
},
|
||||
{
|
||||
"name": "Edit settings",
|
||||
"action_type": "edit",
|
||||
"object_type": "setting"
|
||||
},
|
||||
{
|
||||
"name": "Generate slugs",
|
||||
"action_type": "generate",
|
||||
"object_type": "slug"
|
||||
},
|
||||
{
|
||||
"name": "Browse tags",
|
||||
"action_type": "browse",
|
||||
"object_type": "tag"
|
||||
},
|
||||
{
|
||||
"name": "Read tags",
|
||||
"action_type": "read",
|
||||
"object_type": "tag"
|
||||
},
|
||||
{
|
||||
"name": "Edit tags",
|
||||
"action_type": "edit",
|
||||
"object_type": "tag"
|
||||
},
|
||||
{
|
||||
"name": "Add tags",
|
||||
"action_type": "add",
|
||||
"object_type": "tag"
|
||||
},
|
||||
{
|
||||
"name": "Delete tags",
|
||||
"action_type": "destroy",
|
||||
"object_type": "tag"
|
||||
},
|
||||
{
|
||||
"name": "Browse themes",
|
||||
"action_type": "browse",
|
||||
"object_type": "theme"
|
||||
},
|
||||
{
|
||||
"name": "Edit themes",
|
||||
"action_type": "edit",
|
||||
"object_type": "theme"
|
||||
},
|
||||
{
|
||||
"name": "Browse users",
|
||||
"action_type": "browse",
|
||||
"object_type": "user"
|
||||
},
|
||||
{
|
||||
"name": "Read users",
|
||||
"action_type": "read",
|
||||
"object_type": "user"
|
||||
},
|
||||
{
|
||||
"name": "Edit users",
|
||||
"action_type": "edit",
|
||||
"object_type": "user"
|
||||
},
|
||||
{
|
||||
"name": "Add users",
|
||||
"action_type": "add",
|
||||
"object_type": "user"
|
||||
},
|
||||
{
|
||||
"name": "Delete users",
|
||||
"action_type": "destroy",
|
||||
"object_type": "user"
|
||||
},
|
||||
{
|
||||
"name": "Assign a role",
|
||||
"action_type": "assign",
|
||||
"object_type": "role"
|
||||
},
|
||||
{
|
||||
"name": "Browse roles",
|
||||
"action_type": "browse",
|
||||
"object_type": "role"
|
||||
}
|
||||
]
|
||||
},
|
||||
"relations": [
|
||||
{
|
||||
"name": "Getting Started",
|
||||
"slug": "getting-started",
|
||||
"description": null,
|
||||
"parent_id": null,
|
||||
"meta_title": null,
|
||||
"meta_description": null
|
||||
}
|
||||
],
|
||||
|
||||
"roles": [
|
||||
{
|
||||
"name": "Administrator",
|
||||
"description": "Administrators"
|
||||
"from": {
|
||||
"model": "Role",
|
||||
"match": "name",
|
||||
"relation": "permissions"
|
||||
},
|
||||
"to": {
|
||||
"model": "Permission",
|
||||
"match": ["object_type", "action_type"]
|
||||
},
|
||||
"entries": {
|
||||
"Administrator": {
|
||||
"db": "all",
|
||||
"mail": "all",
|
||||
"notification": "all",
|
||||
"post": "all",
|
||||
"setting": "all",
|
||||
"slug": "all",
|
||||
"tag": "all",
|
||||
"theme": "all",
|
||||
"user": "all",
|
||||
"role": "all"
|
||||
},
|
||||
"Editor": {
|
||||
"post": "all",
|
||||
"setting": ["browse", "read"],
|
||||
"slug": "all",
|
||||
"tag": "all",
|
||||
"user": "all",
|
||||
"role": "all"
|
||||
},
|
||||
"Author": {
|
||||
"post": ["browse", "read", "add"],
|
||||
"setting": ["browse", "read"],
|
||||
"slug": "all",
|
||||
"tag": ["browse", "read", "add"],
|
||||
"user": ["browse", "read"],
|
||||
"role": ["browse"]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "Editor",
|
||||
"description": "Editors"
|
||||
},
|
||||
{
|
||||
"name": "Author",
|
||||
"description": "Authors"
|
||||
},
|
||||
{
|
||||
"name": "Owner",
|
||||
"description": "Blog Owner"
|
||||
}
|
||||
],
|
||||
|
||||
"clients": [
|
||||
{
|
||||
"name": "Ghost Admin",
|
||||
"slug": "ghost-admin",
|
||||
"status": "enabled"
|
||||
},
|
||||
{
|
||||
"name": "Ghost Frontend",
|
||||
"slug": "ghost-frontend",
|
||||
"status": "enabled"
|
||||
"from": {
|
||||
"model": "Post",
|
||||
"match": "title",
|
||||
"relation": "tags"
|
||||
},
|
||||
"to": {
|
||||
"model": "Tag",
|
||||
"match": "name"
|
||||
},
|
||||
"entries": {
|
||||
"Welcome to Ghost": ["Getting Started"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,361 +1,9 @@
|
|||
// # Fixtures
|
||||
// This module handles populating or updating fixtures.
|
||||
//
|
||||
// Currently fixtures only change between data version 002 and 003, therefore the update logic is hard coded
|
||||
// rather than abstracted into a migration system. The upgrade function checks that its changes are safe before
|
||||
// making them.
|
||||
|
||||
var Promise = require('bluebird'),
|
||||
crypto = require('crypto'),
|
||||
_ = require('lodash'),
|
||||
fixtures = require('./fixtures'),
|
||||
permissions = require('./permissions/index'),
|
||||
notifications = require('../../../api/notifications'),
|
||||
config = require('../../../config'),
|
||||
errors = require('../../../errors'),
|
||||
i18n = require('../../../i18n'),
|
||||
models = require('../../../models'),
|
||||
utils = require('../../../utils'),
|
||||
sequence = require('../../../utils/sequence'),
|
||||
|
||||
// Private
|
||||
logInfo,
|
||||
to003,
|
||||
to004,
|
||||
convertAdminToOwner,
|
||||
createOwner,
|
||||
options = {context: {internal: true}},
|
||||
|
||||
// Public
|
||||
populate,
|
||||
update;
|
||||
|
||||
logInfo = function logInfo(message) {
|
||||
errors.logInfo('Migrations', message);
|
||||
};
|
||||
|
||||
/**
|
||||
* Convert admin to Owner
|
||||
* Changes an admin user to have the owner role
|
||||
* @returns {Promise|*}
|
||||
*/
|
||||
convertAdminToOwner = function convertAdminToOwner() {
|
||||
var adminUser;
|
||||
|
||||
return models.User.findOne({role: 'Administrator'}).then(function (user) {
|
||||
adminUser = user;
|
||||
return models.Role.findOne({name: 'Owner'});
|
||||
}).then(function (ownerRole) {
|
||||
if (adminUser) {
|
||||
logInfo('Converting admin to owner');
|
||||
return adminUser.roles().updatePivot({role_id: ownerRole.id});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Create Owner
|
||||
* Creates the user fixture and gives it the owner role
|
||||
* @returns {Promise|*}
|
||||
*/
|
||||
createOwner = function createOwner() {
|
||||
var user = fixtures.users[0];
|
||||
|
||||
return models.Role.findOne({name: 'Owner'}).then(function (ownerRole) {
|
||||
user.roles = [ownerRole.id];
|
||||
user.password = utils.uid(50);
|
||||
|
||||
logInfo('Creating owner');
|
||||
return models.User.add(user, options);
|
||||
});
|
||||
};
|
||||
|
||||
populate = function populate() {
|
||||
var ops = [],
|
||||
relations = [],
|
||||
Post = models.Post,
|
||||
Tag = models.Tag,
|
||||
Role = models.Role,
|
||||
Client = models.Client;
|
||||
|
||||
logInfo('Populating fixtures');
|
||||
|
||||
_.each(fixtures.posts, function (post) {
|
||||
ops.push(Post.add(post, options));
|
||||
});
|
||||
|
||||
_.each(fixtures.tags, function (tag) {
|
||||
ops.push(Tag.add(tag, options));
|
||||
});
|
||||
|
||||
_.each(fixtures.roles, function (role) {
|
||||
ops.push(Role.add(role, options));
|
||||
});
|
||||
|
||||
_.each(fixtures.clients, function (client) {
|
||||
ops.push(Client.add(client, options));
|
||||
});
|
||||
|
||||
// add the tag to the post
|
||||
relations.push(function () {
|
||||
return Post.forge({slug: fixtures.posts[0].slug}).fetch().then(function (post) {
|
||||
return Tag.forge({slug: fixtures.tags[0].slug}).fetch().then(function (tag) {
|
||||
return post.related('tags').attach(tag.id);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(ops).then(function () {
|
||||
return sequence(relations);
|
||||
}).then(function () {
|
||||
return permissions.populate(options);
|
||||
}).then(function () {
|
||||
return createOwner();
|
||||
}).catch(function (errs) {
|
||||
errors.logError(errs);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ### Update fixtures to 003
|
||||
* Need to add client & owner role, then update permissions to 003 as well
|
||||
* By doing this in a way that checks before adding, we can ensure that it's possible to force a migration safely.
|
||||
*
|
||||
* Note: At the moment this is pretty adhoc & untestable, in future it would be better to have a config based system.
|
||||
* @returns {Promise|*}
|
||||
*/
|
||||
to003 = function to003() {
|
||||
var ops = [],
|
||||
upgradeOp,
|
||||
Role = models.Role,
|
||||
Client = models.Client;
|
||||
|
||||
logInfo('Upgrading fixtures to 003');
|
||||
|
||||
// Add the client fixture if missing
|
||||
upgradeOp = Client.findOne({slug: fixtures.clients[0].slug}).then(function (client) {
|
||||
if (!client) {
|
||||
logInfo('Adding ghost-admin client fixture');
|
||||
return Client.add(fixtures.clients[0], options);
|
||||
}
|
||||
});
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// Add the owner role if missing
|
||||
upgradeOp = Role.findOne({name: fixtures.roles[3].name}).then(function (owner) {
|
||||
if (!owner) {
|
||||
logInfo('Adding owner role fixture');
|
||||
_.each(fixtures.roles.slice(3), function (role) {
|
||||
return Role.add(role, options);
|
||||
});
|
||||
}
|
||||
});
|
||||
ops.push(upgradeOp);
|
||||
|
||||
return Promise.all(ops).then(function () {
|
||||
return permissions.to003(options);
|
||||
}).then(function () {
|
||||
return convertAdminToOwner();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Update ghost_foot to include a CDN of jquery if the DB is migrating from
|
||||
* @return {Promise}
|
||||
*/
|
||||
to004 = function to004() {
|
||||
var value,
|
||||
ops = [],
|
||||
upgradeOp,
|
||||
// These messages are shown in the admin UI, not the console, and should therefore be translated
|
||||
jquery = [
|
||||
i18n.t('notices.data.fixtures.canSafelyDelete'),
|
||||
'<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>\n\n'
|
||||
],
|
||||
privacyMessage = [
|
||||
i18n.t('notices.data.fixtures.jQueryRemoved'),
|
||||
i18n.t('notices.data.fixtures.canBeChanged')
|
||||
];
|
||||
|
||||
logInfo('Upgrading fixtures to 004');
|
||||
|
||||
// add jquery setting and privacy info
|
||||
upgradeOp = function () {
|
||||
return models.Settings.findOne('ghost_foot').then(function (setting) {
|
||||
if (setting) {
|
||||
value = setting.attributes.value;
|
||||
// Only add jQuery if it's not already in there
|
||||
if (value.indexOf(jquery.join('')) === -1) {
|
||||
logInfo('Adding jQuery link to ghost_foot');
|
||||
value = jquery.join('') + value;
|
||||
return models.Settings.edit({key: 'ghost_foot', value: value}, options).then(function () {
|
||||
if (_.isEmpty(config.privacy)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
logInfo(privacyMessage.join(' ').replace(/<\/?strong>/g, ''));
|
||||
return notifications.add({notifications: [{
|
||||
type: 'info',
|
||||
message: privacyMessage.join(' ')
|
||||
}]}, options);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// change `type` for protected blog `isPrivate` setting
|
||||
upgradeOp = function () {
|
||||
return models.Settings.findOne('isPrivate').then(function (setting) {
|
||||
if (setting) {
|
||||
logInfo('Update isPrivate setting');
|
||||
return models.Settings.edit({key: 'isPrivate', type: 'private'}, options);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// change `type` for protected blog `password` setting
|
||||
upgradeOp = function () {
|
||||
return models.Settings.findOne('password').then(function (setting) {
|
||||
if (setting) {
|
||||
logInfo('Update password setting');
|
||||
return models.Settings.edit({key: 'password', type: 'private'}, options);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// Update ghost-admin client fixture
|
||||
// ghost-admin should exist from 003 version
|
||||
upgradeOp = function () {
|
||||
return models.Client.findOne({slug: fixtures.clients[0].slug}).then(function (client) {
|
||||
if (client) {
|
||||
logInfo('Update ghost-admin client fixture');
|
||||
var adminClient = fixtures.clients[0];
|
||||
adminClient.secret = crypto.randomBytes(6).toString('hex');
|
||||
return models.Client.edit(adminClient, _.extend({}, options, {id: client.id}));
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// add ghost-frontend client if missing
|
||||
upgradeOp = function () {
|
||||
return models.Client.findOne({slug: fixtures.clients[1].slug}).then(function (client) {
|
||||
if (!client) {
|
||||
logInfo('Add ghost-frontend client fixture');
|
||||
var frontendClient = fixtures.clients[1];
|
||||
return models.Client.add(frontendClient, options);
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// clean up broken tags
|
||||
upgradeOp = function () {
|
||||
return models.Tag.findAll(options).then(function (tags) {
|
||||
var tagOps = [];
|
||||
if (tags) {
|
||||
tags.each(function (tag) {
|
||||
var name = tag.get('name'),
|
||||
updated = name.replace(/^(,+)/, '').trim();
|
||||
|
||||
// If we've ended up with an empty string, default to just 'tag'
|
||||
updated = updated === '' ? 'tag' : updated;
|
||||
|
||||
if (name !== updated) {
|
||||
tagOps.push(tag.save({name: updated}, options));
|
||||
}
|
||||
});
|
||||
if (tagOps.length > 0) {
|
||||
logInfo('Cleaning ' + tagOps.length + ' malformed tags');
|
||||
return Promise.all(tagOps);
|
||||
}
|
||||
}
|
||||
return Promise.resolve();
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// Add post_tag order
|
||||
upgradeOp = function () {
|
||||
var tagOps = [];
|
||||
logInfo('Collecting data on tag order for posts...');
|
||||
return models.Post.findAll(_.extend({}, options)).then(function (posts) {
|
||||
if (posts) {
|
||||
return posts.mapThen(function (post) {
|
||||
return post.load(['tags']);
|
||||
});
|
||||
}
|
||||
return [];
|
||||
}).then(function (posts) {
|
||||
_.each(posts, function (post) {
|
||||
var order = 0;
|
||||
post.related('tags').each(function (tag) {
|
||||
tagOps.push((function (order) {
|
||||
var sortOrder = order;
|
||||
return function () {
|
||||
return post.tags().updatePivot(
|
||||
{sort_order: sortOrder}, _.extend({}, options, {query: {where: {tag_id: tag.id}}})
|
||||
);
|
||||
};
|
||||
}(order)));
|
||||
order += 1;
|
||||
});
|
||||
});
|
||||
|
||||
if (tagOps.length > 0) {
|
||||
logInfo('Updating order on ' + tagOps.length + ' tag relationships (could take a while)...');
|
||||
return sequence(tagOps).then(function () {
|
||||
logInfo('Tag order successfully updated');
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
// Add a new draft post
|
||||
upgradeOp = function () {
|
||||
return models.Post.findOne({slug: fixtures.posts_0_7[0].slug, status: 'all'}, options).then(function (post) {
|
||||
if (!post) {
|
||||
logInfo('Adding 0.7 upgrade post fixture');
|
||||
// Set the published_at timestamp, but keep the post as a draft so doesn't appear on the frontend
|
||||
// This is a hack to ensure that this post appears at the very top of the drafts list, because
|
||||
// unpublished posts always appear first
|
||||
fixtures.posts_0_7[0].published_at = Date.now();
|
||||
return models.Post.add(fixtures.posts_0_7[0], options);
|
||||
}
|
||||
});
|
||||
};
|
||||
ops.push(upgradeOp);
|
||||
|
||||
return sequence(ops);
|
||||
};
|
||||
|
||||
update = function update(fromVersion, toVersion) {
|
||||
var ops = [];
|
||||
|
||||
logInfo('Updating fixtures');
|
||||
// Are we migrating to, or past 003?
|
||||
if ((fromVersion < '003' && toVersion >= '003') ||
|
||||
fromVersion === '003' && toVersion === '003' && process.env.FORCE_MIGRATION) {
|
||||
ops.push(to003);
|
||||
}
|
||||
|
||||
if (fromVersion < '004' && toVersion === '004' ||
|
||||
fromVersion === '004' && toVersion === '004' && process.env.FORCE_MIGRATION) {
|
||||
ops.push(to004);
|
||||
}
|
||||
|
||||
return sequence(ops);
|
||||
};
|
||||
var populate = require('./populate'),
|
||||
update = require('./update'),
|
||||
fixtures = require('./fixtures');
|
||||
|
||||
module.exports = {
|
||||
populate: populate,
|
||||
update: update
|
||||
update: update,
|
||||
fixtures: fixtures
|
||||
};
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
// # Permissions Fixtures
|
||||
// Sets up the permissions, and the default permissions_roles relationships
|
||||
var Promise = require('bluebird'),
|
||||
_ = require('lodash'),
|
||||
errors = require('../../../../errors'),
|
||||
models = require('../../../../models'),
|
||||
sequence = require('../../../../utils/sequence'),
|
||||
fixtures = require('./permissions'),
|
||||
|
||||
// private
|
||||
logInfo,
|
||||
addAllPermissions,
|
||||
addAllRolesPermissions,
|
||||
addRolesPermissionsForRole,
|
||||
|
||||
// public
|
||||
populate,
|
||||
to003;
|
||||
|
||||
logInfo = function logInfo(message) {
|
||||
errors.logInfo('Migrations', message);
|
||||
};
|
||||
|
||||
addRolesPermissionsForRole = function (roleName) {
|
||||
var fixturesForRole = fixtures.permissions_roles[roleName],
|
||||
permissionsToAdd;
|
||||
|
||||
return models.Role.forge({name: roleName}).fetch({withRelated: ['permissions']}).then(function (role) {
|
||||
return models.Permissions.forge().fetch().then(function (permissions) {
|
||||
if (_.isObject(fixturesForRole)) {
|
||||
permissionsToAdd = _.map(permissions.toJSON(), function (permission) {
|
||||
var objectPermissions = fixturesForRole[permission.object_type];
|
||||
if (objectPermissions === 'all') {
|
||||
return permission.id;
|
||||
} else if (_.isArray(objectPermissions) && _.contains(objectPermissions, permission.action_type)) {
|
||||
return permission.id;
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
return role.permissions().attach(_.compact(permissionsToAdd));
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
addAllRolesPermissions = function () {
|
||||
var roleNames = _.keys(fixtures.permissions_roles),
|
||||
ops = [];
|
||||
|
||||
_.each(roleNames, function (roleName) {
|
||||
ops.push(addRolesPermissionsForRole(roleName));
|
||||
});
|
||||
|
||||
return Promise.all(ops);
|
||||
};
|
||||
|
||||
addAllPermissions = function (options) {
|
||||
var ops = [];
|
||||
_.each(fixtures.permissions, function (permissions, objectType) {
|
||||
_.each(permissions, function (permission) {
|
||||
ops.push(function () {
|
||||
permission.object_type = objectType;
|
||||
return models.Permission.add(permission, options);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return sequence(ops);
|
||||
};
|
||||
|
||||
// ## Populate
|
||||
populate = function (options) {
|
||||
logInfo('Populating permissions');
|
||||
// ### Ensure all permissions are added
|
||||
return addAllPermissions(options).then(function () {
|
||||
// ### Ensure all roles_permissions are added
|
||||
return addAllRolesPermissions();
|
||||
});
|
||||
};
|
||||
|
||||
// ## Update
|
||||
// Update permissions to 003
|
||||
// Need to rename old permissions, and then add all of the missing ones
|
||||
to003 = function (options) {
|
||||
var ops = [];
|
||||
|
||||
logInfo('Upgrading permissions');
|
||||
|
||||
// To safely upgrade, we need to clear up the existing permissions and permissions_roles before recreating the new
|
||||
// full set of permissions defined as of version 003
|
||||
return models.Permissions.forge().fetch().then(function (permissions) {
|
||||
logInfo('Removing old permissions');
|
||||
permissions.each(function (permission) {
|
||||
ops.push(permission.related('roles').detach().then(function () {
|
||||
return permission.destroy();
|
||||
}));
|
||||
});
|
||||
|
||||
// Now we can perform the normal populate
|
||||
return Promise.all(ops).then(function () {
|
||||
return populate(options);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
populate: populate,
|
||||
to003: to003
|
||||
};
|
|
@ -1,174 +0,0 @@
|
|||
{
|
||||
"permissions": {
|
||||
"db": [
|
||||
{
|
||||
"name": "Export database",
|
||||
"action_type": "exportContent"
|
||||
},
|
||||
{
|
||||
"name": "Import database",
|
||||
"action_type": "importContent"
|
||||
},
|
||||
{
|
||||
"name": "Delete all content",
|
||||
"action_type": "deleteAllContent"
|
||||
}
|
||||
],
|
||||
"mail": [
|
||||
{
|
||||
"name": "Send mail",
|
||||
"action_type": "send"
|
||||
}
|
||||
],
|
||||
"notification": [
|
||||
{
|
||||
"name": "Browse notifications",
|
||||
"action_type": "browse"
|
||||
},
|
||||
{
|
||||
"name": "Add notifications",
|
||||
"action_type": "add"
|
||||
},
|
||||
{
|
||||
"name": "Delete notifications",
|
||||
"action_type": "destroy"
|
||||
}
|
||||
],
|
||||
"post": [
|
||||
{
|
||||
"name": "Browse posts",
|
||||
"action_type": "browse"
|
||||
},
|
||||
{
|
||||
"name": "Read posts",
|
||||
"action_type": "read"
|
||||
},
|
||||
{
|
||||
"name": "Edit posts",
|
||||
"action_type": "edit"
|
||||
},
|
||||
{
|
||||
"name": "Add posts",
|
||||
"action_type": "add"
|
||||
},
|
||||
{
|
||||
"name": "Delete posts",
|
||||
"action_type": "destroy"
|
||||
}
|
||||
],
|
||||
"setting": [
|
||||
{
|
||||
"name": "Browse settings",
|
||||
"action_type": "browse"
|
||||
},
|
||||
{
|
||||
"name": "Read settings",
|
||||
"action_type": "read"
|
||||
},
|
||||
{
|
||||
"name": "Edit settings",
|
||||
"action_type": "edit"
|
||||
}
|
||||
],
|
||||
"slug": [
|
||||
{
|
||||
"name": "Generate slugs",
|
||||
"action_type": "generate"
|
||||
}
|
||||
],
|
||||
"tag": [
|
||||
{
|
||||
"name": "Browse tags",
|
||||
"action_type": "browse"
|
||||
},
|
||||
{
|
||||
"name": "Read tags",
|
||||
"action_type": "read"
|
||||
},
|
||||
{
|
||||
"name": "Edit tags",
|
||||
"action_type": "edit"
|
||||
},
|
||||
{
|
||||
"name": "Add tags",
|
||||
"action_type": "add"
|
||||
},
|
||||
{
|
||||
"name": "Delete tags",
|
||||
"action_type": "destroy"
|
||||
}
|
||||
],
|
||||
"theme": [
|
||||
{
|
||||
"name": "Browse themes",
|
||||
"action_type": "browse"
|
||||
},
|
||||
{
|
||||
"name": "Edit themes",
|
||||
"action_type": "edit"
|
||||
}
|
||||
],
|
||||
"user": [
|
||||
{
|
||||
"name": "Browse users",
|
||||
"action_type": "browse"
|
||||
},
|
||||
{
|
||||
"name": "Read users",
|
||||
"action_type": "read"
|
||||
},
|
||||
{
|
||||
"name": "Edit users",
|
||||
"action_type": "edit"
|
||||
},
|
||||
{
|
||||
"name": "Add users",
|
||||
"action_type": "add"
|
||||
},
|
||||
{
|
||||
"name": "Delete users",
|
||||
"action_type": "destroy"
|
||||
}
|
||||
],
|
||||
"role": [
|
||||
{
|
||||
"name": "Assign a role",
|
||||
"action_type": "assign"
|
||||
},
|
||||
{
|
||||
"name": "Browse roles",
|
||||
"action_type": "browse"
|
||||
}
|
||||
]
|
||||
},
|
||||
"permissions_roles": {
|
||||
"Administrator": {
|
||||
"db": "all",
|
||||
"mail": "all",
|
||||
"notification": "all",
|
||||
"post": "all",
|
||||
"setting": "all",
|
||||
"slug": "all",
|
||||
"tag": "all",
|
||||
"theme": "all",
|
||||
"user": "all",
|
||||
"role": "all"
|
||||
},
|
||||
"Editor": {
|
||||
"post": "all",
|
||||
"setting": ["browse", "read"],
|
||||
"slug": "all",
|
||||
"tag": "all",
|
||||
"user": "all",
|
||||
"role": "all"
|
||||
},
|
||||
"Author": {
|
||||
"post": ["browse", "read", "add"],
|
||||
"setting": ["browse", "read"],
|
||||
"slug": "all",
|
||||
"tag": ["browse", "read", "add"],
|
||||
"user": ["browse", "read"],
|
||||
"role": ["browse"]
|
||||
}
|
||||
}
|
||||
}
|
173
core/server/data/migration/fixtures/populate.js
Normal file
173
core/server/data/migration/fixtures/populate.js
Normal file
|
@ -0,0 +1,173 @@
|
|||
// # Populate Fixtures
|
||||
// This module handles populating fixtures on a fresh install.
|
||||
// This is done automatically, by reading the fixtures.json file
|
||||
// All models, and relationships inside the file are then setup.
|
||||
|
||||
var Promise = require('bluebird'),
|
||||
_ = require('lodash'),
|
||||
models = require('../../../models'),
|
||||
utils = require('../../../utils'),
|
||||
sequence = require('../../../utils/sequence'),
|
||||
fixtures = require('./fixtures'),
|
||||
|
||||
// private
|
||||
addAllModels,
|
||||
addAllRelations,
|
||||
fetchRelationData,
|
||||
matchFunc,
|
||||
createOwner,
|
||||
|
||||
// public
|
||||
populate;
|
||||
|
||||
/**
|
||||
* ### Add All Models
|
||||
* Sequentially calls add on all the models specified in fixtures.json
|
||||
*
|
||||
* @param {Object} modelOptions
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
addAllModels = function addAllModels(modelOptions) {
|
||||
var ops = [];
|
||||
|
||||
_.each(fixtures.models, function (items, modelName) {
|
||||
_.each(items, function (item) {
|
||||
ops.push(function () {
|
||||
return models[modelName].add(item, modelOptions);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
return sequence(ops);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### Fetch Relation Data
|
||||
* Before we build relations we need to fetch all of the models from both sides so that we can
|
||||
* use filter and find to quickly locate the correct models.
|
||||
*
|
||||
* @param {Object} relation
|
||||
* @param {Object} modelOptions
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
fetchRelationData = function fetchRelationData(relation, modelOptions) {
|
||||
var props = {
|
||||
from: models[relation.from.model].findAll(modelOptions),
|
||||
to: models[relation.to.model].findAll(modelOptions)
|
||||
};
|
||||
|
||||
return Promise.props(props);
|
||||
};
|
||||
|
||||
/**
|
||||
* ### Match Func
|
||||
* Figures out how to match across various combinations of keys and values.
|
||||
* Match can be a string or an array containing 2 strings
|
||||
* Key and Value are the values to be found
|
||||
* Value can also be an array, in which case we look for a match in the array.
|
||||
*
|
||||
* @param {String|Array} match
|
||||
* @param {String} key
|
||||
* @param {String|Array} [value]
|
||||
* @returns {Function}
|
||||
*/
|
||||
matchFunc = function matchFunc(match, key, value) {
|
||||
if (_.isArray(match)) {
|
||||
return function (item) {
|
||||
var valueTest = true;
|
||||
|
||||
if (_.isArray(value)) {
|
||||
valueTest = value.indexOf(item.get(match[1])) > -1;
|
||||
} else if (value !== 'all') {
|
||||
valueTest = item.get(match[1]) === value;
|
||||
}
|
||||
|
||||
return item.get(match[0]) === key && valueTest;
|
||||
};
|
||||
}
|
||||
|
||||
return function (item) {
|
||||
key = key === 0 && value ? value : key;
|
||||
return item.get(match) === key;
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* ### Add All Relations
|
||||
* Sequentially calls add on all the relations specified in fixtures.json
|
||||
*
|
||||
* @param {Object} modelOptions
|
||||
* @returns {Promise|Array}
|
||||
*/
|
||||
addAllRelations = function addAllRelations(modelOptions) {
|
||||
return Promise.map(fixtures.relations, function (relation) {
|
||||
return fetchRelationData(relation, modelOptions).then(function (data) {
|
||||
var ops = [];
|
||||
|
||||
_.each(relation.entries, function (entry, key) {
|
||||
var fromItem = data.from.find(matchFunc(relation.from.match, key));
|
||||
|
||||
_.each(entry, function (value, key) {
|
||||
var toItem = data.to.filter(matchFunc(relation.to.match, key, value));
|
||||
if (toItem) {
|
||||
ops.push(function () {
|
||||
return fromItem[relation.from.relation]().attach(toItem);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return sequence(ops);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ### Create Owner
|
||||
* Creates the user fixture and gives it the owner role.
|
||||
* By default, users are given the Author role, making it hard to do this using the fixture system
|
||||
*
|
||||
* @param {Object} modelOptions
|
||||
* @param {Function} logInfo
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
createOwner = function createOwner(modelOptions, logInfo) {
|
||||
var user = {
|
||||
name: 'Ghost Owner',
|
||||
email: 'ghost@ghost.org',
|
||||
status: 'inactive',
|
||||
password: utils.uid(50)
|
||||
};
|
||||
|
||||
return models.Role.findOne({name: 'Owner'}).then(function (ownerRole) {
|
||||
if (ownerRole) {
|
||||
user.roles = [ownerRole.id];
|
||||
|
||||
logInfo('Creating owner');
|
||||
return models.User.add(user, modelOptions);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Populate
|
||||
* Sequentially creates all models, in the order they are specified, and then
|
||||
* creates all the relationships, also maintaining order.
|
||||
*
|
||||
* @param {Object} modelOptions
|
||||
* @param {Function} logInfo
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
populate = function populate(modelOptions, logInfo) {
|
||||
logInfo('Populating fixtures');
|
||||
|
||||
// ### Ensure all models are added
|
||||
return addAllModels(modelOptions).then(function () {
|
||||
// ### Ensure all relations are added
|
||||
return addAllRelations(modelOptions);
|
||||
}).then(function () {
|
||||
return createOwner(modelOptions, logInfo);
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = populate;
|
64
core/server/data/migration/fixtures/update.js
Normal file
64
core/server/data/migration/fixtures/update.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
// # Update Fixtures
|
||||
// This module handles updating fixtures.
|
||||
// This is done manually, through a series of files stored in an adjacent folder
|
||||
// E.g. if we update to version 004, all the tasks in /004/ are executed
|
||||
|
||||
var sequence = require('../../../utils/sequence'),
|
||||
|
||||
// Private
|
||||
getVersionTasks,
|
||||
|
||||
// Public
|
||||
update;
|
||||
|
||||
/**
|
||||
* ### Get Version Tasks
|
||||
* Tries to require a directory matching the version number
|
||||
*
|
||||
* This was split from update to make testing easier
|
||||
*
|
||||
* @param {String} version
|
||||
* @param {Function} logInfo
|
||||
* @returns {Array}
|
||||
*/
|
||||
getVersionTasks = function getVersionTasks(version, logInfo) {
|
||||
var tasks = [];
|
||||
|
||||
try {
|
||||
tasks = require('./' + version);
|
||||
} catch (e) {
|
||||
logInfo('No fixture updates found for version', version);
|
||||
}
|
||||
|
||||
return tasks;
|
||||
};
|
||||
|
||||
/**
|
||||
* ## Update
|
||||
* Handles doing subsequent updates for versions
|
||||
*
|
||||
* @param {Array} versions
|
||||
* @param {Object} modelOptions
|
||||
* @param {Function} logInfo
|
||||
* @returns {Promise<*>}
|
||||
*/
|
||||
update = function update(versions, modelOptions, logInfo) {
|
||||
var ops = [];
|
||||
|
||||
logInfo('Updating fixtures');
|
||||
|
||||
versions.forEach(function (version) {
|
||||
var tasks = getVersionTasks(version, logInfo);
|
||||
|
||||
if (tasks && tasks.length > 0) {
|
||||
ops.push(function () {
|
||||
logInfo('Updating fixtures to', version);
|
||||
return sequence(require('./' + version), modelOptions, logInfo);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return sequence(ops, modelOptions, logInfo);
|
||||
};
|
||||
|
||||
module.exports = update;
|
|
@ -17,6 +17,7 @@ var _ = require('lodash'),
|
|||
schemaTables = _.keys(schema),
|
||||
|
||||
// private
|
||||
modelOptions,
|
||||
logInfo,
|
||||
populateDefaultSettings,
|
||||
fixClientSecret,
|
||||
|
@ -28,6 +29,9 @@ var _ = require('lodash'),
|
|||
migrateUpFreshDb,
|
||||
backupDatabase;
|
||||
|
||||
// modelOptions & logInfo are passed through to migration/fixture actions
|
||||
modelOptions = {context: {internal: true}};
|
||||
|
||||
logInfo = function logInfo(message) {
|
||||
errors.logInfo('Migrations', message);
|
||||
};
|
||||
|
@ -147,7 +151,7 @@ migrateUpFreshDb = function (tablesOnly) {
|
|||
}
|
||||
return tableSequence.then(function () {
|
||||
// Load the fixtures
|
||||
return fixtures.populate();
|
||||
return fixtures.populate(modelOptions, logInfo);
|
||||
}).then(function () {
|
||||
return populateDefaultSettings();
|
||||
});
|
||||
|
@ -159,6 +163,12 @@ migrateUp = function (fromVersion, toVersion) {
|
|||
modifyUniCommands = [],
|
||||
migrateOps = [];
|
||||
|
||||
// Is the current version lower than the version we can migrate from?
|
||||
// E.g. is this blog's DB older than 003?
|
||||
if (fromVersion < versioning.canMigrateFromVersion) {
|
||||
return versioning.showCannotMigrateError();
|
||||
}
|
||||
|
||||
return backupDatabase().then(function () {
|
||||
return commands.getTables();
|
||||
}).then(function (tables) {
|
||||
|
@ -198,8 +208,11 @@ migrateUp = function (fromVersion, toVersion) {
|
|||
// Ensure all of the current default settings are created (these are fixtures, so should be inserted first)
|
||||
return populateDefaultSettings();
|
||||
}).then(function () {
|
||||
// Finally, run any updates to the fixtures, including default settings
|
||||
return fixtures.update(fromVersion, toVersion);
|
||||
fromVersion = process.env.FORCE_MIGRATION ? versioning.canMigrateFromVersion : fromVersion;
|
||||
var versions = versioning.getMigrationVersions(fromVersion, toVersion);
|
||||
// Finally, run any updates to the fixtures, including default settings, that are required
|
||||
// for anything other than the from/current version (which we're already on)
|
||||
return fixtures.update(versions.slice(1), modelOptions, logInfo);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
@ -57,8 +57,33 @@ function setDatabaseVersion() {
|
|||
.update({value: defaultDatabaseVersion});
|
||||
}
|
||||
|
||||
function pad(num, width) {
|
||||
return Array(Math.max(width - String(num).length + 1, 0)).join(0) + num;
|
||||
}
|
||||
|
||||
function getMigrationVersions(fromVersion, toVersion) {
|
||||
var versions = [],
|
||||
i;
|
||||
for (i = parseInt(fromVersion, 10); i <= toVersion; i += 1) {
|
||||
versions.push(pad(i, 3));
|
||||
}
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
function showCannotMigrateError() {
|
||||
return errors.logAndRejectError(
|
||||
i18n.t('errors.data.versioning.index.cannotMigrate.error'),
|
||||
i18n.t('errors.data.versioning.index.cannotMigrate.context'),
|
||||
i18n.t('common.seeLinkForInstructions', {link: 'http://support.ghost.org/how-to-upgrade/'})
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
canMigrateFromVersion: '003',
|
||||
showCannotMigrateError: showCannotMigrateError,
|
||||
getDefaultDatabaseVersion: getDefaultDatabaseVersion,
|
||||
getDatabaseVersion: getDatabaseVersion,
|
||||
setDatabaseVersion: setDatabaseVersion
|
||||
setDatabaseVersion: setDatabaseVersion,
|
||||
getMigrationVersions: getMigrationVersions
|
||||
};
|
||||
|
|
|
@ -402,7 +402,11 @@
|
|||
"versioning": {
|
||||
"index": {
|
||||
"dbVersionNotRecognized": "Database version is not recognized",
|
||||
"settingsTableDoesNotExist": "Settings table does not exist"
|
||||
"settingsTableDoesNotExist": "Settings table does not exist",
|
||||
"cannotMigrate": {
|
||||
"error": "Unable to upgrade from version 0.4.2 or earlier",
|
||||
"context": "Please upgrade to 0.7.1 first"
|
||||
}
|
||||
}
|
||||
},
|
||||
"xml": {
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
var Promise = require('bluebird');
|
||||
|
||||
function sequence(tasks) {
|
||||
function sequence(tasks /* Any Arguments */) {
|
||||
var args = Array.prototype.slice.call(arguments, 1);
|
||||
return Promise.reduce(tasks, function (results, task) {
|
||||
return task().then(function (result) {
|
||||
return task.apply(this, args).then(function (result) {
|
||||
results.push(result);
|
||||
|
||||
return results;
|
||||
|
|
|
@ -1,39 +1,185 @@
|
|||
/*globals describe, before, beforeEach, afterEach, it */
|
||||
var testUtils = require('../utils'),
|
||||
should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
_ = require('lodash'),
|
||||
Promise = require('bluebird'),
|
||||
|
||||
migration = require('../../server/data/migration/index'),
|
||||
Models = require('../../server/models');
|
||||
fixtures = require('../../server/data/migration/fixtures'),
|
||||
Models = require('../../server/models'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Database Migration (special functions)', function () {
|
||||
before(testUtils.teardown);
|
||||
afterEach(testUtils.teardown);
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('004', function () {
|
||||
beforeEach(testUtils.setup('settings'));
|
||||
describe('Fixtures', function () {
|
||||
// Custom assertion for detection that a permissions is assigned to the correct roles
|
||||
should.Assertion.add('AssignedToRoles', function (roles) {
|
||||
var roleNames;
|
||||
this.params = {operator: 'to have role'};
|
||||
|
||||
it('should add jQuery to ghost_foot injection setting', function (done) {
|
||||
Models.Settings.findOne('ghost_foot').then(function (setting) {
|
||||
should.exist(setting);
|
||||
should.exist(setting.attributes);
|
||||
setting.attributes.value.should.equal('');
|
||||
should.exist(this.obj);
|
||||
|
||||
process.env.FORCE_MIGRATION = true; // force a migration
|
||||
migration.init().then(function () {
|
||||
Models.Settings.findOne('ghost_foot').then(function (result) {
|
||||
var jquery = [
|
||||
'<!-- You can safely delete this line if your theme does not require jQuery -->\n',
|
||||
'<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>\n\n'
|
||||
];
|
||||
this.obj.should.be.an.Object().with.property(['roles']);
|
||||
this.obj.roles.should.be.an.Array();
|
||||
roleNames = _.pluck(this.obj.roles, 'name');
|
||||
roleNames.should.eql(roles);
|
||||
});
|
||||
|
||||
should.exist(result);
|
||||
should.exist(result.attributes);
|
||||
result.attributes.value.should.equal(jquery.join(''));
|
||||
// Custom assertion to wrap all permissions
|
||||
should.Assertion.add('CompletePermissions', function () {
|
||||
this.params = {operator: 'to have a complete set of permissions'};
|
||||
var permissions = this.obj;
|
||||
|
||||
done();
|
||||
});
|
||||
// DB
|
||||
permissions[0].name.should.eql('Export database');
|
||||
permissions[0].should.be.AssignedToRoles(['Administrator']);
|
||||
permissions[1].name.should.eql('Import database');
|
||||
permissions[1].should.be.AssignedToRoles(['Administrator']);
|
||||
permissions[2].name.should.eql('Delete all content');
|
||||
permissions[2].should.be.AssignedToRoles(['Administrator']);
|
||||
|
||||
// Mail
|
||||
permissions[3].name.should.eql('Send mail');
|
||||
permissions[3].should.be.AssignedToRoles(['Administrator']);
|
||||
|
||||
// Notifications
|
||||
permissions[4].name.should.eql('Browse notifications');
|
||||
permissions[4].should.be.AssignedToRoles(['Administrator']);
|
||||
permissions[5].name.should.eql('Add notifications');
|
||||
permissions[5].should.be.AssignedToRoles(['Administrator']);
|
||||
permissions[6].name.should.eql('Delete notifications');
|
||||
permissions[6].should.be.AssignedToRoles(['Administrator']);
|
||||
|
||||
// Posts
|
||||
permissions[7].name.should.eql('Browse posts');
|
||||
permissions[7].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[8].name.should.eql('Read posts');
|
||||
permissions[8].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[9].name.should.eql('Edit posts');
|
||||
permissions[9].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
permissions[10].name.should.eql('Add posts');
|
||||
permissions[10].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[11].name.should.eql('Delete posts');
|
||||
permissions[11].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
|
||||
// Settings
|
||||
permissions[12].name.should.eql('Browse settings');
|
||||
permissions[12].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[13].name.should.eql('Read settings');
|
||||
permissions[13].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[14].name.should.eql('Edit settings');
|
||||
permissions[14].should.be.AssignedToRoles(['Administrator']);
|
||||
|
||||
// Slugs
|
||||
permissions[15].name.should.eql('Generate slugs');
|
||||
permissions[15].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
|
||||
// Tags
|
||||
permissions[16].name.should.eql('Browse tags');
|
||||
permissions[16].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[17].name.should.eql('Read tags');
|
||||
permissions[17].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[18].name.should.eql('Edit tags');
|
||||
permissions[18].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
permissions[19].name.should.eql('Add tags');
|
||||
permissions[19].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[20].name.should.eql('Delete tags');
|
||||
permissions[20].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
|
||||
// Themes
|
||||
permissions[21].name.should.eql('Browse themes');
|
||||
permissions[21].should.be.AssignedToRoles(['Administrator']);
|
||||
permissions[22].name.should.eql('Edit themes');
|
||||
permissions[22].should.be.AssignedToRoles(['Administrator']);
|
||||
|
||||
// Users
|
||||
permissions[23].name.should.eql('Browse users');
|
||||
permissions[23].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[24].name.should.eql('Read users');
|
||||
permissions[24].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
permissions[25].name.should.eql('Edit users');
|
||||
permissions[25].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
permissions[26].name.should.eql('Add users');
|
||||
permissions[26].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
permissions[27].name.should.eql('Delete users');
|
||||
permissions[27].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
|
||||
// Roles
|
||||
permissions[28].name.should.eql('Assign a role');
|
||||
permissions[28].should.be.AssignedToRoles(['Administrator', 'Editor']);
|
||||
permissions[29].name.should.eql('Browse roles');
|
||||
permissions[29].should.be.AssignedToRoles(['Administrator', 'Editor', 'Author']);
|
||||
});
|
||||
|
||||
beforeEach(testUtils.setup());
|
||||
|
||||
it('should populate all fixtures correctly', function (done) {
|
||||
var logStub = sandbox.stub();
|
||||
|
||||
fixtures.populate({context: {internal: true}}, logStub).then(function () {
|
||||
var props = {
|
||||
posts: Models.Post.findAll({include: ['tags']}),
|
||||
tags: Models.Tag.findAll(),
|
||||
users: Models.User.findAll({include: ['roles']}),
|
||||
clients: Models.Client.findAll(),
|
||||
roles: Models.Role.findAll(),
|
||||
permissions: Models.Permission.findAll({include: ['roles']})
|
||||
};
|
||||
|
||||
logStub.called.should.be.true();
|
||||
|
||||
return Promise.props(props).then(function (result) {
|
||||
should.exist(result);
|
||||
|
||||
// Post
|
||||
should.exist(result.posts);
|
||||
result.posts.length.should.eql(1);
|
||||
result.posts.at(0).get('title').should.eql('Welcome to Ghost');
|
||||
|
||||
// Tag
|
||||
should.exist(result.tags);
|
||||
result.tags.length.should.eql(1);
|
||||
result.tags.at(0).get('name').should.eql('Getting Started');
|
||||
|
||||
// Post Tag relation
|
||||
result.posts.at(0).related('tags').length.should.eql(1);
|
||||
result.posts.at(0).related('tags').at(0).get('name').should.eql('Getting Started');
|
||||
|
||||
// Clients
|
||||
should.exist(result.clients);
|
||||
result.clients.length.should.eql(2);
|
||||
result.clients.at(0).get('name').should.eql('Ghost Admin');
|
||||
result.clients.at(1).get('name').should.eql('Ghost Frontend');
|
||||
|
||||
// User (Owner)
|
||||
should.exist(result.users);
|
||||
result.users.length.should.eql(1);
|
||||
result.users.at(0).get('name').should.eql('Ghost Owner');
|
||||
result.users.at(0).related('roles').length.should.eql(1);
|
||||
result.users.at(0).related('roles').at(0).get('name').should.eql('Owner');
|
||||
|
||||
// Roles
|
||||
should.exist(result.roles);
|
||||
result.roles.length.should.eql(4);
|
||||
result.roles.at(0).get('name').should.eql('Administrator');
|
||||
result.roles.at(1).get('name').should.eql('Editor');
|
||||
result.roles.at(2).get('name').should.eql('Author');
|
||||
result.roles.at(3).get('name').should.eql('Owner');
|
||||
|
||||
// Permissions
|
||||
result.permissions.length.should.eql(30);
|
||||
result.permissions.toJSON().should.be.CompletePermissions();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
|
586
core/test/unit/migration_fixture_spec.js
Normal file
586
core/test/unit/migration_fixture_spec.js
Normal file
|
@ -0,0 +1,586 @@
|
|||
/*global describe, it, beforeEach, afterEach */
|
||||
var should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
rewire = require('rewire'),
|
||||
Promise = require('bluebird'),
|
||||
|
||||
// Stuff we are testing
|
||||
configUtils = require('../utils/configUtils'),
|
||||
models = require('../../server/models'),
|
||||
notifications = require('../../server/api/notifications'),
|
||||
update = rewire('../../server/data/migration/fixtures/update'),
|
||||
populate = rewire('../../server/data/migration/fixtures/populate'),
|
||||
fixtures004 = require('../../server/data/migration/fixtures/004'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Fixtures', function () {
|
||||
beforeEach(function (done) {
|
||||
models.init().then(function () {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
configUtils.restore();
|
||||
});
|
||||
|
||||
describe('Update fixtures', function () {
|
||||
it('should call `getVersionTasks` when upgrading from 003 -> 004', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
getVersionTasksStub = sandbox.stub().returns([]),
|
||||
reset = update.__set__('getVersionTasks', getVersionTasksStub);
|
||||
|
||||
update(['004'], {}, logStub).then(function () {
|
||||
logStub.calledOnce.should.be.true();
|
||||
getVersionTasksStub.calledOnce.should.be.true();
|
||||
reset();
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('should NOT call `getVersionTasks` when upgrading from 004 -> 004', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
getVersionTasksStub = sandbox.stub().returns(Promise.resolve()),
|
||||
reset = update.__set__('getVersionTasks', getVersionTasksStub);
|
||||
|
||||
update([], {}, logStub).then(function () {
|
||||
logStub.calledOnce.should.be.true();
|
||||
getVersionTasksStub.calledOnce.should.be.false();
|
||||
reset();
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('`getVersionTasks` returns empty array if no tasks are found', function () {
|
||||
var logStub = sandbox.stub();
|
||||
|
||||
update.__get__('getVersionTasks')('999', logStub).should.eql([]);
|
||||
logStub.calledOnce.should.be.true();
|
||||
});
|
||||
|
||||
describe('Update to 004', function () {
|
||||
it('should call all the 004 fixture upgrades', function (done) {
|
||||
// Stub all the model methods so that nothing happens
|
||||
var logStub = sandbox.stub(),
|
||||
settingsOneStub = sandbox.stub(models.Settings, 'findOne').returns(Promise.resolve()),
|
||||
settingsEditStub = sandbox.stub(models.Settings, 'edit').returns(Promise.resolve()),
|
||||
clientOneStub = sandbox.stub(models.Client, 'findOne'),
|
||||
clientEditStub = sandbox.stub(models.Client, 'edit').returns(Promise.resolve()),
|
||||
clientAddStub = sandbox.stub(models.Client, 'add').returns(Promise.resolve()),
|
||||
tagAllStub = sandbox.stub(models.Tag, 'findAll').returns(Promise.resolve()),
|
||||
postAllStub = sandbox.stub(models.Post, 'findAll').returns(Promise.resolve()),
|
||||
postOneStub = sandbox.stub(models.Post, 'findOne').returns(Promise.resolve({})),
|
||||
postAddStub = sandbox.stub(models.Post, 'add').returns(Promise.resolve());
|
||||
|
||||
clientOneStub.withArgs({slug: 'ghost-admin'}).returns(Promise.resolve());
|
||||
clientOneStub.withArgs({slug: 'ghost-frontend'}).returns(Promise.resolve({}));
|
||||
|
||||
update(['004'], {}, logStub).then(function (result) {
|
||||
should.exist(result);
|
||||
|
||||
logStub.called.should.be.true();
|
||||
settingsOneStub.calledThrice.should.be.true();
|
||||
settingsEditStub.called.should.be.false();
|
||||
clientOneStub.calledTwice.should.be.true();
|
||||
clientEditStub.called.should.be.false();
|
||||
clientAddStub.called.should.be.false();
|
||||
tagAllStub.calledOnce.should.be.true();
|
||||
postAllStub.calledOnce.should.be.true();
|
||||
postOneStub.calledOnce.should.be.true();
|
||||
postAddStub.called.should.be.false();
|
||||
|
||||
sinon.assert.callOrder(
|
||||
settingsOneStub, settingsOneStub, settingsOneStub, clientOneStub, clientOneStub, tagAllStub,
|
||||
postAllStub, postOneStub
|
||||
);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
describe('01-move-jquery-with-alert', function () {
|
||||
it('tries to move jQuery to ghost_foot', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
settingsOneStub = sandbox.stub(models.Settings, 'findOne').returns(Promise.resolve({
|
||||
attributes: {value: ''}
|
||||
})),
|
||||
settingsEditStub = sandbox.stub(models.Settings, 'edit').returns(Promise.resolve());
|
||||
|
||||
fixtures004[0]({}, logStub).then(function () {
|
||||
settingsOneStub.calledOnce.should.be.true();
|
||||
settingsOneStub.calledWith('ghost_foot').should.be.true();
|
||||
settingsEditStub.calledOnce.should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('does not move jQuery to ghost_foot if it is already there', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
settingsOneStub = sandbox.stub(models.Settings, 'findOne').returns(Promise.resolve({
|
||||
attributes: {
|
||||
value: '<!-- You can safely delete this line if your theme does not require jQuery -->\n'
|
||||
+ '<script type="text/javascript" src="https://code.jquery.com/jquery-1.11.3.min.js"></script>\n\n'
|
||||
}
|
||||
})),
|
||||
settingsEditStub = sandbox.stub(models.Settings, 'edit').returns(Promise.resolve());
|
||||
|
||||
fixtures004[0]({}, logStub).then(function () {
|
||||
settingsOneStub.calledOnce.should.be.true();
|
||||
settingsOneStub.calledWith('ghost_foot').should.be.true();
|
||||
settingsEditStub.calledOnce.should.be.false();
|
||||
logStub.called.should.be.false();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('tried to move jQuery AND add a privacy message if any privacy settings are on', function (done) {
|
||||
configUtils.set({privacy: {useGoogleFonts: false}});
|
||||
var logStub = sandbox.stub(),
|
||||
settingsOneStub = sandbox.stub(models.Settings, 'findOne').returns(Promise.resolve({
|
||||
attributes: {value: ''}
|
||||
})),
|
||||
settingsEditStub = sandbox.stub(models.Settings, 'edit').returns(Promise.resolve()),
|
||||
notificationsAddStub = sandbox.stub(notifications, 'add').returns(Promise.resolve());
|
||||
|
||||
fixtures004[0]({}, logStub).then(function () {
|
||||
settingsOneStub.calledOnce.should.be.true();
|
||||
settingsOneStub.calledWith('ghost_foot').should.be.true();
|
||||
settingsEditStub.calledOnce.should.be.true();
|
||||
notificationsAddStub.calledOnce.should.be.true();
|
||||
logStub.calledTwice.should.be.true();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('02-update-private-setting-type', function () {
|
||||
it('tries to update setting type correctly', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
settingsOneStub = sandbox.stub(models.Settings, 'findOne').returns(Promise.resolve({})),
|
||||
settingsEditStub = sandbox.stub(models.Settings, 'edit').returns(Promise.resolve());
|
||||
|
||||
fixtures004[1]({}, logStub).then(function () {
|
||||
settingsOneStub.calledOnce.should.be.true();
|
||||
settingsOneStub.calledWith('isPrivate').should.be.true();
|
||||
settingsEditStub.calledOnce.should.be.true();
|
||||
settingsEditStub.calledWith({key: 'isPrivate', type: 'private'}).should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(settingsOneStub, logStub, settingsEditStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('03-update-password-setting-type', function () {
|
||||
it('tries to update setting type correctly', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
settingsOneStub = sandbox.stub(models.Settings, 'findOne').returns(Promise.resolve({})),
|
||||
settingsEditStub = sandbox.stub(models.Settings, 'edit').returns(Promise.resolve());
|
||||
|
||||
fixtures004[2]({}, logStub).then(function () {
|
||||
settingsOneStub.calledOnce.should.be.true();
|
||||
settingsOneStub.calledWith('password').should.be.true();
|
||||
settingsEditStub.calledOnce.should.be.true();
|
||||
settingsEditStub.calledWith({key: 'password', type: 'private'}).should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(settingsOneStub, logStub, settingsEditStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('04-update-ghost-admin-client', function () {
|
||||
it('tries to update client correctly', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
clientOneStub = sandbox.stub(models.Client, 'findOne').returns(Promise.resolve({})),
|
||||
clientEditStub = sandbox.stub(models.Client, 'edit').returns(Promise.resolve());
|
||||
|
||||
fixtures004[3]({}, logStub).then(function () {
|
||||
clientOneStub.calledOnce.should.be.true();
|
||||
clientOneStub.calledWith({slug: 'ghost-admin'}).should.be.true();
|
||||
clientEditStub.calledOnce.should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(clientOneStub, logStub, clientEditStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('05-add-ghost-frontend-client', function () {
|
||||
it('tries to add client correctly', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
clientOneStub = sandbox.stub(models.Client, 'findOne').returns(Promise.resolve()),
|
||||
clientAddStub = sandbox.stub(models.Client, 'add').returns(Promise.resolve());
|
||||
|
||||
fixtures004[4]({}, logStub).then(function () {
|
||||
clientOneStub.calledOnce.should.be.true();
|
||||
clientOneStub.calledWith({slug: 'ghost-frontend'}).should.be.true();
|
||||
clientAddStub.calledOnce.should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(clientOneStub, logStub, clientAddStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('06-clean-broken-tags', function () {
|
||||
it('tries to clean broken tags correctly', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
tagObjStub = {
|
||||
get: sandbox.stub().returns(',hello'),
|
||||
save: sandbox.stub().returns(Promise.resolve)
|
||||
},
|
||||
tagCollStub = {each: sandbox.stub().callsArgWith(0, tagObjStub)},
|
||||
tagAllStub = sandbox.stub(models.Tag, 'findAll').returns(Promise.resolve(tagCollStub));
|
||||
|
||||
fixtures004[5]({}, logStub).then(function () {
|
||||
tagAllStub.calledOnce.should.be.true();
|
||||
tagCollStub.each.calledOnce.should.be.true();
|
||||
tagObjStub.get.calledOnce.should.be.true();
|
||||
tagObjStub.get.calledWith('name').should.be.true();
|
||||
tagObjStub.save.calledOnce.should.be.true();
|
||||
tagObjStub.save.calledWith({name: 'hello'}).should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(tagAllStub, tagCollStub.each, tagObjStub.get, tagObjStub.save, logStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('tries can handle tags which end up empty', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
tagObjStub = {
|
||||
get: sandbox.stub().returns(','),
|
||||
save: sandbox.stub().returns(Promise.resolve)
|
||||
},
|
||||
tagCollStub = {each: sandbox.stub().callsArgWith(0, tagObjStub)},
|
||||
tagAllStub = sandbox.stub(models.Tag, 'findAll').returns(Promise.resolve(tagCollStub));
|
||||
|
||||
fixtures004[5]({}, logStub).then(function () {
|
||||
tagAllStub.calledOnce.should.be.true();
|
||||
tagCollStub.each.calledOnce.should.be.true();
|
||||
tagObjStub.get.calledOnce.should.be.true();
|
||||
tagObjStub.get.calledWith('name').should.be.true();
|
||||
tagObjStub.save.calledOnce.should.be.true();
|
||||
tagObjStub.save.calledWith({name: 'tag'}).should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(tagAllStub, tagCollStub.each, tagObjStub.get, tagObjStub.save, logStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('tries only changes a tag if necessary', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
tagObjStub = {
|
||||
get: sandbox.stub().returns('hello'),
|
||||
save: sandbox.stub().returns(Promise.resolve)
|
||||
},
|
||||
tagCollStub = {each: sandbox.stub().callsArgWith(0, tagObjStub)},
|
||||
tagAllStub = sandbox.stub(models.Tag, 'findAll').returns(Promise.resolve(tagCollStub));
|
||||
|
||||
fixtures004[5]({}, logStub).then(function () {
|
||||
tagAllStub.calledOnce.should.be.true();
|
||||
tagCollStub.each.calledOnce.should.be.true();
|
||||
tagObjStub.get.calledOnce.should.be.true();
|
||||
tagObjStub.get.calledWith('name').should.be.true();
|
||||
tagObjStub.save.called.should.be.false();
|
||||
logStub.calledOnce.should.be.false();
|
||||
sinon.assert.callOrder(tagAllStub, tagCollStub.each, tagObjStub.get);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('07-add-post-tag-order', function () {
|
||||
it('calls load on each post', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
postObjStub = {
|
||||
load: sandbox.stub().returnsThis()
|
||||
},
|
||||
postCollStub = {mapThen: sandbox.stub().callsArgWith(0, postObjStub)},
|
||||
postAllStub = sandbox.stub(models.Post, 'findAll').returns(Promise.resolve(postCollStub));
|
||||
|
||||
fixtures004[6]({}, logStub).then(function () {
|
||||
postAllStub.calledOnce.should.be.true();
|
||||
postCollStub.mapThen.calledOnce.should.be.true();
|
||||
postObjStub.load.calledOnce.should.be.true();
|
||||
postObjStub.load.calledWith(['tags']).should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(logStub, postAllStub, postCollStub.mapThen, postObjStub.load);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('tries to add order to posts_tags', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
postObjStub = {
|
||||
load: sandbox.stub().returnsThis(),
|
||||
related: sandbox.stub().returnsThis(),
|
||||
tags: sandbox.stub().returnsThis(),
|
||||
each: sandbox.stub().callsArgWith(0, {id: 5}),
|
||||
updatePivot: sandbox.stub().returns(Promise.resolve())
|
||||
},
|
||||
postCollStub = {mapThen: sandbox.stub().returns([postObjStub])},
|
||||
postAllStub = sandbox.stub(models.Post, 'findAll').returns(Promise.resolve(postCollStub));
|
||||
|
||||
fixtures004[6]({}, logStub).then(function () {
|
||||
postAllStub.calledOnce.should.be.true();
|
||||
postCollStub.mapThen.calledOnce.should.be.true();
|
||||
postObjStub.load.called.should.be.false();
|
||||
postObjStub.related.calledOnce.should.be.true();
|
||||
postObjStub.each.calledOnce.should.be.true();
|
||||
postObjStub.tags.calledOnce.should.be.true();
|
||||
postObjStub.updatePivot.calledOnce.should.be.true();
|
||||
logStub.calledThrice.should.be.true();
|
||||
sinon.assert.callOrder(
|
||||
logStub, postAllStub, postCollStub.mapThen, postObjStub.related, postObjStub.each,
|
||||
logStub, postObjStub.tags, postObjStub.updatePivot, logStub
|
||||
);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('08-add-post-fixture', function () {
|
||||
it('tries to add a new post fixture correctly', function (done) {
|
||||
var logStub = sandbox.stub(),
|
||||
postOneStub = sandbox.stub(models.Post, 'findOne').returns(Promise.resolve()),
|
||||
postAddStub = sandbox.stub(models.Post, 'add').returns(Promise.resolve());
|
||||
|
||||
fixtures004[7]({}, logStub).then(function () {
|
||||
postOneStub.calledOnce.should.be.true();
|
||||
logStub.calledOnce.should.be.true();
|
||||
postAddStub.calledOnce.should.be.true();
|
||||
sinon.assert.callOrder(postOneStub, logStub, postAddStub);
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Populate fixtures', function () {
|
||||
// This tests that all the models & relations get called correctly
|
||||
it('should call all the fixture populations', function (done) {
|
||||
// Stub all the model methods so that nothing happens
|
||||
var logStub = sandbox.stub(),
|
||||
postAddStub = sandbox.stub(models.Post, 'add').returns(Promise.resolve()),
|
||||
tagAddStub = sandbox.stub(models.Tag, 'add').returns(Promise.resolve()),
|
||||
roleAddStub = sandbox.stub(models.Role, 'add').returns(Promise.resolve()),
|
||||
clientAddStub = sandbox.stub(models.Client, 'add').returns(Promise.resolve()),
|
||||
permsAddStub = sandbox.stub(models.Permission, 'add').returns(Promise.resolve()),
|
||||
|
||||
// Relations
|
||||
modelMethodStub = {filter: sandbox.stub(), find: sandbox.stub()},
|
||||
permsAllStub = sandbox.stub(models.Permission, 'findAll').returns(Promise.resolve(modelMethodStub)),
|
||||
rolesAllStub = sandbox.stub(models.Role, 'findAll').returns(Promise.resolve(modelMethodStub)),
|
||||
postsAllStub = sandbox.stub(models.Post, 'findAll').returns(Promise.resolve(modelMethodStub)),
|
||||
tagsAllStub = sandbox.stub(models.Tag, 'findAll').returns(Promise.resolve(modelMethodStub)),
|
||||
|
||||
// Create Owner
|
||||
roleOneStub = sandbox.stub(models.Role, 'findOne').returns(Promise.resolve({id: 1})),
|
||||
userAddStub = sandbox.stub(models.User, 'add').returns(Promise.resolve({}));
|
||||
|
||||
populate({}, logStub).then(function () {
|
||||
logStub.called.should.be.true();
|
||||
|
||||
postAddStub.calledOnce.should.be.true();
|
||||
tagAddStub.calledOnce.should.be.true();
|
||||
roleAddStub.callCount.should.eql(4);
|
||||
clientAddStub.calledTwice.should.be.true();
|
||||
|
||||
permsAddStub.called.should.be.true();
|
||||
permsAddStub.callCount.should.eql(30);
|
||||
|
||||
permsAllStub.calledOnce.should.be.true();
|
||||
rolesAllStub.calledOnce.should.be.true();
|
||||
postsAllStub.calledOnce.should.be.true();
|
||||
tagsAllStub.calledOnce.should.be.true();
|
||||
|
||||
// Relations
|
||||
modelMethodStub.filter.called.should.be.true();
|
||||
// 22 permissions, 1 tag
|
||||
modelMethodStub.filter.callCount.should.eql(22 + 1);
|
||||
modelMethodStub.find.called.should.be.true();
|
||||
// 3 roles, 1 post
|
||||
modelMethodStub.find.callCount.should.eql(3 + 1);
|
||||
|
||||
// Create Owner
|
||||
roleOneStub.calledOnce.should.be.true();
|
||||
userAddStub.calledOnce.should.be.true();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
describe('Add All Relations', function () {
|
||||
it('should call attach if relation models are found', function (done) {
|
||||
var addAllRelations = populate.__get__('addAllRelations'),
|
||||
emptyMethodStub = {filter: sandbox.stub(), find: sandbox.stub()},
|
||||
// Setup a chain of methods
|
||||
dataMethodStub = {
|
||||
filter: sandbox.stub().returnsThis(),
|
||||
find: sandbox.stub().returnsThis(),
|
||||
tags: sandbox.stub().returnsThis(),
|
||||
attach: sandbox.stub().returns(Promise.resolve())
|
||||
},
|
||||
permsAllStub = sandbox.stub(models.Permission, 'findAll').returns(Promise.resolve(emptyMethodStub)),
|
||||
rolesAllStub = sandbox.stub(models.Role, 'findAll').returns(Promise.resolve(emptyMethodStub)),
|
||||
postsAllStub = sandbox.stub(models.Post, 'findAll').returns(Promise.resolve(dataMethodStub)),
|
||||
tagsAllStub = sandbox.stub(models.Tag, 'findAll').returns(Promise.resolve(dataMethodStub));
|
||||
|
||||
addAllRelations().then(function () {
|
||||
permsAllStub.calledOnce.should.be.true();
|
||||
rolesAllStub.calledOnce.should.be.true();
|
||||
postsAllStub.calledOnce.should.be.true();
|
||||
tagsAllStub.calledOnce.should.be.true();
|
||||
|
||||
// Permissions & Roles
|
||||
emptyMethodStub.filter.called.should.be.true();
|
||||
emptyMethodStub.filter.callCount.should.eql(22);
|
||||
emptyMethodStub.find.called.should.be.true();
|
||||
emptyMethodStub.find.callCount.should.eql(3);
|
||||
|
||||
// Posts & Tags
|
||||
dataMethodStub.filter.calledOnce.should.be.true();
|
||||
dataMethodStub.find.calledOnce.should.be.true();
|
||||
dataMethodStub.tags.calledOnce.should.be.true();
|
||||
dataMethodStub.attach.calledOnce.should.be.true();
|
||||
dataMethodStub.attach.calledWith(dataMethodStub).should.be.true();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create Owner', function () {
|
||||
it('createOwner will add user if owner role is present', function (done) {
|
||||
var createOwner = populate.__get__('createOwner'),
|
||||
logStub = sandbox.stub(),
|
||||
roleOneStub = sandbox.stub(models.Role, 'findOne').returns(Promise.resolve({id: 1})),
|
||||
userAddStub = sandbox.stub(models.User, 'add').returns(Promise.resolve({}));
|
||||
|
||||
createOwner({}, logStub).then(function () {
|
||||
logStub.called.should.be.true();
|
||||
roleOneStub.calledOnce.should.be.true();
|
||||
userAddStub.called.should.be.true();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
||||
it('createOwner does not add user if owner role is not present', function (done) {
|
||||
var createOwner = populate.__get__('createOwner'),
|
||||
roleOneStub = sandbox.stub(models.Role, 'findOne').returns(Promise.resolve()),
|
||||
userAddStub = sandbox.stub(models.User, 'add').returns(Promise.resolve({}));
|
||||
|
||||
createOwner().then(function () {
|
||||
roleOneStub.calledOnce.should.be.true();
|
||||
userAddStub.called.should.be.false();
|
||||
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Match Func', function () {
|
||||
var matchFunc = populate.__get__('matchFunc');
|
||||
|
||||
it('should match undefined with no args', function () {
|
||||
var getStub = sandbox.stub();
|
||||
|
||||
matchFunc()({get: getStub}).should.be.true();
|
||||
getStub.calledOnce.should.be.true();
|
||||
getStub.calledWith(undefined).should.be.true();
|
||||
});
|
||||
|
||||
it('should match key with match string', function () {
|
||||
var getStub = sandbox.stub();
|
||||
getStub.withArgs('foo').returns('bar');
|
||||
|
||||
matchFunc('foo', 'bar')({get: getStub}).should.be.true();
|
||||
getStub.calledOnce.should.be.true();
|
||||
getStub.calledWith('foo').should.be.true();
|
||||
|
||||
matchFunc('foo', 'buz')({get: getStub}).should.be.false();
|
||||
getStub.calledTwice.should.be.true();
|
||||
getStub.secondCall.calledWith('foo').should.be.true();
|
||||
});
|
||||
|
||||
it('should match value when key is 0', function () {
|
||||
var getStub = sandbox.stub();
|
||||
getStub.withArgs('foo').returns('bar');
|
||||
|
||||
matchFunc('foo', 0, 'bar')({get: getStub}).should.be.true();
|
||||
getStub.calledOnce.should.be.true();
|
||||
getStub.calledWith('foo').should.be.true();
|
||||
|
||||
matchFunc('foo', 0, 'buz')({get: getStub}).should.be.false();
|
||||
getStub.calledTwice.should.be.true();
|
||||
getStub.secondCall.calledWith('foo').should.be.true();
|
||||
});
|
||||
|
||||
it('should match key & value when match is array', function () {
|
||||
var getStub = sandbox.stub();
|
||||
getStub.withArgs('foo').returns('bar');
|
||||
getStub.withArgs('fun').returns('baz');
|
||||
|
||||
matchFunc(['foo', 'fun'], 'bar', 'baz')({get: getStub}).should.be.true();
|
||||
getStub.calledTwice.should.be.true();
|
||||
getStub.getCall(0).calledWith('fun').should.be.true();
|
||||
getStub.getCall(1).calledWith('foo').should.be.true();
|
||||
|
||||
matchFunc(['foo', 'fun'], 'baz', 'bar')({get: getStub}).should.be.false();
|
||||
getStub.callCount.should.eql(4);
|
||||
getStub.getCall(2).calledWith('fun').should.be.true();
|
||||
getStub.getCall(3).calledWith('foo').should.be.true();
|
||||
});
|
||||
|
||||
it('should match key only when match is array, but value is all', function () {
|
||||
var getStub = sandbox.stub();
|
||||
getStub.withArgs('foo').returns('bar');
|
||||
getStub.withArgs('fun').returns('baz');
|
||||
|
||||
matchFunc(['foo', 'fun'], 'bar', 'all')({get: getStub}).should.be.true();
|
||||
getStub.calledOnce.should.be.true();
|
||||
getStub.calledWith('foo').should.be.true();
|
||||
|
||||
matchFunc(['foo', 'fun'], 'all', 'bar')({get: getStub}).should.be.false();
|
||||
getStub.callCount.should.eql(3);
|
||||
getStub.getCall(1).calledWith('fun').should.be.true();
|
||||
getStub.getCall(2).calledWith('foo').should.be.true();
|
||||
});
|
||||
|
||||
it('should match key & value when match and value are arrays', function () {
|
||||
var getStub = sandbox.stub();
|
||||
getStub.withArgs('foo').returns('bar');
|
||||
getStub.withArgs('fun').returns('baz');
|
||||
|
||||
matchFunc(['foo', 'fun'], 'bar', ['baz', 'buz'])({get: getStub}).should.be.true();
|
||||
getStub.calledTwice.should.be.true();
|
||||
getStub.getCall(0).calledWith('fun').should.be.true();
|
||||
getStub.getCall(1).calledWith('foo').should.be.true();
|
||||
|
||||
matchFunc(['foo', 'fun'], 'bar', ['biz', 'buz'])({get: getStub}).should.be.false();
|
||||
getStub.callCount.should.eql(4);
|
||||
getStub.getCall(2).calledWith('fun').should.be.true();
|
||||
getStub.getCall(3).calledWith('foo').should.be.true();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,17 +1,24 @@
|
|||
/*globals describe, it*/
|
||||
/*globals describe, it, afterEach*/
|
||||
var should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
_ = require('lodash'),
|
||||
crypto = require('crypto'),
|
||||
|
||||
// Stuff we are testing
|
||||
schema = require('../../server/data/schema'),
|
||||
permissions = require('../../server/data/migration/fixtures/permissions/permissions'),
|
||||
defaultSettings = schema.defaultSettings;
|
||||
fixtures = require('../../server/data/migration/fixtures'),
|
||||
defaultSettings = schema.defaultSettings,
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
// To stop jshint complaining
|
||||
should.equal(true, true);
|
||||
|
||||
describe('Migrations', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
// Check version integrity
|
||||
// These tests exist to ensure that developers are not able to modify the database schema, or permissions fixtures
|
||||
// without knowing that they also need to update the default database version,
|
||||
|
@ -20,14 +27,14 @@ describe('Migrations', function () {
|
|||
// Only these variables should need updating
|
||||
var currentDbVersion = '004',
|
||||
currentSchemaHash = 'a195562bf4915e3f3f610f6d178aba01',
|
||||
currentPermissionsHash = '42e486732270cda623fc5efc04808c0c';
|
||||
currentFixturesHash = '17d6aa36a6ba904adca90279eb929381';
|
||||
|
||||
// If this test is failing, then it is likely a change has been made that requires a DB version bump,
|
||||
// and the values above will need updating as confirmation
|
||||
it('should not change without fixing this test', function () {
|
||||
var tablesNoValidation = _.cloneDeep(schema.tables),
|
||||
schemaHash,
|
||||
permissionsHash;
|
||||
fixturesHash;
|
||||
|
||||
_.each(tablesNoValidation, function (table) {
|
||||
return _.each(table, function (column, name) {
|
||||
|
@ -36,12 +43,15 @@ describe('Migrations', function () {
|
|||
});
|
||||
|
||||
schemaHash = crypto.createHash('md5').update(JSON.stringify(tablesNoValidation)).digest('hex');
|
||||
permissionsHash = crypto.createHash('md5').update(JSON.stringify(permissions)).digest('hex');
|
||||
fixturesHash = crypto.createHash('md5').update(JSON.stringify(fixtures.fixtures)).digest('hex');
|
||||
|
||||
// Test!
|
||||
defaultSettings.core.databaseVersion.defaultValue.should.eql(currentDbVersion);
|
||||
schemaHash.should.eql(currentSchemaHash);
|
||||
permissionsHash.should.eql(currentPermissionsHash);
|
||||
fixturesHash.should.eql(currentFixturesHash);
|
||||
schema.versioning.canMigrateFromVersion.should.eql('003');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Builder', function () {});
|
||||
});
|
||||
|
|
58
core/test/unit/versioning_spec.js
Normal file
58
core/test/unit/versioning_spec.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
/*globals describe, it, afterEach */
|
||||
var should = require('should'),
|
||||
sinon = require('sinon'),
|
||||
|
||||
// Stuff we are testing
|
||||
versioning = require('../../server/data/schema').versioning,
|
||||
errors = require('../../server/errors'),
|
||||
|
||||
sandbox = sinon.sandbox.create();
|
||||
|
||||
describe('Versioning', function () {
|
||||
afterEach(function () {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
describe('getMigrationVersions', function () {
|
||||
it('should output a single item if the from and to versions are the same', function () {
|
||||
should.exist(versioning.getMigrationVersions);
|
||||
versioning.getMigrationVersions('003', '003').should.eql(['003']);
|
||||
versioning.getMigrationVersions('004', '004').should.eql(['004']);
|
||||
});
|
||||
|
||||
it('should output an empty array if the toVersion is higher than the fromVersion', function () {
|
||||
versioning.getMigrationVersions('003', '002').should.eql([]);
|
||||
});
|
||||
|
||||
it('should output all the versions between two versions', function () {
|
||||
versioning.getMigrationVersions('003', '004').should.eql(['003', '004']);
|
||||
versioning.getMigrationVersions('003', '005').should.eql(['003', '004', '005']);
|
||||
versioning.getMigrationVersions('003', '006').should.eql(['003', '004', '005', '006']);
|
||||
versioning.getMigrationVersions('010', '011').should.eql(['010', '011']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDefaultDatabaseVersion', function () {
|
||||
it('should return the correct version', function () {
|
||||
var currentVersion = require('../../server/data/schema').defaultSettings.core.databaseVersion.defaultValue;
|
||||
// This function has an internal cache, so we call it twice.
|
||||
// First, to check that it fetches the correct version from default-settings.json.
|
||||
versioning.getDefaultDatabaseVersion().should.eql(currentVersion);
|
||||
// Second, to check that it returns the same value from the cache.
|
||||
versioning.getDefaultDatabaseVersion().should.eql(currentVersion);
|
||||
});
|
||||
});
|
||||
|
||||
describe('showCannotMigrateError', function () {
|
||||
it('should output a detailed error message', function () {
|
||||
var errorStub = sandbox.stub(errors, 'logAndRejectError');
|
||||
versioning.showCannotMigrateError();
|
||||
errorStub.calledOnce.should.be.true();
|
||||
errorStub.calledWith(
|
||||
'Unable to upgrade from version 0.4.2 or earlier',
|
||||
'Please upgrade to 0.7.1 first',
|
||||
'See http://support.ghost.org/how-to-upgrade/ for instructions.'
|
||||
).should.be.true();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -5,10 +5,10 @@ var Promise = require('bluebird'),
|
|||
uuid = require('node-uuid'),
|
||||
db = require('../../server/data/db'),
|
||||
migration = require('../../server/data/migration/'),
|
||||
mainFixtures = require('../../server/data/migration/fixtures').fixtures,
|
||||
Models = require('../../server/models'),
|
||||
SettingsAPI = require('../../server/api/settings'),
|
||||
permissions = require('../../server/permissions'),
|
||||
permsFixtures = require('../../server/data/migration/fixtures/permissions/permissions.json'),
|
||||
sequence = require('../../server/utils/sequence'),
|
||||
DataGenerator = require('./fixtures/data-generator'),
|
||||
filterData = require('./fixtures/filter-param'),
|
||||
|
@ -316,8 +316,8 @@ fixtures = {
|
|||
},
|
||||
|
||||
permissionsFor: function permissionsFor(obj) {
|
||||
var permsToInsert = permsFixtures.permissions[obj],
|
||||
permsRolesToInsert = permsFixtures.permissions_roles,
|
||||
var permsToInsert = _.filter(mainFixtures.models.Permission, function (perm) { return perm.object_type === obj; }),
|
||||
permsRolesToInsert = mainFixtures.relations[0].entries,
|
||||
actions = [],
|
||||
permissionsRoles = [],
|
||||
roles = {
|
||||
|
|
Loading…
Add table
Reference in a new issue