Skip to content
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
### Adds

* Translation strings added for the layout- and layout-column-widgets.
* Adds `@apostrophecms/doc:get-apos-doc-id` and `@apostrophecms/doc:set-apos-doc-id` tasks.
* When switching locale from the doc editor, ask if the user wants to localize the current document in the target locale or want to start a blank document.

### Changes
Expand Down
128 changes: 126 additions & 2 deletions modules/@apostrophecms/doc/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ const _ = require('lodash');
const { createId } = require('@paralleldrive/cuid2');
const { SemanticAttributes } = require('@opentelemetry/semantic-conventions');
const { klona } = require('klona');
const legacyMigrations = require('./lib/legacy-migrations.js');
const migrations = require('./lib/migrations.js');

// This module is responsible for managing all of the documents (apostrophe
// "docs") in the `aposDocs` mongodb collection.
Expand Down Expand Up @@ -1843,8 +1845,130 @@ module.exports = {
return existing?.aposDocId || self.apos.util.generateId();
},

...require('./lib/legacy-migrations')(self),
...require('./lib/migrations')(self)
async getAposDocId({
_id, slug, locale
}) {
if (!_id && !slug) {
throw self.apos.error('invalid', 'Either _id or slug must be provided');
}
if (!locale) {
throw self.apos.error('invalid', 'Missing locale');
}

// const req = self.apos.task.getReq({ mode: 'draft', locale });
const aposLocale = new RegExp(`^${self.apos.util.regExpQuote(locale)}:`);
const criteria = _id

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One last thing, sorry... since the _id parameter has to be a full _id, which already contains the locale, there's no need to make locale mandatory or even part of the query when _id is present.

(Technically we don't need to make a query at all when _id is the argument, because _id already contains aposDocId, but I like the idea of making the query because it validates that the document actually does exist.)

? {
_id,
aposLocale
}
: {
slug,
aposLocale
};

const doc = await self.apos.doc.db
.findOne(criteria, { projection: { aposDocId: 1 } });
if (!doc || !doc.aposDocId) {
throw self.apos.error('notfound');
}

return doc.aposDocId;
},
async setAposDocId({
newId, oldId, slug, locale
}) {
if (!newId) {
throw self.apos.error('invalid', 'Missing newId');
}
if (!oldId && !slug) {
throw self.apos.error('invalid', 'Either oldId or slug must be provided');
}
if (!locale) {
throw self.apos.error('invalid', 'Missing locale');
}

const originalId = (slug && !oldId)
? await self.getAposDocId({
slug,
locale
})
: oldId;

const modes = [ 'previous', 'draft', 'published' ];
const pairs = modes.map(mode =>
[
`${originalId}:${locale}:${mode}`,
`${newId}:${locale}:${mode}`
]
);

// Filter non existing from _id from the list
const existing = (
await self.apos.doc.db
.find(
{ _id: { $in: pairs.map(([ from ]) => from) } },
{ projection: { _id: 1 } }
)
.toArray()
)
.map(({ _id }) => _id);
const { renamed } = await self.changeDocIds(
pairs.filter(([ from ]) => existing.includes(from)),
{ keep: false }
);

return {
oldId: originalId,
newId,
locale,
renamed
};
},

...legacyMigrations(self),
...migrations(self)
};
},
tasks(self) {
return {
'get-apos-doc-id': {
usage: 'Retrieve the aposDocId from the _id or slug, and the locale. Usage: "node app.js @apostrophecms/doc:get-apos-doc-id --_id=pfh0haxfpzowht3oi213cqos:fr:draft --locale=fr" or "node app.js @apostrophecms/doc:get-apos-doc-id --slug=test --locale=fr"',
task: async (argv) => {
const {
_id, slug, locale
} = argv;

const aposDocId = await self.getAposDocId({
_id,
slug,
locale
});

self.apos.util.info(aposDocId);

return aposDocId;
}
},
'set-apos-doc-id': {
usage: 'Change the aposDocId of an existing document. You need the new aposDocId (new-id), the old aposDocId (old-id) or the slug, and the locale. Usage: "node app.js @apostrophecms/doc:set-apos-doc-id --new-id=tz4a98xxat96iws9zmbrgj3a --old-id=pfh0haxfpzowht3oi213cqos --locale=fr" or "node app.js @apostrophecms/doc:set-apos-doc-id --new-id=tz4a98xxat96iws9zmbrgj3a --slug=test --locale=fr"',
task: async (argv) => {
const {
'new-id': newId, 'old-id': oldId, slug, locale
} = argv;

const result = await self.setAposDocId({
newId,
oldId,
slug,
locale
});

self.apos.util.info(`"${result.oldId}" has been changed to "${result.newId}" for locale "${result.locale}", ${result.renamed} documents changed.`);

return result;
}
}
};
}
};
Loading