From edbff44c8255ddc4044218e7561d3d98ea8df739 Mon Sep 17 00:00:00 2001 From: KalanyuZ Date: Wed, 16 Oct 2019 00:17:54 +0900 Subject: [PATCH] Add GraphQL register/login (#3879) * Add GraphQL login * Add GraphQL register * Add graphql login/register/delete End2End test * Update from requests * Remove logging * Update to beta.16 * Update * Add error handling * Util function * Update --- packages/strapi-admin/index.js | 2 +- .../config/schema.graphql | 67 ++++++++- .../controllers/User.js | 1 - .../test/users-graphql.test.e2e.js | 138 ++++++++++++++++++ .../lib/index.js | 47 +++--- 5 files changed, 229 insertions(+), 26 deletions(-) create mode 100644 packages/strapi-plugin-users-permissions/test/users-graphql.test.e2e.js diff --git a/packages/strapi-admin/index.js b/packages/strapi-admin/index.js index 6bc8fb59ab..967f3b005b 100644 --- a/packages/strapi-admin/index.js +++ b/packages/strapi-admin/index.js @@ -201,7 +201,7 @@ async function watchAdmin({ dir, port, options }) { clientLogLevel: 'silent', hot: true, quiet: true, - open: true, + open: true, publicPath: options.publicPath, historyApiFallback: { index: options.publicPath, diff --git a/packages/strapi-plugin-users-permissions/config/schema.graphql b/packages/strapi-plugin-users-permissions/config/schema.graphql index b41b6df2d1..85d3c9b3dd 100644 --- a/packages/strapi-plugin-users-permissions/config/schema.graphql +++ b/packages/strapi-plugin-users-permissions/config/schema.graphql @@ -1,4 +1,18 @@ const _ = require('lodash'); +const { ApolloError } = require('apollo-server-koa'); + +/** +* Throws an ApolloError if context body contains a bad request +* @param contextBody - body of the context object given to the resolver +* @throws ApolloError if the body is a bad request +*/ +function checkBadRequest(contextBody) { + if (_.get(contextBody, 'output.payload.statusCode', 200) !== 200) { + const statusCode = _.get(contextBody, 'output.payload.statusCode', 400); + const message = _.get(contextBody, 'output.payload.message', 'Bad Request'); + throw new ApolloError(message, statusCode, _.omit(contextBody, ['output'])); + } +} module.exports = { type: { @@ -20,10 +34,25 @@ module.exports = { description: String type: String } + + input UsersPermissionsLoginInput { + identifier: String! + password: String! + provider: String = "local" + } + + type UsersPermissionsLoginPayload { + jwt: String! + user: UsersPermissionsUser! + } `, query: ` me: UsersPermissionsMe `, + mutation: ` + login(input: UsersPermissionsLoginInput!): UsersPermissionsLoginPayload! + register(input: UserInput!): UsersPermissionsLoginPayload! + `, resolver: { Query: { me: { @@ -158,8 +187,40 @@ module.exports = { return { user, }; - }, + } }, - }, - }, + register: { + description: 'Register a user', + plugin: 'users-permissions', + resolverOf: 'Auth.register', + resolver: async (obj, options, {context}) => { + context.request.body = _.toPlainObject(options.input); + + await strapi.plugins['users-permissions'].controllers.auth.register(context); + let output = context.body.toJSON ? context.body.toJSON() : context.body; + + checkBadRequest(output); + return { + user: output.user || output, jwt: output.jwt + }; + } + }, + login: { + resolverOf: 'Auth.callback', + plugin: 'users-permissions', + resolver: async (obj, options, {context}) => { + context.params = {...context.params, provider: options.input.provider}; + context.request.body = _.toPlainObject(options.input); + + await strapi.plugins['users-permissions'].controllers.auth.callback(context); + let output = context.body.toJSON ? context.body.toJSON() : context.body; + + checkBadRequest(output); + return { + user: output.user || output, jwt: output.jwt + }; + } + } + } + } }; diff --git a/packages/strapi-plugin-users-permissions/controllers/User.js b/packages/strapi-plugin-users-permissions/controllers/User.js index ef4d0770e1..37ecf5a71e 100644 --- a/packages/strapi-plugin-users-permissions/controllers/User.js +++ b/packages/strapi-plugin-users-permissions/controllers/User.js @@ -246,7 +246,6 @@ module.exports = { const data = await strapi.plugins['users-permissions'].services.user.remove( { id } ); - ctx.send(data); }, diff --git a/packages/strapi-plugin-users-permissions/test/users-graphql.test.e2e.js b/packages/strapi-plugin-users-permissions/test/users-graphql.test.e2e.js new file mode 100644 index 0000000000..af216116b1 --- /dev/null +++ b/packages/strapi-plugin-users-permissions/test/users-graphql.test.e2e.js @@ -0,0 +1,138 @@ +// Test a simple default API with no relations + +const { registerAndLogin } = require('../../../test/helpers/auth'); +const { createAuthRequest } = require('../../../test/helpers/request'); + +let rq; +let graphqlQuery; +let data = {}; + +describe('Test Graphql Users API End to End', () => { + beforeAll(async () => { + const token = await registerAndLogin(); + rq = createAuthRequest(token); + + graphqlQuery = body => { + return rq({ + url: '/graphql', + method: 'POST', + body, + }); + }; + }, 60000); + + describe('Test register and login', () => { + const user = { + username: 'User 1', + email: 'user1@strapi.io', + password: 'test1234', + }; + + test('Register a user', async () => { + const res = await graphqlQuery({ + query: /* GraphQL */ ` + mutation register($input: UserInput!) { + register(input: $input) { + jwt + user { + id + email + } + } + } + `, + variables: { + input: user, + }, + }); + + const { body } = res; + + expect(res.statusCode).toBe(200); + expect(body).toMatchObject({ + data: { + register: { + jwt: expect.any(String), + user: { + id: expect.any(String), + email: user.email, + }, + }, + }, + }); + data.user = res.body.data.register.user; + }); + + test('Log in a user', async () => { + const res = await graphqlQuery({ + query: /* GraphQL */ ` + mutation login($input: UsersPermissionsLoginInput!) { + login(input: $input) { + jwt + user { + id + email + } + } + } + `, + variables: { + input: { + identifier: user.username, + password: user.password, + }, + }, + }); + + const { body } = res; + + expect(res.statusCode).toBe(200); + expect(body).toMatchObject({ + data: { + login: { + jwt: expect.any(String), + user: { + id: expect.any(String), + email: user.email, + }, + }, + }, + }); + data.user = res.body.data.login.user; + }); + + test('Delete a user', async () => { + const res = await graphqlQuery({ + query: /* GraphQL */ ` + mutation deleteUser($input: deleteUserInput) { + deleteUser(input: $input) { + user { + email + } + } + } + `, + variables: { + input: { + where: { + id: data.user.id, + }, + }, + }, + }); + + const { body } = res; + + expect(res.statusCode).toBe(200); + expect(body).toMatchObject({ + data: { + deleteUser: { + user: { + email: data.user.email, + }, + }, + }, + }); + }); + }); +}); diff --git a/packages/strapi-provider-email-sendmail/lib/index.js b/packages/strapi-provider-email-sendmail/lib/index.js index 9808289e60..0ced57f85b 100644 --- a/packages/strapi-provider-email-sendmail/lib/index.js +++ b/packages/strapi-provider-email-sendmail/lib/index.js @@ -7,7 +7,7 @@ // Public node modules. const _ = require('lodash'); const sendmail = require('sendmail')({ - silent: true + silent: true, }); /* eslint-disable no-unused-vars */ @@ -17,14 +17,14 @@ module.exports = { auth: { sendmail_default_from: { label: 'Sendmail Default From', - type: 'text' + type: 'text', }, sendmail_default_replyto: { label: 'Sendmail Default Reply-To', - type: 'text' - } + type: 'text', + }, }, - init: (config) => { + init: config => { return { send: (options, cb) => { return new Promise((resolve, reject) => { @@ -35,23 +35,28 @@ module.exports = { options.text = options.text || options.html; options.html = options.html || options.text; - sendmail({ - from: options.from, - to: options.to, - replyTo: options.replyTo, - subject: options.subject, - text: options.text, - html: options.html, - attachments: options.attachments - }, function (err) { - if (err) { - reject([{ messages: [{ id: 'Auth.form.error.email.invalid' }] }]); - } else { - resolve(); + sendmail( + { + from: options.from, + to: options.to, + replyTo: options.replyTo, + subject: options.subject, + text: options.text, + html: options.html, + attachments: options.attachments, + }, + function(err) { + if (err) { + reject([ + { messages: [{ id: 'Auth.form.error.email.invalid' }] }, + ]); + } else { + resolve(); + } } - }); + ); }); - } + }, }; - } + }, };