mirror of
https://github.com/strapi/strapi.git
synced 2025-11-04 20:07:19 +00:00
Single type routes
Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com>
This commit is contained in:
parent
7509a16152
commit
2bbd47ba2c
@ -86,12 +86,83 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
"method": "GET",
|
||||||
|
"path": "/single-types/:model",
|
||||||
|
"handler": "single-types.find",
|
||||||
|
"config": {
|
||||||
|
"policies": [
|
||||||
|
"routing",
|
||||||
|
"admin::isAuthenticatedAdmin",
|
||||||
|
["plugins::content-manager.hasPermissions", ["plugins::content-manager.explorer.read"]]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "PUT",
|
||||||
|
"path": "/single-types/:model",
|
||||||
|
"handler": "single-types.createOrUpdate",
|
||||||
|
"config": {
|
||||||
|
"policies": [
|
||||||
|
"routing",
|
||||||
|
"admin::isAuthenticatedAdmin",
|
||||||
|
[
|
||||||
|
"plugins::content-manager.hasPermissions",
|
||||||
|
[
|
||||||
|
"plugins::content-manager.explorer.create",
|
||||||
|
"plugins::content-manager.explorer.update"
|
||||||
|
],
|
||||||
|
{ "hasAtLeastOne": true }
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "DELETE",
|
||||||
|
"path": "/single-types/:model",
|
||||||
|
"handler": "single-types.delete",
|
||||||
|
"config": {
|
||||||
|
"policies": [
|
||||||
|
"routing",
|
||||||
|
"admin::isAuthenticatedAdmin",
|
||||||
|
["plugins::content-manager.hasPermissions", ["plugins::content-manager.explorer.delete"]]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/single-types/:model/actions/publish",
|
||||||
|
"handler": "single-types.publish",
|
||||||
|
"config": {
|
||||||
|
"policies": [
|
||||||
|
"routing",
|
||||||
|
"plugins::content-manager.has-draft-and-publish",
|
||||||
|
"admin::isAuthenticatedAdmin",
|
||||||
|
["plugins::content-manager.hasPermissions", ["plugins::content-manager.explorer.publish"]]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"method": "POST",
|
||||||
|
"path": "/single-types/:model/actions/unpublish",
|
||||||
|
"handler": "single-types.unpublish",
|
||||||
|
"config": {
|
||||||
|
"policies": [
|
||||||
|
"routing",
|
||||||
|
"plugins::content-manager.has-draft-and-publish",
|
||||||
|
"admin::isAuthenticatedAdmin",
|
||||||
|
["plugins::content-manager.hasPermissions", ["plugins::content-manager.explorer.publish"]]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
"method": "GET",
|
"method": "GET",
|
||||||
"path": "/explorer/:model",
|
"path": "/explorer/:model",
|
||||||
"handler": "ContentManager.find",
|
"handler": "ContentManager.find",
|
||||||
"config": {
|
"config": {
|
||||||
"policies": ["routing", "admin::isAuthenticatedAdmin"]
|
"policies": ["routing", "admin::isAuthenticatedAdmin"]
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
@ -0,0 +1,61 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const createContext = require('../../../../test/helpers/create-context');
|
||||||
|
const singleTypes = require('../single-types');
|
||||||
|
const { ACTIONS } = require('../constants');
|
||||||
|
|
||||||
|
describe('Single Types', () => {
|
||||||
|
test('find', async () => {
|
||||||
|
const state = {
|
||||||
|
userAbility: {
|
||||||
|
can: jest.fn(),
|
||||||
|
cannot: jest.fn(() => false),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const notFound = jest.fn();
|
||||||
|
const createPermissionsManager = jest.fn(() => ({
|
||||||
|
ability: state.userAbility,
|
||||||
|
}));
|
||||||
|
|
||||||
|
global.strapi = {
|
||||||
|
admin: {
|
||||||
|
services: {
|
||||||
|
permission: {
|
||||||
|
createPermissionsManager,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
plugins: {
|
||||||
|
'content-manager': {
|
||||||
|
services: {
|
||||||
|
'single-types': {
|
||||||
|
fetchEntitiyWithCreatorRoles() {
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
entityService: {
|
||||||
|
find: jest.fn(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const modelUid = 'test-model';
|
||||||
|
|
||||||
|
const ctx = createContext(
|
||||||
|
{
|
||||||
|
params: {
|
||||||
|
model: modelUid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ state, notFound }
|
||||||
|
);
|
||||||
|
|
||||||
|
await singleTypes.find(ctx);
|
||||||
|
|
||||||
|
expect(state.userAbility.cannot).toHaveBeenCalledWith(ACTIONS.create, modelUid);
|
||||||
|
expect(notFound).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const ACTIONS = {
|
||||||
|
read: 'plugins::content-manager.explorer.read',
|
||||||
|
create: 'plugins::content-manager.explorer.create',
|
||||||
|
edit: 'plugins::content-manager.explorer.update',
|
||||||
|
delete: 'plugins::content-manager.explorer.delete',
|
||||||
|
publish: 'plugins::content-manager.explorer.publish',
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
ACTIONS,
|
||||||
|
};
|
||||||
@ -0,0 +1,214 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { prop, pipe, assoc, assign } = require('lodash/fp');
|
||||||
|
const { contentTypes: contentTypesUtils } = require('strapi-utils');
|
||||||
|
const { getService } = require('../utils');
|
||||||
|
const parseBody = require('../utils/parse-body');
|
||||||
|
const { ACTIONS } = require('./constants');
|
||||||
|
|
||||||
|
const {
|
||||||
|
CREATED_BY_ATTRIBUTE,
|
||||||
|
UPDATED_BY_ATTRIBUTE,
|
||||||
|
PUBLISHED_AT_ATTRIBUTE,
|
||||||
|
} = contentTypesUtils.constants;
|
||||||
|
|
||||||
|
const pickPermittedFields = ({ pm, action, model }) => data => {
|
||||||
|
return pm.pickPermittedFieldsOf(data, { action, subject: model });
|
||||||
|
};
|
||||||
|
|
||||||
|
const setCreatorFields = ({ user, isEdition = false }) => data => {
|
||||||
|
if (isEdition) {
|
||||||
|
return assoc(UPDATED_BY_ATTRIBUTE, user.id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return assign(data, {
|
||||||
|
[CREATED_BY_ATTRIBUTE]: user.id,
|
||||||
|
[UPDATED_BY_ATTRIBUTE]: user.id,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
async find(ctx) {
|
||||||
|
const { userAbility } = ctx.state;
|
||||||
|
const { model } = ctx.params;
|
||||||
|
|
||||||
|
const pm = strapi.admin.services.permission.createPermissionsManager(
|
||||||
|
userAbility,
|
||||||
|
ACTIONS.read,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
const singleTypeService = getService('single-types');
|
||||||
|
|
||||||
|
const entity = await singleTypeService.fetchEntitiyWithCreatorRoles(model);
|
||||||
|
|
||||||
|
// allow user with create permission to know a single type is not created
|
||||||
|
if (!entity) {
|
||||||
|
if (pm.ability.cannot(ACTIONS.create, model)) {
|
||||||
|
return ctx.forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx.notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pm.ability.cannot(ACTIONS.read, pm.toSubject(entity))) {
|
||||||
|
return ctx.forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body = pm.sanitize(entity, { action: ACTIONS.read });
|
||||||
|
},
|
||||||
|
|
||||||
|
async createOrUpdate(ctx) {
|
||||||
|
const { user, userAbility } = ctx.state;
|
||||||
|
const { model } = ctx.params;
|
||||||
|
|
||||||
|
const { data, files } = parseBody(ctx);
|
||||||
|
|
||||||
|
const singleTypeService = getService('single-types');
|
||||||
|
const existingEntity = await singleTypeService.fetchEntitiyWithCreatorRoles(model);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!existingEntity) {
|
||||||
|
const pm = strapi.admin.services.permission.createPermissionsManager(
|
||||||
|
userAbility,
|
||||||
|
ACTIONS.create,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
const sanitizedData = pipe([
|
||||||
|
pickPermittedFields({ pm, action: ACTIONS.create, model }),
|
||||||
|
setCreatorFields({ user }),
|
||||||
|
])(data);
|
||||||
|
|
||||||
|
const entity = await singleTypeService.create({ data: sanitizedData, files }, { model });
|
||||||
|
|
||||||
|
ctx.body = pm.sanitize(entity, { action: ACTIONS.read });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pm = strapi.admin.services.permission.createPermissionsManager(
|
||||||
|
userAbility,
|
||||||
|
ACTIONS.edit,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pm.ability.cannot(ACTIONS.edit, pm.toSubject(existingEntity))) {
|
||||||
|
return strapi.errors.forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
const sanitizedData = pipe([
|
||||||
|
pickPermittedFields({ pm, action: ACTIONS.edit, model: pm.toSubject(existingEntity) }),
|
||||||
|
setCreatorFields({ user, isEdition: true }),
|
||||||
|
])(data);
|
||||||
|
|
||||||
|
const entity = await singleTypeService.update(
|
||||||
|
existingEntity,
|
||||||
|
{ data: sanitizedData, files },
|
||||||
|
{ model }
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.body = pm.sanitize(entity, { action: ACTIONS.read });
|
||||||
|
} catch (error) {
|
||||||
|
strapi.log.error(error);
|
||||||
|
ctx.badRequest(null, [
|
||||||
|
{
|
||||||
|
messages: [{ id: error.message, message: error.message, field: error.field }],
|
||||||
|
errors: prop('data.errors', error),
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
async delete(ctx) {
|
||||||
|
const { userAbility } = ctx.state;
|
||||||
|
const { model } = ctx.params;
|
||||||
|
|
||||||
|
const singleTypeService = getService('single-types');
|
||||||
|
|
||||||
|
const existingEntity = await singleTypeService.fetchEntitiyWithCreatorRoles(model);
|
||||||
|
|
||||||
|
const pm = strapi.admin.services.permission.createPermissionsManager(
|
||||||
|
userAbility,
|
||||||
|
ACTIONS.delete,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pm.ability.cannot(ACTIONS.delete, pm.toSubject(existingEntity))) {
|
||||||
|
return strapi.errors.forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
const deletedEntity = await singleTypeService.delete(existingEntity, { userAbility, model });
|
||||||
|
|
||||||
|
ctx.body = pm.sanitize(deletedEntity, { action: ACTIONS.read });
|
||||||
|
},
|
||||||
|
|
||||||
|
async publish(ctx) {
|
||||||
|
const { userAbility } = ctx.state;
|
||||||
|
const { model } = ctx.params;
|
||||||
|
|
||||||
|
const singleTypeService = getService('single-types');
|
||||||
|
|
||||||
|
const existingEntity = await singleTypeService.fetchEntitiyWithCreatorRoles(model);
|
||||||
|
|
||||||
|
if (!existingEntity) {
|
||||||
|
return ctx.notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const pm = strapi.admin.services.permission.createPermissionsManager(
|
||||||
|
userAbility,
|
||||||
|
ACTIONS.publish,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pm.ability.cannot(ACTIONS.publish, pm.toSubject(existingEntity))) {
|
||||||
|
return ctx.forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
await strapi.entityValidator.validateEntityCreation(strapi.getModel(model), existingEntity);
|
||||||
|
|
||||||
|
if (existingEntity[PUBLISHED_AT_ATTRIBUTE]) {
|
||||||
|
return ctx.badRequest('Already published');
|
||||||
|
}
|
||||||
|
|
||||||
|
const publishedEntry = await getService('contentmanager').publish(
|
||||||
|
{ id: existingEntity.id },
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.body = pm.sanitize(publishedEntry, { action: ACTIONS.read });
|
||||||
|
},
|
||||||
|
|
||||||
|
async unpublish(ctx) {
|
||||||
|
const { userAbility } = ctx.state;
|
||||||
|
const { model } = ctx.params;
|
||||||
|
|
||||||
|
const singleTypeService = getService('single-types');
|
||||||
|
|
||||||
|
const existingEntity = await singleTypeService.fetchEntitiyWithCreatorRoles(model);
|
||||||
|
|
||||||
|
if (!existingEntity) {
|
||||||
|
return ctx.notFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
const pm = strapi.admin.services.permission.createPermissionsManager(
|
||||||
|
userAbility,
|
||||||
|
ACTIONS.publish,
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
if (pm.ability.cannot(ACTIONS.publish, pm.toSubject(existingEntity))) {
|
||||||
|
return ctx.forbidden();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existingEntity[PUBLISHED_AT_ATTRIBUTE]) {
|
||||||
|
return ctx.badRequest('Already a draft');
|
||||||
|
}
|
||||||
|
|
||||||
|
const unpublishedEntry = await getService('contentmanager').unpublish(
|
||||||
|
{ id: existingEntity.id },
|
||||||
|
model
|
||||||
|
);
|
||||||
|
|
||||||
|
ctx.body = pm.sanitize(unpublishedEntry, { action: ACTIONS.read });
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -305,9 +305,7 @@ paths:
|
|||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
id:
|
id:
|
||||||
oneOf:
|
$ref: '#/components/schemas/id'
|
||||||
- type: string
|
|
||||||
- type: integer
|
|
||||||
'[primaryKey]':
|
'[primaryKey]':
|
||||||
oneOf:
|
oneOf:
|
||||||
- type: string
|
- type: string
|
||||||
@ -338,47 +336,129 @@ paths:
|
|||||||
tags:
|
tags:
|
||||||
- Collection Types content management
|
- Collection Types content management
|
||||||
description: Get one entry
|
description: Get one entry
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
- Collection Types content management
|
- Collection Types content management
|
||||||
description: Update one entry
|
description: Update one entry
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
- Collection Types content management
|
- Collection Types content management
|
||||||
description: Delete one entry
|
description: Delete one entry
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
/content-manager/collection-type/{model}/{id}/actions/publish:
|
/content-manager/collection-type/{model}/{id}/actions/publish:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Collection Types content management
|
- Collection Types content management
|
||||||
description: Publish one entry
|
description: Publish one entry
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
/content-manager/collection-type/{model}/{id}/actions/unpublish:
|
/content-manager/collection-type/{model}/{id}/actions/unpublish:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Collection Types content management
|
- Collection Types content management
|
||||||
description: Unpublish one entry
|
description: Unpublish one entry
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
# Single type
|
# Single type
|
||||||
/content-manager/single-type/{model}:
|
/content-manager/single-types/{model}:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
- Single Types content management
|
- Single Types content management
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
put:
|
put:
|
||||||
tags:
|
tags:
|
||||||
- Single Types content management
|
- Single Types content management
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
- Single Types content management
|
- Single Types content management
|
||||||
/content-manager/single-type/{model}/actions/publish:
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
|
|
||||||
|
/content-manager/single-types/{model}/actions/publish:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Single Types content management
|
- Single Types content management
|
||||||
/content-manager/single-type/{model}/actions/unpublish:
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
|
|
||||||
|
/content-manager/single-types/{model}/actions/unpublish:
|
||||||
post:
|
post:
|
||||||
tags:
|
tags:
|
||||||
- Single Types content management
|
- Single Types content management
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/entity'
|
||||||
|
|
||||||
components:
|
components:
|
||||||
schemas:
|
schemas:
|
||||||
|
id:
|
||||||
|
oneOf:
|
||||||
|
- type: string
|
||||||
|
- type: integer
|
||||||
|
|
||||||
|
entity:
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- created_by
|
||||||
|
- updated_by
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
$ref: '#/components/schemas/id'
|
||||||
|
created_by:
|
||||||
|
$ref: '#/components/schemas/user'
|
||||||
|
updated_by:
|
||||||
|
$ref: '#/components/schemas/user'
|
||||||
|
additionalProperties:
|
||||||
|
type: any
|
||||||
|
|
||||||
contentType:
|
contentType:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
@ -521,6 +601,20 @@ components:
|
|||||||
- singleType
|
- singleType
|
||||||
- collectionType
|
- collectionType
|
||||||
|
|
||||||
|
user:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
oneOf:
|
||||||
|
- type: integer
|
||||||
|
- type: string
|
||||||
|
firstname:
|
||||||
|
type: string
|
||||||
|
lastname:
|
||||||
|
type: string
|
||||||
|
email:
|
||||||
|
type: string
|
||||||
|
|
||||||
examples:
|
examples:
|
||||||
restaurant:
|
restaurant:
|
||||||
uid: application::restaurant.restaurant
|
uid: application::restaurant.restaurant
|
||||||
|
|||||||
@ -13,7 +13,7 @@ const { ENTRY_PUBLISH, ENTRY_UNPUBLISH } = webhookUtils.webhookEvents;
|
|||||||
* A set of functions called "actions" for `ContentManager`
|
* A set of functions called "actions" for `ContentManager`
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
fetchAll(model, query) {
|
fetchAll(model, query = {}) {
|
||||||
const { query: request, populate, ...filters } = query;
|
const { query: request, populate, ...filters } = query;
|
||||||
|
|
||||||
const queryFilter = !_.isEmpty(request)
|
const queryFilter = !_.isEmpty(request)
|
||||||
@ -113,6 +113,7 @@ module.exports = {
|
|||||||
{ params, data: { [PUBLISHED_AT_ATTRIBUTE]: null } },
|
{ params, data: { [PUBLISHED_AT_ATTRIBUTE]: null } },
|
||||||
{ model }
|
{ model }
|
||||||
);
|
);
|
||||||
|
|
||||||
strapi.eventHub.emit(ENTRY_UNPUBLISH, {
|
strapi.eventHub.emit(ENTRY_UNPUBLISH, {
|
||||||
model: modelDef.modelName,
|
model: modelDef.modelName,
|
||||||
entry: sanitizeEntity(unpublishedEntry, { model: modelDef }),
|
entry: sanitizeEntity(unpublishedEntry, { model: modelDef }),
|
||||||
|
|||||||
@ -0,0 +1,66 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const { omit, prop, has, assoc } = require('lodash/fp');
|
||||||
|
const { contentTypes: contentTypesUtils } = require('strapi-utils');
|
||||||
|
const { getService } = require('../utils');
|
||||||
|
|
||||||
|
const { CREATED_BY_ATTRIBUTE } = contentTypesUtils.constants;
|
||||||
|
|
||||||
|
const pickWritableFields = ({ model }) => {
|
||||||
|
return omit(contentTypesUtils.getNonWritableAttributes(strapi.getModel(model)));
|
||||||
|
};
|
||||||
|
|
||||||
|
const fetchCreatorRoles = entity => {
|
||||||
|
const createdByPath = `${CREATED_BY_ATTRIBUTE}.id`;
|
||||||
|
|
||||||
|
if (has(createdByPath, entity)) {
|
||||||
|
const creatorId = prop(createdByPath, entity);
|
||||||
|
return strapi.query('role', 'admin').find({ 'users.id': creatorId }, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
async fetchEntitiyWithCreatorRoles(model) {
|
||||||
|
const entity = await getService('contentmanager').fetchAll(model);
|
||||||
|
|
||||||
|
if (!entity) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
|
||||||
|
const roles = await fetchCreatorRoles(entity);
|
||||||
|
return assoc(`${CREATED_BY_ATTRIBUTE}.roles`, roles, entity);
|
||||||
|
},
|
||||||
|
|
||||||
|
async create(body, { model }) {
|
||||||
|
const { files } = body;
|
||||||
|
|
||||||
|
const data = pickWritableFields({ model })(body.data);
|
||||||
|
|
||||||
|
const entity = await getService('contentmanager').create({ data, files }, { model });
|
||||||
|
|
||||||
|
await strapi.telemetry.send('didCreateFirstContentTypeEntry', { model });
|
||||||
|
return entity;
|
||||||
|
},
|
||||||
|
|
||||||
|
async update(existingEntity, body, { model }) {
|
||||||
|
const { files } = body;
|
||||||
|
|
||||||
|
const data = pickWritableFields({ model })(body.data);
|
||||||
|
|
||||||
|
const entity = await getService('contentmanager').edit(
|
||||||
|
{ id: existingEntity.id },
|
||||||
|
{ data, files },
|
||||||
|
{ model }
|
||||||
|
);
|
||||||
|
|
||||||
|
return entity;
|
||||||
|
},
|
||||||
|
|
||||||
|
async delete(existingEntity, { model }) {
|
||||||
|
return getService('contentmanager').delete(model, {
|
||||||
|
id: existingEntity.id,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
};
|
||||||
@ -31,7 +31,7 @@ describe('Content Manager single types', () => {
|
|||||||
|
|
||||||
test('Label is not pluralized', async () => {
|
test('Label is not pluralized', async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
url: `/content-manager/schemas/content-types?kind=singleType`,
|
url: `/content-manager/content-types?kind=singleType`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -39,7 +39,9 @@ describe('Content Manager single types', () => {
|
|||||||
expect(res.body.data).toEqual(
|
expect(res.body.data).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
label: 'Single-type-model',
|
info: expect.objectContaining({
|
||||||
|
label: 'Single-type-model',
|
||||||
|
}),
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
@ -47,7 +49,7 @@ describe('Content Manager single types', () => {
|
|||||||
|
|
||||||
test('find single type content returns 404 when not created', async () => {
|
test('find single type content returns 404 when not created', async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
url: `/content-manager/explorer/${uid}`,
|
url: `/content-manager/single-types/${uid}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -56,8 +58,8 @@ describe('Content Manager single types', () => {
|
|||||||
|
|
||||||
test('Create content', async () => {
|
test('Create content', async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
url: `/content-manager/explorer/${uid}`,
|
url: `/content-manager/single-types/${uid}`,
|
||||||
method: 'POST',
|
method: 'PUT',
|
||||||
body: {
|
body: {
|
||||||
title: 'Title',
|
title: 'Title',
|
||||||
},
|
},
|
||||||
@ -72,7 +74,7 @@ describe('Content Manager single types', () => {
|
|||||||
|
|
||||||
test('find single type content returns an object ', async () => {
|
test('find single type content returns an object ', async () => {
|
||||||
const res = await rq({
|
const res = await rq({
|
||||||
url: `/content-manager/explorer/${uid}`,
|
url: `/content-manager/single-types/${uid}`,
|
||||||
method: 'GET',
|
method: 'GET',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
const { prop } = require('lodash/fp');
|
const { prop } = require('lodash/fp');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
// retrieve a local service from the contet manager plugin to make the code more readable
|
// retrieve a local service
|
||||||
getService(name) {
|
getService(name) {
|
||||||
return prop(`content-manager.services.${name}`, strapi.plugins);
|
return prop(`content-manager.services.${name}`, strapi.plugins);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
'use strict';
|
||||||
|
|
||||||
|
const parseMultipartBody = require('./parse-multipart');
|
||||||
|
|
||||||
|
module.exports = ctx => {
|
||||||
|
const { body } = ctx.request;
|
||||||
|
return ctx.is('multipart') ? parseMultipartBody(ctx) : { data: body };
|
||||||
|
};
|
||||||
@ -20,8 +20,8 @@
|
|||||||
nav-accent-color=""
|
nav-accent-color=""
|
||||||
primary-color=""
|
primary-color=""
|
||||||
theme="dark"
|
theme="dark"
|
||||||
|
|
||||||
schema-style="table"
|
schema-style="table"
|
||||||
|
default-schema-tab="example"
|
||||||
>
|
>
|
||||||
</rapi-doc>
|
</rapi-doc>
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user