2020-04-29 18:44:27 +03:00
const should = require ( 'should' ) ;
const sinon = require ( 'sinon' ) ;
const testUtils = require ( '../../utils' ) ;
const Promise = require ( 'bluebird' ) ;
2020-05-27 15:51:06 +03:00
const moment = require ( 'moment-timezone' ) ;
2020-04-29 18:44:27 +03:00
const ObjectId = require ( 'bson-objectid' ) ;
const assert = require ( 'assert' ) ;
const _ = require ( 'lodash' ) ;
const validator = require ( 'validator' ) ;
// Stuff we are testing
const db = require ( '../../../core/server/data/db' ) ;
const models = require ( '../../../core/server/models' ) ;
const importer = require ( '../../../core/server/data/importer' ) ;
const dataImporter = importer . importers [ 1 ] ;
const importOptions = {
returnImportedData : true
} ;
const knex = db . knex ;
2013-09-25 14:30:59 +04:00
2018-07-19 13:26:47 +03:00
const exportedLatestBody = ( ) => {
return _ . clone ( {
db : [ {
meta : {
exported _on : 1504269105806 ,
2019-08-19 14:41:09 +03:00
version : '2.0.0'
2018-07-19 13:26:47 +03:00
} ,
data : {
app _fields : [ ] ,
app _settings : [ ] ,
apps : [ ] ,
brute : [ ] ,
invites : [ ] ,
migrations : [ ] ,
permissions : [ ] ,
permissions _roles : [ ] ,
permissions _users : [ ] ,
posts : [ ] ,
posts _tags : [ ] ,
posts _authors : [ ] ,
roles : [ ] ,
roles _users : [ ] ,
settings : [ ] ,
subscribers : [ ] ,
tags : [ ] ,
users : [ ]
}
} ]
} ) ;
} ;
const exportedPreviousBody = ( ) => {
return _ . clone ( {
db : [ {
meta : {
exported _on : 1504269105806 ,
2019-08-19 14:41:09 +03:00
version : '1.20.0'
2018-07-19 13:26:47 +03:00
} ,
data : {
app _fields : [ ] ,
app _settings : [ ] ,
apps : [ ] ,
brute : [ ] ,
invites : [ ] ,
migrations : [ ] ,
permissions : [ ] ,
permissions _roles : [ ] ,
permissions _users : [ ] ,
posts : [ ] ,
posts _tags : [ ] ,
posts _authors : [ ] ,
roles : [ ] ,
roles _users : [ ] ,
settings : [ ] ,
subscribers : [ ] ,
tags : [ ] ,
users : [ ]
}
} ]
} ) ;
} ;
const exportedLegacyBody = ( ) => {
return _ . clone ( {
db : [ {
meta : {
exported _on : 1504269105806 ,
2019-08-19 14:41:09 +03:00
version : '300'
2018-07-19 13:26:47 +03:00
} ,
data : {
app _fields : [ ] ,
app _settings : [ ] ,
apps : [ ] ,
brute : [ ] ,
invites : [ ] ,
permissions : [ ] ,
permissions _roles : [ ] ,
permissions _users : [ ] ,
posts : [ ] ,
posts _tags : [ ] ,
roles : [ ] ,
roles _users : [ ] ,
settings : [ ] ,
subscribers : [ ] ,
tags : [ ] ,
users : [ ]
}
} ]
} ) ;
} ;
2014-08-09 23:16:54 +04:00
// Tests in here do an import for each test
2021-02-17 02:24:54 +03:00
describe ( 'Integration: Importer' , function ( ) {
2020-02-24 23:51:09 +03:00
before ( testUtils . teardownDb ) ;
2017-05-23 19:18:13 +03:00
beforeEach ( function ( ) {
2019-01-21 19:53:44 +03:00
sinon . stub ( importer , 'cleanUp' ) ;
2017-05-23 19:18:13 +03:00
} ) ;
2020-02-24 23:51:09 +03:00
afterEach ( testUtils . teardownDb ) ;
2014-07-21 21:50:04 +04:00
afterEach ( function ( ) {
2019-01-21 19:53:44 +03:00
sinon . restore ( ) ;
2014-07-21 21:50:04 +04:00
} ) ;
2013-09-25 14:30:59 +04:00
should . exist ( importer ) ;
2018-07-19 13:26:47 +03:00
describe ( 'Empty database (except of owner user), general tests' , function ( ) {
2014-09-25 05:18:34 +04:00
beforeEach ( testUtils . setup ( 'roles' , 'owner' , 'settings' ) ) ;
2018-07-19 13:26:47 +03:00
it ( 'ensure return structure' , function ( ) {
let exportData ;
2014-09-25 05:18:34 +04:00
2019-08-19 14:41:09 +03:00
return dataImporter . doImport ( exportedLatestBody ( ) . db [ 0 ] , importOptions )
2018-07-19 13:26:47 +03:00
. then ( function ( importResult ) {
should . exist ( importResult ) ;
importResult . hasOwnProperty ( 'data' ) . should . be . true ( ) ;
importResult . hasOwnProperty ( 'problems' ) . should . be . true ( ) ;
} ) ;
2014-09-25 05:18:34 +04:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'cares about invalid dates and date formats' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-09-25 05:18:34 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
2019-08-19 14:41:09 +03:00
created _at : '00-00-0000 00:00:00' ,
updated _at : 'Fri, 18 Oct 2013 23:58:44 +0000' ,
2018-07-19 13:26:47 +03:00
published _at : 1388318310783
} ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
created _at : 1388318310000 ,
updated _at : 1388318310000 ,
published _at : 1388404710000 ,
slug : 'post2'
} ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
created _at : 1388318310000 ,
updated _at : 1388318310000 ,
published _at : 1388404710000 ,
slug : 'post3'
} ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( {
2019-08-19 14:41:09 +03:00
updated _at : '2016-07-17T12:02:54.000Z'
2018-07-19 13:26:47 +03:00
} ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
should . exist ( importResult . data . posts ) ;
importResult . data . posts . length . should . equal ( 2 ) ;
importResult . problems . length . should . eql ( 1 ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
importResult . problems [ 0 ] . message . should . eql ( 'Date is in a wrong format and invalid. ' +
'It was replaced with the current timestamp.' ) ;
importResult . problems [ 0 ] . help . should . eql ( 'Post' ) ;
2014-09-25 05:18:34 +04:00
2018-07-19 13:26:47 +03:00
moment ( importResult . data . posts [ 0 ] . created _at ) . isValid ( ) . should . eql ( true ) ;
moment ( importResult . data . posts [ 0 ] . updated _at ) . format ( ) . should . eql ( '2013-10-18T23:58:44Z' ) ;
moment ( importResult . data . posts [ 0 ] . published _at ) . format ( ) . should . eql ( '2013-12-29T11:58:30Z' ) ;
moment ( importResult . data . tags [ 0 ] . updated _at ) . format ( ) . should . eql ( '2016-07-17T12:02:54Z' ) ;
2014-09-25 05:18:34 +04:00
2018-07-19 13:26:47 +03:00
// Ensure sqlite3 & mysql import of dates works as expected
assert . equal ( moment ( importResult . data . posts [ 1 ] . created _at ) . valueOf ( ) , 1388318310000 ) ;
assert . equal ( moment ( importResult . data . posts [ 1 ] . updated _at ) . valueOf ( ) , 1388318310000 ) ;
assert . equal ( moment ( importResult . data . posts [ 1 ] . published _at ) . valueOf ( ) , 1388404710000 ) ;
} ) ;
2018-02-16 02:49:15 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'warning that theme was not imported' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-09-25 05:18:34 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( {
2019-08-19 14:41:09 +03:00
key : 'active_theme' ,
value : 'mytheme' ,
2018-07-19 13:26:47 +03:00
type : 'theme'
} ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
importResult . problems . length . should . eql ( 1 ) ;
importResult . problems [ 0 ] . message . should . eql ( 'Theme not imported, please upload in Settings - Design' ) ;
return models . Settings . findOne ( _ . merge ( { key : 'active_theme' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . attributes . value . should . eql ( 'casper' ) ;
2014-09-25 05:18:34 +04:00
} ) ;
} ) ;
2017-07-20 13:24:23 +03:00
2018-07-19 13:26:47 +03:00
it ( 'removes duplicate users' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2017-07-20 13:24:23 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( {
2019-08-19 14:41:09 +03:00
name : 'Joe Bloggs' ,
slug : 'joe-bloggs' ,
email : 'jbloggs@example.com'
2018-07-19 13:26:47 +03:00
} ) ;
2014-09-25 05:18:34 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 1 ] = testUtils . DataGenerator . forKnex . createUser ( ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
should . exist ( importResult . data . users ) ;
importResult . data . users . length . should . equal ( 1 ) ;
importResult . problems . length . should . eql ( 1 ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
importResult . problems [ 0 ] . message . should . eql ( 'Entry was not imported and ignored. Detected duplicated entry.' ) ;
importResult . problems [ 0 ] . help . should . eql ( 'User' ) ;
} ) ;
} ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
it ( 'removes duplicate posts' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2013-09-25 14:30:59 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
2019-08-19 14:41:09 +03:00
slug : 'same'
2018-07-19 13:26:47 +03:00
} ) ;
2017-01-10 22:38:20 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
2019-08-19 14:41:09 +03:00
slug : 'same'
2018-07-19 13:26:47 +03:00
} ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
should . exist ( importResult . data . posts ) ;
importResult . data . posts . length . should . equal ( 1 ) ;
importResult . problems . length . should . eql ( 1 ) ;
2017-05-12 15:56:40 +03:00
2018-07-19 13:26:47 +03:00
importResult . problems [ 0 ] . message . should . eql ( 'Entry was not imported and ignored. Detected duplicated entry.' ) ;
importResult . problems [ 0 ] . help . should . eql ( 'Post' ) ;
} ) ;
} ) ;
2013-09-25 14:30:59 +04:00
2019-08-09 13:53:20 +03:00
it ( 'does not treat posts without slug as duplicate' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . posts [ 0 ] = {
2019-08-19 14:41:09 +03:00
title : 'duplicate title'
2019-08-09 13:53:20 +03:00
} ;
exportData . data . posts [ 1 ] = {
2019-08-19 14:41:09 +03:00
title : 'duplicate title'
2019-08-09 13:53:20 +03:00
} ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
should . exist ( importResult . data . posts ) ;
importResult . data . posts . length . should . equal ( 2 ) ;
importResult . problems . length . should . eql ( 0 ) ;
importResult . data . posts [ 0 ] . title . should . equal ( 'duplicate title' ) ;
importResult . data . posts [ 1 ] . title . should . equal ( 'duplicate title' ) ;
importResult . data . posts [ 0 ] . slug . should . equal ( 'duplicate-title' ) ;
importResult . data . posts [ 1 ] . slug . should . equal ( 'duplicate-title-2' ) ;
} ) ;
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'can import user with missing allowed fields' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2013-09-25 14:30:59 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( ) ;
delete exportData . data . users [ 0 ] . website ;
delete exportData . data . users [ 0 ] . bio ;
delete exportData . data . users [ 0 ] . accessibility ;
delete exportData . data . users [ 0 ] . cover _image ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
importResult . data . users [ 0 ] . hasOwnProperty ( 'website' ) ;
importResult . data . users [ 0 ] . hasOwnProperty ( 'bio' ) ;
importResult . data . users [ 0 ] . hasOwnProperty ( 'accessibility' ) ;
importResult . data . users [ 0 ] . hasOwnProperty ( 'cover_image' ) ;
} ) ;
2013-09-25 14:30:59 +04:00
} ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
it ( 'removes duplicate tags and updates associations' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2013-12-26 07:48:16 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( ) ;
2013-11-24 18:29:36 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'getting-started'
} ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 1 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'getting-started'
} ) ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts _tags = [
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 0 ] . id ) ,
2019-07-05 14:40:43 +03:00
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 1 ] . id )
2018-07-19 13:26:47 +03:00
] ;
2013-12-26 07:48:16 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
should . exist ( importResult . data . tags ) ;
should . exist ( importResult . originalData . posts _tags ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
importResult . data . tags . length . should . equal ( 1 ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
// Check we imported all posts_tags associations
importResult . originalData . posts _tags . length . should . equal ( 2 ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
// Check the post_tag.tag_id was updated when we removed duplicate tag
_ . every ( importResult . originalData . posts _tags , function ( postTag ) {
return postTag . tag _id !== 2 ;
} ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
importResult . problems . length . should . equal ( 1 ) ;
2013-12-26 07:48:16 +04:00
2018-07-19 13:26:47 +03:00
importResult . problems [ 0 ] . message . should . eql ( 'Entry was not imported and ignored. Detected duplicated entry.' ) ;
importResult . problems [ 0 ] . help . should . eql ( 'Tag' ) ;
2018-04-25 18:13:35 +03:00
} ) ;
2013-11-24 18:29:36 +04:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'removes broken tags from post (not in db, not in file)' , function ( ) {
let exportData = exportedLatestBody ( ) . db [ 0 ] ;
2013-12-29 00:13:47 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'welcome-to-ghost-2'
} ) ;
2013-11-21 00:36:02 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts _tags = [
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , '100' ) ,
2019-07-05 14:40:43 +03:00
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , '200' )
2018-07-19 13:26:47 +03:00
] ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . Post . findPage ( { withRelated : [ 'tags' ] } )
] ) ;
} )
. then ( function ( data ) {
2018-09-26 15:11:22 +03:00
data [ 0 ] . data . length . should . eql ( 1 ) ;
data [ 0 ] . data [ 0 ] . toJSON ( ) . slug . should . eql ( 'welcome-to-ghost-2' ) ;
data [ 0 ] . data [ 0 ] . toJSON ( ) . tags . length . should . eql ( 0 ) ;
2013-11-21 00:36:02 +04:00
} ) ;
} ) ;
2014-01-15 17:29:23 +04:00
2018-07-19 13:26:47 +03:00
it ( 'imports post status' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-01-15 17:29:23 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( { status : 'scheduled' , slug : 'post1' } ) ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( { status : 'published' , slug : 'post2' } ) ;
2014-01-15 17:29:23 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return models . Post . findPage ( testUtils . context . internal ) ;
} )
. then ( function ( result ) {
2018-09-26 15:11:22 +03:00
result . data . length . should . equal ( exportData . data . posts . length , 'Wrong number of posts' ) ;
result . data [ 0 ] . toJSON ( ) . status . should . eql ( 'scheduled' ) ;
result . data [ 1 ] . toJSON ( ) . status . should . eql ( 'published' ) ;
2018-07-19 13:26:47 +03:00
} ) ;
} ) ;
2014-01-15 17:29:23 +04:00
2018-07-19 13:26:47 +03:00
// @TODO: ensure permissions, roles etc are not imported (!)
it ( 'ensure complex JSON get\'s fully imported' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
// Grab the data from tables
return Promise . all ( [
knex ( 'users' ) . select ( ) ,
models . Post . findPage ( testUtils . context . internal ) ,
knex ( 'settings' ) . select ( ) ,
2019-10-09 18:26:14 +03:00
knex ( 'tags' ) . select ( )
2018-07-19 13:26:47 +03:00
] ) ;
} )
. then ( function ( importedData ) {
should . exist ( importedData ) ;
2014-01-15 17:29:23 +04:00
2019-10-09 18:26:14 +03:00
importedData . length . should . equal ( 4 , 'Did not get data successfully' ) ;
2018-04-25 18:13:35 +03:00
2020-04-29 18:44:27 +03:00
const users = importedData [ 0 ] ;
const posts = importedData [ 1 ] . data ;
const settings = importedData [ 2 ] ;
const tags = importedData [ 3 ] ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
// we always have 1 user, the owner user we added
users . length . should . equal ( 1 , 'There should only be one user' ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
settings . length . should . be . above ( 0 , 'Wrong number of settings' ) ;
posts . length . should . equal ( exportData . data . posts . length , 'no new posts' ) ;
2018-04-25 18:13:35 +03:00
tags . length . should . equal ( exportData . data . tags . length , 'no new tags' ) ;
} ) ;
2014-01-15 17:29:23 +04:00
} ) ;
2014-02-25 00:28:18 +04:00
2018-07-19 13:26:47 +03:00
it ( 'import owner, ensure original owner stays as is' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-07-31 23:53:55 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( ) ;
exportData . data . roles _users [ 0 ] = [
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 0 ] . id , testUtils . DataGenerator . Content . roles [ 3 ] . id )
] ;
✨Dynamic Routing Beta (#9596)
refs #9601
### Dynamic Routing
This is the beta version of dynamic routing.
- we had a initial implementation of "channels" available in the codebase
- we have removed and moved this implementation
- there is now a centralised place for dynamic routing - server/services/routing
- each routing component is represented by a router type e.g. collections, routes, static pages, taxonomies, rss, preview of posts
- keep as much as possible logic of routing helpers, middlewares and controllers
- ensure test coverage
- connect all the things together
- yaml file + validation
- routing + routers
- url service
- sitemaps
- url access
- deeper implementation of yaml validations
- e.g. hard require slashes
- ensure routing hierarchy/order
- e.g. you enable the subscriber app
- you have a custom static page, which lives under the same slug /subscribe
- static pages are stronger than apps
- e.g. the first collection owns the post it has filtered
- a post cannot live in two collections
- ensure apps are still working and hook into the routers layer (or better said: and register in the routing service)
- put as much as possible comments to the code base for better understanding
- ensure a clean debug log
- ensure we can unmount routes
- e.g. you have a collection permalink of /:slug/ represented by {globals.permalink}
- and you change the permalink in the admin to dated permalink
- the express route get's refreshed from /:slug/ to /:year/:month/:day/:slug/
- unmount without server restart, yey
- ensure we are backwards compatible
- e.g. render home.hbs for collection index if collection route is /
- ensure you can access your configured permalink from the settings table with {globals.permalink}
### Render 503 if url service did not finish
- return 503 if the url service has not finished generating the resource urls
### Rewrite sitemaps
- we have rewritten the sitemaps "service", because the url generator does no longer happen on runtime
- we generate all urls on bootstrap
- the sitemaps service will consume created resource and router urls
- these urls will be shown on the xml pages
- we listen on url events
- we listen on router events
- we no longer have to fetch the resources, which is nice
- the urlservice pre-fetches resources and emits their urls
- the urlservice is the only component who knows which urls are valid
- i made some ES6 adaptions
- we keep the caching logic -> only regenerate xml if there is a change
- updated tests
- checked test coverage (100%)
### Re-work usage of Url utility
- replace all usages of `urlService.utils.urlFor` by `urlService.getByResourceId`
- only for resources e.g. post, author, tag
- this is important, because with dynamic routing we no longer create static urls based on the settings permalink on runtime
- adapt url utility
- adapt tests
2018-06-05 20:02:20 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return models . User . findAll ( Object . assign ( { withRelated : [ 'roles' ] } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . models . length . should . eql ( 2 ) ;
2014-07-31 23:53:55 +04:00
2018-07-19 13:26:47 +03:00
result . models [ 0 ] . get ( 'email' ) . should . equal ( testUtils . DataGenerator . Content . users [ 0 ] . email ) ;
result . models [ 0 ] . get ( 'slug' ) . should . equal ( testUtils . DataGenerator . Content . users [ 0 ] . slug ) ;
result . models [ 0 ] . get ( 'name' ) . should . equal ( testUtils . DataGenerator . Content . users [ 0 ] . name ) ;
2014-07-31 23:53:55 +04:00
2018-07-19 13:26:47 +03:00
result . models [ 1 ] . get ( 'email' ) . should . equal ( exportData . data . users [ 0 ] . email ) ;
result . models [ 1 ] . get ( 'slug' ) . should . equal ( exportData . data . users [ 0 ] . slug ) ;
result . models [ 1 ] . get ( 'name' ) . should . equal ( exportData . data . users [ 0 ] . name ) ;
2014-07-31 23:53:55 +04:00
2018-07-19 13:26:47 +03:00
return models . User . isPasswordCorrect ( {
hashedPassword : result . models [ 0 ] . get ( 'password' ) ,
plainPassword : testUtils . DataGenerator . Content . users [ 0 ] . password
} ) ;
2018-04-25 18:13:35 +03:00
} ) ;
2014-07-31 23:53:55 +04:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'imports comment_id correctly' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2018-01-28 20:58:37 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( ) ;
2018-01-28 20:58:37 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importResult ) {
importResult . problems . length . should . eql ( 0 ) ;
importResult . data . posts [ 0 ] . comment _id . should . eql ( exportData . data . posts [ 0 ] . id . toString ( ) ) ;
} ) ;
2014-07-29 01:41:45 +04:00
} ) ;
2014-02-25 00:28:18 +04:00
2018-07-19 13:26:47 +03:00
it ( 'handles validation errors nicely' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-07-28 02:22:00 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post1' } ) ;
exportData . data . posts [ 0 ] . title = null ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post2' } ) ;
exportData . data . posts [ 1 ] . title = new Array ( 600 ) . join ( 'a' ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( { slug : 'tag1' } ) ;
exportData . data . tags [ 0 ] . name = null ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 1 ] = testUtils . DataGenerator . forKnex . createTag ( { slug : 'tag2' } ) ;
exportData . data . tags [ 1 ] . meta _title = new Array ( 305 ) . join ( 'a' ) ;
2018-01-28 15:13:11 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( ) ;
exportData . data . users [ 0 ] . bio = new Array ( 300 ) . join ( 'a' ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 1 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : 'thisisareallylongemailaddressIamhappytobeusingacharactercounterbutIhavealongwaytogoyetImeanserioulsywhohasemailaddressthislongthereisnowaythiswillpassvalidationsonghost100andisarealedgecase'
} ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( ) ;
exportData . data . settings [ 0 ] . key = null ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
( 1 ) . should . eql ( 0 , 'Allowed import of duplicate data.' ) ;
} )
. catch ( function ( response ) {
response . length . should . equal ( 7 ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
// NOTE: a duplicated tag.slug is a warning
response [ 0 ] . errorType . should . equal ( 'ValidationError' ) ;
response [ 0 ] . message . should . eql ( 'Value in [users.bio] exceeds maximum length of 200 characters.' ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
response [ 1 ] . errorType . should . equal ( 'ValidationError' ) ;
response [ 1 ] . message . should . eql ( 'Validation (isEmail) failed for email' ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
response [ 2 ] . errorType . should . equal ( 'ValidationError' ) ;
response [ 2 ] . message . should . eql ( 'Value in [tags.name] cannot be blank.' ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
response [ 3 ] . errorType . should . equal ( 'ValidationError' ) ;
response [ 3 ] . message . should . eql ( 'Value in [tags.meta_title] exceeds maximum length of 300 characters.' ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
response [ 4 ] . message . should . eql ( 'Value in [posts.title] cannot be blank.' ) ;
response [ 4 ] . errorType . should . eql ( 'ValidationError' ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
response [ 5 ] . errorType . should . equal ( 'ValidationError' ) ;
response [ 5 ] . message . should . eql ( 'Value in [posts.title] exceeds maximum length of 255 characters.' ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
response [ 6 ] . errorType . should . equal ( 'ValidationError' ) ;
response [ 6 ] . message . should . eql ( 'Value in [settings.key] cannot be blank.' ) ;
} ) ;
2014-07-28 02:22:00 +04:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'does import data with invalid user references' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( { author _id : 2 , published _by : 2 } ) ;
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( ) ;
exportData . data . users [ 0 ] . updated _by = null ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] . created _by = exportData . data . users [ 0 ] . id ;
2014-08-22 23:04:52 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( importedData ) {
importedData . problems . length . should . eql ( 2 ) ;
importedData . problems [ 0 ] . message . should . eql ( 'Entry was imported, but we were not able to resolve the ' +
'following user references: updated_by. The user does not exist, fallback to owner user.' ) ;
importedData . problems [ 0 ] . help . should . eql ( 'User' ) ;
importedData . problems [ 1 ] . message . should . eql ( 'Entry was imported, but we were not able to ' +
'resolve the following user references: author_id, published_by. The user does not exist, fallback to owner user.' ) ;
importedData . problems [ 1 ] . help . should . eql ( 'Post' ) ;
// Grab the data from tables
return Promise . all ( [
models . User . findPage ( testUtils . context . internal ) ,
models . Post . findPage ( testUtils . context . internal )
] ) ;
} )
. then ( function ( importedData ) {
should . exist ( importedData ) ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
importedData . length . should . equal ( 2 , 'Did not get data successfully' ) ;
2017-05-23 21:12:08 +03:00
2019-07-05 14:40:43 +03:00
const users = importedData [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
const posts = importedData [ 1 ] . data . map ( model => model . toJSON ( ) ) ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . equal ( 1 , 'Wrong number of posts' ) ;
users . length . should . equal ( 2 , 'Wrong number of users' ) ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
// NOTE: we fallback to owner user for invalid user references
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
users [ 1 ] . slug . should . eql ( exportData . data . users [ 0 ] . slug ) ;
users [ 1 ] . updated _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
posts [ 0 ] . slug . should . eql ( exportData . data . posts [ 0 ] . slug ) ;
posts [ 0 ] . author . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
posts [ 0 ] . published _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
posts [ 0 ] . created _by . should . eql ( users [ 1 ] . id ) ;
} ) ;
} ) ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
it ( 'invalid uuid' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( { uuid : '528258181e668' , slug : 'post1' } ) ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( { uuid : '' , slug : 'post2' } ) ;
exportData . data . posts [ 2 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post3' } ) ;
delete exportData . data . posts [ 2 ] . uuid ;
exportData . data . posts [ 3 ] = testUtils . DataGenerator . forKnex . createPost ( { uuid : 'hey-i\'m-not-a-uuid-at-all' , slug : 'post4' } ) ;
2017-05-23 21:12:08 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return models . Post . findPage ( testUtils . context . internal ) ;
} ) . then ( function ( result ) {
2018-09-26 15:11:22 +03:00
assert . equal ( validator . isUUID ( result . data [ 0 ] . toJSON ( ) . uuid ) , true , 'Old Ghost UUID NOT fixed' ) ;
assert . equal ( validator . isUUID ( result . data [ 1 ] . toJSON ( ) . uuid ) , true , 'Empty UUID NOT fixed' ) ;
assert . equal ( validator . isUUID ( result . data [ 2 ] . toJSON ( ) . uuid ) , true , 'Missing UUID NOT fixed' ) ;
assert . equal ( validator . isUUID ( result . data [ 3 ] . toJSON ( ) . uuid ) , true , 'Malformed UUID NOT fixed' ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2017-05-23 21:12:08 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'ensure post tag order is correct' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post1' , published _at : moment ( ) . add ( 3 , 'day' ) . toDate ( ) } ) ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post2' , published _at : moment ( ) . add ( 1 , 'day' ) . toDate ( ) } ) ;
exportData . data . posts [ 2 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post3' , published _at : moment ( ) . add ( 2 , 'day' ) . toDate ( ) } ) ;
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( { slug : 'two' } ) ;
exportData . data . tags [ 1 ] = testUtils . DataGenerator . forKnex . createTag ( { slug : 'one' } ) ;
exportData . data . tags [ 2 ] = testUtils . DataGenerator . forKnex . createTag ( { slug : 'three' } ) ;
exportData . data . posts _tags = [
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 0 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 1 ] . id , exportData . data . tags [ 1 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 1 ] . id , exportData . data . tags [ 0 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 2 ] . id , exportData . data . tags [ 2 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 2 ] . id , exportData . data . tags [ 0 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 2 ] . id , exportData . data . tags [ 1 ] . id )
] ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . Post . findPage ( Object . assign ( { withRelated : [ 'tags' ] } , testUtils . context . internal ) ) ,
2019-07-05 14:40:43 +03:00
models . Tag . findPage ( Object . assign ( { order : 'slug ASC' } , testUtils . context . internal ) )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
const tags = result [ 1 ] . data . map ( model => model . toJSON ( ) ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . equal ( exportData . data . posts . length , 'Wrong number of posts' ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
// post1
posts [ 0 ] . slug . should . eql ( exportData . data . posts [ 0 ] . slug ) ;
posts [ 0 ] . tags . length . should . eql ( 1 ) ;
posts [ 0 ] . tags [ 0 ] . slug . should . eql ( exportData . data . tags [ 0 ] . slug ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
// post3, has a specific sort_order
posts [ 1 ] . slug . should . eql ( exportData . data . posts [ 2 ] . slug ) ;
posts [ 1 ] . tags . length . should . eql ( 3 ) ;
posts [ 1 ] . tags [ 0 ] . slug . should . eql ( exportData . data . tags [ 2 ] . slug ) ;
posts [ 1 ] . tags [ 1 ] . slug . should . eql ( exportData . data . tags [ 0 ] . slug ) ;
posts [ 1 ] . tags [ 2 ] . slug . should . eql ( exportData . data . tags [ 1 ] . slug ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
// post2, sort_order property is missing (order depends on the posts_tags entries)
posts [ 2 ] . slug . should . eql ( exportData . data . posts [ 1 ] . slug ) ;
posts [ 2 ] . tags . length . should . eql ( 2 ) ;
posts [ 2 ] . tags [ 0 ] . slug . should . eql ( exportData . data . tags [ 1 ] . slug ) ;
posts [ 2 ] . tags [ 1 ] . slug . should . eql ( exportData . data . tags [ 0 ] . slug ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
// test tags
tags . length . should . equal ( exportData . data . tags . length , 'no new tags' ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
} ) ;
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'import multiple users, tags, posts' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user1@ghost.org' , slug : 'user1' } ) ;
exportData . data . users [ 1 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user2@ghost.org' , slug : 'user2' , created _by : exportData . data . users [ 0 ] . id } ) ;
exportData . data . users [ 2 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user3@ghost.org' , slug : 'user3' } ) ;
exportData . data . users [ 3 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user4@ghost.org' , slug : 'user4' , updated _by : exportData . data . users [ 1 ] . id } ) ;
exportData . data . roles = [
testUtils . DataGenerator . forKnex . createRole ( { name : 'Administrator' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Editor' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Author' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Owner' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Contributor' } )
] ;
exportData . data . roles _users = [
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 0 ] . id , exportData . data . roles [ 0 ] . id ) ,
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 2 ] . id , exportData . data . roles [ 2 ] . id ) ,
2019-07-05 14:40:43 +03:00
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 3 ] . id , exportData . data . roles [ 4 ] . id )
2018-07-19 13:26:47 +03:00
] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
title : 'title1' ,
author _id : exportData . data . users [ 0 ] . id ,
created _by : exportData . data . users [ 0 ] . id ,
updated _by : exportData . data . users [ 1 ] . id ,
2019-07-05 14:40:43 +03:00
published _by : exportData . data . users [ 1 ] . id
2018-07-19 13:26:47 +03:00
} ) ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2' ,
title : 'title2' ,
author _id : exportData . data . users [ 3 ] . id ,
created _by : exportData . data . users [ 2 ] . id ,
updated _by : exportData . data . users [ 0 ] . id ,
2019-07-05 14:40:43 +03:00
published _by : exportData . data . users [ 1 ] . id
2018-07-19 13:26:47 +03:00
} ) ;
exportData . data . posts [ 2 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post3' ,
title : 'title3' ,
author _id : exportData . data . users [ 0 ] . id ,
created _by : exportData . data . users [ 3 ] . id ,
updated _by : exportData . data . users [ 3 ] . id ,
2019-07-05 14:40:43 +03:00
published _by : exportData . data . users [ 3 ] . id
2018-07-19 13:26:47 +03:00
} ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'tag1' ,
created _by : exportData . data . users [ 3 ] . id ,
updated _by : exportData . data . users [ 0 ] . id
} ) ;
exportData . data . tags [ 1 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'tag2' ,
created _by : exportData . data . users [ 1 ] . id ,
updated _by : exportData . data . users [ 3 ] . id
} ) ;
exportData . data . tags [ 2 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'tag3' ,
created _by : exportData . data . users [ 2 ] . id ,
updated _by : exportData . data . users [ 2 ] . id
} ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-09-26 15:11:22 +03:00
const postOptions = Object . assign ( { withRelated : [ 'tags' ] } , testUtils . context . internal ) ;
const tagOptions = Object . assign ( { order : 'slug ASC' } , testUtils . context . internal ) ;
const userOptions = Object . assign ( { withRelated : [ 'roles' ] } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( postOptions ) ,
models . Tag . findPage ( tagOptions ) ,
models . User . findPage ( userOptions )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( postOptions ) ) ;
const tags = result [ 1 ] . data . map ( model => model . toJSON ( tagOptions ) ) ;
const users = result [ 2 ] . data . map ( model => model . toJSON ( userOptions ) ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . equal ( exportData . data . posts . length , 'Wrong number of posts' ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
2018-07-19 13:26:47 +03:00
// findPage returns the posts in correct order (latest created post is the first)
posts [ 0 ] . title . should . equal ( exportData . data . posts [ 2 ] . title ) ;
posts [ 1 ] . title . should . equal ( exportData . data . posts [ 1 ] . title ) ;
posts [ 2 ] . title . should . equal ( exportData . data . posts [ 0 ] . title ) ;
posts [ 0 ] . slug . should . equal ( exportData . data . posts [ 2 ] . slug ) ;
posts [ 1 ] . slug . should . equal ( exportData . data . posts [ 1 ] . slug ) ;
posts [ 2 ] . slug . should . equal ( exportData . data . posts [ 0 ] . slug ) ;
posts [ 0 ] . author . should . equal ( users [ 1 ] . id ) ;
posts [ 1 ] . author . should . equal ( users [ 4 ] . id ) ;
posts [ 2 ] . author . should . equal ( users [ 1 ] . id ) ;
posts [ 0 ] . created _by . should . equal ( users [ 4 ] . id ) ;
posts [ 1 ] . created _by . should . equal ( users [ 3 ] . id ) ;
posts [ 2 ] . created _by . should . equal ( users [ 1 ] . id ) ;
posts [ 0 ] . updated _by . should . equal ( users [ 4 ] . id ) ;
posts [ 1 ] . updated _by . should . equal ( users [ 1 ] . id ) ;
posts [ 2 ] . updated _by . should . equal ( users [ 2 ] . id ) ;
posts [ 0 ] . published _by . should . equal ( users [ 4 ] . id ) ;
posts [ 1 ] . published _by . should . equal ( users [ 2 ] . id ) ;
posts [ 2 ] . published _by . should . equal ( users [ 2 ] . id ) ;
tags . length . should . equal ( exportData . data . tags . length , 'Wrong number of tags' ) ;
tags [ 0 ] . created _by . should . equal ( users [ 4 ] . id ) ;
tags [ 1 ] . created _by . should . equal ( users [ 2 ] . id ) ;
tags [ 2 ] . created _by . should . equal ( users [ 3 ] . id ) ;
tags [ 0 ] . updated _by . should . equal ( users [ 1 ] . id ) ;
tags [ 1 ] . updated _by . should . equal ( users [ 4 ] . id ) ;
tags [ 2 ] . updated _by . should . equal ( users [ 3 ] . id ) ;
// 4 imported users + 1 owner user
users . length . should . equal ( exportData . data . users . length + 1 , 'Wrong number of users' ) ;
users [ 0 ] . email . should . equal ( testUtils . DataGenerator . Content . users [ 0 ] . email ) ;
users [ 1 ] . email . should . equal ( exportData . data . users [ 0 ] . email ) ;
users [ 2 ] . email . should . equal ( exportData . data . users [ 1 ] . email ) ;
users [ 3 ] . email . should . equal ( exportData . data . users [ 2 ] . email ) ;
users [ 4 ] . email . should . equal ( exportData . data . users [ 3 ] . email ) ;
users [ 0 ] . status . should . equal ( 'active' ) ;
users [ 1 ] . status . should . equal ( 'locked' ) ;
users [ 2 ] . status . should . equal ( 'locked' ) ;
users [ 3 ] . status . should . equal ( 'locked' ) ;
users [ 4 ] . status . should . equal ( 'locked' ) ;
users [ 1 ] . created _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 0 ] . created _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 2 ] . created _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 1 ] . created _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 3 ] . created _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 2 ] . created _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 4 ] . created _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 3 ] . created _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 1 ] . updated _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 0 ] . updated _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 2 ] . updated _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 1 ] . updated _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 3 ] . updated _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 2 ] . updated _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 4 ] . updated _at . toISOString ( ) . should . equal ( moment ( exportData . data . users [ 3 ] . updated _at ) . startOf ( 'seconds' ) . toISOString ( ) ) ;
users [ 1 ] . created _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
users [ 1 ] . updated _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
users [ 2 ] . created _by . should . eql ( users [ 1 ] . id ) ;
users [ 2 ] . updated _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
users [ 3 ] . created _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
users [ 3 ] . updated _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
users [ 4 ] . created _by . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
users [ 4 ] . updated _by . should . eql ( users [ 2 ] . id ) ;
users [ 0 ] . roles [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . roles [ 3 ] . id ) ;
users [ 1 ] . roles [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . roles [ 0 ] . id ) ;
users [ 2 ] . roles [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . roles [ 2 ] . id ) ;
users [ 3 ] . roles [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . roles [ 2 ] . id ) ;
users [ 4 ] . roles [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . roles [ 4 ] . id ) ;
Added more database soft limits (#9225)
refs #8143
Sets soft limits for certain db fields:
- `posts`:
- `title`: 255 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `users`:
- `bio`: 200 chars (current hard limit: 65,535 chars)
- `location`: 150 chars (current hard limit: 65,535 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `tags`:
- `description`: 500 chars (current hard limit: 65,535 chars)
- `meta_title`: 300 chars (current hard limit: 2,000 chars)
- `meta_description`: 500 chars (current hard limit: 2,000 chars)
- same error message for isLength validator as for hard limits (more improvements are comming with https://github.com/TryGhost/Ghost/issues/6050)
- added more tests for importer
- added dynamic translation key handling for validators errors (isLength is only supported atm)
2017-11-09 17:22:20 +03:00
} ) ;
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'can handle if user has multiple roles attached' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
🚨 database: change hard limits and field types (#7932)
refs #7432
🚨 database: change hard limits and field types
- we went over all schema fields and decided to decrease/increase the hard limits
- the core goal is to have more flexibility in the future
- we reconsidered string vs. text
There are 5 groups:
- small strings: 50 characters
- static strings
- status, visibility, language, role name, permission name, client name etc.
- medium strings: 191 characters
- all unique fields or fields which can be unique in the future
- slug, tokens, user name, password, tag name, email
- large strings: 1000-2000 characters
- these fields need to be very flexible
- these fields get a soft limit attached (in a different PR)
- post title, meta title, meta description, urls
- medium text: 64kb characters
- bio, settings, location, tour
- long text: 1000000000 chars
- html, amp, mobiledoc, markdown
🙄 sort_order for tests
- sort order was not set for the tests, so it was always 0
- mysql could return a different result
in my case:
- field length 156 returned the following related tags ["bacon", "kitchen"]
- field length 157 returned the following related tags ["kitchen", "kitchen"]
Change client.secret to 191
Tweak field lengths
- Add 24 char limit for ids
- Limited fields are the exact length they need
- Unified 1000 and 2000 char string classes to all be 2000
- Changed descriptions to be either 2000, except user & tag which is text 65535 as these may be used to store HTML later?!
- Updated tests
🛠 Update importer tests
- The old 001-003 tests are kind of less relevant now.
- Rather than worrying about past versions of the data structure, we should check that the importer only imports what we consider to be valid data
- I've changed the tests to treat the title-length check as a length-validation check, rather than a test for each of the old versions
🔥 Remove foreign key from subscribers.post_id
- There's no real need to have an index on this column, it just makes deleting posts hard.
- Same as created_by type columns, we can reference ids without needing keys/indexes
2017-02-18 01:20:59 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : 'user1@ghost.org' ,
slug : 'user1'
} ) ;
🚨 database: change hard limits and field types (#7932)
refs #7432
🚨 database: change hard limits and field types
- we went over all schema fields and decided to decrease/increase the hard limits
- the core goal is to have more flexibility in the future
- we reconsidered string vs. text
There are 5 groups:
- small strings: 50 characters
- static strings
- status, visibility, language, role name, permission name, client name etc.
- medium strings: 191 characters
- all unique fields or fields which can be unique in the future
- slug, tokens, user name, password, tag name, email
- large strings: 1000-2000 characters
- these fields need to be very flexible
- these fields get a soft limit attached (in a different PR)
- post title, meta title, meta description, urls
- medium text: 64kb characters
- bio, settings, location, tour
- long text: 1000000000 chars
- html, amp, mobiledoc, markdown
🙄 sort_order for tests
- sort order was not set for the tests, so it was always 0
- mysql could return a different result
in my case:
- field length 156 returned the following related tags ["bacon", "kitchen"]
- field length 157 returned the following related tags ["kitchen", "kitchen"]
Change client.secret to 191
Tweak field lengths
- Add 24 char limit for ids
- Limited fields are the exact length they need
- Unified 1000 and 2000 char string classes to all be 2000
- Changed descriptions to be either 2000, except user & tag which is text 65535 as these may be used to store HTML later?!
- Updated tests
🛠 Update importer tests
- The old 001-003 tests are kind of less relevant now.
- Rather than worrying about past versions of the data structure, we should check that the importer only imports what we consider to be valid data
- I've changed the tests to treat the title-length check as a length-validation check, rather than a test for each of the old versions
🔥 Remove foreign key from subscribers.post_id
- There's no real need to have an index on this column, it just makes deleting posts hard.
- Same as created_by type columns, we can reference ids without needing keys/indexes
2017-02-18 01:20:59 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . roles = [
testUtils . DataGenerator . forKnex . createRole ( { name : 'Administrator' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Editor' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Author' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Owner' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Contributor' } )
] ;
exportData . data . roles _users = [
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 0 ] . id , exportData . data . roles [ 0 ] . id ) ,
2019-07-05 14:40:43 +03:00
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 0 ] . id , exportData . data . roles [ 4 ] . id )
2018-07-19 13:26:47 +03:00
] ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . User . findPage ( Object . assign ( { withRelated : [ 'roles' ] } , testUtils . context . internal ) )
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const users = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
2018-07-19 13:26:47 +03:00
users . length . should . eql ( 2 ) ;
users [ 1 ] . slug . should . eql ( exportData . data . users [ 0 ] . slug ) ;
users [ 1 ] . slug . should . eql ( exportData . data . users [ 0 ] . slug ) ;
users [ 1 ] . roles . length . should . eql ( 1 ) ;
users [ 1 ] . roles [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . roles [ 4 ] . id ) ;
🚨 database: change hard limits and field types (#7932)
refs #7432
🚨 database: change hard limits and field types
- we went over all schema fields and decided to decrease/increase the hard limits
- the core goal is to have more flexibility in the future
- we reconsidered string vs. text
There are 5 groups:
- small strings: 50 characters
- static strings
- status, visibility, language, role name, permission name, client name etc.
- medium strings: 191 characters
- all unique fields or fields which can be unique in the future
- slug, tokens, user name, password, tag name, email
- large strings: 1000-2000 characters
- these fields need to be very flexible
- these fields get a soft limit attached (in a different PR)
- post title, meta title, meta description, urls
- medium text: 64kb characters
- bio, settings, location, tour
- long text: 1000000000 chars
- html, amp, mobiledoc, markdown
🙄 sort_order for tests
- sort order was not set for the tests, so it was always 0
- mysql could return a different result
in my case:
- field length 156 returned the following related tags ["bacon", "kitchen"]
- field length 157 returned the following related tags ["kitchen", "kitchen"]
Change client.secret to 191
Tweak field lengths
- Add 24 char limit for ids
- Limited fields are the exact length they need
- Unified 1000 and 2000 char string classes to all be 2000
- Changed descriptions to be either 2000, except user & tag which is text 65535 as these may be used to store HTML later?!
- Updated tests
🛠 Update importer tests
- The old 001-003 tests are kind of less relevant now.
- Rather than worrying about past versions of the data structure, we should check that the importer only imports what we consider to be valid data
- I've changed the tests to treat the title-length check as a length-validation check, rather than a test for each of the old versions
🔥 Remove foreign key from subscribers.post_id
- There's no real need to have an index on this column, it just makes deleting posts hard.
- Same as created_by type columns, we can reference ids without needing keys/indexes
2017-02-18 01:20:59 +03:00
} ) ;
} ) ;
2014-08-09 23:16:54 +04:00
2019-07-16 13:01:44 +03:00
it ( 'can handle related tags with missing optional fields' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( ) ;
// NOTE: not including slug, description etc. fields as the only required field
// to handle the import of tags is 'name'
exportData . data . tags [ 0 ] = {
id : ObjectId . generate ( ) ,
name : 'first tag'
} ;
exportData . data . tags [ 1 ] = {
id : ObjectId . generate ( ) ,
name : 'second tag'
} ;
exportData . data . tags [ 2 ] = {
id : ObjectId . generate ( ) ,
name : 'third tag'
} ;
exportData . data . posts _tags = [
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 0 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 1 ] . id ) ,
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 2 ] . id )
] ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
imported . problems . length . should . eql ( 0 ) ;
return Promise . all ( [
models . Tag . findPage ( Object . assign ( { order : 'slug ASC' } , testUtils . context . internal ) ) ,
models . Post . findPage ( Object . assign ( { withRelated : [ 'tags' ] } , testUtils . context . internal ) )
] ) ;
} ) . then ( function ( result ) {
const tags = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
const posts = result [ 1 ] . data . map ( model => model . toJSON ( ) ) ;
posts . length . should . eql ( 1 ) ;
tags . length . should . eql ( 3 ) ;
posts [ 0 ] . tags . length . should . eql ( 3 ) ;
tags [ 0 ] . name . should . eql ( 'first tag' ) ;
tags [ 0 ] . slug . should . eql ( 'first-tag' ) ;
tags [ 1 ] . name . should . eql ( 'second tag' ) ;
tags [ 2 ] . name . should . eql ( 'third tag' ) ;
} ) ;
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'can handle uppercase tags' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( ) ;
2017-05-23 19:18:13 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'TAG-1'
} ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts _tags = [
testUtils . DataGenerator . forKnex . createPostsTags ( exportData . data . posts [ 0 ] . id , exportData . data . tags [ 0 ] . id )
] ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
imported . problems . length . should . eql ( 0 ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
return Promise . all ( [
2018-08-10 13:33:53 +03:00
models . Tag . findPage ( Object . assign ( { order : 'slug ASC' } , testUtils . context . internal ) ) ,
2018-07-19 13:26:47 +03:00
models . Post . findPage ( Object . assign ( { withRelated : [ 'tags' ] } , testUtils . context . internal ) )
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const tags = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
const posts = result [ 1 ] . data . map ( model => model . toJSON ( ) ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 1 ) ;
tags . length . should . eql ( 1 ) ;
2018-04-25 18:13:35 +03:00
2018-07-19 13:26:47 +03:00
posts [ 0 ] . tags . length . should . eql ( 1 ) ;
tags [ 0 ] . slug . should . eql ( 'tag-1' ) ;
2018-04-25 18:13:35 +03:00
} ) ;
2014-12-11 18:50:10 +03:00
} ) ;
2014-08-09 23:16:54 +04:00
2021-02-15 10:17:57 +03:00
it ( 'does not import settings: labs' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'labs' ,
value : JSON . stringify ( { members : true } )
} ) ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
imported . problems . length . should . eql ( 0 ) ;
return models . Settings . findOne ( _ . merge ( { key : 'labs' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
should . equal ( result , null ) ;
} ) ;
} ) ;
2020-07-14 11:10:59 +03:00
it ( 'does not import settings: slack_url' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'slack_url' ,
value : 'https://ignoreme.tld'
} ) ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
imported . problems . length . should . eql ( 0 ) ;
return models . Settings . findOne ( _ . merge ( { key : 'slack_url' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . attributes . value . should . eql ( '' ) ;
} ) ;
} ) ;
it ( 'does not import settings: slack_url from slack object' , function ( ) {
2018-07-19 13:26:47 +03:00
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2017-07-20 13:11:56 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'slack' ,
2020-07-14 11:10:59 +03:00
value : '[{"url":"https://hook.slack.com"}]'
2018-07-19 13:26:47 +03:00
} ) ;
2017-07-20 13:11:56 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
2020-06-23 02:58:19 +03:00
imported . problems . length . should . eql ( 0 ) ;
2020-07-14 11:10:59 +03:00
return models . Settings . findOne ( _ . merge ( { key : 'slack_url' } , testUtils . context . internal ) ) ;
2018-08-06 18:18:59 +03:00
} )
. then ( function ( result ) {
2020-07-14 11:10:59 +03:00
result . attributes . value . should . eql ( '' ) ;
2014-12-11 18:50:10 +03:00
} ) ;
2014-08-09 23:16:54 +04:00
} ) ;
2014-09-10 08:06:24 +04:00
2020-06-23 03:45:05 +03:00
it ( 'imports settings fields deprecated in v2 and removed in v3: slack hook, permalinks' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'default_locale' ,
value : 'ua'
} ) ;
exportData . data . settings [ 1 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'active_timezone' ,
value : 'Pacific/Auckland'
} ) ;
exportData . data . settings [ 2 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'ghost_foot' ,
value : 'AVADA KEDAVRA'
} ) ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
imported . problems . length . should . eql ( 0 ) ;
return models . Settings . findOne ( _ . merge ( { key : 'lang' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . attributes . value . should . eql ( 'ua' ) ;
} )
. then ( function ( ) {
return models . Settings . findOne ( _ . merge ( { key : 'timezone' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . attributes . value . should . eql ( 'Pacific/Auckland' ) ;
} )
. then ( function ( ) {
return models . Settings . findOne ( _ . merge ( { key : 'codeinjection_foot' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . attributes . value . should . eql ( 'AVADA KEDAVRA' ) ;
} ) ;
} ) ;
2019-03-07 14:59:50 +03:00
it ( 'does import settings with string booleans' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . settings [ 0 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'amp' ,
value : 'true'
} ) ;
exportData . data . settings [ 1 ] = testUtils . DataGenerator . forKnex . createSetting ( {
key : 'is_private' ,
value : '0'
} ) ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
imported . problems . length . should . eql ( 0 ) ;
return models . Settings . findOne ( _ . merge ( { key : 'amp' } , testUtils . context . internal ) ) ;
} )
. then ( function ( result ) {
result . attributes . value . should . eql ( true ) ;
return models . Settings . findOne ( _ . merge ( { key : 'is_private' } , testUtils . context . internal ) ) ;
} )
. then ( ( result ) => {
result . attributes . value . should . eql ( false ) ;
return db
. knex ( 'settings' )
. where ( 'key' , 'amp' ) ;
} )
. then ( ( result ) => {
result [ 0 ] . value . should . eql ( 'true' ) ;
return db
. knex ( 'settings' )
. where ( 'key' , 'is_private' ) ;
} )
. then ( ( result ) => {
result [ 0 ] . value . should . eql ( 'false' ) ;
} ) ;
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'import comment_id' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-12-11 18:50:10 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
comment _id : ObjectId . generate ( )
} ) ;
2014-12-11 18:50:10 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( { slug : 'post2' } ) ;
2014-09-10 08:06:24 +04:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . Post . findPage ( testUtils . context . internal )
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
2014-09-10 08:06:24 +04:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 2 ) ;
posts [ 0 ] . comment _id . should . eql ( exportData . data . posts [ 1 ] . id ) ;
posts [ 1 ] . comment _id . should . eql ( exportData . data . posts [ 0 ] . comment _id ) ;
2014-12-11 18:50:10 +03:00
} ) ;
} ) ;
2014-09-10 08:06:24 +04:00
2018-07-19 13:26:47 +03:00
it ( 'ensure authors are imported correctly' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user1@ghost.org' , slug : 'user1' } ) ;
exportData . data . users [ 1 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user2@ghost.org' , slug : 'user2' } ) ;
exportData . data . users [ 2 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user3@ghost.org' , slug : 'user3' } ) ;
exportData . data . users [ 3 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user4@ghost.org' , slug : 'user4' } ) ;
exportData . data . users [ 4 ] = testUtils . DataGenerator . forKnex . createUser ( { email : 'user4@ghost.org' , slug : 'user4' } ) ;
exportData . data . users [ 5 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : testUtils . DataGenerator . Content . users [ 0 ] . email ,
slug : 'user5'
} ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
author _id : testUtils . DataGenerator . Content . users [ 0 ] . id
} ) ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2' ,
author _id : testUtils . DataGenerator . Content . users [ 0 ] . id
} ) ;
exportData . data . posts [ 2 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post3' ,
author _id : testUtils . DataGenerator . Content . users [ 0 ] . id
} ) ;
2014-12-11 18:50:10 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts _authors = [
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 0 ] . id , exportData . data . users [ 1 ] . id , 0 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 0 ] . id , exportData . data . users [ 1 ] . id , 0 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 0 ] . id , exportData . data . users [ 0 ] . id , 2 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 0 ] . id , exportData . data . users [ 2 ] . id , 4 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( 'unknown' , exportData . data . users [ 0 ] . id , 1 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 2 ] . id , exportData . data . users [ 3 ] . id , 0 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 2 ] . id , ObjectId . generate ( ) , 1 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 2 ] . id , exportData . data . users [ 4 ] . id , 2 ) ,
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 2 ] . id , exportData . data . users [ 4 ] . id , 2 ) ,
2019-07-05 14:40:43 +03:00
testUtils . DataGenerator . forKnex . createPostsAuthors ( exportData . data . posts [ 1 ] . id , exportData . data . users [ 5 ] . id )
2018-07-19 13:26:47 +03:00
] ;
delete exportData . data . posts _authors [ 9 ] . sort _order ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( imported ) {
// one user is a duplicate
imported . problems . length . should . eql ( 2 ) ;
imported . problems [ 0 ] . context . should . match ( /user4@ghost.org/ ) ;
imported . problems [ 1 ] . context . should . match ( /user5/ ) ;
return Promise . all ( [
models . Post . findPage ( Object . assign ( { withRelated : [ 'authors' ] } , testUtils . context . internal ) ) ,
models . User . findPage ( testUtils . context . internal )
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
const users = result [ 1 ] . data . map ( model => model . toJSON ( ) ) ;
2018-07-19 13:26:47 +03:00
// 2 duplicates, 1 owner, 4 imported users
users . length . should . eql ( exportData . data . users . length - 2 + 1 ) ;
posts . length . should . eql ( 3 ) ;
2014-12-11 18:50:10 +03:00
2018-07-19 13:26:47 +03:00
// has 4 posts_authors relations, but 3 of them are invalid
posts [ 0 ] . slug . should . eql ( exportData . data . posts [ 2 ] . slug ) ;
posts [ 0 ] . authors . length . should . eql ( 1 ) ;
posts [ 0 ] . authors [ 0 ] . id . should . eql ( users [ 4 ] . id ) ;
posts [ 0 ] . author . should . eql ( users [ 4 ] . id ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
// no valid authors reference, use owner author_id
posts [ 1 ] . slug . should . eql ( exportData . data . posts [ 1 ] . slug ) ;
posts [ 1 ] . authors . length . should . eql ( 1 ) ;
posts [ 1 ] . author . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
posts [ 1 ] . authors [ 0 ] . id . should . eql ( testUtils . DataGenerator . Content . users [ 0 ] . id ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
posts [ 2 ] . slug . should . eql ( exportData . data . posts [ 0 ] . slug ) ;
posts [ 2 ] . authors . length . should . eql ( 3 ) ;
posts [ 2 ] . author . should . eql ( users [ 2 ] . id ) ;
posts [ 2 ] . authors . length . should . eql ( 3 ) ;
posts [ 2 ] . authors [ 0 ] . id . should . eql ( users [ 2 ] . id ) ;
posts [ 2 ] . authors [ 1 ] . id . should . eql ( users [ 1 ] . id ) ;
posts [ 2 ] . authors [ 2 ] . id . should . eql ( users [ 3 ] . id ) ;
2014-12-11 18:50:10 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2018-10-26 12:30:39 +03:00
2021-02-15 19:42:01 +03:00
it ( 'import 1.0 Koenig post format' , function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
mobiledoc : JSON . stringify ( {
version : '0.3.1' ,
markups : [ ] ,
atoms : [ ] ,
cards : [
[ 'image' , {
src : 'source' ,
cardWidth : 'wide'
} ] ,
[ 'card-markdown' , {
markdown : '# Post Content'
} ]
] ,
sections : [ [ 10 , 0 ] , [ 10 , 1 ] ]
} )
} ) ;
delete exportData . data . posts [ 0 ] . html ;
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . Post . findPage ( options )
] ) ;
} ) . then ( function ( result ) {
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
posts . length . should . eql ( 1 ) ;
2021-02-16 15:08:40 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["image",{"src":"source","cardWidth":"wide"}],["markdown",{"markdown":"# Post Content"}]],"sections":[[10,0],[10,1]],"ghostVersion":"3.0"}' ) ;
2021-02-15 19:42:01 +03:00
posts [ 0 ] . html . should . eql ( '<figure class="kg-card kg-image-card kg-width-wide"><img src="source" class="kg-image" alt></figure><!--kg-card-begin: markdown--><h1 id="postcontent">Post Content</h1>\n<!--kg-card-end: markdown-->' ) ;
} ) ;
} ) ;
2019-08-19 14:41:09 +03:00
it ( 'import 2.0 Koenig post format' , function ( ) {
2018-10-26 12:30:39 +03:00
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
mobiledoc : JSON . stringify ( {
version : '0.3.1' ,
markups : [ ] ,
atoms : [ ] ,
cards : [
[ 'image' , {
src : 'source' ,
2019-07-05 14:40:43 +03:00
cardWidth : 'wide'
2018-10-26 12:30:39 +03:00
} ] ,
[ 'markdown' , {
markdown : '# Post Content'
} ]
] ,
sections : [ [ 10 , 0 ] , [ 10 , 1 ] ]
} )
} ) ;
delete exportData . data . posts [ 0 ] . html ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2' ,
mobiledoc : JSON . stringify ( {
version : '0.3.1' ,
markups : [ ] ,
atoms : [ ] ,
cards : [
[ 'markdown' , {
markdown : '## Post Content'
} ] ,
[ 'image' , {
src : 'source2' ,
cardWidth : 'not-wide'
} ]
] ,
sections : [ [ 10 , 0 ] , [ 10 , 1 ] ]
} ) ,
html : '<div class="kg-post"><h2 id="postcontent">Post Content</h2></div>\n'
} ) ;
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . Post . findPage ( options )
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2018-10-26 12:30:39 +03:00
posts . length . should . eql ( 2 ) ;
2021-02-16 15:08:40 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["markdown",{"markdown":"## Post Content"}],["image",{"src":"source2","cardWidth":"not-wide"}]],"sections":[[10,0],[10,1]],"ghostVersion":"3.0"}' ) ;
2020-06-15 11:41:11 +03:00
posts [ 0 ] . html . should . eql ( '<!--kg-card-begin: markdown--><h2 id="postcontent">Post Content</h2>\n<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-width-not-wide"><img src="source2" class="kg-image" alt></figure>' ) ;
2018-10-26 12:30:39 +03:00
2021-02-16 15:08:40 +03:00
posts [ 1 ] . mobiledoc . should . eql ( '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["image",{"src":"source","cardWidth":"wide"}],["markdown",{"markdown":"# Post Content"}]],"sections":[[10,0],[10,1]],"ghostVersion":"3.0"}' ) ;
2020-06-15 11:41:11 +03:00
posts [ 1 ] . html . should . eql ( '<figure class="kg-card kg-image-card kg-width-wide"><img src="source" class="kg-image" alt></figure><!--kg-card-begin: markdown--><h1 id="postcontent">Post Content</h1>\n<!--kg-card-end: markdown-->' ) ;
2018-10-26 12:30:39 +03:00
} ) ;
} ) ;
2020-07-20 15:59:23 +03:00
it ( 'Can import stripe plans with an "amount" of 0' , async function ( ) {
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
exportData . data . settings . push ( {
id : 'blahblah' ,
group : 'members' ,
type : 'array' ,
flags : null ,
created _at : '2020-04-20 16:20:00' ,
updated _at : '2020-04-20 16:20:00' ,
key : 'stripe_plans' ,
value : JSON . stringify ( [ {
name : 'Monthly' ,
interval : 'month' ,
currency : 'usd' ,
amount : 0
} , {
name : 'Yearly' ,
interval : 'year' ,
currency : 'usd' ,
amount : 0
} ] )
} ) ;
await dataImporter . doImport ( exportData , importOptions ) ;
} ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
describe ( 'Existing database' , function ( ) {
2020-02-24 23:51:09 +03:00
beforeEach ( testUtils . teardownDb ) ;
2019-09-12 16:54:39 +03:00
beforeEach ( testUtils . setup ( 'users:roles' , 'posts' , 'settings' ) ) ;
2014-08-09 23:16:54 +04:00
2019-09-12 16:54:39 +03:00
it ( 'import multiple users, tags, posts' , function ( ) {
2018-07-19 13:26:47 +03:00
const exportData = exportedLatestBody ( ) . db [ 0 ] ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . users [ 0 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : 'user1@ghost.org' ,
slug : 'user1'
} ) ;
exportData . data . users [ 1 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : 'user2@ghost.org' ,
slug : 'user2' ,
created _by : exportData . data . users [ 0 ] . id
} ) ;
exportData . data . users [ 2 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : 'user3@ghost.org' ,
slug : 'user3'
} ) ;
exportData . data . users [ 3 ] = testUtils . DataGenerator . forKnex . createUser ( {
email : 'user4@ghost.org' ,
slug : 'user4' ,
updated _by : exportData . data . users [ 1 ] . id
} ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . roles = [
testUtils . DataGenerator . forKnex . createRole ( { name : 'Administrator' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Editor' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Author' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Owner' } ) ,
testUtils . DataGenerator . forKnex . createRole ( { name : 'Contributor' } )
] ;
exportData . data . roles _users = [
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 0 ] . id , exportData . data . roles [ 0 ] . id ) ,
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 2 ] . id , exportData . data . roles [ 2 ] . id ) ,
2019-07-05 14:40:43 +03:00
testUtils . DataGenerator . forKnex . createUsersRoles ( exportData . data . users [ 3 ] . id , exportData . data . roles [ 4 ] . id )
2018-07-19 13:26:47 +03:00
] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
title : 'title1' ,
author _id : exportData . data . users [ 0 ] . id ,
created _by : exportData . data . users [ 0 ] . id ,
updated _by : exportData . data . users [ 1 ] . id ,
2019-07-05 14:40:43 +03:00
published _by : exportData . data . users [ 1 ] . id
2018-07-19 13:26:47 +03:00
} ) ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2' ,
title : 'title2' ,
author _id : exportData . data . users [ 3 ] . id ,
created _by : exportData . data . users [ 2 ] . id ,
updated _by : exportData . data . users [ 0 ] . id ,
2019-07-05 14:40:43 +03:00
published _by : exportData . data . users [ 1 ] . id
2018-07-19 13:26:47 +03:00
} ) ;
exportData . data . posts [ 2 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post3' ,
title : 'title3' ,
author _id : exportData . data . users [ 0 ] . id ,
created _by : exportData . data . users [ 3 ] . id ,
updated _by : exportData . data . users [ 3 ] . id ,
2019-07-05 14:40:43 +03:00
published _by : exportData . data . users [ 3 ] . id
2018-07-19 13:26:47 +03:00
} ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
exportData . data . tags [ 0 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'tag1' ,
created _by : exportData . data . users [ 3 ] . id ,
updated _by : exportData . data . users [ 0 ] . id
} ) ;
exportData . data . tags [ 1 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'tag2' ,
created _by : exportData . data . users [ 1 ] . id ,
updated _by : exportData . data . users [ 3 ] . id
} ) ;
exportData . data . tags [ 2 ] = testUtils . DataGenerator . forKnex . createTag ( {
slug : 'tag3' ,
created _by : exportData . data . users [ 2 ] . id ,
updated _by : exportData . data . users [ 2 ] . id
} ) ;
2014-08-09 23:16:54 +04:00
2018-07-19 13:26:47 +03:00
const clonedImportOptions = _ . cloneDeep ( importOptions ) ;
2018-09-26 15:11:22 +03:00
const postOptions = Object . assign ( { withRelated : [ 'tags' ] } , testUtils . context . internal ) ;
const tagOptions = Object . assign ( { order : 'slug ASC' } , testUtils . context . internal ) ;
const userOptions = Object . assign ( { withRelated : [ 'roles' ] } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , clonedImportOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( postOptions ) ,
models . Tag . findPage ( tagOptions ) ,
2019-09-12 16:54:39 +03:00
models . User . findPage ( userOptions )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( postOptions ) ) ;
const tags = result [ 1 ] . data . map ( model => model . toJSON ( tagOptions ) ) ;
const users = result [ 2 ] . data . map ( model => model . toJSON ( userOptions ) ) ;
2018-07-19 13:26:47 +03:00
posts . length . should . equal ( exportData . data . posts . length + testUtils . DataGenerator . Content . posts . length , 'Wrong number of posts' ) ;
tags . length . should . equal ( exportData . data . tags . length + testUtils . DataGenerator . Content . tags . length , 'Wrong number of tags' ) ;
// the test env only inserts the user defined in the `forKnex` array
users . length . should . equal ( exportData . data . users . length + testUtils . DataGenerator . forKnex . users . length , 'Wrong number of users' ) ;
2014-12-11 18:50:10 +03:00
} ) ;
2014-08-09 23:16:54 +04:00
} ) ;
} ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2015-05-12 22:40:01 +03:00
2018-07-19 13:26:47 +03:00
describe ( '1.0' , function ( ) {
2020-02-24 23:51:09 +03:00
beforeEach ( testUtils . teardownDb ) ;
2018-07-19 13:26:47 +03:00
beforeEach ( testUtils . setup ( 'roles' , 'owner' , 'settings' ) ) ;
2015-05-12 22:40:01 +03:00
2018-07-19 13:26:47 +03:00
it ( 'ensure amp field get\'s respected' , function ( ) {
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
2015-05-12 22:40:01 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
amp : 2
2015-05-12 22:40:01 +03:00
} ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2' ,
amp : null
2017-06-04 12:53:00 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
models . Post . findPage ( testUtils . context . internal )
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( ) ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 2 ) ;
posts [ 0 ] . comment _id . should . eql ( exportData . data . posts [ 1 ] . id ) ;
posts [ 1 ] . comment _id . should . eql ( '2' ) ;
} ) ;
2017-06-04 12:53:00 +03:00
} ) ;
2019-08-19 14:41:09 +03:00
describe ( 'migrate mobiledoc/html' , function ( ) {
it ( 'invalid mobiledoc structure' , function ( ) {
2018-07-19 13:26:47 +03:00
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
html : 'test' ,
mobiledoc : '{}'
} ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2'
} ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 1 ] . mobiledoc = '{' ;
2018-09-26 15:11:22 +03:00
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( result ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( options )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 2 ) ;
2019-03-19 06:28:21 +03:00
should ( posts [ 0 ] . html ) . eql ( null ) ;
2021-02-15 22:32:32 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","ghostVersion":"4.0","markups":[],"atoms":[],"cards":[],"sections":[[1,"p",[[0,[],0,""]]]]}' ) ;
2017-06-04 12:53:00 +03:00
2019-03-19 06:28:21 +03:00
should ( posts [ 1 ] . html ) . eql ( null ) ;
2021-02-15 22:32:32 +03:00
posts [ 1 ] . mobiledoc . should . eql ( '{"version":"0.3.1","ghostVersion":"4.0","markups":[],"atoms":[],"cards":[],"sections":[[1,"p",[[0,[],0,""]]]]}' ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2017-06-04 12:53:00 +03:00
} ) ;
2019-08-19 14:41:09 +03:00
it ( 'mobiledoc is null, html field is set' , function ( ) {
2018-07-19 13:26:47 +03:00
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
html : '<div><h1>This is my post content.</h1></div>'
} ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] . mobiledoc = null ;
2017-06-04 12:53:00 +03:00
2018-09-26 15:11:22 +03:00
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( options )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2017-06-04 12:53:00 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 1 ) ;
2019-03-19 06:28:21 +03:00
should ( posts [ 0 ] . html ) . eql ( null ) ;
2021-02-15 22:32:32 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","ghostVersion":"4.0","markups":[],"atoms":[],"cards":[],"sections":[[1,"p",[[0,[],0,""]]]]}' ) ;
2017-06-04 12:53:00 +03:00
} ) ;
2017-07-27 12:25:01 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
it ( 'mobiledoc and html is null' , function ( ) {
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
2017-07-27 12:25:01 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1'
} ) ;
2017-07-27 12:25:01 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] . mobiledoc = null ;
exportData . data . posts [ 0 ] . html = null ;
2017-07-27 12:25:01 +03:00
2018-09-26 15:11:22 +03:00
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( options )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2017-07-27 12:25:01 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 1 ) ;
2019-03-19 06:28:21 +03:00
should ( posts [ 0 ] . html ) . eql ( null ) ;
2021-02-15 22:32:32 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","ghostVersion":"4.0","markups":[],"atoms":[],"cards":[],"sections":[[1,"p",[[0,[],0,""]]]]}' ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2017-07-27 12:25:01 +03:00
} ) ;
2017-09-04 10:48:56 +03:00
2018-07-19 13:26:47 +03:00
it ( 'mobiledoc is set and html is null' , function ( ) {
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
2017-09-04 10:48:56 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1'
2018-05-29 00:58:06 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] . html = null ;
2018-09-26 15:11:22 +03:00
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( options )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2018-05-29 00:58:06 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 1 ) ;
2019-02-26 07:58:37 +03:00
posts [ 0 ] . html . should . eql ( '<!--kg-card-begin: markdown--><h2 id="markdown">markdown</h2>\n<!--kg-card-end: markdown-->' ) ;
2021-02-16 15:34:27 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["markdown",{"markdown":"## markdown"}]],"sections":[[10,0]],"ghostVersion":"3.0"}' ) ;
2018-03-27 17:16:15 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
} ) ;
2017-09-04 10:48:56 +03:00
2019-08-19 14:41:09 +03:00
it ( 'post has "kg-card-markdown" class' , function ( ) {
2018-07-19 13:26:47 +03:00
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
2018-06-07 11:14:06 +03:00
2018-07-19 13:26:47 +03:00
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
html : '<div class="kg-card-markdown"><h1>This is my post content.</h1></div>' ,
mobiledoc : testUtils . DataGenerator . markdownToMobiledoc ( '# This is my post content' )
} ) ;
2017-09-04 10:48:56 +03:00
2018-09-26 15:11:22 +03:00
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( options )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2017-09-12 18:06:12 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 1 ) ;
2021-02-16 15:34:27 +03:00
posts [ 0 ] . html . should . eql ( '<!--kg-card-begin: markdown--><h1 id="thisismypostcontent">This is my post content</h1>\n<!--kg-card-end: markdown-->' ) ;
const expectedMobiledoc = JSON . parse ( exportData . data . posts [ 0 ] . mobiledoc ) ;
expectedMobiledoc . ghostVersion = '3.0' ;
posts [ 0 ] . mobiledoc . should . eql ( JSON . stringify ( expectedMobiledoc ) ) ;
2018-03-27 17:16:15 +03:00
} ) ;
} ) ;
2019-08-19 14:41:09 +03:00
it ( 'import old Koenig Beta post format' , function ( ) {
2018-07-19 13:26:47 +03:00
const exportData = exportedPreviousBody ( ) . db [ 0 ] ;
exportData . data . posts [ 0 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post1' ,
mobiledoc : JSON . stringify ( {
version : '0.3.1' ,
markups : [ ] ,
atoms : [ ] ,
cards : [
[ 'image' , {
imageStyle : 'wide' ,
src : 'source'
} ] ,
[ 'markdown' , {
markdown : '# Post Content'
} ]
] ,
sections : [ [ 10 , 0 ] , [ 10 , 1 ] ]
} )
2018-07-31 13:50:11 +03:00
} ) ;
2018-07-19 13:26:47 +03:00
delete exportData . data . posts [ 0 ] . html ;
exportData . data . posts [ 1 ] = testUtils . DataGenerator . forKnex . createPost ( {
slug : 'post2' ,
mobiledoc : JSON . stringify ( {
version : '0.3.1' ,
markups : [ ] ,
atoms : [ ] ,
cards : [
[ 'markdown' , {
markdown : '## Post Content'
} ] ,
[ 'image' , {
imageStyle : 'not-wide' ,
src : 'source2'
} ]
] ,
sections : [ [ 10 , 0 ] , [ 10 , 1 ] ]
} ) ,
html : '<div class="kg-post"><h2 id="postcontent">Post Content</h2></div>\n'
2018-07-31 13:50:11 +03:00
} ) ;
2018-09-26 15:11:22 +03:00
const options = Object . assign ( { formats : 'mobiledoc,html' } , testUtils . context . internal ) ;
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
return Promise . all ( [
2018-09-26 15:11:22 +03:00
models . Post . findPage ( options )
2018-07-19 13:26:47 +03:00
] ) ;
} ) . then ( function ( result ) {
2019-07-05 14:40:43 +03:00
const posts = result [ 0 ] . data . map ( model => model . toJSON ( options ) ) ;
2018-07-31 13:50:11 +03:00
2018-07-19 13:26:47 +03:00
posts . length . should . eql ( 2 ) ;
2017-09-04 10:48:56 +03:00
2021-02-16 15:34:27 +03:00
posts [ 0 ] . mobiledoc . should . eql ( '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["markdown",{"markdown":"## Post Content"}],["image",{"src":"source2","cardWidth":"not-wide"}]],"sections":[[10,0],[10,1]],"ghostVersion":"3.0"}' ) ;
2020-06-15 11:41:11 +03:00
posts [ 0 ] . html . should . eql ( '<!--kg-card-begin: markdown--><h2 id="postcontent">Post Content</h2>\n<!--kg-card-end: markdown--><figure class="kg-card kg-image-card kg-width-not-wide"><img src="source2" class="kg-image" alt></figure>' ) ;
2018-03-27 17:16:15 +03:00
2021-02-16 15:34:27 +03:00
posts [ 1 ] . mobiledoc . should . eql ( '{"version":"0.3.1","markups":[],"atoms":[],"cards":[["image",{"src":"source","cardWidth":"wide"}],["markdown",{"markdown":"# Post Content"}]],"sections":[[10,0],[10,1]],"ghostVersion":"3.0"}' ) ;
posts [ 1 ] . html . should . eql ( '<figure class="kg-card kg-image-card kg-width-wide"><img src="source" class="kg-image" alt></figure><!--kg-card-begin: markdown--><h1 id="postcontent">Post Content</h1>\n<!--kg-card-end: markdown-->' ) ;
2018-07-19 13:26:47 +03:00
} ) ;
} ) ;
} ) ;
} ) ;
2018-03-27 17:16:15 +03:00
2018-07-19 13:26:47 +03:00
describe ( 'LTS' , function ( ) {
2020-02-24 23:51:09 +03:00
beforeEach ( testUtils . teardownDb ) ;
2018-07-19 13:26:47 +03:00
beforeEach ( testUtils . setup ( 'roles' , 'owner' , 'settings' ) ) ;
2018-03-27 17:16:15 +03:00
2018-07-19 13:26:47 +03:00
it ( 'disallows importing LTS imports' , function ( ) {
const exportData = exportedLegacyBody ( ) . db [ 0 ] ;
2018-03-27 17:16:15 +03:00
2018-07-19 13:26:47 +03:00
return dataImporter . doImport ( exportData , importOptions )
. then ( function ( ) {
2019-08-19 14:41:09 +03:00
'0' . should . eql ( 1 , 'LTS import should fail' ) ;
2018-07-19 13:26:47 +03:00
} )
. catch ( function ( err ) {
2018-08-11 00:22:32 +03:00
err . message . should . eql ( 'Detected unsupported file structure.' ) ;
2017-09-04 10:48:56 +03:00
} ) ;
} ) ;
2014-08-09 23:16:54 +04:00
} ) ;