Merge pull request #3052 from n8n-io/n8n-3174-add-get-usersidentifier-endpoint

 Add GET /users/:identifier endpoint
This commit is contained in:
Ricardo Espinoza 2022-03-27 18:35:21 -04:00 committed by GitHub
commit 9ef42372e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 12620 additions and 53790 deletions

66217
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -114,7 +114,7 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/InputValidationError'
/users/{userId}:
/users/{identifier}:
get:
x-eov-operation-id: getUser
x-eov-operation-handler: routes/Users
@ -124,7 +124,7 @@ paths:
description: Retrieve a user from your instance. Only available for the instance owner.
operationId: getUser
parameters:
- name: userId
- name: identifier
in: path
description: The ID or email of the user
required: true
@ -132,6 +132,14 @@ paths:
explode: false
schema:
type: string
- name: includeRole
in: query
required: false
style: form
explode: true
schema:
type: string
example: true
responses:
"200":
description: Successful operation
@ -154,7 +162,7 @@ paths:
description: Deletes a user from your instance. Only available for the instance owner.
operationId: deleteUser
parameters:
- name: userId
- name: identifier
in: path
description: The name that needs to be deleted
required: true

View file

@ -1,6 +1,7 @@
import express = require('express');
import { getConnection } from 'typeorm';
import { validate as uuidValidate } from 'uuid';
import { UserRequest } from '../../../../requests';
import { User } from '../../../../databases/entities/User';
@ -19,7 +20,32 @@ export = {
res.json({ success: true });
},
getUser: async (req: UserRequest.Get, res: express.Response): Promise<void> => {
res.json({ success: true });
const includeRole = req.query?.includeRole?.toLowerCase() === 'true' || false;
const { identifier } = req.params;
const query = getConnection(connectionName())
.getRepository(User)
.createQueryBuilder()
.leftJoinAndSelect('User.globalRole', 'Role')
.select(getSelectableProperties('user')?.map((property) => `User.${property}`));
if (includeRole) {
query.addSelect(getSelectableProperties('role')?.map((property) => `Role.${property}`));
}
if (uuidValidate(identifier)) {
query.where({ id: identifier });
} else {
query.where({ email: identifier });
}
const user = await query.getOne();
if (user === undefined) {
res.status(404);
}
res.json(user);
},
getUsers: async (req: UserRequest.Get, res: express.Response): Promise<void> => {
let offset = 0;

View file

@ -204,7 +204,7 @@ export declare namespace UserRequest {
>;
export type Get = AuthenticatedRequest<
{ id: string; email: string },
{ id: string; email: string; identifier: string },
{},
{},
{ limit: string; cursor: string; includeRole: string }

View file

@ -173,6 +173,155 @@ test('GET /users should return all users', async () => {
}
});
test('GET /users/:identifier should fail due to missing API Key', async () => {
const owner = await Db.collections.User!.findOneOrFail();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: false, user: owner });
await testDb.createUser();
const response = await authOwnerAgent.get(`/v1/users/${owner.id}`);
expect(response.statusCode).toBe(401);
});
test('GET /users/:identifier should fail due to invalid API Key', async () => {
const owner = await Db.collections.User!.findOneOrFail();
owner.apiKey = null;
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: false, user: owner });
const response = await authOwnerAgent.get(`/v1/users/${owner.id}`);
expect(response.statusCode).toBe(401);
});
test('GET /users/:identifier should fail due to member trying to access owner only endpoint', async () => {
const member = await testDb.createUser();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: true, user: member });
const response = await authOwnerAgent.get(`/v1/users/${member.id}`);
expect(response.statusCode).toBe(403);
});
test('GET /users/:identifier should fail due no instance owner not setup', async () => {
config.set('userManagement.isInstanceOwnerSetUp', false);
const owner = await Db.collections.User!.findOneOrFail();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: true, user: owner });
const response = await authOwnerAgent.get(`/v1/users/${owner.id}`);
expect(response.statusCode).toBe(400);
});
test('GET /users/:email with unexisting email should return 404', async () => {
const owner = await Db.collections.User!.findOneOrFail();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: true, user: owner });
const response = await authOwnerAgent.get(`/v1/users/jhondoe@gmail.com`);
expect(response.statusCode).toBe(404);
});
test('GET /users/:id with unexisting id should return 404', async () => {
const owner = await Db.collections.User!.findOneOrFail();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: true, user: owner });
const response = await authOwnerAgent.get(`/v1/users/123`);
expect(response.statusCode).toBe(404);
});
test('GET /users/:email should return a user', async () => {
const owner = await Db.collections.User!.findOneOrFail();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: true, user: owner });
const response = await authOwnerAgent.get(`/v1/users/${owner.email}`);
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
createdAt,
updatedAt,
} = response.body;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBeDefined();
expect(firstName).toBeDefined();
expect(lastName).toBeDefined();
expect(personalizationAnswers).toBeUndefined();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
//virtual method not working
//expect(isPending).toBe(false);
expect(globalRole).toBeUndefined();
expect(createdAt).toBeDefined();
expect(updatedAt).toBeDefined();
});
test('GET /users/:id should return a user', async () => {
const owner = await Db.collections.User!.findOneOrFail();
const authOwnerAgent = utils.createAgent(app, { apiPath: 'public', auth: true, user: owner });
const response = await authOwnerAgent.get(`/v1/users/${owner.id}`);
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
createdAt,
updatedAt,
} = response.body;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBeDefined();
expect(firstName).toBeDefined();
expect(lastName).toBeDefined();
expect(personalizationAnswers).toBeUndefined();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
//virtual method not working
//expect(isPending).toBe(false);
expect(globalRole).toBeUndefined();
expect(createdAt).toBeDefined();
expect(updatedAt).toBeDefined();
});
const INITIAL_TEST_USER = {
id: uuid(),
email: randomEmail(),