-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PRO-6561: export documents which are related via rich text widget "internal pages" links and inline images #98
base: main
Are you sure you want to change the base?
Changes from 6 commits
dd0fe7c
8b0d4ab
4a274b9
62822a8
c331738
524b5fe
6973fb1
7c43d5a
6b9794f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -35,7 +35,6 @@ module.exports = self => { | |
|
||
const docs = (await self.getDocs(req, ids, hasRelatedTypes, manager, reporting)) | ||
.map((doc) => self.apos.util.clonePermanent(doc)); | ||
|
||
if (!hasRelatedTypes) { | ||
return self.exportFile( | ||
req, | ||
|
@@ -210,14 +209,23 @@ module.exports = self => { | |
mode = doc.aposMode || req.mode | ||
}) { | ||
recursion++; | ||
if ((doc.type === '@apostrophecms/rich-text') && (type === 'relationship')) { | ||
await self.getRelatedDocsFromRichTextWidget(req, { | ||
doc, | ||
relatedTypes, | ||
storedData, | ||
recursion, | ||
mode | ||
}); | ||
} | ||
for (const field of schema) { | ||
const fieldValue = doc[field.name]; | ||
const shouldRecurse = recursion <= MAX_RECURSION; | ||
|
||
if (!field.withType && !fieldValue) { | ||
continue; | ||
} | ||
if (field.withType && relatedTypes && !relatedTypes.includes(field.withType)) { | ||
if (field.withType && relatedTypes && !relatedTypesIncludes(field.withType)) { | ||
continue; | ||
} | ||
if (field.withType && !self.canExport(req, field.withType)) { | ||
|
@@ -282,6 +290,70 @@ module.exports = self => { | |
}); | ||
} | ||
} | ||
|
||
function relatedTypesIncludes(name) { | ||
name = normalizeName(name); | ||
return relatedTypes.includes(name); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it's not a big deal here, but if we can take the habit to avoid reassigning stuff like params it would be nice. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
}, | ||
|
||
async getRelatedDocsFromRichTextWidget(req, { | ||
doc, | ||
relatedTypes, | ||
storedData, | ||
recursion, | ||
mode | ||
}) { | ||
const linkedDocs = await self.apos.doc.db.find({ | ||
aposDocId: { | ||
$in: doc.permalinkIds | ||
} | ||
}).project({ | ||
type: 1, | ||
aposDocId: 1, | ||
slug: 1 | ||
}).toArray(); | ||
const linkedIdsByType = new Map(); | ||
for (const linkedDoc of linkedDocs) { | ||
// Normalization is a little different here because these | ||
// are individual pages or pieces | ||
const name = linkedDoc.slug.startsWith('/') ? '@apostrophecms/any-page-type' : linkedDoc.type; | ||
const linkedIds = linkedIdsByType.get(name) || new Set(); | ||
linkedIds.add(linkedDoc.aposDocId); | ||
if (linkedIds.size === 1) { | ||
linkedIdsByType.set(name, linkedIds); | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be clearer to check if key exist in map using map has method.: for (const linkedDoc of linkedDocs) {
// Normalization is a little different here because these
// are individual pages or pieces
const docType = linkedDoc.slug.startsWith('/')
? '@apostrophecms/any-page-type'
: linkedDoc.type;
const isTypeStored = linkedIdsByType.has(docType);
const linkedIds = isTypeStored ? linkedIdsByType.get(docType) : new Set();
linkedIds.add(linkedDoc.aposDocId);
if (!isTypeStored) {
linkedIdsByType.set(name, linkedIds);
}
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
} | ||
if (doc.imageIds?.length > 0) { | ||
linkedIdsByType.set('@apostrophecms/image', new Set(doc.imageIds)); | ||
} | ||
const virtualDoc = { | ||
type: '@apostrophecms/rich-text_related' | ||
}; | ||
const virtualSchema = []; | ||
for (const [ linkedType, linkedIds ] of linkedIdsByType.entries()) { | ||
const baseName = self.apos.util.slugify(linkedType); | ||
const fieldName = `_${baseName}`; | ||
const idsStorage = `${baseName}Ids`; | ||
virtualSchema.push({ | ||
name: fieldName, | ||
type: 'relationship', | ||
withType: linkedType, | ||
idsStorage | ||
}); | ||
const ids = [ ...linkedIds.values() ]; | ||
virtualDoc[idsStorage] = ids; | ||
virtualDoc[fieldName] = ids.map(id => ({ aposDocId: id })); | ||
} | ||
await self.getRelatedDocsFromSchema(req, { | ||
doc: virtualDoc, | ||
schema: virtualSchema, | ||
relatedTypes, | ||
storedData, | ||
type: 'relationship', | ||
recursion, | ||
mode | ||
}); | ||
}, | ||
|
||
async handleRelatedField(req, { | ||
|
@@ -478,35 +550,76 @@ module.exports = self => { | |
}, | ||
|
||
getRelatedTypes(req, schema = [], related = []) { | ||
return findSchemaRelatedTypes(schema, related); | ||
|
||
findSchemaRelatedTypes(schema, related); | ||
return related; | ||
function findSchemaRelatedTypes(schema, related, recursions = 0) { | ||
recursions++; | ||
if (recursions >= MAX_RECURSION) { | ||
return related; | ||
return; | ||
} | ||
for (const field of schema) { | ||
if ( | ||
field.type === 'relationship' && | ||
self.canExport(req, field.withType) && | ||
!related.includes(field.withType) | ||
) { | ||
related.push(field.withType); | ||
pushRelated(related, field.withType); | ||
const relatedManager = self.apos.doc.getManager(field.withType); | ||
findSchemaRelatedTypes(relatedManager.schema, related, recursions); | ||
} else if ([ 'array', 'object' ].includes(field.type)) { | ||
findSchemaRelatedTypes(field.schema, related, recursions); | ||
} else if (field.type === 'area') { | ||
const widgets = self.apos.area.getWidgets(field.options); | ||
for (const widget of Object.keys(widgets)) { | ||
const { schema = [] } = self.apos.modules[`${widget}-widget`]; | ||
for (const [ widget, options ] of Object.entries(widgets)) { | ||
const schema = self.apos.area.getWidgetManager(widget).schema; | ||
if (widget === '@apostrophecms/rich-text') { | ||
self.getRelatedTypesFromRichTextWidget(req, { | ||
options, | ||
related | ||
}); | ||
} | ||
findSchemaRelatedTypes(schema, related, recursions); | ||
} | ||
} | ||
} | ||
|
||
return related; | ||
} | ||
}, | ||
// Does not currently utilize req, but it could be relevant in overrides and is | ||
// always the first argument by convention, so it is included in the signature | ||
getRelatedTypesFromRichTextWidget(req, { | ||
options, | ||
related | ||
}) { | ||
const manager = self.apos.modules['@apostrophecms/rich-text-widget']; | ||
const rteOptions = { | ||
...manager.options.defaultOptions, | ||
...options | ||
}; | ||
if ((rteOptions.toolbar?.includes('image') || rteOptions.insert?.includes('image')) && !related.includes('@apostrophecms/image')) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please indentation: if (
(rteOptions.toolbar?.includes('image') || rteOptions.insert?.includes('image')) &&
!related.includes('@apostrophecms/image')
) { There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
pushRelated(related, '@apostrophecms/image'); | ||
} | ||
if (rteOptions.toolbar?.includes('link')) { | ||
for (const name of manager.linkFields.linkTo.choices.map(choice => choice.value)) { | ||
if (self.apos.doc.getManager(name) && !related.includes(name)) { | ||
pushRelated(related, name); | ||
} | ||
} | ||
} | ||
} | ||
}; | ||
}; | ||
|
||
function normalizeName(name) { | ||
if (name === '@apostrophecms/page') { | ||
return '@apostrophecms/any-page-type'; | ||
} else { | ||
return name; | ||
} | ||
} | ||
|
||
function pushRelated(related, name) { | ||
name = normalizeName(name); | ||
if (!related.includes(name)) { | ||
related.push(name); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that in that case
schema
will always be an empty array?Maybe we can just return this function
getRelatedDocsFromRichTextWidget
here since there nothing else to do with it?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm leaving this in place because at least in A2 we eventually created situations where the rich text widget also had a conventional schema. It's at least possible so this is a little more future proof.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok makes sense then