mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
⚡ Add GET /users/:identifier endpoint
This commit is contained in:
parent
8829684d5b
commit
924773ef5d
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:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/InputValidationError'
|
$ref: '#/components/schemas/InputValidationError'
|
||||||
/users/{userId}:
|
/users/{identifier}:
|
||||||
get:
|
get:
|
||||||
x-eov-operation-id: getUser
|
x-eov-operation-id: getUser
|
||||||
x-eov-operation-handler: routes/Users
|
x-eov-operation-handler: routes/Users
|
||||||
|
@ -124,7 +124,7 @@ paths:
|
||||||
description: Retrieve a user from your instance. Only available for the instance owner.
|
description: Retrieve a user from your instance. Only available for the instance owner.
|
||||||
operationId: getUser
|
operationId: getUser
|
||||||
parameters:
|
parameters:
|
||||||
- name: userId
|
- name: identifier
|
||||||
in: path
|
in: path
|
||||||
description: The ID or email of the user
|
description: The ID or email of the user
|
||||||
required: true
|
required: true
|
||||||
|
@ -132,6 +132,14 @@ paths:
|
||||||
explode: false
|
explode: false
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
- name: includeRole
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
style: form
|
||||||
|
explode: true
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
example: true
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: Successful operation
|
description: Successful operation
|
||||||
|
@ -154,7 +162,7 @@ paths:
|
||||||
description: Deletes a user from your instance. Only available for the instance owner.
|
description: Deletes a user from your instance. Only available for the instance owner.
|
||||||
operationId: deleteUser
|
operationId: deleteUser
|
||||||
parameters:
|
parameters:
|
||||||
- name: userId
|
- name: identifier
|
||||||
in: path
|
in: path
|
||||||
description: The name that needs to be deleted
|
description: The name that needs to be deleted
|
||||||
required: true
|
required: true
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import express = require('express');
|
import express = require('express');
|
||||||
import { getConnection } from 'typeorm';
|
import { getConnection } from 'typeorm';
|
||||||
|
|
||||||
|
import { validate as uuidValidate } from 'uuid';
|
||||||
import { UserRequest } from '../../../../requests';
|
import { UserRequest } from '../../../../requests';
|
||||||
|
|
||||||
import { User } from '../../../../databases/entities/User';
|
import { User } from '../../../../databases/entities/User';
|
||||||
|
@ -19,7 +20,32 @@ export = {
|
||||||
res.json({ success: true });
|
res.json({ success: true });
|
||||||
},
|
},
|
||||||
getUser: async (req: UserRequest.Get, res: express.Response): Promise<void> => {
|
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> => {
|
getUsers: async (req: UserRequest.Get, res: express.Response): Promise<void> => {
|
||||||
let offset = 0;
|
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<
|
export type Get = AuthenticatedRequest<
|
||||||
{ id: string; email: string },
|
{ id: string; email: string; identifier: string },
|
||||||
{},
|
{},
|
||||||
{},
|
{},
|
||||||
{ limit: string; cursor: string; includeRole: 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 = {
|
const INITIAL_TEST_USER = {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
email: randomEmail(),
|
email: randomEmail(),
|
||||||
|
|
Loading…
Reference in a new issue