merge master

This commit is contained in:
Virginie Ky 2019-09-19 17:09:29 +02:00
commit 230ba6b41f
46 changed files with 614 additions and 221 deletions

View File

@ -17,6 +17,10 @@
"restaurant": {
"model": "restaurant",
"via": "menu"
},
"menusections": {
"collection": "menusection",
"via": "menu"
}
}
}

View File

@ -25,7 +25,8 @@
"repeatable": true
},
"menu": {
"model": "menu"
"model": "menu",
"via": "menusections"
}
}
}

View File

@ -1,7 +1,7 @@
{
"name": "getstarted",
"private": true,
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "A Strapi application.",
"scripts": {
"develop": "strapi develop",
@ -15,23 +15,23 @@
"mysql": "^2.17.1",
"pg": "^7.10.0",
"sqlite3": "^4.0.6",
"strapi": "3.0.0-beta.16.4",
"strapi-admin": "3.0.0-beta.16.4",
"strapi-hook-bookshelf": "3.0.0-beta.16.4",
"strapi-hook-knex": "3.0.0-beta.16.4",
"strapi-hook-mongoose": "3.0.0-beta.16.4",
"strapi-middleware-views": "3.0.0-beta.16.4",
"strapi-plugin-content-manager": "3.0.0-beta.16.4",
"strapi-plugin-content-type-builder": "3.0.0-beta.16.4",
"strapi-plugin-documentation": "3.0.0-beta.16.4",
"strapi-plugin-email": "3.0.0-beta.16.4",
"strapi-plugin-graphql": "3.0.0-beta.16.4",
"strapi-plugin-settings-manager": "3.0.0-beta.16.4",
"strapi-plugin-upload": "3.0.0-beta.16.4",
"strapi-plugin-users-permissions": "3.0.0-beta.16.4",
"strapi-provider-email-mailgun": "3.0.0-beta.16.4",
"strapi-provider-upload-aws-s3": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4"
"strapi": "3.0.0-beta.16.5",
"strapi-admin": "3.0.0-beta.16.5",
"strapi-hook-bookshelf": "3.0.0-beta.16.5",
"strapi-hook-knex": "3.0.0-beta.16.5",
"strapi-hook-mongoose": "3.0.0-beta.16.5",
"strapi-middleware-views": "3.0.0-beta.16.5",
"strapi-plugin-content-manager": "3.0.0-beta.16.5",
"strapi-plugin-content-type-builder": "3.0.0-beta.16.5",
"strapi-plugin-documentation": "3.0.0-beta.16.5",
"strapi-plugin-email": "3.0.0-beta.16.5",
"strapi-plugin-graphql": "3.0.0-beta.16.5",
"strapi-plugin-settings-manager": "3.0.0-beta.16.5",
"strapi-plugin-upload": "3.0.0-beta.16.5",
"strapi-plugin-users-permissions": "3.0.0-beta.16.5",
"strapi-provider-email-mailgun": "3.0.0-beta.16.5",
"strapi-provider-upload-aws-s3": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5"
},
"strapi": {
"uuid": "getstarted"

View File

@ -1,5 +1,5 @@
{
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"packages": [
"packages/*",
"examples/*"

View File

@ -1,6 +1,6 @@
{
"name": "create-strapi-app",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate a new Strapi application.",
"license": "MIT",
"homepage": "http://strapi.io",
@ -21,7 +21,7 @@
],
"dependencies": {
"commander": "^2.20.0",
"strapi-generate-new": "3.0.0-beta.16.4"
"strapi-generate-new": "3.0.0-beta.16.5"
},
"scripts": {
"test": "echo \"no tests yet\""

View File

@ -1,6 +1,6 @@
{
"name": "strapi-admin",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Strapi Admin",
"repository": {
"type": "git",
@ -72,8 +72,8 @@
"sanitize.css": "^4.1.0",
"sass-loader": "^7.1.0",
"shelljs": "^0.7.8",
"strapi-helper-plugin": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4",
"strapi-helper-plugin": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5",
"style-loader": "^0.23.1",
"styled-components": "^4.2.0",
"terser-webpack-plugin": "^1.2.3",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-api",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate an API for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-controller",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate a controller for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-model",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate a model for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-new",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate a new Strapi application.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-plugin",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate an plugin for a Strapi application.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-policy",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate a policy for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate-service",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Generate a service for a Strapi API.",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-generate",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Master of ceremonies for the Strapi generators.",
"homepage": "http://strapi.io",
"keywords": [
@ -20,7 +20,7 @@
"fs-extra": "^8.0.1",
"lodash": "^4.17.11",
"reportback": "^2.0.2",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-utils": "3.0.0-beta.16.5"
},
"author": {
"name": "Strapi team",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-helper-plugin",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Helper for Strapi plugins development",
"files": [
"dist"

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-bookshelf",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Bookshelf hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -22,8 +22,8 @@
"lodash": "^4.17.11",
"pluralize": "^7.0.0",
"rimraf": "^2.6.3",
"strapi-hook-knex": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-hook-knex": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5"
},
"strapi": {
"dependencies": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-ejs",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "EJS hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-knex",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Knex hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-mongoose",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Mongoose hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -20,7 +20,7 @@
"mongoose-float": "^1.0.4",
"mongoose-long": "^0.2.1",
"pluralize": "^7.0.0",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-utils": "3.0.0-beta.16.5"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-hook-redis",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Redis hook for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [
@ -19,7 +19,7 @@
"lodash": "^4.17.11",
"rimraf": "^2.6.3",
"stack-trace": "0.0.10",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-utils": "3.0.0-beta.16.5"
},
"author": {
"email": "hi@strapi.io",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-middleware-views",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Views middleware to enable server-side rendering for the Strapi framework",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-content-manager",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "A powerful UI to easily manage your data.",
"strapi": {
"name": "Content Manager",
@ -32,8 +32,8 @@
"redux-immutable": "^4.0.0",
"reselect": "^3.0.1",
"showdown": "^1.9.0",
"strapi-helper-plugin": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4",
"strapi-helper-plugin": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5",
"styled-components": "^4.2.0",
"yup": "^0.27.0"
},

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-content-type-builder",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Strapi plugin to create content type (API).",
"strapi": {
"name": "Content Type Builder",
@ -29,9 +29,9 @@
"redux": "^4.0.1",
"redux-immutable": "^4.0.0",
"reselect": "^3.0.1",
"strapi-generate": "3.0.0-beta.16.4",
"strapi-generate-api": "3.0.0-beta.16.4",
"strapi-helper-plugin": "3.0.0-beta.16.4",
"strapi-generate": "3.0.0-beta.16.5",
"strapi-generate-api": "3.0.0-beta.16.5",
"strapi-helper-plugin": "3.0.0-beta.16.5",
"yup": "^0.27.0"
},
"author": {

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-documentation",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Documentation",
@ -32,7 +32,7 @@
"redux": "^4.0.1",
"redux-immutable": "^4.0.0",
"reselect": "^4.0.0",
"strapi-helper-plugin": "3.0.0-beta.16.4",
"strapi-helper-plugin": "3.0.0-beta.16.5",
"swagger-ui-dist": "3.22.1"
},
"author": {

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-email",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Email",
@ -12,13 +12,13 @@
"test": "echo \"no tests yet\""
},
"dependencies": {
"strapi-provider-email-sendmail": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-provider-email-sendmail": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5"
},
"devDependencies": {
"react-copy-to-clipboard": "5.0.1",
"rimraf": "^2.6.3",
"strapi-helper-plugin": "3.0.0-beta.16.4"
"strapi-helper-plugin": "3.0.0-beta.16.5"
},
"author": {
"name": "Strapi team",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-graphql",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "This is the description of the plugin.",
"strapi": {
"name": "graphql",
@ -23,7 +23,7 @@
"graphql-type-long": "^0.1.1",
"koa-compose": "^4.1.0",
"pluralize": "^7.0.0",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-utils": "3.0.0-beta.16.5"
},
"devDependencies": {
"cross-env": "^5.2.0",

View File

@ -174,7 +174,8 @@ module.exports = {
)
);
return async (obj, options, { context }) => {
return async (obj, options, graphqlCtx) => {
const { context } = graphqlCtx;
// Hack to be able to handle permissions for each query.
const ctx = Object.assign(_.clone(context), {
request: Object.assign(_.clone(context.request), {
@ -234,7 +235,7 @@ module.exports = {
: body;
}
return resolver.call(null, obj, options, context);
return resolver.call(null, obj, options, graphqlCtx);
}
// Resolver can be a promise.

View File

@ -202,56 +202,63 @@ const schemaBuilder = {
// Transform object to only contain function.
Object.keys(resolvers).reduce((acc, type) => {
return Object.keys(acc[type]).reduce((acc, resolver) => {
return Object.keys(acc[type]).reduce((acc, resolverName) => {
const resolverObj = acc[type][resolverName];
// Disabled this query.
if (acc[type][resolver] === false) {
delete acc[type][resolver];
if (resolverObj === false) {
delete acc[type][resolverName];
return acc;
}
if (!_.isFunction(acc[type][resolver])) {
acc[type][resolver] = acc[type][resolver].resolver;
if (_.isFunction(resolverObj)) {
return acc;
}
if (
_.isString(acc[type][resolver]) ||
_.isPlainObject(acc[type][resolver])
) {
const { plugin = '' } = _.isPlainObject(acc[type][resolver])
? acc[type][resolver]
: {};
let plugin;
if (_.has(resolverObj, ['plugin'])) {
plugin = resolverObj.plugin;
} else if (_.has(resolverObj, ['resolver', 'plugin'])) {
plugin = resolverObj.resolver.plugin;
}
switch (type) {
case 'Mutation': {
let name, action;
if (_.isString(acc[type][resolver])) {
[name, action] = acc[type][resolver].split('.');
} else if (
_.isPlainObject(acc[type][resolver]) &&
_.isString(acc[type][resolver].handler)
) {
[name, action] = acc[type][resolver].handler.split('.');
}
acc[type][resolver] = Mutation.composeMutationResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: _.toLower(name),
action,
});
break;
switch (type) {
case 'Mutation': {
let name, action;
if (
_.has(resolverObj, ['resolver']) &&
_.isString(resolverObj.resolver)
) {
[name, action] = resolverObj.resolver.split('.');
} else if (
_.has(resolverObj, ['resolver', 'handler']) &&
_.isString(resolverObj.handler)
) {
[name, action] = resolverObj.resolver.handler.split('.');
} else {
name = null;
action = resolverName;
}
case 'Query':
default:
acc[type][resolver] = Query.composeQueryResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: resolver,
isSingular: 'force', // Avoid singular/pluralize and force query name.
});
break;
const mutationResolver = Mutation.composeMutationResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: _.toLower(name),
action,
});
acc[type][resolverName] = mutationResolver;
break;
}
case 'Query':
default:
acc[type][resolverName] = Query.composeQueryResolver({
_schema: strapi.plugins.graphql.config._schema.graphql,
plugin,
name: resolverName,
isSingular: 'force', // Avoid singular/pluralize and force query name.
});
break;
}
return acc;

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-settings-manager",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Strapi plugin to manage settings.",
"strapi": {
"name": "Settings Manager",
@ -27,7 +27,7 @@
"redux": "^4.0.1",
"reselect": "^3.0.1",
"shelljs": "^0.7.8",
"strapi-helper-plugin": "3.0.0-beta.16.4"
"strapi-helper-plugin": "3.0.0-beta.16.5"
},
"author": {
"name": "Strapi team",

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-upload",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "This is the description of the plugin.",
"strapi": {
"name": "Files Upload",
@ -23,9 +23,9 @@
"react-router-dom": "^5.0.0",
"react-transition-group": "^2.5.0",
"reactstrap": "^5.0.0",
"strapi-helper-plugin": "3.0.0-beta.16.4",
"strapi-provider-upload-local": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4",
"strapi-helper-plugin": "3.0.0-beta.16.5",
"strapi-provider-upload-local": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5",
"stream-to-array": "^2.3.0",
"uuid": "^3.2.1"
},

View File

@ -0,0 +1,131 @@
'use strict';
const fs = require('fs');
const { registerAndLogin } = require('../../../test/helpers/auth');
const { createAuthRequest } = require('../../../test/helpers/request');
let rq;
const defaultProviderConfig = {
provider: 'local',
name: 'Local server',
enabled: true,
sizeLimit: 1000000,
};
const resetProviderConfigToDefault = () => {
return setConfigOptions(defaultProviderConfig);
};
const setConfigOptions = assign => {
return rq.put('/upload/settings/development', {
body: {
...defaultProviderConfig,
...assign,
},
});
};
describe('Upload plugin end to end tests', () => {
beforeAll(async () => {
const token = await registerAndLogin();
rq = createAuthRequest(token);
}, 60000);
afterEach(async () => {
await resetProviderConfigToDefault();
});
test('Upload a single file', async () => {
const req = rq.post('/graphql');
const form = req.form();
form.append(
'operations',
JSON.stringify({
query: /* GraphQL */ `
mutation uploadFiles($file: Upload!) {
upload(file: $file) {
id
name
mime
url
}
}
`,
variables: {
file: null,
},
})
);
form.append(
'map',
JSON.stringify({
0: ['variables.file'],
})
);
form.append('0', fs.createReadStream(__dirname + '/rec.jpg'));
const res = await req;
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
upload: {
id: expect.anything(),
name: 'rec.jpg',
},
},
});
});
test('Upload multiple files', async () => {
const req = rq.post('/graphql');
const form = req.form();
form.append(
'operations',
JSON.stringify({
query: /* GraphQL */ `
mutation uploadFiles($files: [Upload]!) {
multipleUpload(files: $files) {
id
name
mime
url
}
}
`,
variables: {
files: [null, null],
},
})
);
form.append(
'map',
JSON.stringify({
0: ['variables.files.0'],
1: ['variables.files.1'],
})
);
form.append('0', fs.createReadStream(__dirname + '/rec.jpg'));
form.append('1', fs.createReadStream(__dirname + '/rec.jpg'));
const res = await req;
expect(res.statusCode).toBe(200);
expect(res.body).toEqual({
data: {
multipleUpload: expect.arrayContaining([
expect.objectContaining({
id: expect.anything(),
name: 'rec.jpg',
}),
]),
},
});
});
});

View File

@ -4,19 +4,8 @@ const fs = require('fs');
// Helpers.
const { registerAndLogin } = require('../../../test/helpers/auth');
// const createModelsUtils = require('../../../test/helpers/models');
// const form = require('../../../test/helpers/generators');
const { createAuthRequest } = require('../../../test/helpers/request');
// const cleanDate = entry => {
// delete entry.updatedAt;
// delete entry.createdAt;
// delete entry.created_at;
// delete entry.updated_at;
// };
// let data;
// let modelsUtils;
let rq;
const defaultProviderConfig = {
@ -43,28 +32,6 @@ describe('Upload plugin end to end tests', () => {
beforeAll(async () => {
const token = await registerAndLogin();
rq = createAuthRequest(token);
// modelsUtils = createModelsUtils({ rq });
// await modelsUtils.createModels([
// form.article,
// form.tag,
// form.category,
// form.reference,
// form.product,
// form.articlewithtag,
// ]);
}, 60000);
afterAll(() => {
// modelsUtils.deleteModels([
// 'article',
// 'tag',
// 'category',
// 'reference',
// 'product',
// 'articlewithtag',
// ]),
}, 60000);
afterEach(async () => {

View File

@ -2,7 +2,7 @@ const _ = require('lodash');
module.exports = {
type: {
UsersPermissionsPermission: false // Make this type NOT queriable.
UsersPermissionsPermission: false, // Make this type NOT queriable.
},
definition: `
type UsersPermissionsMe {
@ -30,105 +30,136 @@ module.exports = {
resolverOf: 'User.me',
resolver: {
plugin: 'users-permissions',
handler: 'User.me'
}
handler: 'User.me',
},
},
role: {
plugin: 'users-permissions',
resolverOf: 'UsersPermissions.getRole',
resolver: async (obj, options, { context }) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.getRole(context);
resolver: async (obj, options, { context }) => {
await strapi.plugins[
'users-permissions'
].controllers.userspermissions.getRole(context);
return context.body.role;
}
},
},
roles: {
description: `Retrieve all the existing roles. You can't apply filters on this query.`,
plugin: 'users-permissions',
resolverOf: 'UsersPermissions.getRoles', // Apply the `getRoles` permissions on the resolver.
resolver: async (obj, options, { context }) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.getRoles(context);
resolver: async (obj, options, { context }) => {
await strapi.plugins[
'users-permissions'
].controllers.userspermissions.getRoles(context);
return context.body.roles;
}
}
},
},
},
Mutation: {
createRole: {
description: 'Create a new role',
plugin: 'users-permissions',
resolverOf: 'UsersPermissions.createRole',
resolver: async (obj, options, { context }) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.createRole(context);
resolver: async (obj, options, { context }) => {
await strapi.plugins[
'users-permissions'
].controllers.userspermissions.createRole(context);
return { ok: true };
}
},
},
updateRole: {
description: 'Update an existing role',
plugin: 'users-permissions',
resolverOf: 'UsersPermissions.updateRole',
resolver: async (obj, options, { context }) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.updateRole(context.params, context.body);
resolver: async (obj, options, { context }) => {
await strapi.plugins[
'users-permissions'
].controllers.userspermissions.updateRole(
context.params,
context.body
);
return { ok: true };
}
},
},
deleteRole: {
description: 'Delete an existing role',
plugin: 'users-permissions',
resolverOf: 'UsersPermissions.deleteRole',
resolver: async (obj, options, { context }) => {
await strapi.plugins['users-permissions'].controllers.userspermissions.deleteRole(context);
resolver: async (obj, options, { context }) => {
await strapi.plugins[
'users-permissions'
].controllers.userspermissions.deleteRole(context);
return { ok: true };
}
},
},
createUser: {
description: 'Create a new user',
plugin: 'users-permissions',
resolverOf: 'User.create',
resolver: async (obj, options, { context }) => {
context.params = _.toPlainObject(options.input.where);
context.params = _.toPlainObject(options.input.where);
context.request.body = _.toPlainObject(options.input.data);
await strapi.plugins['users-permissions'].controllers.user.create(context);
await strapi.plugins['users-permissions'].controllers.user.create(
context
);
return {
user: context.body.toJSON ? context.body.toJSON() : context.body
user: context.body.toJSON ? context.body.toJSON() : context.body,
};
}
},
},
updateUser: {
description: 'Update an existing user',
plugin: 'users-permissions',
resolverOf: 'User.update',
resolver: async (obj, options, { context }) => {
context.params = _.toPlainObject(options.input.where);
context.params = _.toPlainObject(options.input.where);
context.request.body = _.toPlainObject(options.input.data);
await strapi.plugins['users-permissions'].controllers.user.update(context);
await strapi.plugins['users-permissions'].controllers.user.update(
context
);
return {
user: context.body.toJSON ? context.body.toJSON() : context.body
return {
user: context.body.toJSON ? context.body.toJSON() : context.body,
};
}
},
},
deleteUser: {
description: 'Delete an existing user',
plugin: 'users-permissions',
resolverOf: 'User.destroy',
resolver: async (obj, options, { context }) => {
// Set parameters to context.
context.params = _.toPlainObject(options.input.where);
context.params = _.toPlainObject(options.input.where);
context.request.body = _.toPlainObject(options.input.data);
// Retrieve user to be able to return it because
// Retrieve user to be able to return it because
// Bookshelf doesn't return the row once deleted.
await strapi.plugins['users-permissions'].controllers.user.findOne(context);
await strapi.plugins['users-permissions'].controllers.user.findOne(
context
);
// Assign result to user.
const user = context.body.toJSON ? context.body.toJSON() : context.body;
const user = context.body.toJSON
? context.body.toJSON()
: context.body;
// Run destroy query.
await strapi.plugins['users-permissions'].controllers.user.destroy(context);
await strapi.plugins['users-permissions'].controllers.user.destroy(
context
);
return {
user
user,
};
}
}
}
}
},
},
},
},
};

View File

@ -170,27 +170,37 @@ module.exports = {
const { id } = ctx.params;
const { email, username, password } = ctx.request.body;
if (!email) return ctx.badRequest('missing.email');
if (!username) return ctx.badRequest('missing.username');
if (!password) return ctx.badRequest('missing.password');
const userWithSameUsername = await strapi
.query('user', 'users-permissions')
.findOne({ username });
if (userWithSameUsername && userWithSameUsername.id != id) {
return ctx.badRequest(
null,
ctx.request.admin
? adminError({
message: 'Auth.form.error.username.taken',
field: ['username'],
})
: 'username.alreadyTaken.'
);
if (_.has(ctx.request.body, 'email') && !email) {
return ctx.badRequest('email.notNull');
}
if (advancedConfigs.unique_email) {
if (_.has(ctx.request.body, 'username') && !username) {
return ctx.badRequest('username.notNull');
}
if (_.has(ctx.request.body, 'password') && !password) {
return ctx.badRequest('password.notNull');
}
if (_.has(ctx.request.body, 'username')) {
const userWithSameUsername = await strapi
.query('user', 'users-permissions')
.findOne({ username });
if (userWithSameUsername && userWithSameUsername.id != id) {
return ctx.badRequest(
null,
ctx.request.admin
? adminError({
message: 'Auth.form.error.username.taken',
field: ['username'],
})
: 'username.alreadyTaken.'
);
}
}
if (_.has(ctx.request.body, 'email') && advancedConfigs.unique_email) {
const userWithSameEmail = await strapi
.query('user', 'users-permissions')
.findOne({ email });
@ -216,7 +226,7 @@ module.exports = {
...ctx.request.body,
};
if (password === user.password) {
if (_.has(ctx.request.body, 'password') && password === user.password) {
delete updateData.password;
}

View File

@ -1,6 +1,6 @@
{
"name": "strapi-plugin-users-permissions",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Protect your API with a full-authentication process based on JWT",
"strapi": {
"name": "Roles & Permissions",
@ -31,8 +31,8 @@
"reactstrap": "^5.0.0",
"redux-saga": "^0.16.0",
"request": "^2.83.0",
"strapi-helper-plugin": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4",
"strapi-helper-plugin": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5",
"uuid": "^3.1.0"
},
"devDependencies": {

View File

@ -0,0 +1,241 @@
// Helpers.
const { registerAndLogin } = require('../../../test/helpers/auth');
const {
createAuthRequest,
createRequest,
} = require('../../../test/helpers/request');
let authReq;
const data = {};
describe('Test Graphql user service', () => {
beforeAll(async () => {
const token = await registerAndLogin();
authReq = createAuthRequest(token);
}, 60000);
describe('Check createUser authorizations', () => {
test('createUser is forbidden to public', async () => {
const rq = createRequest();
const res = await rq({
url: '/graphql',
method: 'POST',
body: {
query: /* GraphQL */ `
mutation {
createUser(
input: {
data: { username: "test", email: "test", password: "test" }
}
) {
user {
id
username
}
}
}
`,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
createUser: null,
},
errors: [
{
message: 'Forbidden',
},
],
});
});
test('createUser is authorized for admins', async () => {
const res = await authReq({
url: '/graphql',
method: 'POST',
body: {
query: /* GraphQL */ `
mutation {
createUser(
input: {
data: {
username: "test"
email: "test@strapi.io"
password: "test"
}
}
) {
user {
id
username
}
}
}
`,
},
});
expect(res.statusCode).toBe(201);
expect(res.body).toMatchObject({
data: {
createUser: {
user: {
id: expect.anything(),
username: 'test',
},
},
},
});
data.user = res.body.data.createUser.user;
});
});
describe('Check updateUser authorizations', () => {
test('updateUser is forbidden to public', async () => {
const rq = createRequest();
const res = await rq({
url: '/graphql',
method: 'POST',
body: {
query: /* GraphQL */ `
mutation {
updateUser(
input: {
where: { id: 1 }
data: { username: "test", email: "test", password: "test" }
}
) {
user {
id
username
}
}
}
`,
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
updateUser: null,
},
errors: [
{
message: 'Forbidden',
},
],
});
});
test('updateUser is authorized for admins', async () => {
const res = await authReq({
url: '/graphql',
method: 'POST',
body: {
query: /* GraphQL */ `
mutation updateUser($id: ID!) {
updateUser(
input: { where: { id: $id }, data: { username: "newUsername" } }
) {
user {
id
username
}
}
}
`,
variables: {
id: data.user.id,
},
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
updateUser: {
user: {
id: expect.anything(),
username: 'newUsername',
},
},
},
});
data.user = res.body.data.updateUser.user;
});
});
describe('Check deleteUser authorizations', () => {
test('deleteUser is forbidden to public', async () => {
const rq = createRequest();
const res = await rq({
url: '/graphql',
method: 'POST',
body: {
query: /* GraphQL */ `
mutation deleteUser($id: ID!) {
deleteUser(input: { where: { id: $id } }) {
user {
id
username
}
}
}
`,
variables: {
id: data.user.id,
},
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
deleteUser: null,
},
errors: [
{
message: 'Forbidden',
},
],
});
});
test('deleteUser is authorized for admins', async () => {
const res = await authReq({
url: '/graphql',
method: 'POST',
body: {
query: /* GraphQL */ `
mutation deleteUser($id: ID!) {
deleteUser(input: { where: { id: $id } }) {
user {
id
username
}
}
}
`,
variables: {
id: data.user.id,
},
},
});
expect(res.statusCode).toBe(200);
expect(res.body).toMatchObject({
data: {
deleteUser: {
user: data.user,
},
},
});
});
});
});

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-amazon-ses",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Amazon SES provider for strapi email",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-mailgun",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Mailgun provider for strapi email plugin",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-sendgrid",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Sendgrid provider for strapi email",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-email-sendmail",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Sendmail provider for strapi email",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-aws-s3",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "AWS S3 provider for strapi upload",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-cloudinary",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Cloudinary provider for strapi upload",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-local",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Local provider for strapi upload",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi-provider-upload-rackspace",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Rackspace provider for strapi upload",
"main": "./lib",
"keywords": [],

View File

@ -1,6 +1,6 @@
{
"name": "strapi-utils",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "Shared utilities for the Strapi packages",
"homepage": "http://strapi.io",
"keywords": [

View File

@ -1,6 +1,6 @@
{
"name": "strapi",
"version": "3.0.0-beta.16.4",
"version": "3.0.0-beta.16.5",
"description": "An open source headless CMS solution to create and manage your own API. It provides a powerful dashboard and features to make your life easier. Databases supported: MongoDB, MySQL, MariaDB, PostgreSQL, SQLite",
"homepage": "http://strapi.io",
"directories": {
@ -47,15 +47,15 @@
"resolve-cwd": "^3.0.0",
"rimraf": "^2.6.2",
"shelljs": "^0.8.3",
"strapi-generate": "3.0.0-beta.16.4",
"strapi-generate-api": "3.0.0-beta.16.4",
"strapi-generate-controller": "3.0.0-beta.16.4",
"strapi-generate-model": "3.0.0-beta.16.4",
"strapi-generate-new": "3.0.0-beta.16.4",
"strapi-generate-plugin": "3.0.0-beta.16.4",
"strapi-generate-policy": "3.0.0-beta.16.4",
"strapi-generate-service": "3.0.0-beta.16.4",
"strapi-utils": "3.0.0-beta.16.4"
"strapi-generate": "3.0.0-beta.16.5",
"strapi-generate-api": "3.0.0-beta.16.5",
"strapi-generate-controller": "3.0.0-beta.16.5",
"strapi-generate-model": "3.0.0-beta.16.5",
"strapi-generate-new": "3.0.0-beta.16.5",
"strapi-generate-plugin": "3.0.0-beta.16.5",
"strapi-generate-policy": "3.0.0-beta.16.5",
"strapi-generate-service": "3.0.0-beta.16.5",
"strapi-utils": "3.0.0-beta.16.5"
},
"scripts": {
"test": "jest --verbose",