Merge branch 'v4/backend' into pluginAPI/loadPlugin

This commit is contained in:
Alexandre Bodin 2021-08-02 08:32:02 +02:00
commit c02ceab686
24 changed files with 247 additions and 174 deletions

View File

@ -97,7 +97,7 @@
"basic.simple"
]
},
"one_way_tag_edit": {
"one_way_tag": {
"type": "relation",
"relation": "oneToOne",
"target": "application::tag.tag"
@ -106,6 +106,7 @@
"type": "relation",
"relation": "oneToOne",
"target": "application::tag.tag",
"private": true,
"inversedBy": "one_to_one_kitchensink"
},
"one_to_many_tags": {

View File

@ -2,7 +2,8 @@
"kind": "collectionType",
"collectionName": "tags",
"info": {
"name": "tag"
"name": "tag",
"description": ""
},
"options": {
"draftAndPublish": true
@ -12,29 +13,29 @@
"name": {
"type": "string"
},
"one_to_one_kitchensink": {
"type": "relation",
"target": "application::kitchensink.kitchensink",
"relation": "oneToOne",
"mappedBy": "one_to_one_tag"
},
"many_to_one_kitchensink": {
"type": "relation",
"target": "application::kitchensink.kitchensink",
"relation": "manyToOne",
"target": "application::kitchensink.kitchensink",
"inversedBy": "one_to_many_tags"
},
"one_to_many_kitchensinks": {
"type": "relation",
"target": "application::kitchensink.kitchensink",
"relation": "oneToMany",
"target": "application::kitchensink.kitchensink",
"mappedBy": "many_to_one_tag"
},
"many_to_many_kitchensinks": {
"type": "relation",
"target": "application::kitchensink.kitchensink",
"relation": "manyToMany",
"target": "application::kitchensink.kitchensink",
"mappedBy": "many_to_many_tags"
},
"one_to_one_kitchensink": {
"type": "relation",
"relation": "oneToOne",
"target": "application::kitchensink.kitchensink",
"mappedBy": "one_to_one_tag"
}
}
}

View File

@ -4,5 +4,5 @@
"target": "es6"
},
"include": ["packages/**/*"],
"exclude": ["node_modules", "**/node_modules/*"]
"exclude": ["**/node_modules/*"]
}

View File

@ -1,6 +1,6 @@
'use strict';
const { has, pipe, prop, pick } = require('lodash/fp');
const { pipe, prop, pick } = require('lodash/fp');
const { MANY_RELATIONS } = require('@strapi/utils').relations.constants;
const { setCreatorFields } = require('@strapi/utils');

View File

@ -34,7 +34,7 @@ describe('Content-Manager', () => {
expect(strapi.entityService.update).toBeCalledWith(uid, entity.id, {
data: { published_at: expect.any(Date) },
params: {
populate: [],
populate: {},
},
});
});
@ -63,7 +63,7 @@ describe('Content-Manager', () => {
expect(strapi.entityService.update).toHaveBeenCalledWith(uid, entity.id, {
data: { published_at: null },
params: {
populate: [],
populate: {},
},
});
});

View File

@ -61,6 +61,10 @@ const getDeepPopulate = (uid, populate, depth = 0) => {
};
}
if (attribute.type === 'media') {
populateAcc[attributeName] = true;
}
if (attribute.type === 'dynamiczone') {
populateAcc[attributeName] = {
populate: (attribute.components || []).reduce((acc, componentUID) => {
@ -82,7 +86,9 @@ const getBasePopulate = (uid, populate) => {
const { attributes } = strapi.getModel(uid);
return Object.keys(attributes).filter(attributeName => {
return ['relation', 'component', 'dynamiczone'].includes(attributes[attributeName].type);
return ['relation', 'component', 'dynamiczone', 'media'].includes(
attributes[attributeName].type
);
});
};
@ -121,7 +127,7 @@ module.exports = ({ strapi }) => ({
},
async findOne(id, uid, populate) {
const params = { populate: getBasePopulate(uid, populate) };
const params = { populate: getDeepPopulate(uid, populate) };
return strapi.entityService.findOne(uid, id, { params });
},
@ -144,7 +150,7 @@ module.exports = ({ strapi }) => ({
publishData[PUBLISHED_AT_ATTRIBUTE] = null;
}
const params = { populate: getBasePopulate(uid) };
const params = { populate: getDeepPopulate(uid) };
return strapi.entityService.create(uid, { params, data: publishData });
},
@ -152,13 +158,13 @@ module.exports = ({ strapi }) => ({
update(entity, body, uid) {
const publishData = omitPublishedAtField(body);
const params = { populate: getBasePopulate(uid) };
const params = { populate: getDeepPopulate(uid) };
return strapi.entityService.update(uid, entity.id, { params, data: publishData });
},
delete(entity, uid) {
const params = { populate: getBasePopulate(uid) };
const params = { populate: getDeepPopulate(uid) };
return strapi.entityService.delete(uid, entity.id, { params });
},
@ -180,7 +186,7 @@ module.exports = ({ strapi }) => ({
const data = { [PUBLISHED_AT_ATTRIBUTE]: new Date() };
const params = { populate: getBasePopulate(uid) };
const params = { populate: getDeepPopulate(uid) };
return strapi.entityService.update(uid, entity.id, { params, data });
}),
@ -192,7 +198,7 @@ module.exports = ({ strapi }) => ({
const data = { [PUBLISHED_AT_ATTRIBUTE]: null };
const params = { populate: getBasePopulate(uid) };
const params = { populate: getDeepPopulate(uid) };
return strapi.entityService.update(uid, entity.id, { params, data });
}),

View File

@ -90,14 +90,12 @@ describe('CM API - Basic + compo', () => {
test('Read product with compo', async () => {
const res = await rq({
method: 'GET',
url: '/content-manager/collection-types/application::product-with-compo.product-with-compo',
url: `/content-manager/collection-types/application::product-with-compo.product-with-compo/${data.productsWithCompo[0].id}`,
});
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body.results)).toBe(true);
expect(res.body.results).toHaveLength(1);
expect(res.body.results[0]).toMatchObject(data.productsWithCompo[0]);
res.body.results.forEach(p => expect(p.published_at).toBeUndefined());
expect(res.body).toMatchObject(data.productsWithCompo[0]);
expect(res.body.published_at).toBeUndefined();
});
test('Update product with compo', async () => {

View File

@ -87,14 +87,12 @@ describe('CM API - Basic + compo', () => {
test('Read product with compo', async () => {
const res = await rq({
method: 'GET',
url: '/content-manager/collection-types/application::product-with-compo.product-with-compo',
url: `/content-manager/collection-types/application::product-with-compo.product-with-compo/${data.productsWithCompo[0].id}`,
});
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body.results)).toBe(true);
expect(res.body.results).toHaveLength(1);
expect(res.body.results[0]).toMatchObject(data.productsWithCompo[0]);
res.body.results.forEach(p => expect(p.published_at).toBeUndefined());
expect(res.body).toMatchObject(data.productsWithCompo[0]);
expect(res.body.published_at).toBeUndefined();
});
test('Update product with compo', async () => {

View File

@ -94,17 +94,12 @@ describe('CM API - Basic + compo + draftAndPublish', () => {
test('Read product with compo', async () => {
const res = await rq({
method: 'GET',
url:
'/content-manager/collection-types/application::product-with-compo-and-dp.product-with-compo-and-dp',
url: `/content-manager/collection-types/application::product-with-compo-and-dp.product-with-compo-and-dp/${data.productsWithCompoAndDP[0].id}`,
});
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body.results)).toBe(true);
expect(res.body.results).toHaveLength(1);
expect(res.body.results[0]).toMatchObject(data.productsWithCompoAndDP[0]);
res.body.results.forEach(p => {
expect(p.published_at).toBeNull();
});
expect(res.body).toMatchObject(data.productsWithCompoAndDP[0]);
expect(res.body.published_at).toBeNull();
});
test('Update product with compo', async () => {

View File

@ -91,17 +91,12 @@ describe('CM API - Basic + compo + draftAndPublish', () => {
test('Read product with compo', async () => {
const res = await rq({
method: 'GET',
url:
'/content-manager/collection-types/application::product-with-compo-and-dp.product-with-compo-and-dp',
url: `/content-manager/collection-types/application::product-with-compo-and-dp.product-with-compo-and-dp/${data.productsWithCompoAndDP[0].id}`,
});
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body.results)).toBe(true);
expect(res.body.results).toHaveLength(1);
expect(res.body.results[0]).toMatchObject(data.productsWithCompoAndDP[0]);
res.body.results.forEach(p => {
expect(p.published_at).toBeNull();
});
expect(res.body).toMatchObject(data.productsWithCompoAndDP[0]);
expect(res.body.published_at).toBeNull();
});
test('Update product with compo', async () => {

View File

@ -94,17 +94,12 @@ describe('CM API - Basic + dz + draftAndPublish', () => {
test('Read product with compo', async () => {
const res = await rq({
method: 'GET',
url:
'/content-manager/collection-types/application::product-with-dz-and-dp.product-with-dz-and-dp',
url: `/content-manager/collection-types/application::product-with-dz-and-dp.product-with-dz-and-dp/${data.productsWithDzAndDP[0].id}`,
});
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body.results)).toBe(true);
expect(res.body.results).toHaveLength(1);
expect(res.body.results[0]).toMatchObject(data.productsWithDzAndDP[0]);
res.body.results.forEach(p => {
expect(p.published_at).toBeNull();
});
expect(res.body).toMatchObject(data.productsWithDzAndDP[0]);
expect(res.body.published_at).toBeNull();
});
test('Update product with compo', async () => {

View File

@ -90,14 +90,12 @@ describe('Core API - Basic + dz', () => {
test('Read product with compo', async () => {
const res = await rq({
method: 'GET',
url: '/content-manager/collection-types/application::product-with-dz.product-with-dz',
url: `/content-manager/collection-types/application::product-with-dz.product-with-dz/${data.productsWithDz[0].id}`,
});
expect(res.statusCode).toBe(200);
expect(Array.isArray(res.body.results)).toBe(true);
expect(res.body.results).toHaveLength(1);
expect(res.body.results[0]).toMatchObject(data.productsWithDz[0]);
res.body.results.forEach(p => expect(p.published_at).toBeUndefined());
expect(res.body).toMatchObject(data.productsWithDz[0]);
expect(res.body.published_at).toBeUndefined();
});
test('Update product with compo', async () => {

View File

@ -9,9 +9,28 @@ const { isRelation, isConfigurable } = require('../../utils/attributes');
const { typeKinds } = require('../constants');
const createSchemaHandler = require('./schema-handler');
const reuseUnsetPreviousProperties = (newAttribute, oldAttribute) => {
_.defaults(
newAttribute,
_.omit(oldAttribute, [
'configurable',
'required',
'private',
'unique',
'pluginOptions',
'inversedBy',
'mappedBy',
])
);
};
module.exports = function createComponentBuilder() {
return {
setRelation({ key, uid, attribute }) {
if (!_.has(attribute, 'target')) {
return;
}
const targetCT = this.contentTypes.get(attribute.target);
const targetAttribute = targetCT.getAttribute(attribute.targetAttribute);
@ -31,6 +50,10 @@ module.exports = function createComponentBuilder() {
},
unsetRelation(attribute) {
if (!_.has(attribute, 'target')) {
return;
}
const targetCT = this.contentTypes.get(attribute.target);
const targetAttributeName = attribute.inversedBy || attribute.mappedBy;
@ -38,11 +61,6 @@ module.exports = function createComponentBuilder() {
if (!targetAttribute) return;
// TODO: do not delete polymorphic relations
// if (false) {
// return;
// }
return targetCT.deleteAttribute(targetAttributeName);
},
@ -156,17 +174,21 @@ module.exports = function createComponentBuilder() {
if (isRelation(oldAttribute) && isRelation(newAttribute)) {
const oldTargetAttributeName = oldAttribute.inversedBy || oldAttribute.mappedBy;
if (
!_.isNil(oldTargetAttributeName) &&
oldTargetAttributeName !== newAttribute.targetAttribute
) {
const sameRelation = oldAttribute.relation === newAttribute.relation;
const targetAttributeHasChanged = oldTargetAttributeName !== newAttribute.targetAttribute;
if (!sameRelation || targetAttributeHasChanged) {
this.unsetRelation(oldAttribute);
}
// TODO: handle edition to keep the direction
// keep extra options that were set manually on oldAttribute
_.defaults(newAttribute, oldAttribute);
reuseUnsetPreviousProperties(newAttribute, oldAttribute);
if (oldAttribute.inversedBy) {
newAttribute.dominant = true;
} else if (oldAttribute.mappedBy) {
newAttribute.dominant = false;
}
return this.setRelation({
key,
@ -239,7 +261,12 @@ const generateRelation = ({ key, attribute, uid, targetAttribute = {} }) => {
switch (attribute.relation) {
case 'oneToOne': {
opts.relation = 'oneToOne';
opts.mappedBy = key;
if (attribute.dominant) {
opts.mappedBy = key;
} else {
opts.inversedBy = key;
}
break;
}
case 'oneToMany': {
@ -254,12 +281,25 @@ const generateRelation = ({ key, attribute, uid, targetAttribute = {} }) => {
}
case 'manyToMany': {
opts.relation = 'manyToMany';
opts.mappedBy = key;
if (attribute.dominant) {
opts.mappedBy = key;
} else {
opts.inversedBy = key;
}
break;
}
default:
}
return opts;
// we do this just to make sure we have the same key order when writing to files
const { type, relation, target, ...restOptions } = opts;
return {
type,
relation,
target,
...restOptions,
};
};

View File

@ -93,45 +93,51 @@ function createSchemaBuilder({ components, contentTypes }) {
return Object.keys(attributes).reduce((acc, key) => {
const attribute = attributes[key];
const { configurable } = attribute;
const { configurable, private: isPrivate } = attribute;
const baseProperties = {
private: isPrivate === true ? true : undefined,
configurable: configurable === false ? false : undefined,
};
if (attribute.type === 'relation') {
const { target, relation, targetAttribute, private: isPrivate } = attribute;
const { target, relation, targetAttribute, dominant, ...restOfProperties } = attribute;
const attr = {
type: 'relation',
relation,
target,
configurable: configurable === false ? false : undefined,
private: isPrivate === true ? true : undefined,
...restOfProperties,
...baseProperties,
};
acc[key] = attr;
if (target && !this.contentTypes.has(target)) {
throw new Error(`target: ${target} does not exist`);
}
// FIXME: this will create inversion of inversedBy & mappedBy fields
if (
['oneToOne', 'manyToOne', 'manyToMany'].includes(relation) &&
!_.isNil(targetAttribute)
) {
if (_.isNil(targetAttribute)) {
return acc;
}
if (['oneToOne', 'manyToMany'].includes(relation) && dominant === true) {
attr.inversedBy = targetAttribute;
} else if (['oneToMany'].includes(relation) && !_.isNil(targetAttribute)) {
} else if (['oneToOne', 'manyToMany'].includes(relation) && dominant === false) {
attr.mappedBy = targetAttribute;
} else if (['oneToOne', 'manyToOne', 'manyToMany'].includes(relation)) {
attr.inversedBy = targetAttribute;
} else if (['oneToMany'].includes(relation)) {
attr.mappedBy = targetAttribute;
}
acc[key] = attr;
return acc;
}
if (_.has(attribute, 'type')) {
acc[key] = {
...attribute,
configurable: configurable === false ? false : undefined,
};
return acc;
}
acc[key] = {
...attribute,
...baseProperties,
};
return acc;
}, {});

View File

@ -7,6 +7,9 @@ const { createQueryBuilder } = require('./query');
const { createRepository } = require('./entity-repository');
const { isBidirectional } = require('./metadata/relations');
const toId = value => value.id || value;
const toIds = value => _.castArray(value || []).map(toId);
// TODO: move to query layer
const toRow = (metadata, data = {}) => {
const { attributes } = metadata;
@ -53,13 +56,24 @@ const toRow = (metadata, data = {}) => {
const value = data[attributeName];
if (value === null) {
Object.assign(obj, {
[idColumn.name]: null,
[typeColumn.name]: null,
});
continue;
}
if (!_.isUndefined(value)) {
if (!_.has('id', value) || !_.has(typeField, value)) {
throw new Error(`Expects properties ${typeField} an id to make a morph association`);
}
obj[idColumn.name] = value.id;
obj[typeColumn.name] = value[typeField];
Object.assign(obj, {
[idColumn.name]: value.id,
[typeColumn.name]: value[typeField],
});
}
}
}
@ -278,15 +292,15 @@ const createEntityManager = db => {
await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: data[attributeName] })
.where({ id: toId(data[attributeName]) })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
} else if (targetAttribute.relation === 'morphToMany') {
const { joinTable } = targetAttribute;
const { joinColumn, morphColumn } = joinTable;
const { idColumn, typeColumn } = morphColumn;
const rows = _.castArray(data[attributeName]).map((dataID, idx) => ({
const rows = toIds(data[attributeName]).map((dataID, idx) => ({
[joinColumn.name]: dataID,
[idColumn.name]: id,
[typeColumn.name]: uid,
@ -313,7 +327,7 @@ const createEntityManager = db => {
const { idColumn, typeColumn, typeField = '__type' } = morphColumn;
const rows = _.castArray(data[attributeName]).map((data, idx) => ({
const rows = _.castArray(data[attributeName] || []).map((data, idx) => ({
[joinColumn.name]: id,
[idColumn.name]: data.id,
[typeColumn.name]: data[typeField],
@ -426,17 +440,6 @@ const createEntityManager = db => {
continue;
}
/*
if morphOne | morphMany
clear previous:
if morphBy is morphToOne
set null
set new
if morphBy is morphToMany
delete links
add links
*/
if (attribute.relation === 'morphOne' || attribute.relation === 'morphMany') {
const { target, morphBy } = attribute;
@ -451,11 +454,13 @@ const createEntityManager = db => {
.where({ [idColumn.name]: id, [typeColumn.name]: uid })
.execute();
await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: data[attributeName] })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
if (!_.isNull(data[attributeName])) {
await this.createQueryBuilder(target)
.update({ [idColumn.name]: id, [typeColumn.name]: uid })
.where({ id: toId(data[attributeName]) })
.execute();
}
} else if (targetAttribute.relation === 'morphToMany') {
const { joinTable } = targetAttribute;
const { joinColumn, morphColumn } = joinTable;
@ -470,7 +475,7 @@ const createEntityManager = db => {
})
.execute();
const rows = _.castArray(data[attributeName]).map((dataID, idx) => ({
const rows = toIds(data[attributeName] || []).map((dataID, idx) => ({
[joinColumn.name]: dataID,
[idColumn.name]: id,
[typeColumn.name]: uid,
@ -490,21 +495,11 @@ const createEntityManager = db => {
continue;
}
/*
if morphToOne
set new values in morph columns
*/
if (attribute.relation === 'morphToOne') {
// do nothing
// handled on the entry itself
continue;
}
/*
if morphToMany
delete old links
create new links
*/
if (attribute.relation === 'morphToMany') {
const { joinTable } = attribute;
const { joinColumn, morphColumn } = joinTable;
@ -519,7 +514,7 @@ const createEntityManager = db => {
})
.execute();
const rows = _.castArray(data[attributeName]).map((data, idx) => ({
const rows = _.castArray(data[attributeName] || []).map((data, idx) => ({
[joinColumn.name]: id,
[idColumn.name]: data.id,
[typeColumn.name]: data[typeField],
@ -577,13 +572,13 @@ const createEntityManager = db => {
if (['oneToOne', 'oneToMany'].includes(attribute.relation)) {
await this.createQueryBuilder(joinTable.name)
.delete()
.where({ [inverseJoinColumn.name]: _.castArray(data[attributeName]) })
.where({ [inverseJoinColumn.name]: _.castArray(data[attributeName] || []) })
.where(joinTable.on || {})
.execute();
}
if (!_.isNull(data[attributeName])) {
const insert = _.castArray(data[attributeName]).map(datum => {
const insert = _.castArray(data[attributeName] || []).map(datum => {
return {
[joinColumn.name]: id,
[inverseJoinColumn.name]: datum,
@ -644,7 +639,7 @@ const createEntityManager = db => {
.update({ [idColumn.name]: null, [typeColumn.name]: null })
.where({ [idColumn.name]: id, [typeColumn.name]: uid })
.execute();
} else if (targetAttribute.type === 'morphToMany') {
} else if (targetAttribute.relation === 'morphToMany') {
const { joinTable } = targetAttribute;
const { morphColumn } = joinTable;

View File

@ -168,7 +168,7 @@ const createManyToMany = (attributeName, attribute, meta, metadata) => {
* @param {ModelMetadata} meta
* @param {Metadata} metadata
*/
const createMorphToOne = (attributeName, attribute, meta, metadata) => {
const createMorphToOne = (attributeName, attribute /*meta, metadata*/) => {
const idColumnName = 'target_id';
const typeColumnName = 'target_type';
@ -344,7 +344,7 @@ const createJoinColum = (metadata, { attribute, attributeName /*meta */ }) => {
if (isBidirectional(attribute)) {
const inverseAttribute = targetMeta.attributes[attribute.inversedBy];
// TODO: do not invert here but invert in the query ? => means we need to use owner info in the query layer
Object.assign(inverseAttribute, {
joinColumn: {
name: joinColumn.referencedColumn,

View File

@ -799,7 +799,7 @@ const applyPopulate = async (results, populate, ctx) => {
});
continue;
} else if (attribute.relation in ['morphOne', 'morphMany']) {
} else if (['morphOne', 'morphMany'].includes(attribute.relation)) {
const { target, morphBy } = attribute;
const targetAttribute = db.metadata.get(target).attributes[morphBy];
@ -849,7 +849,7 @@ const applyPopulate = async (results, populate, ctx) => {
if (_.isEmpty(referencedValues)) {
results.forEach(result => {
result[key] = [];
result[key] = attribute.relation === 'morphOne' ? null : [];
});
continue;

View File

@ -56,6 +56,7 @@ const createTable = meta => {
// NOTE: we could pass uniquness for oneToOne to avoid creating more than one to one
const { name: columnName, referencedColumn, referencedTable } = attribute.joinColumn;
table.columns.push(
createColumn(columnName, {
type: 'integer',

View File

@ -6,7 +6,7 @@ const transformAttribute = attribute => {
// TODO: handle a filter on field
return {
type: 'relation',
relation: attribute.single === true ? 'morphOne' : 'morphMany',
relation: attribute.multiple === true ? 'morphMany' : 'morphOne',
target: 'plugins::upload.file',
morphBy: 'related',
};

View File

@ -57,6 +57,21 @@ module.exports = ctx => {
return service;
};
// TODO: remove once the front is migrated
const convertOldQuery = params => {
const obj = {};
Object.keys(params).forEach(key => {
if (key.startsWith('_')) {
obj[key.slice(1)] = params[key];
} else {
obj[key] = params[key];
}
});
return obj;
};
// TODO: move to Controller ?
const transformParamsToQuery = (uid, params = {}) => {
const model = strapi.getModel(uid);
@ -75,10 +90,13 @@ const transformParamsToQuery = (uid, params = {}) => {
fields,
populate,
publicationState,
_q,
_where,
...rest
} = params;
if (params._q) {
query._q = params._q;
if (_q) {
query._q = _q;
}
if (page) {
@ -105,6 +123,12 @@ const transformParamsToQuery = (uid, params = {}) => {
query.where = filters;
}
if (_where) {
query.where = {
$and: [_where].concat(query.where || []),
};
}
if (fields) {
query.select = _.castArray(fields);
}
@ -133,7 +157,12 @@ const transformParamsToQuery = (uid, params = {}) => {
}
}
return query;
const finalQuery = {
...convertOldQuery(rest),
...query,
};
return finalQuery;
};
const pickSelectionParams = pick(['fields', 'populate']);

View File

@ -35,6 +35,20 @@ const wrapParams = async (params = {}, ctx = {}) => {
};
}
// TODO: remove when the _locale is renamed to locale
if (has('_locale', params)) {
if (params['_locale'] === 'all') {
return omit('_locale', params);
}
return {
...omit('_locale', params),
filters: {
$and: [{ locale: params['_locale'] }].concat(params.filters || []),
},
};
}
const entityDefinedById = paramsContain('id', params) && SINGLE_ENTRY_ACTIONS.includes(action);
const entitiesDefinedByIds = paramsContain('id.$in', params) && BULK_ACTIONS.includes(action);

View File

@ -174,7 +174,7 @@
{
"method": "GET",
"path": "/connect/*",
"handler": "Auth.connect",
"handler": "auth.connect",
"config": {
"policies": ["plugins::users-permissions.ratelimit"],
"prefix": "",
@ -188,7 +188,7 @@
{
"method": "POST",
"path": "/auth/local",
"handler": "Auth.callback",
"handler": "auth.callback",
"config": {
"policies": ["plugins::users-permissions.ratelimit"],
"prefix": "",
@ -202,7 +202,7 @@
{
"method": "POST",
"path": "/auth/local/register",
"handler": "Auth.register",
"handler": "auth.register",
"config": {
"policies": ["plugins::users-permissions.ratelimit"],
"prefix": "",
@ -217,7 +217,7 @@
{
"method": "GET",
"path": "/auth/:provider/callback",
"handler": "Auth.callback",
"handler": "auth.callback",
"config": {
"policies": [],
"prefix": "",
@ -231,7 +231,7 @@
{
"method": "POST",
"path": "/auth/forgot-password",
"handler": "Auth.forgotPassword",
"handler": "auth.forgotPassword",
"config": {
"policies": ["plugins::users-permissions.ratelimit"],
"prefix": "",
@ -245,7 +245,7 @@
{
"method": "POST",
"path": "/auth/reset-password",
"handler": "Auth.resetPassword",
"handler": "auth.resetPassword",
"config": {
"policies": ["plugins::users-permissions.ratelimit"],
"prefix": "",
@ -259,7 +259,7 @@
{
"method": "GET",
"path": "/auth/email-confirmation",
"handler": "Auth.emailConfirmation",
"handler": "auth.emailConfirmation",
"config": {
"policies": [],
"prefix": "",
@ -273,7 +273,7 @@
{
"method": "POST",
"path": "/auth/send-email-confirmation",
"handler": "Auth.sendEmailConfirmation",
"handler": "auth.sendEmailConfirmation",
"config": {
"policies": [],
"prefix": "",
@ -287,7 +287,7 @@
{
"method": "GET",
"path": "/users/count",
"handler": "User.count",
"handler": "user.count",
"config": {
"prefix": "",
"policies": []
@ -296,7 +296,7 @@
{
"method": "GET",
"path": "/users",
"handler": "User.find",
"handler": "user.find",
"config": {
"policies": [],
"prefix": "",
@ -311,7 +311,7 @@
{
"method": "GET",
"path": "/users/me",
"handler": "User.me",
"handler": "user.me",
"config": {
"policies": [],
"prefix": "",
@ -326,7 +326,7 @@
{
"method": "GET",
"path": "/users/:id",
"handler": "User.findOne",
"handler": "user.findOne",
"config": {
"policies": [],
"prefix": "",
@ -341,7 +341,7 @@
{
"method": "POST",
"path": "/users",
"handler": "User.create",
"handler": "user.create",
"config": {
"policies": [],
"prefix": ""
@ -350,7 +350,7 @@
{
"method": "PUT",
"path": "/users/:id",
"handler": "User.update",
"handler": "user.update",
"config": {
"policies": [],
"prefix": "",
@ -365,7 +365,7 @@
{
"method": "DELETE",
"path": "/users/:id",
"handler": "User.destroy",
"handler": "user.destroy",
"config": {
"policies": [],
"prefix": "",

View File

@ -35,12 +35,12 @@ module.exports = ({ strapi }) => ({
*/
async add(values) {
if (values.password) {
values.password = await strapi.plugins['users-permissions'].services.user.hashPassword(
values
);
values.password = await getService('user').hashPassword(values);
}
return strapi.query('plugins::users-permissions.user').create({ data: values });
return strapi
.query('plugins::users-permissions.user')
.create({ data: values, populate: ['role'] });
},
/**
@ -52,7 +52,9 @@ module.exports = ({ strapi }) => ({
values.password = await getService('user').hashPassword(values);
}
return strapi.query('plugins::users-permissions.user').update({ where: params, data: values });
return strapi
.query('plugins::users-permissions.user')
.update({ where: params, data: values, populate: ['role'] });
},
/**
@ -121,7 +123,7 @@ module.exports = ({ strapi }) => ({
},
async sendConfirmationEmail(user) {
const userPermissionService = strapi.plugins['users-permissions'].services.userspermissions;
const userPermissionService = getService('users-permissions');
const pluginStore = await strapi.store({
environment: '',
type: 'plugin',

View File

@ -10,6 +10,7 @@ const DEFAULT_PERMISSIONS = [
{ action: 'callback', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'connect', controller: 'auth', type: 'users-permissions', roleType: null },
{ action: 'forgotpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'resetpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'register', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{
action: 'emailconfirmation',
@ -17,20 +18,18 @@ const DEFAULT_PERMISSIONS = [
type: 'users-permissions',
roleType: 'public',
},
{ action: 'resetpassword', controller: 'auth', type: 'users-permissions', roleType: 'public' },
{ action: 'init', controller: 'userspermissions', type: null, roleType: null },
{ action: 'me', controller: 'user', type: 'users-permissions', roleType: null },
{ action: 'autoreload', controller: null, type: null, roleType: null },
];
const isPermissionEnabled = (permission, role) =>
DEFAULT_PERMISSIONS.some(
const isEnabledByDefault = (permission, role) => {
return DEFAULT_PERMISSIONS.some(
defaultPerm =>
(defaultPerm.action === null || permission.action === defaultPerm.action) &&
(defaultPerm.controller === null || permission.controller === defaultPerm.controller) &&
(defaultPerm.type === null || permission.type === defaultPerm.type) &&
(defaultPerm.roleType === null || role.type === defaultPerm.roleType)
);
};
module.exports = ({ strapi }) => ({
async createRole(params) {
@ -254,7 +253,7 @@ module.exports = ({ strapi }) => ({
async updatePermissions() {
const roles = await strapi.query('plugins::users-permissions.role').findMany();
const rolesMap = _.groupBy(roles, 'id');
const rolesMap = _.keyBy(roles, 'id');
const dbPermissions = await strapi
.query('plugins::users-permissions.permission')
@ -319,18 +318,18 @@ module.exports = ({ strapi }) => ({
// Execute request to update entries in database for each role.
await Promise.all(
toAdd.map(permission =>
query.create({
toAdd.map(permission => {
return query.create({
data: {
type: permission.type,
controller: permission.controller,
action: permission.action,
enabled: isPermissionEnabled(permission, rolesMap[permission.roleId]),
enabled: isEnabledByDefault(permission, rolesMap[permission.roleId]),
policy: '',
role: permission.roleId,
},
})
)
});
})
);
await Promise.all(