mirror of
https://github.com/n8n-io/n8n.git
synced 2025-01-11 21:07:28 -08:00
Merge pull request #3052 from n8n-io/n8n-3174-add-get-usersidentifier-endpoint
⚡ Add GET /users/:identifier endpoint
This commit is contained in:
commit
9ef42372e7
66217
package-lock.json
generated
66217
package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
2
packages/cli/src/requests.d.ts
vendored
2
packages/cli/src/requests.d.ts
vendored
|
@ -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 }
|
||||
|
|
|
@ -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(),
|
||||
|
|
Loading…
Reference in a new issue