@stackbit/cms-core 1.0.19-develop.1 → 1.0.19-develop.2

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.
@@ -3,40 +3,31 @@ import _ from 'lodash';
3
3
  import { ContentStoreTypes } from '../';
4
4
  import { STACKBIT_PRESET_MODEL_NAME } from '../consts';
5
5
  import { getContentSourceDataByIdOrThrow, getContentSourceId } from '../content-store-utils';
6
- import { mapCSIAssetsToStoreAssets, mapCSIDocumentsToStoreDocuments } from './csi-to-store-docs-converter';
7
- import { getAllModelsFromCSIDocument } from './document-utils';
6
+ import { mapCSIAssetsToStoreAssets } from './csi-to-store-docs-converter';
8
7
 
9
8
  export const getFilteredDocumentsForUser = ({
10
9
  user,
11
10
  documents,
12
- filterModel,
13
- filterDocument,
11
+ permissionsForModel,
12
+ permissionsForDocument,
14
13
  contentSourceDataById,
15
- assetSources,
16
14
  createConfigDelegate,
17
- customActionRunStateMap,
18
15
  logger
19
16
  }: {
20
17
  user?: ContentStoreTypes.User;
21
- filterModel: CSITypes.StackbitConfig['filterModel'];
22
- filterDocument: CSITypes.StackbitConfig['filterDocument'];
18
+ permissionsForModel: CSITypes.StackbitConfig['permissionsForModel'];
19
+ permissionsForDocument: CSITypes.StackbitConfig['permissionsForDocument'];
23
20
  documents: ContentStoreTypes.Document[];
24
21
  contentSourceDataById: Record<string, ContentStoreTypes.ContentSourceData>;
25
- assetSources: CSITypes.AssetSource[];
26
22
  createConfigDelegate: () => CSITypes.ConfigDelegate;
27
- customActionRunStateMap: ContentStoreTypes.CustomActionRunStateMap;
28
23
  logger: CSITypes.Logger;
29
24
  }): ContentStoreTypes.Document[] => {
30
- if (!user || (!filterDocument && !filterModel)) {
25
+ if (!user) {
31
26
  return documents;
32
27
  }
33
28
 
34
29
  const documentsBySourceId = _.groupBy(documents, (object) => getContentSourceId(object.srcType, object.srcProjectId));
35
-
36
- const transformedCsiDocuments: CSITypes.DocumentWithSource[] = [];
37
-
38
30
  const resultDocuments: ContentStoreTypes.Document[] = [];
39
-
40
31
  const configDelegate = createConfigDelegate();
41
32
 
42
33
  for (const [contentSourceId, contentSourceDocuments] of Object.entries(documentsBySourceId)) {
@@ -48,74 +39,41 @@ export const getFilteredDocumentsForUser = ({
48
39
  if (!csiDoc) {
49
40
  throw new Error(`Document with id '${document.srcObjectId}' not found in content source '${contentSourceId}'`);
50
41
  }
51
-
52
- getAllModelsFromCSIDocument({ document: csiDoc }).forEach((modelName) => {
53
- if (!filteredModelsMap[modelName]) {
54
- const filteredModel = getFilteredModelForUser({
55
- user,
56
- name: modelName,
57
- contentSourceData,
58
- configDelegate,
59
- filterModel
60
- });
61
- filteredModelsMap[modelName] = filteredModel;
62
- }
63
- });
64
- const documentModel = filteredModelsMap[document.srcModelName];
42
+ const modelName = csiDoc.modelName;
43
+ if (!filteredModelsMap[modelName]) {
44
+ filteredModelsMap[modelName] = getFilteredModelForUser({
45
+ user,
46
+ name: modelName,
47
+ contentSourceData,
48
+ configDelegate,
49
+ permissionsForModel
50
+ });
51
+ }
52
+ const documentModel = filteredModelsMap[modelName];
65
53
  if (!documentModel) {
66
54
  throw new Error(
67
55
  `Can't find model with name '${document.srcModelName}' for object with id '${document.srcObjectId}' in content source '${contentSourceId}'`
68
56
  );
69
57
  }
70
- if (documentModel.hidden) {
71
- // model is hidden - return csiDocument right away as hidden
72
- resultDocuments.push({
73
- ...document,
74
- hidden: true
75
- });
76
- return;
77
- }
78
-
79
- if (!filterDocument) {
80
- // no filter function is defined, but the model is not hidden - just add this document as is
81
- resultDocuments.push(document);
82
- return;
83
- }
84
-
85
- const csiDocWithSource: CSITypes.DocumentWithSource = {
86
- ..._.cloneDeep(csiDoc),
87
- srcType: contentSourceData.srcType,
88
- srcProjectId: contentSourceData.srcProjectId
89
- };
90
- const shouldIncludeDoc = filterDocument({
91
- ...configDelegate,
92
- document: csiDocWithSource,
93
- userContext: user
58
+ const docPermissions = _.defaults(csiDoc.permissions, documentModel.permissions);
59
+ const permissions =
60
+ permissionsForDocument?.({
61
+ ...configDelegate,
62
+ document: {
63
+ ...csiDoc,
64
+ permissions: docPermissions,
65
+ srcType: contentSourceData.srcType,
66
+ srcProjectId: contentSourceData.srcProjectId
67
+ },
68
+ userContext: user
69
+ }) ?? docPermissions;
70
+ resultDocuments.push({
71
+ ...document,
72
+ permissions,
73
+ hidden: documentModel.hidden || document.hidden || permissions?.canView === false
94
74
  });
95
- if (typeof shouldIncludeDoc === 'undefined') {
96
- transformedCsiDocuments.push(csiDocWithSource);
97
- } else {
98
- transformedCsiDocuments.push({
99
- ...csiDocWithSource,
100
- hidden: !shouldIncludeDoc
101
- });
102
- }
75
+ return;
103
76
  });
104
-
105
- if (transformedCsiDocuments.length) {
106
- const csResultDocuments = mapCSIDocumentsToStoreDocuments({
107
- csiDocuments: transformedCsiDocuments,
108
- contentSourceInstance: contentSourceData.instance,
109
- modelMap: filteredModelsMap,
110
- defaultLocaleCode: contentSourceData.defaultLocaleCode,
111
- assetSources,
112
- customActionRunStateMap,
113
- createConfigDelegate,
114
- logger
115
- });
116
-
117
- resultDocuments.push(...(csResultDocuments ?? []));
118
- }
119
77
  }
120
78
 
121
79
  return resultDocuments;
@@ -191,12 +149,12 @@ export const getContentSourceFilteredModelsForUser = ({
191
149
  user,
192
150
  configDelegate,
193
151
  contentSourceData,
194
- filterModel
152
+ permissionsForModel
195
153
  }: {
196
154
  user?: ContentStoreTypes.User;
197
155
  configDelegate: CSITypes.ConfigDelegate;
198
156
  contentSourceData: ContentStoreTypes.ContentSourceData;
199
- filterModel: CSITypes.StackbitConfig['filterModel'];
157
+ permissionsForModel: CSITypes.StackbitConfig['permissionsForModel'];
200
158
  }): CSITypes.Model[] => {
201
159
  const filteredModels = contentSourceData.models.map((model) => {
202
160
  return getFilteredModelForUser({
@@ -204,7 +162,7 @@ export const getContentSourceFilteredModelsForUser = ({
204
162
  configDelegate,
205
163
  name: model.name,
206
164
  contentSourceData,
207
- filterModel
165
+ permissionsForModel
208
166
  });
209
167
  });
210
168
  const cleanModels = filteredModels.filter((model) => model.name !== STACKBIT_PRESET_MODEL_NAME);
@@ -216,19 +174,21 @@ export const getFilteredModelForUser = ({
216
174
  name,
217
175
  configDelegate,
218
176
  contentSourceData,
219
- filterModel
177
+ permissionsForModel
220
178
  }: {
221
179
  user?: ContentStoreTypes.User;
222
180
  name: string;
223
181
  configDelegate: CSITypes.ConfigDelegate;
224
182
  contentSourceData: ContentStoreTypes.ContentSourceData;
225
- filterModel: CSITypes.StackbitConfig['filterModel'];
183
+ permissionsForModel: CSITypes.StackbitConfig['permissionsForModel'];
226
184
  }): CSITypes.Model => {
227
185
  const model = contentSourceData.modelMap[name];
228
186
  if (!model) {
229
187
  throw new Error(`Model with name ${name} not found in source`);
230
188
  }
231
- if (!user || !filterModel) {
189
+
190
+ const shouldResolvePermissions = permissionsForModel || typeof model?.permissions === 'function';
191
+ if (!user || !shouldResolvePermissions) {
232
192
  return model;
233
193
  }
234
194
  const modelWithSource = {
@@ -236,12 +196,21 @@ export const getFilteredModelForUser = ({
236
196
  srcType: contentSourceData.srcType,
237
197
  srcProjectId: contentSourceData.srcProjectId
238
198
  };
239
- const shouldIncludeModel = filterModel({ ...configDelegate, model: modelWithSource, userContext: user });
240
- if (typeof shouldIncludeModel === 'undefined') {
241
- return model;
242
- }
199
+
200
+ const permissionsResult =
201
+ typeof model.permissions === 'function' ? model.permissions?.({ ...configDelegate, model: modelWithSource, userContext: user }) : model.permissions;
202
+ const permissionsHookResult =
203
+ permissionsForModel?.({
204
+ ...configDelegate,
205
+ model: { ...modelWithSource, permissions: permissionsResult },
206
+ userContext: user
207
+ }) ?? permissionsResult;
208
+ const permissions = _.isEmpty(permissionsHookResult) ? undefined : permissionsHookResult;
209
+
210
+ const shouldHideModel = permissions?.canView === false;
243
211
  return {
244
212
  ...model,
245
- hidden: !shouldIncludeModel
213
+ permissions,
214
+ hidden: shouldHideModel
246
215
  };
247
216
  };
@@ -1,3 +0,0 @@
1
- import * as CSITypes from '@stackbit/types';
2
- export declare function convertModels(models: Map<string, any>): (CSITypes.ObjectModel<unknown> | CSITypes.DataModel<unknown>)[];
3
- //# sourceMappingURL=model-converter.d.mts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model-converter.d.mts","sourceRoot":"","sources":["../../src/connector/model-converter.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,iBAAiB,CAAC;AAE5C,wBAAgB,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,mEAYrD"}
@@ -1,138 +0,0 @@
1
- export function convertModels(models) {
2
- const createModels = [];
3
- models.forEach((model) => {
4
- if (model.getTypeName() === `Image`) {
5
- return;
6
- }
7
- const createModel = convertModel(model, models);
8
- if (createModel) {
9
- createModels.push(createModel);
10
- }
11
- });
12
- return createModels;
13
- }
14
- function convertModel(model, models) {
15
- let fieldGroups = model.fieldGroups;
16
- if (model.devOnlyFieldGroup) {
17
- fieldGroups || (fieldGroups = []);
18
- fieldGroups.push(model.devOnlyFieldGroup);
19
- }
20
- // Create doesn't have named union types
21
- if (model.isUnionType) {
22
- return false;
23
- }
24
- const name = model.originalName || model.typeName;
25
- const csiModel = {
26
- name: name,
27
- label: model.label || model.name,
28
- type: model.isObjectType ? `object` : `data`,
29
- fieldGroups,
30
- fields: sdkFieldsToStackbitFields(model.fields, models)
31
- };
32
- return csiModel;
33
- }
34
- function sdkFieldsToStackbitFields(fields, models) {
35
- return fields.map((field) => {
36
- const definedTypename = field.type;
37
- const fieldModel = models.get(definedTypename);
38
- const typename = fieldModel?.originalName || definedTypename;
39
- const isObject = fieldModel?.isObjectType;
40
- const scalarTypename = isObject
41
- ? `object`
42
- : {
43
- // create only has a number field
44
- float: 'number',
45
- int: 'number'
46
- }[typename.toLowerCase()] ||
47
- // all other scalar types are supported as lowercase typenames
48
- typename.toLowerCase();
49
- const isImage = typename === `Image`;
50
- const isReference = !isImage && fieldModel?.isNodeType;
51
- const isUnion = fieldModel?.isUnionType;
52
- const firstUnionType = isUnion && fieldModel?.compositeTypes && models.get(fieldModel.compositeTypes[0]);
53
- const isObjectUnion = firstUnionType && firstUnionType.isObjectType;
54
- const isReferenceUnion = firstUnionType && firstUnionType.isNodeType;
55
- const type = (() => {
56
- if ( /*isObject || */isObjectUnion) {
57
- return `model`;
58
- }
59
- if (isReference || isReferenceUnion) {
60
- return `reference`;
61
- }
62
- if (isUnion) {
63
- // throw new ModelError(`Unhandled union type for model ${typename}. This is a bug in the Netlify SDK.`);
64
- }
65
- if (isImage) {
66
- return `image`;
67
- }
68
- return scalarTypename;
69
- })();
70
- const stackbitField = {
71
- type,
72
- name: field.name
73
- };
74
- if (typename.toLowerCase() === `float`) {
75
- stackbitField.subtype = `float`;
76
- }
77
- //TODO
78
- if (isObject) {
79
- stackbitField.fields = fieldModel.sdkFieldsToStackbitFields();
80
- }
81
- // if (isObject) {
82
- // (stackbitField as CSITypes.FieldModelProps).models = [typename];
83
- // }
84
- // if (isObjectUnion) {
85
- // (stackbitField as CSITypes.FieldModelProps).models = fieldModel.compositeTypes.map((ct: any) => {
86
- // const fullType = models.get(ct);
87
- // return fullType!.getOriginalName();
88
- // });
89
- // }
90
- // any field names starting with _ are internal mandatory fields.
91
- // they shouldn't be set as required in the Create UI as content admins
92
- // don't need to set these fields, connector authors do.
93
- if (`required` in field && !field.name.startsWith(`_`)) {
94
- stackbitField.required = field.required;
95
- }
96
- if (`label` in field) {
97
- stackbitField.label = field.label;
98
- }
99
- if (`hidden` in field) {
100
- stackbitField.hidden = field.hidden;
101
- }
102
- if (`readOnly` in field) {
103
- stackbitField.readOnly = field.readOnly;
104
- }
105
- if (`localized` in field) {
106
- stackbitField.localized = field.localized;
107
- }
108
- if (`defaultValue` in field) {
109
- stackbitField.default = field.defaultValue;
110
- }
111
- if (`group` in field) {
112
- stackbitField.group = field.group;
113
- }
114
- if (isUnion) {
115
- stackbitField.models = (fieldModel.compositeTypes || []).map((ct) => {
116
- const fullType = models.get(ct);
117
- return fullType.getOriginalName();
118
- });
119
- }
120
- else if (isReference) {
121
- stackbitField.models = [fieldModel.getOriginalName()];
122
- }
123
- if (field.list) {
124
- const { name, required, hidden, ...items } = stackbitField;
125
- return {
126
- name,
127
- required,
128
- hidden,
129
- type: `list`,
130
- items
131
- };
132
- }
133
- else {
134
- return stackbitField;
135
- }
136
- });
137
- }
138
- //# sourceMappingURL=model-converter.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"model-converter.mjs","sourceRoot":"","sources":["../../src/connector/model-converter.mts"],"names":[],"mappings":"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"}