From 69b871a754dc4919eb1e3ea6773386052d56b1c0 Mon Sep 17 00:00:00 2001 From: Jacob Gable Date: Sun, 27 Jul 2014 17:22:00 -0500 Subject: [PATCH] Make importer more robust for tags Closes #3242 - Add checks for valid fields in tags and posts - Add unit test with empty tag export data file - Add unit test with empty post export data file --- core/server/data/import/000.js | 30 +- core/test/integration/import_spec.js | 50 ++- .../utils/fixtures/export-003-nullPosts.json | 396 ++++++++++++++++++ .../utils/fixtures/export-003-nullTags.json | 388 +++++++++++++++++ 4 files changed, 858 insertions(+), 6 deletions(-) create mode 100644 core/test/utils/fixtures/export-003-nullPosts.json create mode 100644 core/test/utils/fixtures/export-003-nullTags.json diff --git a/core/server/data/import/000.js b/core/server/data/import/000.js index 7f0dd1c03a..6acea35e64 100644 --- a/core/server/data/import/000.js +++ b/core/server/data/import/000.js @@ -3,8 +3,18 @@ var when = require('when'), models = require('../../models'), Importer000, updatedSettingKeys, + areEmpty, internal = {context: {internal: true}}; +areEmpty = function (object) { + var fields = _.toArray(arguments).slice(1), + areEmpty = _.all(fields, function (field) { + return _.isEmpty(object[field]); + }); + + return areEmpty; +}; + updatedSettingKeys = { activePlugins: 'activeApps', installedPlugins: 'installedApps' @@ -75,9 +85,12 @@ function preProcessPostTags(tableData) { }); post.tags = []; _.each(tags, function (tag) { - // names are unique.. this should get the right tags added - // as long as tags are added first; - post.tags.push({name: tag.name}); + // Only add valid tags + if (!_.isEmpty(tag.uuid)) { + // names are unique.. this should get the right tags added + // as long as tags are added first; + post.tags.push({name: tag.name}); + } }); } }); @@ -88,6 +101,11 @@ function preProcessPostTags(tableData) { function importTags(ops, tableData, transaction) { tableData = stripProperties(['id'], tableData); _.each(tableData, function (tag) { + // Validate minimum tag fields + if (areEmpty(tag, 'name', 'slug')) { + return; + } + ops.push(models.Tag.findOne({name: tag.name}, {transacting: transaction}).then(function (_tag) { if (!_tag) { return models.Tag.add(tag, _.extend(internal, {transacting: transaction})) @@ -104,6 +122,11 @@ function importTags(ops, tableData, transaction) { function importPosts(ops, tableData, transaction) { tableData = stripProperties(['id'], tableData); _.each(tableData, function (post) { + // Validate minimum post fields + if (areEmpty(post, 'title', 'slug', 'markdown')) { + return; + } + ops.push(models.Post.add(post, _.extend(internal, {transacting: transaction, importing: true})) // add pass-through error handling so that bluebird doesn't think we've dropped it .catch(function (error) { @@ -116,6 +139,7 @@ function importUsers(ops, tableData, transaction) { // don't override the users credentials tableData = stripProperties(['id', 'email', 'password'], tableData); tableData[0].id = 1; + ops.push(models.User.edit(tableData[0], _.extend(internal, {id: 1, transacting: transaction})) // add pass-through error handling so that bluebird doesn't think we've dropped it .catch(function (error) { diff --git a/core/test/integration/import_spec.js b/core/test/integration/import_spec.js index 868e365dd9..e687d783a8 100644 --- a/core/test/integration/import_spec.js +++ b/core/test/integration/import_spec.js @@ -39,9 +39,10 @@ describe('Import', function () { beforeEach(testUtils.setup()); beforeEach(function () { var newConfig = _.extend(config, defaultConfig); - migration.__get__('config', newConfig); - configUpdate(newConfig); - knex = config.database.knex; + + migration.__get__('config', newConfig); + configUpdate(newConfig); + knex = config.database.knex; }); it('resolves 000', function (done) { @@ -563,5 +564,48 @@ describe('Import', function () { done(); }); }); + + it('doesn\'t import invalid tags data from 003', function (done) { + var exportData; + + testUtils.fixtures.loadExportFixture('export-003-nullTags').then(function (exported) { + exportData = exported; + + exportData.data.tags.length.should.be.above(1); + exportData.data.posts_tags.length.should.be.above(1); + + return importer('003', exportData); + }).then(function () { + done(new Error('Allowed import of invalid tags data')); + }).catch(function (response) { + response.length.should.equal(4); + response[0].type.should.equal('ValidationError'); + response[0].message.should.eql('Value in [tags.uuid] cannot be blank.'); + response[1].type.should.equal('ValidationError'); + response[1].message.should.eql('Validation (isUUID) failed for uuid'); + response[2].type.should.equal('ValidationError'); + response[2].message.should.eql('Value in [tags.name] cannot be blank.'); + response[3].type.should.equal('ValidationError'); + response[3].message.should.eql('Value in [tags.slug] cannot be blank.'); + done(); + }); + }); + + it('doesn\'t import invalid posts data from 003', function (done) { + var exportData; + + testUtils.fixtures.loadExportFixture('export-003-nullPosts').then(function (exported) { + exportData = exported; + + exportData.data.posts.length.should.be.above(1); + + return importer('003', exportData); + }).then(function () { + done(new Error('Allowed import of invalid tags data')); + }).catch(function (response) { + response.length.should.equal(6); + done(); + }); + }); }); }); diff --git a/core/test/utils/fixtures/export-003-nullPosts.json b/core/test/utils/fixtures/export-003-nullPosts.json new file mode 100644 index 0000000000..9edb9042ac --- /dev/null +++ b/core/test/utils/fixtures/export-003-nullPosts.json @@ -0,0 +1,396 @@ +{ + "meta": { + "exported_on": 1388318311015, + "version": "003" + }, + "data": { + "posts": [ + { + "id": 1, + "uuid": "8492fbba-1102-4b53-8e3e-abe207952f0c", + "title": "Welcome to Ghost", + "slug": "welcome-to-ghost", + "markdown": "You're live! Nice.", + "html": "

You're live! Nice.

", + "image": null, + "featured": 0, + "page": 0, + "status": "published", + "language": "en_US", + "meta_title": null, + "meta_description": null, + "author_id": 1, + "created_at": 1388318310782, + "created_by": 1, + "updated_at": 1388318310782, + "updated_by": 1, + "published_at": 1388318310783, + "published_by": 1 + }, + { + "id": null, + "uuid": null, + "title": null, + "slug": null, + "markdown": null, + "html": null, + "image": null, + "featured": 0, + "page": 0, + "status": null, + "language": null, + "meta_title": null, + "meta_description": null, + "author_id": 1, + "created_at": 1388318310782, + "created_by": 1, + "updated_at": 1388318310782, + "updated_by": 1, + "published_at": 1388318310783, + "published_by": 1 + } + ], + "users": [ + { + "id": 1, + "uuid": "e5188224-4742-4c32-a2d6-e9c5c5d4c123", + "name": "Josephine Bloggs", + "slug": "josephine-blogs", + "password": "$2a$10$.pZeeBE0gHXd0PTnbT/ph.GEKgd0Wd3q2pWna3ynTGBkPKnGIKABC", + "email": "josephinebloggs@example.com", + "image": null, + "cover": null, + "bio": "A blogger", + "website": null, + "location": null, + "accessibility": null, + "status": "active", + "language": "en_US", + "meta_title": null, + "meta_description": null, + "last_login": null, + "created_at": 1388319501897, + "created_by": 1, + "updated_at": null, + "updated_by": null + } + ], + "roles": [ + { + "id": 1, + "uuid": "d2ea9c7f-7e6b-4cae-b009-35c298206852", + "name": "Administrator", + "description": "Administrators", + "created_at": 1388318310794, + "created_by": 1, + "updated_at": 1388318310794, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "b0d7d6b0-5b88-45b5-b0e5-a487741b843d", + "name": "Editor", + "description": "Editors", + "created_at": 1388318310796, + "created_by": 1, + "updated_at": 1388318310796, + "updated_by": 1 + }, + { + "id": 3, + "uuid": "9f72e817-5490-4ccf-bc78-c557dc9613ca", + "name": "Author", + "description": "Authors", + "created_at": 1388318310799, + "created_by": 1, + "updated_at": 1388318310799, + "updated_by": 1 + } + ], + "roles_users": [ + { + "id": 1, + "role_id": 1, + "user_id": 1 + } + ], + "permissions": [ + { + "id": 1, + "uuid": "bdfbd261-e0fb-4c8e-abab-aece7a9e8e34", + "name": "Edit posts", + "object_type": "post", + "action_type": "edit", + "object_id": null, + "created_at": 1388318310803, + "created_by": 1, + "updated_at": 1388318310803, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "580d31c4-e3db-40f3-969d-9a1caea9d1bb", + "name": "Remove posts", + "object_type": "post", + "action_type": "remove", + "object_id": null, + "created_at": 1388318310814, + "created_by": 1, + "updated_at": 1388318310814, + "updated_by": 1 + }, + { + "id": 3, + "uuid": "c1f8b024-e383-494a-835d-6fb673f143db", + "name": "Create posts", + "object_type": "post", + "action_type": "create", + "object_id": null, + "created_at": 1388318310818, + "created_by": 1, + "updated_at": 1388318310818, + "updated_by": 1 + } + ], + "permissions_users": [], + "permissions_roles": [ + { + "id": 1, + "role_id": 1, + "permission_id": 1 + }, + { + "id": 2, + "role_id": 1, + "permission_id": 2 + }, + { + "id": 3, + "role_id": 1, + "permission_id": 3 + } + ], + "settings": [ + { + "id": 1, + "uuid": "f90aa810-4fa2-49fe-a39b-7c0d2ebb473e", + "key": "databaseVersion", + "value": "001", + "type": "core", + "created_at": 1388318310829, + "created_by": 1, + "updated_at": 1388318310829, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "95ce1c53-69b0-4f5f-be91-d3aeb39046b5", + "key": "dbHash", + "value": null, + "type": "core", + "created_at": 1388318310829, + "created_by": 1, + "updated_at": 1388318310829, + "updated_by": 1 + }, + { + "id": 3, + "uuid": "c356fbde-0bc5-4fe1-9309-2510291aa34d", + "key": "title", + "value": "Ghost", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 4, + "uuid": "858dc11f-8f9e-4011-99ee-d94c48d5a2ce", + "key": "description", + "value": "Just a blogging platform.", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 5, + "uuid": "37ca5ae7-bca6-4dd5-8021-4ef6c6dcb097", + "key": "email", + "value": "josephinebloggs@example.com", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 6, + "uuid": "1672d62c-fab7-4f22-b333-8cf760189f67", + "key": "logo", + "value": "", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 7, + "uuid": "cd8b0456-578b-467a-857e-551bad17a14d", + "key": "cover", + "value": "", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 8, + "uuid": "c4a074a4-05c7-49f7-83eb-068302c15d82", + "key": "defaultLang", + "value": "en_US", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 9, + "uuid": "21f2f5da-9bee-4dae-b3b7-b8d7baf8be33", + "key": "postsPerPage", + "value": "6", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 10, + "uuid": "2d21b736-f85a-4119-a0e3-5fc898b1bf47", + "key": "forceI18n", + "value": "true", + "type": "blog", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 11, + "uuid": "5c5b91b8-6062-4104-b855-9e121f72b0f0", + "key": "permalinks", + "value": "/:slug/", + "type": "blog", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 12, + "uuid": "795cb328-3e38-4906-81a8-fcdff19d914f", + "key": "activeTheme", + "value": "notcasper", + "type": "theme", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 13, + "uuid": "f3afce35-5166-453e-86c3-50dfff74dca7", + "key": "activeApps", + "value": "[]", + "type": "plugin", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 14, + "uuid": "2ea560a3-2304-449d-a62b-f7b622987510", + "key": "installedApps", + "value": "[]", + "type": "plugin", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + } + ], + "tags": [ + { + "id": 1, + "uuid": "a950117a-9735-4584-931d-25a28015a80d", + "name": "Getting Started", + "slug": "getting-started", + "description": null, + "parent_id": null, + "meta_title": null, + "meta_description": null, + "created_at": 1388318310790, + "created_by": 1, + "updated_at": 1388318310790, + "updated_by": 1 + } + ], + "posts_tags": [ + { + "id": 1, + "post_id": 1, + "tag_id": 1 + }, + { + "id": 2, + "post_id": 1, + "tag_id": 2 + } + ], + "apps": [ + { + "id": 1, + "uuid": "4d7557f0-0949-4946-9fe8-ec030e0727f0", + "name": "Kudos", + "slug": "kudos", + "version": "0.0.1", + "status": "installed", + "created_at": 1388318312790, + "created_by": 1, + "updated_at": 1388318312790, + "updated_by": 1 + } + ], + "app_settings": [ + { + "id": 1, + "uuid": "790e4551-b9cc-4954-8f5d-b6e651bc7342", + "key": "position", + "value": "bottom", + "app_id": 1, + "created_at": 1388318312790, + "created_by": 1, + "updated_at": 1388318312790, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "29682b66-cdeb-4773-9821-bcf40ea93b58", + "key": "size", + "value": "60", + "app_id": 1, + "created_at": 1388318312790, + "created_by": 1, + "updated_at": 1388318312790, + "updated_by": 1 + } + ] + } +} \ No newline at end of file diff --git a/core/test/utils/fixtures/export-003-nullTags.json b/core/test/utils/fixtures/export-003-nullTags.json new file mode 100644 index 0000000000..63301cfbd1 --- /dev/null +++ b/core/test/utils/fixtures/export-003-nullTags.json @@ -0,0 +1,388 @@ +{ + "meta": { + "exported_on": 1388318311015, + "version": "003" + }, + "data": { + "posts": [ + { + "id": 1, + "uuid": "8492fbba-1102-4b53-8e3e-abe207952f0c", + "title": "Welcome to Ghost", + "slug": "welcome-to-ghost", + "markdown": "You're live! Nice.", + "html": "

You're live! Nice.

", + "image": null, + "featured": 0, + "page": 0, + "status": "published", + "language": "en_US", + "meta_title": null, + "meta_description": null, + "author_id": 1, + "created_at": 1388318310782, + "created_by": 1, + "updated_at": 1388318310782, + "updated_by": 1, + "published_at": 1388318310783, + "published_by": 1 + } + ], + "users": [ + { + "id": 1, + "uuid": "e5188224-4742-4c32-a2d6-e9c5c5d4c123", + "name": "Josephine Bloggs", + "slug": "josephine-blogs", + "password": "$2a$10$.pZeeBE0gHXd0PTnbT/ph.GEKgd0Wd3q2pWna3ynTGBkPKnGIKABC", + "email": "josephinebloggs@example.com", + "image": null, + "cover": null, + "bio": "A blogger", + "website": null, + "location": null, + "accessibility": null, + "status": "active", + "language": "en_US", + "meta_title": null, + "meta_description": null, + "last_login": null, + "created_at": 1388319501897, + "created_by": 1, + "updated_at": null, + "updated_by": null + } + ], + "roles": [ + { + "id": 1, + "uuid": "d2ea9c7f-7e6b-4cae-b009-35c298206852", + "name": "Administrator", + "description": "Administrators", + "created_at": 1388318310794, + "created_by": 1, + "updated_at": 1388318310794, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "b0d7d6b0-5b88-45b5-b0e5-a487741b843d", + "name": "Editor", + "description": "Editors", + "created_at": 1388318310796, + "created_by": 1, + "updated_at": 1388318310796, + "updated_by": 1 + }, + { + "id": 3, + "uuid": "9f72e817-5490-4ccf-bc78-c557dc9613ca", + "name": "Author", + "description": "Authors", + "created_at": 1388318310799, + "created_by": 1, + "updated_at": 1388318310799, + "updated_by": 1 + } + ], + "roles_users": [ + { + "id": 1, + "role_id": 1, + "user_id": 1 + } + ], + "permissions": [ + { + "id": 1, + "uuid": "bdfbd261-e0fb-4c8e-abab-aece7a9e8e34", + "name": "Edit posts", + "object_type": "post", + "action_type": "edit", + "object_id": null, + "created_at": 1388318310803, + "created_by": 1, + "updated_at": 1388318310803, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "580d31c4-e3db-40f3-969d-9a1caea9d1bb", + "name": "Remove posts", + "object_type": "post", + "action_type": "remove", + "object_id": null, + "created_at": 1388318310814, + "created_by": 1, + "updated_at": 1388318310814, + "updated_by": 1 + }, + { + "id": 3, + "uuid": "c1f8b024-e383-494a-835d-6fb673f143db", + "name": "Create posts", + "object_type": "post", + "action_type": "create", + "object_id": null, + "created_at": 1388318310818, + "created_by": 1, + "updated_at": 1388318310818, + "updated_by": 1 + } + ], + "permissions_users": [], + "permissions_roles": [ + { + "id": 1, + "role_id": 1, + "permission_id": 1 + }, + { + "id": 2, + "role_id": 1, + "permission_id": 2 + }, + { + "id": 3, + "role_id": 1, + "permission_id": 3 + } + ], + "settings": [ + { + "id": 1, + "uuid": "f90aa810-4fa2-49fe-a39b-7c0d2ebb473e", + "key": "databaseVersion", + "value": "001", + "type": "core", + "created_at": 1388318310829, + "created_by": 1, + "updated_at": 1388318310829, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "95ce1c53-69b0-4f5f-be91-d3aeb39046b5", + "key": "dbHash", + "value": null, + "type": "core", + "created_at": 1388318310829, + "created_by": 1, + "updated_at": 1388318310829, + "updated_by": 1 + }, + { + "id": 3, + "uuid": "c356fbde-0bc5-4fe1-9309-2510291aa34d", + "key": "title", + "value": "Ghost", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 4, + "uuid": "858dc11f-8f9e-4011-99ee-d94c48d5a2ce", + "key": "description", + "value": "Just a blogging platform.", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 5, + "uuid": "37ca5ae7-bca6-4dd5-8021-4ef6c6dcb097", + "key": "email", + "value": "josephinebloggs@example.com", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 6, + "uuid": "1672d62c-fab7-4f22-b333-8cf760189f67", + "key": "logo", + "value": "", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 7, + "uuid": "cd8b0456-578b-467a-857e-551bad17a14d", + "key": "cover", + "value": "", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 8, + "uuid": "c4a074a4-05c7-49f7-83eb-068302c15d82", + "key": "defaultLang", + "value": "en_US", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 9, + "uuid": "21f2f5da-9bee-4dae-b3b7-b8d7baf8be33", + "key": "postsPerPage", + "value": "6", + "type": "blog", + "created_at": 1388318310830, + "created_by": 1, + "updated_at": 1388318310830, + "updated_by": 1 + }, + { + "id": 10, + "uuid": "2d21b736-f85a-4119-a0e3-5fc898b1bf47", + "key": "forceI18n", + "value": "true", + "type": "blog", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 11, + "uuid": "5c5b91b8-6062-4104-b855-9e121f72b0f0", + "key": "permalinks", + "value": "/:slug/", + "type": "blog", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 12, + "uuid": "795cb328-3e38-4906-81a8-fcdff19d914f", + "key": "activeTheme", + "value": "notcasper", + "type": "theme", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 13, + "uuid": "f3afce35-5166-453e-86c3-50dfff74dca7", + "key": "activeApps", + "value": "[]", + "type": "plugin", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + }, + { + "id": 14, + "uuid": "2ea560a3-2304-449d-a62b-f7b622987510", + "key": "installedApps", + "value": "[]", + "type": "plugin", + "created_at": 1388318310831, + "created_by": 1, + "updated_at": 1388318310831, + "updated_by": 1 + } + ], + "tags": [ + { + "id": 1, + "uuid": "a950117a-9735-4584-931d-25a28015a80d", + "name": "Getting Started", + "slug": "getting-started", + "description": null, + "parent_id": null, + "meta_title": null, + "meta_description": null, + "created_at": 1388318310790, + "created_by": 1, + "updated_at": 1388318310790, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "", + "name": "", + "slug": "", + "description": null, + "parent_id": null, + "meta_title": null, + "meta_description": null, + "created_at": "0000-00-00 00:00:00", + "created_by": 0, + "updated_at": null, + "updated_by": null + } + ], + "posts_tags": [ + { + "id": 1, + "post_id": 1, + "tag_id": 1 + }, + { + "id": 2, + "post_id": 1, + "tag_id": 2 + } + ], + "apps": [ + { + "id": 1, + "uuid": "4d7557f0-0949-4946-9fe8-ec030e0727f0", + "name": "Kudos", + "slug": "kudos", + "version": "0.0.1", + "status": "installed", + "created_at": 1388318312790, + "created_by": 1, + "updated_at": 1388318312790, + "updated_by": 1 + } + ], + "app_settings": [ + { + "id": 1, + "uuid": "790e4551-b9cc-4954-8f5d-b6e651bc7342", + "key": "position", + "value": "bottom", + "app_id": 1, + "created_at": 1388318312790, + "created_by": 1, + "updated_at": 1388318312790, + "updated_by": 1 + }, + { + "id": 2, + "uuid": "29682b66-cdeb-4773-9821-bcf40ea93b58", + "key": "size", + "value": "60", + "app_id": 1, + "created_at": 1388318312790, + "created_by": 1, + "updated_at": 1388318312790, + "updated_by": 1 + } + ] + } +} \ No newline at end of file