mirror of
https://github.com/strapi/strapi.git
synced 2025-12-26 06:35:47 +00:00
Add admin registeration API
Signed-off-by: Alexandre Bodin <bodin.alex@gmail.com>
This commit is contained in:
parent
34de63766f
commit
7a056c2f45
@ -8,35 +8,10 @@
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/currentEnvironment",
|
||||
"handler": "Admin.getCurrentEnvironment",
|
||||
"policies": []
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/gaConfig",
|
||||
"handler": "Admin.getGaConfig",
|
||||
"policies": []
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/strapiVersion",
|
||||
"handler": "Admin.getStrapiVersion",
|
||||
"policies": []
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/layout",
|
||||
"handler": "Admin.getLayout",
|
||||
"policies": []
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/init",
|
||||
"handler": "Admin.init",
|
||||
"policies": []
|
||||
"handler": "Admin.init"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
@ -64,6 +39,11 @@
|
||||
"path": "/renew-token",
|
||||
"handler": "authentication.renewToken"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/register-admin",
|
||||
"handler": "authentication.registerAdmin"
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/registration-info",
|
||||
@ -74,11 +54,6 @@
|
||||
"path": "/register",
|
||||
"handler": "authentication.register"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/auth/local/register",
|
||||
"handler": "Auth.register"
|
||||
},
|
||||
{
|
||||
"method": "POST",
|
||||
"path": "/auth/forgot-password",
|
||||
|
||||
@ -27,47 +27,13 @@ module.exports = {
|
||||
const autoReload = strapi.config.get('autoReload', false);
|
||||
const strapiVersion = strapi.config.get('info.strapi', null);
|
||||
|
||||
const hasAdmin = await strapi.admin.services.user.exists({});
|
||||
|
||||
return ctx.send({
|
||||
data: { uuid, currentEnvironment, autoReload, strapiVersion },
|
||||
data: { uuid, currentEnvironment, autoReload, strapiVersion, hasAdmin },
|
||||
});
|
||||
},
|
||||
|
||||
async getCurrentEnvironment(ctx) {
|
||||
try {
|
||||
const autoReload = strapi.config.autoReload;
|
||||
return ctx.send({ autoReload, currentEnvironment: strapi.app.env });
|
||||
} catch (err) {
|
||||
ctx.badRequest(null, [{ messages: [{ id: 'An error occurred' }] }]);
|
||||
}
|
||||
},
|
||||
|
||||
async getStrapiVersion(ctx) {
|
||||
try {
|
||||
const strapiVersion = strapi.config.get('info.strapi', null);
|
||||
return ctx.send({ strapiVersion });
|
||||
} catch (err) {
|
||||
return ctx.badRequest(null, [{ messages: [{ id: 'The version is not available' }] }]);
|
||||
}
|
||||
},
|
||||
|
||||
async getGaConfig(ctx) {
|
||||
try {
|
||||
ctx.send({ uuid: strapi.config.get('uuid', false) });
|
||||
} catch (err) {
|
||||
ctx.badRequest(null, [{ messages: [{ id: 'An error occurred' }] }]);
|
||||
}
|
||||
},
|
||||
|
||||
async getLayout(ctx) {
|
||||
try {
|
||||
const layout = require('../config/layout.js');
|
||||
|
||||
return ctx.send({ layout });
|
||||
} catch (err) {
|
||||
return ctx.badRequest(null, [{ messages: [{ id: 'An error occurred' }] }]);
|
||||
}
|
||||
},
|
||||
|
||||
async installPlugin(ctx) {
|
||||
try {
|
||||
const { plugin } = ctx.request.body;
|
||||
|
||||
@ -8,21 +8,11 @@
|
||||
|
||||
/* eslint-disable no-useless-escape */
|
||||
const crypto = require('crypto');
|
||||
const _ = require('lodash');
|
||||
|
||||
const emailRegExp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
const formatError = error => [
|
||||
{ messages: [{ id: error.id, message: error.message, field: error.field }] },
|
||||
];
|
||||
|
||||
// this is a temp patch for the next dev
|
||||
const createUser = params => ({
|
||||
...params,
|
||||
isActive: true,
|
||||
firstname: null,
|
||||
lastname: null,
|
||||
});
|
||||
|
||||
module.exports = {
|
||||
async register(ctx) {
|
||||
const params = ctx.request.body;
|
||||
|
||||
@ -5,6 +5,7 @@ const compose = require('koa-compose');
|
||||
|
||||
const {
|
||||
validateRegistrationInput,
|
||||
validateAdminRegistrationInput,
|
||||
validateRegistrationInfoQuery,
|
||||
} = require('../validation/authentication');
|
||||
|
||||
@ -94,4 +95,34 @@ module.exports = {
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
async registerAdmin(ctx) {
|
||||
const input = ctx.request.body;
|
||||
|
||||
try {
|
||||
await validateAdminRegistrationInput(input);
|
||||
} catch (err) {
|
||||
return ctx.badRequest('ValidationError', err);
|
||||
}
|
||||
|
||||
const hasAdmin = await strapi.admin.services.user.exists({});
|
||||
|
||||
if (hasAdmin) {
|
||||
return ctx.badRequest('You cannot register a new super admin');
|
||||
}
|
||||
|
||||
// TODO: assign super admin role
|
||||
const user = await strapi.admin.services.user.create({
|
||||
...input,
|
||||
registrationToken: null,
|
||||
isActive: true,
|
||||
});
|
||||
|
||||
ctx.body = {
|
||||
data: {
|
||||
token: strapi.admin.services.token.createJwtToken(user),
|
||||
user: strapi.admin.services.user.sanitizeUser(user),
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
|
||||
@ -26,11 +26,13 @@ describe('User', () => {
|
||||
test('Creates a user by merging given and default attributes', async () => {
|
||||
const create = jest.fn(user => Promise.resolve(user));
|
||||
const createToken = jest.fn(() => 'token');
|
||||
const hashPassword = jest.fn(() => Promise.resolve('123456789'));
|
||||
|
||||
global.strapi = {
|
||||
admin: {
|
||||
services: {
|
||||
token: { createToken },
|
||||
auth: { hashPassword },
|
||||
},
|
||||
},
|
||||
query() {
|
||||
@ -48,14 +50,56 @@ describe('User', () => {
|
||||
expect(result).toStrictEqual(expected);
|
||||
});
|
||||
|
||||
test('Creates a user by using given attributes', async () => {
|
||||
test('Creates a user and hash password if provided', async () => {
|
||||
const create = jest.fn(user => Promise.resolve(user));
|
||||
const createToken = jest.fn(() => 'token');
|
||||
const hashPassword = jest.fn(() => Promise.resolve('123456789'));
|
||||
|
||||
global.strapi = {
|
||||
admin: {
|
||||
services: {
|
||||
token: { createToken },
|
||||
auth: { hashPassword },
|
||||
},
|
||||
},
|
||||
query() {
|
||||
return { create };
|
||||
},
|
||||
};
|
||||
|
||||
const input = {
|
||||
firstname: 'John',
|
||||
lastname: 'Doe',
|
||||
email: 'johndoe@email.com',
|
||||
password: 'Pcw123',
|
||||
};
|
||||
const expected = {
|
||||
...input,
|
||||
password: expect.any(String),
|
||||
isActive: false,
|
||||
roles: [],
|
||||
registrationToken: 'token',
|
||||
};
|
||||
|
||||
const result = await userService.create(input);
|
||||
|
||||
expect(create).toHaveBeenCalled();
|
||||
expect(hashPassword).toHaveBeenCalledWith(input.password);
|
||||
expect(createToken).toHaveBeenCalled();
|
||||
expect(result).toStrictEqual(expected);
|
||||
expect(result.password !== input.password).toBe(true);
|
||||
});
|
||||
|
||||
test('Creates a user by using given attributes', async () => {
|
||||
const create = jest.fn(user => Promise.resolve(user));
|
||||
const createToken = jest.fn(() => 'token');
|
||||
const hashPassword = jest.fn(() => Promise.resolve('123456789'));
|
||||
|
||||
global.strapi = {
|
||||
admin: {
|
||||
services: {
|
||||
token: { createToken },
|
||||
auth: { hashPassword },
|
||||
},
|
||||
},
|
||||
query() {
|
||||
|
||||
@ -22,6 +22,16 @@ const create = async attributes => {
|
||||
...attributes,
|
||||
});
|
||||
|
||||
// hash password if a new one is sent
|
||||
if (_.has(user, 'password')) {
|
||||
const hashedPassword = await strapi.admin.services.auth.hashPassword(user.password);
|
||||
|
||||
return strapi.query('user', 'admin').create({
|
||||
...user,
|
||||
password: hashedPassword,
|
||||
});
|
||||
}
|
||||
|
||||
return strapi.query('user', 'admin').create(user);
|
||||
};
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ describe('Admin Auth End to End', () => {
|
||||
method: 'POST',
|
||||
body: {
|
||||
email: 'admin@strapi.io',
|
||||
password: 'pcw123',
|
||||
password: 'Password123',
|
||||
},
|
||||
});
|
||||
|
||||
@ -106,7 +106,7 @@ describe('Admin Auth End to End', () => {
|
||||
method: 'POST',
|
||||
body: {
|
||||
email: 'admin@strapi.io',
|
||||
password: 'pcw123',
|
||||
password: 'Password123',
|
||||
},
|
||||
});
|
||||
|
||||
@ -318,4 +318,72 @@ describe('Admin Auth End to End', () => {
|
||||
expect(res.body.data.user.password === userInfo.password).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('GET /register-admin', () => {
|
||||
test('Fails on missing payload', async () => {
|
||||
const res = await rq({
|
||||
url: '/admin/register-admin',
|
||||
method: 'POST',
|
||||
body: {},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toEqual({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'ValidationError',
|
||||
data: {
|
||||
email: ['email is a required field'],
|
||||
firstname: ['firstname is a required field'],
|
||||
lastname: ['lastname is a required field'],
|
||||
password: ['password is a required field'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Fails on invalid password', async () => {
|
||||
const res = await rq({
|
||||
url: '/admin/register-admin',
|
||||
method: 'POST',
|
||||
body: {
|
||||
email: 'test@strapi.io',
|
||||
firstname: 'test',
|
||||
lastname: 'Strapi',
|
||||
password: '123',
|
||||
},
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toEqual({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'ValidationError',
|
||||
data: {
|
||||
password: ['password must contain at least one uppercase character'],
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
test('Fails if already a user', async () => {
|
||||
const userInfo = {
|
||||
email: 'test-admin@strapi.io',
|
||||
firstname: 'test',
|
||||
lastname: 'Strapi',
|
||||
password: '1Test2azda3',
|
||||
};
|
||||
|
||||
const res = await rq({
|
||||
url: '/admin/register-admin',
|
||||
method: 'POST',
|
||||
body: userInfo,
|
||||
});
|
||||
|
||||
expect(res.statusCode).toBe(400);
|
||||
expect(res.body).toEqual({
|
||||
statusCode: 400,
|
||||
error: 'Bad Request',
|
||||
message: 'You cannot register a new super admin',
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -39,7 +39,25 @@ const validateRegistrationInfoQuery = query => {
|
||||
.catch(error => Promise.reject(formatYupErrors(error)));
|
||||
};
|
||||
|
||||
const adminRegistrationSchema = yup
|
||||
.object()
|
||||
.shape({
|
||||
email: validators.email.required(),
|
||||
firstname: validators.firstname.required(),
|
||||
lastname: validators.lastname.required(),
|
||||
password: validators.password.required(),
|
||||
})
|
||||
.required()
|
||||
.noUnknown();
|
||||
|
||||
const validateAdminRegistrationInput = data => {
|
||||
return adminRegistrationSchema
|
||||
.validate(data, { strict: true, abortEarly: false })
|
||||
.catch(error => Promise.reject(formatYupErrors(error)));
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
validateRegistrationInput,
|
||||
validateAdminRegistrationInput,
|
||||
validateRegistrationInfoQuery,
|
||||
};
|
||||
|
||||
@ -8,19 +8,6 @@
|
||||
"policies": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/init",
|
||||
"handler": "UsersPermissions.init",
|
||||
"config": {
|
||||
"policies": [],
|
||||
"description": "Check if the first admin user has already been registered",
|
||||
"tag": {
|
||||
"plugin": "users-permissions",
|
||||
"name": "Role"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"method": "GET",
|
||||
"path": "/search/:id",
|
||||
|
||||
@ -143,12 +143,6 @@ module.exports = {
|
||||
ctx.send({ message: 'ok' });
|
||||
},
|
||||
|
||||
async init(ctx) {
|
||||
const admins = await strapi.query('user', 'admin').find({ _limit: 1 });
|
||||
|
||||
ctx.send({ hasAdmin: admins.length > 0 });
|
||||
},
|
||||
|
||||
async searchUsers(ctx) {
|
||||
const { id } = ctx.params;
|
||||
|
||||
|
||||
@ -1,20 +1,22 @@
|
||||
const { createRequest } = require('./request');
|
||||
|
||||
const auth = {
|
||||
username: 'admin',
|
||||
email: 'admin@strapi.io',
|
||||
password: 'pcw123',
|
||||
firstname: 'admin',
|
||||
lastname: 'admin',
|
||||
password: 'Password123',
|
||||
};
|
||||
|
||||
const rq = createRequest();
|
||||
|
||||
const register = async () => {
|
||||
await rq({
|
||||
url: '/admin/auth/local/register',
|
||||
url: '/admin/register-admin',
|
||||
method: 'POST',
|
||||
body: auth,
|
||||
}).catch(err => {
|
||||
if (err.error.message.includes("You can't register a new admin")) return;
|
||||
console.log(err);
|
||||
if (err.message === 'You cannot register a new super admin') return;
|
||||
throw err;
|
||||
});
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user