Skip to content

Commit

Permalink
feat(api-headless-cms): add createdBy, ownedBy and entryId filtering (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
brunozoric committed May 28, 2021
1 parent f23f9fb commit 7e7b276
Show file tree
Hide file tree
Showing 33 changed files with 1,079 additions and 192 deletions.
17 changes: 17 additions & 0 deletions packages/api-headless-cms-ddb-es/README.md
Expand Up @@ -16,3 +16,20 @@ Or if you prefer yarn:
```
yarn add @webiny/api-headless-cms-ddb-es
```


## Testing
To run the tests only for this package you must filter it with keywords.

### Env variables

###### LOCAL_ELASTICSEARCH
If set, does not run Elasticsearch when starting the tests, use local one. You must install it and run if, of course.

###### ELASTICSEARCH_PORT
Custom port for local elasticsearch.

### Command
````
ELASTICSEARCH_PORT=9200 LOCAL_ELASTICSEARCH=true yarn test packages/api-headless-cms --keyword=cms:ddb-es --keyword=cms:base
````
14 changes: 0 additions & 14 deletions packages/api-headless-cms-ddb-es/__tests__/__api__/README.md

This file was deleted.

Expand Up @@ -50,7 +50,6 @@ interface CreateElasticsearchParams {
context: CmsContext;
model: CmsContentModel;
args: CmsContentEntryListArgs;
ownedBy?: string;
parentObject?: string;
}

Expand All @@ -66,7 +65,6 @@ interface CreateElasticsearchQueryArgs {
context: CmsContext;
where: CmsContentEntryListWhere;
modelFields: ModelFields;
ownedBy?: string;
parentObject?: string;
}

Expand Down Expand Up @@ -148,7 +146,7 @@ const createElasticsearchSortParams = (
* Latest is used in the manage API and published in the read API.
*/
const createInitialQueryValue = (args: CreateElasticsearchQueryArgs): ElasticsearchQuery => {
const { ownedBy, where, context } = args;
const { where, context } = args;

const query: ElasticsearchQuery = {
match: [],
Expand All @@ -163,16 +161,9 @@ const createInitialQueryValue = (args: CreateElasticsearchQueryArgs): Elasticsea
const tenant = context.security.getTenant();
query.must.push({ term: { "tenant.keyword": tenant.id } });
}

// When permission has "only own records" set, we'll have "ownedBy" passed into this function.
if (ownedBy) {
query.must.push({
term: {
"ownedBy.id.keyword": ownedBy
}
});
}

/**
* We must transform published and latest where args into something that is understandable by our Elasticsearch
*/
if (where.published === true) {
query.must.push({
term: {
Expand Down Expand Up @@ -239,8 +230,10 @@ const execElasticsearchBuildQueryPlugins = (
const searchPlugins = searchPluginsList(context);

for (const key in where) {
// we do not need to go further if value is undefined
// it is a possibility on ownedBy field since it is automatically added to the where args
/**
* We do not need to go further if value is undefined.
* There are few hardcoded possibilities when value is undefined, for example, ownedBy.
*/
if (where[key] === undefined) {
continue;
}
Expand All @@ -266,15 +259,19 @@ const execElasticsearchBuildQueryPlugins = (
value: where[key],
context
});
// A possibility to build field custom path in the elasticsearch
/**
* A possibility to build field custom path for the Elasticsearch record.
*/
const customFieldPath =
fieldSearchPlugin && typeof fieldSearchPlugin.createPath === "function"
? fieldSearchPlugin.createPath({
field: modelField.field,
context
})
: null;
const fieldWithParent = isSystemField ? null : customFieldPath || withParentObject(field);
: modelField.path || null;
const fieldWithParent = isSystemField
? customFieldPath
: customFieldPath || withParentObject(field);
plugin.apply(query, {
field: fieldWithParent || field,
value,
Expand All @@ -288,9 +285,17 @@ const execElasticsearchBuildQueryPlugins = (
};

const createSystemField = (field: Partial<CmsContentModelField>): CmsContentModelField => {
if (!field.type) {
if (!field.fieldId) {
throw new WebinyError(
`When creating system field it must have a "entryId".`,
"SYSTEM_FIELD_ERROR",
{
field
}
);
} else if (!field.type) {
throw new WebinyError(
"When creating system field it must have a type, at least.",
`When creating system field it must have a "type".`,
"SYSTEM_FIELD_ERROR",
{
field
Expand All @@ -310,6 +315,7 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
isSearchable: true,
isSortable: true,
field: createSystemField({
fieldId: "id",
type: "text"
})
},
Expand All @@ -319,6 +325,7 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
isSearchable: true,
isSortable: true,
field: createSystemField({
fieldId: "entryId",
type: "text"
})
},
Expand All @@ -329,6 +336,7 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
isSearchable: true,
isSortable: true,
field: createSystemField({
fieldId: "savedOn",
type: "date",
settings: {
type: "dateTimeWithoutTimezone"
Expand All @@ -342,12 +350,25 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
isSearchable: true,
isSortable: true,
field: createSystemField({
fieldId: "createdOn",
type: "text",
settings: {
type: "dateTimeWithoutTimezone"
}
})
},
createdBy: {
type: "text",
unmappedType: undefined,
isSystemField: true,
isSearchable: true,
isSortable: false,
path: "createdBy.id",
field: createSystemField({
fieldId: "createdBy",
type: "text"
})
},
ownedBy: {
type: "text",
unmappedType: undefined,
Expand All @@ -356,6 +377,7 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
isSortable: false,
path: "ownedBy.id",
field: createSystemField({
fieldId: "ownedBy",
type: "text"
})
},
Expand All @@ -366,6 +388,7 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
isSearchable: true,
isSortable: true,
field: createSystemField({
fieldId: "version",
type: "number"
})
}
Expand Down Expand Up @@ -413,7 +436,7 @@ const createModelFieldOptions = (context: CmsContext, model: CmsContentModel): M
};

export const createElasticsearchQueryBody = (params: CreateElasticsearchParams) => {
const { context, model, args, ownedBy, parentObject = null } = params;
const { context, model, args, parentObject = null } = params;
const { where, after, limit, sort } = args;

const modelFields = createModelFieldOptions(context, model);
Expand All @@ -423,7 +446,6 @@ export const createElasticsearchQueryBody = (params: CreateElasticsearchParams)
context,
where,
modelFields,
ownedBy,
parentObject
});

Expand Down
17 changes: 12 additions & 5 deletions packages/api-headless-cms-ddb/README.md
@@ -1,18 +1,25 @@
# @webiny/api-headless-cms-ddb-es
# @webiny/api-headless-cms-ddb

[![](https://img.shields.io/npm/dw/@webiny/api-headless-cms-ddb-es.svg)](https://www.npmjs.com/package/@webiny/api-headless-cms-ddb-es)
[![](https://img.shields.io/npm/v/@webiny/api-headless-cms-ddb-es.svg)](https://www.npmjs.com/package/@webiny/api-headless-cms-ddb-es)
[![](https://img.shields.io/npm/dw/@webiny/api-headless-cms-ddb.svg)](https://www.npmjs.com/package/@webiny/api-headless-cms-ddb)
[![](https://img.shields.io/npm/v/@webiny/api-headless-cms-ddb.svg)](https://www.npmjs.com/package/@webiny/api-headless-cms-ddb)
[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)

## Install

```
npm install --save @webiny/api-headless-cms-ddb-es
npm install --save @webiny/api-headless-cms-ddb
```

Or if you prefer yarn:

```
yarn add @webiny/api-headless-cms-ddb-es
yarn add @webiny/api-headless-cms-ddb
```

## Testing
To run the tests only for this package you must filter it with keywords.
### Command
````
yarn test packages/api-headless-cms --keyword=cms:ddb --keyword=cms:base
````
10 changes: 0 additions & 10 deletions packages/api-headless-cms-ddb/__tests__/__api__/README.md

This file was deleted.

75 changes: 39 additions & 36 deletions packages/api-headless-cms-ddb/src/operations/entry/systemFields.ts
@@ -1,41 +1,44 @@
import { CmsContentModelField } from "@webiny/api-headless-cms/types";

const id = ({
id: "id",
type: "text",
fieldId: "id"
} as unknown) as CmsContentModelField;
const createdOn = ({
id: "createdOn",
type: "datetime",
fieldId: "createdOn"
} as unknown) as CmsContentModelField;
const savedOn = ({
id: "savedOn",
type: "datetime",
fieldId: "savedOn"
} as unknown) as CmsContentModelField;
const createdBy = ({
id: "createdBy",
type: "plainObject",
fieldId: "createdBy",
settings: {
path: "ownedBy.id"
}
} as unknown) as CmsContentModelField;
const ownedBy = ({
id: "ownedBy",
type: "plainObject",
fieldId: "ownedBy",
settings: {
path: "ownedBy.id"
}
} as unknown) as CmsContentModelField;
const createSystemField = (field: Partial<CmsContentModelField>): CmsContentModelField => {
return field as CmsContentModelField;
};

export const systemFields: Record<string, CmsContentModelField> = {
id,
createdOn,
savedOn,
createdBy,
ownedBy
id: createSystemField({
id: "id",
type: "text",
fieldId: "id"
}),
entryId: createSystemField({
id: "entryId",
type: "text",
fieldId: "entryId"
}),
createdOn: createSystemField({
id: "createdOn",
type: "datetime",
fieldId: "createdOn"
}),
savedOn: createSystemField({
id: "savedOn",
type: "datetime",
fieldId: "savedOn"
}),
createdBy: createSystemField({
id: "createdBy",
type: "plainObject",
fieldId: "createdBy",
settings: {
path: "createdBy.id"
}
}),
ownedBy: createSystemField({
id: "ownedBy",
type: "plainObject",
fieldId: "ownedBy",
settings: {
path: "ownedBy.id"
}
})
};

0 comments on commit 7e7b276

Please sign in to comment.