@stackbit/cms-contentful 0.4.45-staging.2 → 0.4.46-feature-document-statuses.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -27,7 +27,8 @@ import {
27
27
  ScheduledActionProps,
28
28
  CursorPaginatedCollectionProp,
29
29
  ReleasePayload,
30
- ReleaseQueryOptions
30
+ ReleaseQueryOptions,
31
+ BulkActionUnpublishPayload
31
32
  } from 'contentful-management';
32
33
  import { Logger } from '@stackbit/types';
33
34
  import { convertScheduledAction, findScheduleForRelease } from './contentful-scheduled-actions-converter';
@@ -77,6 +78,14 @@ export async function unpublishEntry(client: PlainClientAPI, entryId: string) {
77
78
  return client.entry.unpublish({ entryId });
78
79
  }
79
80
 
81
+ export async function archiveEntry(client: PlainClientAPI, entryId: string) {
82
+ return client.entry.archive({ entryId });
83
+ }
84
+
85
+ export async function unarchiveEntry(client: PlainClientAPI, entryId: string) {
86
+ return client.entry.unarchive({ entryId });
87
+ }
88
+
80
89
  export async function deleteEntry(client: PlainClientAPI, entryId: string) {
81
90
  return client.entry.delete({ entryId });
82
91
  }
@@ -113,6 +122,14 @@ export async function createPublishBulkAction(
113
122
  return client.bulkAction.publish(options, data);
114
123
  }
115
124
 
125
+ export async function createUnpublishBulkAction(
126
+ client: PlainClientAPI,
127
+ options: GetSpaceEnvironmentParams,
128
+ data: BulkActionUnpublishPayload
129
+ ): Promise<BulkActionProps<BulkActionUnpublishPayload>> {
130
+ return client.bulkAction.unpublish(options, data);
131
+ }
132
+
116
133
  export async function createWebhook(client: PlainClientAPI, data: CreateWebhooksProps) {
117
134
  return client.webhook.create({}, data);
118
135
  }
@@ -18,7 +18,7 @@ import {
18
18
  SnapshotProps
19
19
  } from 'contentful-management';
20
20
 
21
- import type { DocumentVersion, DocumentVersionWithDocument, FieldList, FieldSpecificProps, Model, Schema } from '@stackbit/types';
21
+ import { DocumentVersion, DocumentVersionWithDocument, FieldList, FieldSpecificProps, Model, Schema } from '@stackbit/types';
22
22
  import type * as ContentSourceTypes from '@stackbit/types';
23
23
  import * as stackbitUtils from '@stackbit/types';
24
24
  import { TaskQueue } from '@stackbit/utils';
@@ -59,7 +59,10 @@ import {
59
59
  getScheduledAction,
60
60
  fetchScheduleById,
61
61
  fetchEntityVersions,
62
- fetchEntityVersion
62
+ fetchEntityVersion,
63
+ createUnpublishBulkAction,
64
+ archiveEntry,
65
+ unarchiveEntry
63
66
  } from './contentful-api-client';
64
67
  import { convertSchema } from './contentful-schema-converter';
65
68
  import {
@@ -809,6 +812,88 @@ export class ContentfulContentSource implements ContentSourceTypes.ContentSource
809
812
  );
810
813
  }
811
814
 
815
+ async unpublishDocuments({
816
+ documents,
817
+ assets,
818
+ userContext
819
+ }: {
820
+ documents: ContextualDocument[];
821
+ assets: ContextualAsset[];
822
+ userContext?: UserContext;
823
+ }): Promise<void> {
824
+ const apiClient = this.getPlainApiClientForUser({ userContext });
825
+
826
+ const entities = [...documents, ...assets];
827
+ // Max active bulk actions per space is limited to 5.
828
+ // Max of 200 items per bulk action.
829
+ const taskQueue = new TaskQueue({ limit: 5 });
830
+ const linkChunks: Link<'Entry' | 'Asset'>[][] = _.chunk(
831
+ entities.map((entity) => ({
832
+ sys: {
833
+ type: 'Link',
834
+ id: entity.id,
835
+ linkType: entity.type === 'document' ? 'Entry' : 'Asset'
836
+ }
837
+ })),
838
+ 200
839
+ );
840
+
841
+ await Promise.all(
842
+ linkChunks.map((links) => {
843
+ return taskQueue.addTask(async (): Promise<void> => {
844
+ const bulkActionOptions = {
845
+ spaceId: this.spaceId,
846
+ environmentId: this.environment
847
+ };
848
+ const bulkActionCreateResult = await createUnpublishBulkAction(apiClient, bulkActionOptions, {
849
+ entities: {
850
+ sys: { type: 'Array' },
851
+ items: links
852
+ }
853
+ });
854
+ await waitBulkActionToComplete(bulkActionCreateResult, apiClient, bulkActionOptions);
855
+ });
856
+ })
857
+ );
858
+ }
859
+
860
+ async archiveDocument({ document, userContext }: { document: ContextualDocument; userContext?: UserContext }): Promise<void> {
861
+ this.logger.debug('archiveDocument');
862
+ const documentId = document.id;
863
+ try {
864
+ const entry = await fetchEntryById(this.plainClient, documentId);
865
+ const apiClient = this.getPlainApiClientForUser({ userContext });
866
+ // Contentful won't let us archive a published entry, so if the entry is
867
+ // published we must unpublish it first.
868
+ if (_.get(entry, 'sys.publishedVersion')) {
869
+ await unpublishEntry(apiClient, documentId);
870
+ }
871
+
872
+ await archiveEntry(apiClient, documentId);
873
+ } catch (err) {
874
+ this.logger.error('Contentful: Failed to archive object', {
875
+ documentId: documentId,
876
+ error: err
877
+ });
878
+ throw err;
879
+ }
880
+ }
881
+
882
+ async unarchiveDocument({ document, userContext }: { document: ContextualDocument; userContext?: UserContext }): Promise<void> {
883
+ this.logger.debug('unarchiveDocument');
884
+ const documentId = document.id;
885
+ try {
886
+ const apiClient = this.getPlainApiClientForUser({ userContext });
887
+ await unarchiveEntry(apiClient, documentId);
888
+ } catch (err) {
889
+ this.logger.error('Contentful: Failed to archive object', {
890
+ documentId: documentId,
891
+ error: err
892
+ });
893
+ throw err;
894
+ }
895
+ }
896
+
812
897
  async onWebhook({ data, headers }: { data: unknown; headers: Record<string, string> }) {
813
898
  const topic = headers['x-contentful-topic'] || '';
814
899
  const didContentTypeChange = topic.startsWith('ContentManagement.ContentType.');
@@ -234,9 +234,12 @@ function commonFields(
234
234
  updatedBy?: string[];
235
235
  } {
236
236
  // currently we only expose isChanged that is treated as isDraft and isChanged because in Sanity there is no way to tell the difference
237
- const isDraft = !entity.sys?.publishedVersion && !entity.sys?.archivedVersion;
237
+ const isArchived = !!entity.sys?.archivedVersion;
238
+ const isPublished = !!entity.sys?.publishedVersion;
239
+ // unpublished and deleted appear the same in contentful's API response.
238
240
  const isChanged = !!entity.sys?.publishedVersion && entity.sys?.version >= entity.sys?.publishedVersion + 2;
239
- const status = isDraft ? 'added' : isChanged ? 'modified' : 'published';
241
+ const status = isChanged ? 'modified' : isArchived ? 'archived' : isPublished ? 'published' : 'added'; // draft is the remaining possible status due to isArchived and isPublished being false.
242
+
240
243
  const createdByEmail = getUserEmailById(entity.sys?.createdBy?.sys?.id, userMap);
241
244
  const updatedByEmail = getUserEmailById(entity.sys?.updatedBy?.sys?.id, userMap);
242
245
  const updatedByList = updatedByEmail ? [updatedByEmail] : [];