@strapi/content-releases 0.0.0-next.73143c28059b343ba62d98c29672ab114562fbbc → 0.0.0-next.78ea7925e0dad75936ae2e937a041a0666e3d65a

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.
@@ -179,7 +179,7 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
179
179
  }
180
180
  });
181
181
  await mapAsync(actions, async (action) => {
182
- if (action.entry) {
182
+ if (action.entry && action.release) {
183
183
  const populatedEntry = await getPopulatedEntry(contentTypeUID, action.entry.id, {
184
184
  strapi
185
185
  });
@@ -207,12 +207,57 @@ async function revalidateChangedContentTypes({ oldContentTypes, contentTypes: co
207
207
  });
208
208
  }
209
209
  }
210
+ async function disableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
211
+ if (!oldContentTypes) {
212
+ return;
213
+ }
214
+ for (const uid in contentTypes2) {
215
+ if (!oldContentTypes[uid]) {
216
+ continue;
217
+ }
218
+ const oldContentType = oldContentTypes[uid];
219
+ const contentType = contentTypes2[uid];
220
+ const i18nPlugin = strapi.plugin("i18n");
221
+ const { isLocalizedContentType } = i18nPlugin.service("content-types");
222
+ if (isLocalizedContentType(oldContentType) && !isLocalizedContentType(contentType)) {
223
+ await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
224
+ locale: null
225
+ }).where({ contentType: uid }).execute();
226
+ }
227
+ }
228
+ }
229
+ async function enableContentTypeLocalized({ oldContentTypes, contentTypes: contentTypes2 }) {
230
+ if (!oldContentTypes) {
231
+ return;
232
+ }
233
+ for (const uid in contentTypes2) {
234
+ if (!oldContentTypes[uid]) {
235
+ continue;
236
+ }
237
+ const oldContentType = oldContentTypes[uid];
238
+ const contentType = contentTypes2[uid];
239
+ const i18nPlugin = strapi.plugin("i18n");
240
+ const { isLocalizedContentType } = i18nPlugin.service("content-types");
241
+ const { getDefaultLocale } = i18nPlugin.service("locales");
242
+ if (!isLocalizedContentType(oldContentType) && isLocalizedContentType(contentType)) {
243
+ const defaultLocale = await getDefaultLocale();
244
+ await strapi.db.queryBuilder(RELEASE_ACTION_MODEL_UID).update({
245
+ locale: defaultLocale
246
+ }).where({ contentType: uid }).execute();
247
+ }
248
+ }
249
+ }
210
250
  const { features: features$2 } = require("@strapi/strapi/dist/utils/ee");
211
251
  const register = async ({ strapi: strapi2 }) => {
212
252
  if (features$2.isEnabled("cms-content-releases")) {
213
253
  await strapi2.admin.services.permission.actionProvider.registerMany(ACTIONS);
214
- strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish);
215
- strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
254
+ strapi2.hook("strapi::content-types.beforeSync").register(deleteActionsOnDisableDraftAndPublish).register(disableContentTypeLocalized);
255
+ strapi2.hook("strapi::content-types.afterSync").register(deleteActionsOnDeleteContentType).register(enableContentTypeLocalized).register(revalidateChangedContentTypes).register(migrateIsValidAndStatusReleases);
256
+ }
257
+ if (strapi2.plugin("graphql")) {
258
+ const graphqlExtensionService = strapi2.plugin("graphql").service("extension");
259
+ graphqlExtensionService.shadowCRUD(RELEASE_MODEL_UID).disable();
260
+ graphqlExtensionService.shadowCRUD(RELEASE_ACTION_MODEL_UID).disable();
216
261
  }
217
262
  };
218
263
  const { features: features$1 } = require("@strapi/strapi/dist/utils/ee");
@@ -483,6 +528,94 @@ const createReleaseService = ({ strapi: strapi2 }) => {
483
528
  release: release2
484
529
  });
485
530
  };
531
+ const publishSingleTypeAction = async (uid, actionType, entryId) => {
532
+ const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
533
+ const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
534
+ const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
535
+ const entry = await strapi2.entityService.findOne(uid, entryId, { populate });
536
+ try {
537
+ if (actionType === "publish") {
538
+ await entityManagerService.publish(entry, uid);
539
+ } else {
540
+ await entityManagerService.unpublish(entry, uid);
541
+ }
542
+ } catch (error) {
543
+ if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft"))
544
+ ;
545
+ else {
546
+ throw error;
547
+ }
548
+ }
549
+ };
550
+ const publishCollectionTypeAction = async (uid, entriesToPublishIds, entriestoUnpublishIds) => {
551
+ const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
552
+ const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
553
+ const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
554
+ const entriesToPublish = await strapi2.entityService.findMany(uid, {
555
+ filters: {
556
+ id: {
557
+ $in: entriesToPublishIds
558
+ }
559
+ },
560
+ populate
561
+ });
562
+ const entriesToUnpublish = await strapi2.entityService.findMany(uid, {
563
+ filters: {
564
+ id: {
565
+ $in: entriestoUnpublishIds
566
+ }
567
+ },
568
+ populate
569
+ });
570
+ if (entriesToPublish.length > 0) {
571
+ await entityManagerService.publishMany(entriesToPublish, uid);
572
+ }
573
+ if (entriesToUnpublish.length > 0) {
574
+ await entityManagerService.unpublishMany(entriesToUnpublish, uid);
575
+ }
576
+ };
577
+ const getFormattedActions = async (releaseId) => {
578
+ const actions = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).findMany({
579
+ where: {
580
+ release: {
581
+ id: releaseId
582
+ }
583
+ },
584
+ populate: {
585
+ entry: {
586
+ fields: ["id"]
587
+ }
588
+ }
589
+ });
590
+ if (actions.length === 0) {
591
+ throw new errors.ValidationError("No entries to publish");
592
+ }
593
+ const collectionTypeActions = {};
594
+ const singleTypeActions = [];
595
+ for (const action of actions) {
596
+ const contentTypeUid = action.contentType;
597
+ if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
598
+ if (!collectionTypeActions[contentTypeUid]) {
599
+ collectionTypeActions[contentTypeUid] = {
600
+ entriesToPublishIds: [],
601
+ entriesToUnpublishIds: []
602
+ };
603
+ }
604
+ if (action.type === "publish") {
605
+ collectionTypeActions[contentTypeUid].entriesToPublishIds.push(action.entry.id);
606
+ } else {
607
+ collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
608
+ }
609
+ } else {
610
+ singleTypeActions.push({
611
+ uid: contentTypeUid,
612
+ action: action.type,
613
+ id: action.entry.id
614
+ });
615
+ }
616
+ }
617
+ return { collectionTypeActions, singleTypeActions };
618
+ };
486
619
  return {
487
620
  async create(releaseData, { user }) {
488
621
  const releaseWithCreatorFields = await setCreatorFields({ user })(releaseData);
@@ -807,145 +940,75 @@ const createReleaseService = ({ strapi: strapi2 }) => {
807
940
  return release2;
808
941
  },
809
942
  async publish(releaseId) {
810
- try {
811
- const releaseWithPopulatedActionEntries = await strapi2.entityService.findOne(
812
- RELEASE_MODEL_UID,
813
- releaseId,
814
- {
815
- populate: {
816
- actions: {
817
- populate: {
818
- entry: {
819
- fields: ["id"]
820
- }
821
- }
822
- }
823
- }
824
- }
825
- );
826
- if (!releaseWithPopulatedActionEntries) {
943
+ const {
944
+ release: release2,
945
+ error
946
+ } = await strapi2.db.transaction(async ({ trx }) => {
947
+ const lockedRelease = await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).select(["id", "name", "releasedAt", "status"]).first().transacting(trx).forUpdate().execute();
948
+ if (!lockedRelease) {
827
949
  throw new errors.NotFoundError(`No release found for id ${releaseId}`);
828
950
  }
829
- if (releaseWithPopulatedActionEntries.releasedAt) {
951
+ if (lockedRelease.releasedAt) {
830
952
  throw new errors.ValidationError("Release already published");
831
953
  }
832
- if (releaseWithPopulatedActionEntries.actions.length === 0) {
833
- throw new errors.ValidationError("No entries to publish");
954
+ if (lockedRelease.status === "failed") {
955
+ throw new errors.ValidationError("Release failed to publish");
834
956
  }
835
- const collectionTypeActions = {};
836
- const singleTypeActions = [];
837
- for (const action of releaseWithPopulatedActionEntries.actions) {
838
- const contentTypeUid = action.contentType;
839
- if (strapi2.contentTypes[contentTypeUid].kind === "collectionType") {
840
- if (!collectionTypeActions[contentTypeUid]) {
841
- collectionTypeActions[contentTypeUid] = {
842
- entriestoPublishIds: [],
843
- entriesToUnpublishIds: []
844
- };
845
- }
846
- if (action.type === "publish") {
847
- collectionTypeActions[contentTypeUid].entriestoPublishIds.push(action.entry.id);
848
- } else {
849
- collectionTypeActions[contentTypeUid].entriesToUnpublishIds.push(action.entry.id);
850
- }
851
- } else {
852
- singleTypeActions.push({
853
- uid: contentTypeUid,
854
- action: action.type,
855
- id: action.entry.id
856
- });
857
- }
858
- }
859
- const entityManagerService = strapi2.plugin("content-manager").service("entity-manager");
860
- const populateBuilderService = strapi2.plugin("content-manager").service("populate-builder");
861
- await strapi2.db.transaction(async () => {
862
- for (const { uid, action, id } of singleTypeActions) {
863
- const populate = await populateBuilderService(uid).populateDeep(Infinity).build();
864
- const entry = await strapi2.entityService.findOne(uid, id, { populate });
865
- try {
866
- if (action === "publish") {
867
- await entityManagerService.publish(entry, uid);
868
- } else {
869
- await entityManagerService.unpublish(entry, uid);
870
- }
871
- } catch (error) {
872
- if (error instanceof errors.ApplicationError && (error.message === "already.published" || error.message === "already.draft")) {
873
- } else {
874
- throw error;
875
- }
957
+ try {
958
+ strapi2.log.info(`[Content Releases] Starting to publish release ${lockedRelease.name}`);
959
+ const { collectionTypeActions, singleTypeActions } = await getFormattedActions(
960
+ releaseId
961
+ );
962
+ await strapi2.db.transaction(async () => {
963
+ for (const { uid, action, id } of singleTypeActions) {
964
+ await publishSingleTypeAction(uid, action, id);
876
965
  }
877
- }
878
- for (const contentTypeUid of Object.keys(collectionTypeActions)) {
879
- const populate = await populateBuilderService(contentTypeUid).populateDeep(Infinity).build();
880
- const { entriestoPublishIds, entriesToUnpublishIds } = collectionTypeActions[contentTypeUid];
881
- const entriesToPublish = await strapi2.entityService.findMany(
882
- contentTypeUid,
883
- {
884
- filters: {
885
- id: {
886
- $in: entriestoPublishIds
887
- }
888
- },
889
- populate
890
- }
891
- );
892
- const entriesToUnpublish = await strapi2.entityService.findMany(
893
- contentTypeUid,
894
- {
895
- filters: {
896
- id: {
897
- $in: entriesToUnpublishIds
898
- }
899
- },
900
- populate
901
- }
902
- );
903
- if (entriesToPublish.length > 0) {
904
- await entityManagerService.publishMany(entriesToPublish, contentTypeUid);
966
+ for (const contentTypeUid of Object.keys(collectionTypeActions)) {
967
+ const uid = contentTypeUid;
968
+ await publishCollectionTypeAction(
969
+ uid,
970
+ collectionTypeActions[uid].entriesToPublishIds,
971
+ collectionTypeActions[uid].entriesToUnpublishIds
972
+ );
905
973
  }
906
- if (entriesToUnpublish.length > 0) {
907
- await entityManagerService.unpublishMany(entriesToUnpublish, contentTypeUid);
974
+ });
975
+ const release22 = await strapi2.db.query(RELEASE_MODEL_UID).update({
976
+ where: {
977
+ id: releaseId
978
+ },
979
+ data: {
980
+ status: "done",
981
+ releasedAt: /* @__PURE__ */ new Date()
908
982
  }
983
+ });
984
+ if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
985
+ dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
986
+ isPublished: true,
987
+ release: release22
988
+ });
909
989
  }
910
- });
911
- const release2 = await strapi2.entityService.update(RELEASE_MODEL_UID, releaseId, {
912
- data: {
913
- /*
914
- * The type returned from the entity service: Partial<Input<"plugin::content-releases.release">> looks like it's wrong
915
- */
916
- // @ts-expect-error see above
917
- releasedAt: /* @__PURE__ */ new Date()
918
- },
919
- populate: {
920
- actions: {
921
- // @ts-expect-error is not expecting count but it is working
922
- count: true
923
- }
990
+ strapi2.telemetry.send("didPublishContentRelease");
991
+ return { release: release22, error: null };
992
+ } catch (error2) {
993
+ if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
994
+ dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
995
+ isPublished: false,
996
+ error: error2
997
+ });
924
998
  }
925
- });
926
- if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
927
- dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
928
- isPublished: true,
929
- release: release2
930
- });
931
- }
932
- strapi2.telemetry.send("didPublishContentRelease");
933
- return release2;
934
- } catch (error) {
935
- if (strapi2.features.future.isEnabled("contentReleasesScheduling")) {
936
- dispatchWebhook(ALLOWED_WEBHOOK_EVENTS.RELEASES_PUBLISH, {
937
- isPublished: false,
938
- error
939
- });
940
- }
941
- strapi2.db.query(RELEASE_MODEL_UID).update({
942
- where: { id: releaseId },
943
- data: {
999
+ await strapi2.db?.queryBuilder(RELEASE_MODEL_UID).where({ id: releaseId }).update({
944
1000
  status: "failed"
945
- }
946
- });
1001
+ }).transacting(trx).execute();
1002
+ return {
1003
+ release: null,
1004
+ error: error2
1005
+ };
1006
+ }
1007
+ });
1008
+ if (error) {
947
1009
  throw error;
948
1010
  }
1011
+ return release2;
949
1012
  },
950
1013
  async updateAction(actionId, releaseId, update) {
951
1014
  const updatedAction = await strapi2.db.query(RELEASE_ACTION_MODEL_UID).update({
@@ -1581,6 +1644,9 @@ const getPlugin = () => {
1581
1644
  };
1582
1645
  }
1583
1646
  return {
1647
+ // Always return register, it handles its own feature check
1648
+ register,
1649
+ // Always return contentTypes to avoid losing data when the feature is disabled
1584
1650
  contentTypes
1585
1651
  };
1586
1652
  };