From 47cdd5310bf58f59f52d5ceed726fd50d7a0e518 Mon Sep 17 00:00:00 2001 From: Jed Date: Tue, 28 Jan 2025 19:02:52 +0100 Subject: [PATCH 1/6] adds method to sort all documents and pages --- lib/methods/export.js | 89 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 73 insertions(+), 16 deletions(-) diff --git a/lib/methods/export.js b/lib/methods/export.js index 09dc4e6..fae0150 100644 --- a/lib/methods/export.js +++ b/lib/methods/export.js @@ -7,7 +7,7 @@ const { uniqBy, uniqueId } = require('lodash'); const MAX_RECURSION = 10; -module.exports = self => { +module.exports = (self) => { return { async export(req, manager, reporting = null) { if (!req.user) { @@ -33,9 +33,11 @@ module.exports = self => { const hasRelatedTypes = !!relatedTypes.length; - const docs = (await self.getDocs(req, ids, hasRelatedTypes, manager, reporting)) + const docs = (await self.getDocs(req, ids, manager, reporting)) .map((doc) => self.apos.util.clonePermanent(doc)); + if (!hasRelatedTypes) { + self.sortDocs(docs); return self.exportFile( req, reporting, @@ -55,6 +57,8 @@ module.exports = self => { }); } + self.sortDocs(allDocs); + if (!format.includeAttachments) { return self.exportFile( req, @@ -88,6 +92,18 @@ module.exports = self => { }) ); + for (const { + _id, title, aposMode, level, rank + } of allDocs) { + console.log('doc:', { + _id, + title, + aposMode, + level, + rank + }); + } + return self.exportFile( req, reporting, @@ -101,28 +117,69 @@ module.exports = self => { ); }, + sortDocs(docs) { + docs.sort((a, b) => { + if (!self.apos.page.isPage(a) && !self.apos.page.isPage(b)) { + return 0; + } + if (self.apos.page.isPage(a) && !self.apos.page.isPage(b)) { + return -1; + } + if (!self.apos.page.isPage(a) && self.apos.page.isPage(b)) { + return 1; + } + if (a.aposMode === 'draft' && b.aposMode === 'published') { + return -1; + } + if (a.aposMode === 'published' && b.aposMode === 'draft') { + return 1; + } + if (a.level > b.level) { + return 1; + } + if (a.level < b.level) { + return -1; + } + if (a.rank < b.rank) { + return -1; + } + if (a.rank > b.rank) { + return 1; + } + return 0; + }); + }, + // Get docs via their manager in order to populate them // so that we can retrieve their relationships IDs later, // and to let the manager handle permissions. - async getDocs(req, docsIds, includeRelationships, manager, reporting) { + async getDocs(req, docsIds, manager, reporting) { if (!docsIds.length) { return []; } + /* const isPage = self.apos.instanceOf(manager, '@apostrophecms/page'); */ const { draftIds, publishedIds } = self.getAllModesIds(docsIds); const isReqDraft = req.mode === 'draft'; const docs = []; const draftReq = isReqDraft ? req : req.clone({ mode: 'draft' }); - const draftDocs = await manager + const cursor = await manager .findForEditing(draftReq, { _id: { $in: draftIds } }) - .relationships(includeRelationships) - .toArray(); + .relationships(false); + + /* if (isPage) { */ + /* cursor.sort({ */ + /* level: 1, */ + /* rank: 1 */ + /* }); */ + /* } */ + const draftDocs = await cursor.toArray(); docs.push(...draftDocs); @@ -133,7 +190,7 @@ module.exports = self => { $in: publishedIds } }) - .relationships(includeRelationships) + .relationships(false) .toArray(); docs.push(...publishedDocs); @@ -225,7 +282,7 @@ module.exports = self => { if (!field.withType && !fieldValue) { continue; } - if (field.withType && relatedTypes && !relatedTypesIncludes(field.withType)) { + if (field.withType && relatedTypes && !self.relatedTypesIncludes(field.withType, relatedTypes)) { continue; } if (field.withType && !self.canExport(req, field.withType)) { @@ -290,16 +347,16 @@ module.exports = self => { }); } } + }, - function relatedTypesIncludes(name) { - if ([ '@apostrophecms/any-page-type', '@apostrophecms/page' ].includes(name)) { - return relatedTypes.some(type => { - const module = self.apos.modules[type]; - return self.apos.instanceOf(module, '@apostrophecms/page-type'); - }); - } - return relatedTypes.includes(name); + relatedTypesIncludes(name, relatedTypes) { + if ([ '@apostrophecms/any-page-type', '@apostrophecms/page' ].includes(name)) { + return relatedTypes.some(type => { + const module = self.apos.modules[type]; + return self.apos.instanceOf(module, '@apostrophecms/page-type'); + }); } + return relatedTypes.includes(name); }, async getRelatedDocsFromRichTextWidget(req, { From e7e239b7529949f88d07d4575d9dca2d4b1e3c1e Mon Sep 17 00:00:00 2001 From: Jed Date: Wed, 29 Jan 2025 10:23:33 +0100 Subject: [PATCH 2/6] removes mongodb logic to sort pages since we sort manually --- lib/methods/export.js | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/lib/methods/export.js b/lib/methods/export.js index fae0150..0a47d38 100644 --- a/lib/methods/export.js +++ b/lib/methods/export.js @@ -92,18 +92,6 @@ module.exports = (self) => { }) ); - for (const { - _id, title, aposMode, level, rank - } of allDocs) { - console.log('doc:', { - _id, - title, - aposMode, - level, - rank - }); - } - return self.exportFile( req, reporting, @@ -158,28 +146,20 @@ module.exports = (self) => { return []; } - /* const isPage = self.apos.instanceOf(manager, '@apostrophecms/page'); */ const { draftIds, publishedIds } = self.getAllModesIds(docsIds); const isReqDraft = req.mode === 'draft'; const docs = []; const draftReq = isReqDraft ? req : req.clone({ mode: 'draft' }); - const cursor = await manager + const draftDocs = await manager .findForEditing(draftReq, { _id: { $in: draftIds } }) - .relationships(false); - - /* if (isPage) { */ - /* cursor.sort({ */ - /* level: 1, */ - /* rank: 1 */ - /* }); */ - /* } */ - const draftDocs = await cursor.toArray(); + .relationships(false) + .toArray(); docs.push(...draftDocs); From b5ca144a03c76e1b706ccfcf622d9f31b282f289 Mon Sep 17 00:00:00 2001 From: Jed Date: Wed, 29 Jan 2025 10:56:52 +0100 Subject: [PATCH 3/6] fixes sort method to put draft before published for normal docs too --- lib/methods/export.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/methods/export.js b/lib/methods/export.js index 0a47d38..2516dcf 100644 --- a/lib/methods/export.js +++ b/lib/methods/export.js @@ -107,6 +107,12 @@ module.exports = (self) => { sortDocs(docs) { docs.sort((a, b) => { + if (a.aposMode === 'draft' && b.aposMode === 'published') { + return -1; + } + if (a.aposMode === 'published' && b.aposMode === 'draft') { + return 1; + } if (!self.apos.page.isPage(a) && !self.apos.page.isPage(b)) { return 0; } @@ -116,12 +122,6 @@ module.exports = (self) => { if (!self.apos.page.isPage(a) && self.apos.page.isPage(b)) { return 1; } - if (a.aposMode === 'draft' && b.aposMode === 'published') { - return -1; - } - if (a.aposMode === 'published' && b.aposMode === 'draft') { - return 1; - } if (a.level > b.level) { return 1; } From bdfe0ae6835ba956c8877474e23ca05f2dece51b Mon Sep 17 00:00:00 2001 From: Jed Date: Wed, 29 Jan 2025 11:13:11 +0100 Subject: [PATCH 4/6] add test and fixes some --- test/index.js | 192 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 170 insertions(+), 22 deletions(-) diff --git a/test/index.js b/test/index.js index cb2c8d6..f01ec7f 100644 --- a/test/index.js +++ b/test/index.js @@ -156,32 +156,32 @@ describe('@apostrophecms/import-export', function () { aposMode: 'draft' }, { - title: 'article2', - aposMode: 'published' + title: 'topic1', + aposMode: 'draft' }, { - title: 'article1', - aposMode: 'published' + title: 'topic3', + aposMode: 'draft' }, { - title: 'topic1', + title: 'topic2', aposMode: 'draft' }, { - title: 'topic3', - aposMode: 'draft' + title: 'article2', + aposMode: 'published' }, { - title: 'topic3', + title: 'article1', aposMode: 'published' }, { - title: 'topic1', + title: 'topic3', aposMode: 'published' }, { - title: 'topic2', - aposMode: 'draft' + title: 'topic1', + aposMode: 'published' }, { title: 'topic2', @@ -286,6 +286,10 @@ describe('@apostrophecms/import-export', function () { title: 'article1', aposMode: 'draft' }, + { + title: 'topic2', + aposMode: 'draft' + }, { title: 'article2', aposMode: 'published' @@ -294,15 +298,10 @@ describe('@apostrophecms/import-export', function () { title: 'article1', aposMode: 'published' }, - { - title: 'topic2', - aposMode: 'draft' - }, { title: 'topic2', aposMode: 'published' } - ], attachmentsLength: 1, attachmentFiles: [ `${attachmentId}-test-image.jpg` ], @@ -350,24 +349,24 @@ describe('@apostrophecms/import-export', function () { aposMode: 'draft' }, { - title: 'page1', - aposMode: 'published' + title: 'image1', + aposMode: 'draft' }, { - title: 'image1', + title: 'article2', aposMode: 'draft' }, { - title: 'image1', + title: 'page1', aposMode: 'published' }, { - title: 'article2', + title: 'image1', aposMode: 'published' }, { title: 'article2', - aposMode: 'draft' + aposMode: 'published' } ], attachmentsLength: 1, @@ -1641,5 +1640,154 @@ describe('@apostrophecms/import-export', function () { assert.equal(pages[1].aposMode, 'published'); assert.equal(pages[1].main.items[0].content, '

rich text - edited

'); }); + + it('should sort all exported documents', async function() { + const docs = [ + { + title: 'doc1', + aposMode: 'draft' + }, + + { + title: 'sub2', + aposMode: 'published', + level: 2, + rank: 1, + slug: '/' + }, + { + title: 'sub2 bis', + aposMode: 'published', + level: 2, + rank: 2, + slug: '/' + }, + + { + title: 'sub2 bis', + aposMode: 'draft', + level: 2, + rank: 2, + slug: '/' + }, + + { + title: 'sub2', + aposMode: 'draft', + level: 2, + rank: 1, + slug: '/' + }, + { + title: 'doc1', + aposMode: 'published' + }, + { + title: 'sub sub1 bis', + aposMode: 'draft', + level: 3, + rank: 2, + slug: '/' + }, + { + title: 'doc3', + aposMode: 'draft' + }, + { + title: 'sub sub1', + aposMode: 'draft', + level: 3, + rank: 1, + slug: '/' + }, + { + title: 'sub sub1', + aposMode: 'published', + level: 3, + rank: 1, + slug: '/' + }, + { + title: 'doc3', + aposMode: 'published' + }, + { + title: 'sub sub1 bis', + aposMode: 'published', + level: 3, + rank: 2, + slug: '/' + }, + { + title: 'doc2', + aposMode: 'published' + }, + { + title: 'doc2', + aposMode: 'draft' + }, + { + title: 'sub1', + aposMode: 'published', + level: 2, + rank: 1, + slug: '/' + }, + { + title: 'parent2', + aposMode: 'published', + level: 1, + rank: 2, + slug: '/' + }, + { + title: 'sub1', + aposMode: 'draft', + level: 2, + rank: 1, + slug: '/' + }, + { + title: 'parent1', + aposMode: 'published', + level: 1, + rank: 1, + slug: '/' + }, + { + title: 'parent1', + aposMode: 'draft', + level: 1, + rank: 1, + slug: '/' + }, + + { + title: 'parent2', + aposMode: 'draft', + level: 1, + rank: 2, + slug: '/' + } + ]; + importExportManager.sortDocs(docs); + + const actual = docs.map(({ title, aposMode }) => `${title}:${aposMode}`); + const expected = [ + 'parent1:draft', 'parent2:draft', + 'sub2:draft', 'sub1:draft', + 'sub2 bis:draft', 'sub sub1:draft', + 'sub sub1 bis:draft', 'doc1:draft', + 'doc3:draft', 'doc2:draft', + 'parent1:published', 'parent2:published', + 'sub2:published', 'sub1:published', + 'sub2 bis:published', 'sub sub1:published', + 'sub sub1 bis:published', 'doc1:published', + 'doc3:published', 'doc2:published' + ]; + + assert.deepEqual(actual, expected); + }); + }); }); From 14ce415959775712bc5676c3973c136047aee173 Mon Sep 17 00:00:00 2001 From: Jed Date: Thu, 30 Jan 2025 16:33:10 +0100 Subject: [PATCH 5/6] feedback: supports 5 params in export getDocs method for BC --- lib/methods/export.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/methods/export.js b/lib/methods/export.js index 2516dcf..1cbd20a 100644 --- a/lib/methods/export.js +++ b/lib/methods/export.js @@ -142,6 +142,11 @@ module.exports = (self) => { // so that we can retrieve their relationships IDs later, // and to let the manager handle permissions. async getDocs(req, docsIds, manager, reporting) { + // For BC, used to accept hasRelatedTypes as third param + if (arguments.length === 5) { + manager = arguments[3]; + reporting = arguments[4]; + } if (!docsIds.length) { return []; } From cc664dab88c6687e37bcefbc71566d26ede7f004 Mon Sep 17 00:00:00 2001 From: Jed Date: Thu, 30 Jan 2025 16:36:07 +0100 Subject: [PATCH 6/6] consistency --- lib/handlers.js | 2 +- lib/methods/export.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/handlers.js b/lib/handlers.js index 7472f94..1f6e377 100644 --- a/lib/handlers.js +++ b/lib/handlers.js @@ -1,5 +1,5 @@ -module.exports = (self) => { +module.exports = self => { return { 'apostrophe:modulesRegistered': { setContextOperations() { diff --git a/lib/methods/export.js b/lib/methods/export.js index 1cbd20a..9a13c20 100644 --- a/lib/methods/export.js +++ b/lib/methods/export.js @@ -7,7 +7,7 @@ const { uniqBy, uniqueId } = require('lodash'); const MAX_RECURSION = 10; -module.exports = (self) => { +module.exports = self => { return { async export(req, manager, reporting = null) { if (!req.user) {