Skip to content

Commit 652913f

Browse files
authored
feat: add support for locale based publishing [TOL-2810] (#1465)
* chore: bump contentful-management [] * feat: support locale based publishing [TOL-2810] * chore: adjust linting rule as it breaks without context * chore: handle floating promise [] * chore: add missing property to validator []
1 parent 5a4086f commit 652913f

24 files changed

+295
-38
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,10 @@ The transform function is expected to return an object with the desired target f
288288
- **`transformEntryForLocale : function (fields, locale, {id}): object`** _(required)_ – Transformation function to be applied.
289289
- `fields` is an object containing each of the `from` fields. Each field will contain their current localized values (i.e. `fields == {myField: {'en-US': 'my field value'}}`)
290290
- `locale` one of the locales in the space being transformed
291-
- `id` id of the current entry in scope
291+
- `id` id of the current entry in scope
292292
The return value must be an object with the same keys as specified in `to`. Their values will be written to the respective entry fields for the current locale (i.e. `{nameField: 'myNewValue'}`). If it returns `undefined`, this the values for this locale on the entry will be left untouched.
293293
- **`shouldPublish : bool | 'preserve'`** _(optional)_ – Flag that specifies publishing of target entries, `preserve` will keep current states of the source entries (default `'preserve'`)
294+
- **`useLocaleBasedPublishing: bool`** _(optional)_ - Flag to use locale based publishing for the target entries. (default: `false`)
294295
295296
##### `transformEntries` Example
296297
Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import Migration from 'contentful-migration'
22

3-
export = function (migration: Migration) {
3+
export default function typeScriptMigration(migration: Migration) {
44
const dog = migration.createContentType('dog', {
55
name: 'Dog'
66
})
77

88
const name = dog.createField('name')
9-
name.name('Name')
10-
.type('Symbol')
11-
.required(true)
12-
}
9+
name.name('Name').type('Symbol').required(true)
10+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// In this example, we fill the "byLine" field with the combined values of 2 other fields.
2+
// It will skip the "de-DE" locale and then automatically publish the entry with locale based publishing.
3+
module.exports = function (migration) {
4+
migration.transformEntries({
5+
contentType: 'newsArticle',
6+
from: ['author', 'authorCity'],
7+
to: ['byline'],
8+
shouldPublish: 'preserve',
9+
useLocaleBasedPublishing: true,
10+
transformEntryForLocale: function (fromFields, currentLocale) {
11+
if (currentLocale === 'de-DE') {
12+
return
13+
}
14+
const newByline = `${fromFields.author[currentLocale]} ${fromFields.authorCity[currentLocale]}`
15+
return { byline: newByline }
16+
}
17+
})
18+
}

index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,8 @@ export interface ITransformEntriesConfig {
492492
) => any
493493
/** (optional) – If true, the transformed entries will be published. If false, they will remain in draft state. When the value is set to "preserve" items will be published only if the original entry was published as well (default true) */
494494
shouldPublish?: boolean | 'preserve'
495+
/** (optional) – If true, the transformed entries will be published with locale based publishing. If false, they will remain in draft state. When the value is set to "preserve" items will be published only if the original entry was published in this locale as well (default false) */
496+
useLocaleBasedPublishing?: boolean
495497
}
496498

497499
export interface ITransformEntriesToTypeConfig {

package-lock.json

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
"callsites": "^3.1.0",
5757
"cardinal": "^2.1.1",
5858
"chalk": "^4.0.0",
59-
"contentful-management": "^11.40.3",
59+
"contentful-management": "^11.47.1",
6060
"didyoumean2": "^5.0.0",
6161
"https-proxy-agent": "^5.0.0",
6262
"inquirer": "^8.1.2",

src/lib/action/entry-derive.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class EntryDeriveAction extends APIAction {
2020
) => Promise<any>
2121
private identityKey: (fromFields: any) => Promise<string>
2222
private shouldPublish: boolean | 'preserve'
23+
private useLocaleBasedPublishing: boolean
2324

2425
constructor(contentTypeId: string, entryDerivation: EntryDerive) {
2526
super()
@@ -32,6 +33,17 @@ class EntryDeriveAction extends APIAction {
3233
this.shouldPublish = isDefined(entryDerivation.shouldPublish)
3334
? entryDerivation.shouldPublish
3435
: true
36+
this.useLocaleBasedPublishing = isDefined(entryDerivation.useLocaleBasedPublishing)
37+
? entryDerivation.useLocaleBasedPublishing
38+
: false
39+
}
40+
41+
private async publishEntry(api: OfflineAPI, entry: Entry, locales: string[]) {
42+
if (this.useLocaleBasedPublishing) {
43+
await api.localeBasedPublishEntry(entry.id, locales)
44+
} else {
45+
await api.publishEntry(entry.id)
46+
}
3547
}
3648

3749
async applyTo(api: OfflineAPI) {
@@ -101,8 +113,8 @@ class EntryDeriveAction extends APIAction {
101113
}
102114
}
103115
await api.saveEntry(targetEntry.id)
104-
if (shouldPublishLocalChanges(this.shouldPublish, entry)) {
105-
await api.publishEntry(targetEntry.id)
116+
if (shouldPublishLocalChanges(this.shouldPublish, entry, this.useLocaleBasedPublishing)) {
117+
await this.publishEntry(api, targetEntry, locales)
106118
}
107119
}
108120
const field = sourceContentType.fields.getField(this.referenceField)
@@ -118,8 +130,8 @@ class EntryDeriveAction extends APIAction {
118130
}
119131

120132
await api.saveEntry(entry.id)
121-
if (shouldPublishLocalChanges(this.shouldPublish, entry)) {
122-
await api.publishEntry(entry.id)
133+
if (shouldPublishLocalChanges(this.shouldPublish, entry, this.useLocaleBasedPublishing)) {
134+
await this.publishEntry(api, entry, locales)
123135
}
124136
}
125137
}

src/lib/action/entry-transform.ts

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,19 +9,21 @@ class EntryTransformAction extends APIAction {
99
private fromFields: string[]
1010
private transformEntryForLocale: Function
1111
private shouldPublish: boolean | 'preserve'
12-
12+
private useLocaleBasedPublishing: boolean
1313
constructor(
1414
contentTypeId: string,
1515
fromFields: string[],
1616
transformation: Function,
17-
shouldPublish: boolean | 'preserve' = 'preserve'
17+
shouldPublish: boolean | 'preserve' = 'preserve',
18+
useLocaleBasedPublishing: boolean = false
1819
) {
1920
super()
2021
this.contentTypeId = contentTypeId
2122
this.fromFields = fromFields
2223
// this.toFields = toFields
2324
this.transformEntryForLocale = transformation
2425
this.shouldPublish = shouldPublish
26+
this.useLocaleBasedPublishing = useLocaleBasedPublishing
2527
}
2628

2729
async applyTo(api: OfflineAPI) {
@@ -57,8 +59,18 @@ class EntryTransformAction extends APIAction {
5759
}
5860
if (changesForThisEntry) {
5961
await api.saveEntry(entry.id)
60-
if (shouldPublishLocalChanges(this.shouldPublish, entry)) {
61-
await api.publishEntry(entry.id)
62+
if (shouldPublishLocalChanges(this.shouldPublish, entry, this.useLocaleBasedPublishing)) {
63+
if (this.useLocaleBasedPublishing) {
64+
const localesToPublish =
65+
this.shouldPublish === 'preserve'
66+
? Object.entries(entry.fieldStatus['*'])
67+
.filter(([, status]) => status === 'published')
68+
.map(([locale]) => locale)
69+
: locales
70+
await api.localeBasedPublishEntry(entry.id, localesToPublish)
71+
} else {
72+
await api.publishEntry(entry.id)
73+
}
6274
}
6375
}
6476
}

src/lib/entities/entry.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { cloneDeep } from 'lodash'
22
import APIEntry from '../interfaces/api-entry'
33
import APITagLink from '../interfaces/api-tag-link'
44
import isDefined from '../utils/is-defined'
5+
import type { EntityMetaSysProps } from 'contentful-management'
56

67
class Entry {
78
private _id: string
@@ -10,6 +11,7 @@ class Entry {
1011
private _fields: object
1112
private _publishedVersion?: number
1213
private _tags?: APITagLink[]
14+
private _fieldStatus?: EntityMetaSysProps['fieldStatus']
1315

1416
constructor(entry: APIEntry) {
1517
this._id = entry.sys.id
@@ -18,6 +20,7 @@ class Entry {
1820
this._contentTypeId = entry.sys.contentType.sys.id
1921
this._publishedVersion = entry.sys.publishedVersion
2022
this._tags = entry.metadata?.tags
23+
this._fieldStatus = entry.sys.fieldStatus
2124
}
2225

2326
get id() {
@@ -86,6 +89,14 @@ class Entry {
8689
this._tags = tags
8790
}
8891

92+
get fieldStatus() {
93+
return this._fieldStatus
94+
}
95+
96+
set fieldStatus(fieldStatus: EntityMetaSysProps['fieldStatus']) {
97+
this._fieldStatus = fieldStatus
98+
}
99+
89100
toApiEntry(): APIEntry {
90101
const sys = {
91102
id: this.id,
@@ -97,7 +108,8 @@ class Entry {
97108
linkType: 'ContentType',
98109
id: this.contentTypeId
99110
}
100-
}
111+
},
112+
fieldStatus: cloneDeep(this.fieldStatus)
101113
}
102114

103115
let payload: APIEntry

src/lib/intent-validator/content-transform.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ class ContentTransformIntentValidator extends SchemaValidator {
2323
from: Joi.array().items(Joi.string()).required(),
2424
to: Joi.array().items(Joi.string()).required(),
2525
transformEntryForLocale: Joi.func().required(),
26-
shouldPublish: Joi.alternatives().try(Joi.boolean(), Joi.string().valid('preserve'))
26+
shouldPublish: Joi.alternatives().try(Joi.boolean(), Joi.string().valid('preserve')),
27+
useLocaleBasedPublishing: Joi.boolean().optional()
2728
}
2829
}
2930
}

0 commit comments

Comments
 (0)