refactor(core): Consolidate CredentialsService.getMany() (no-changelog) (#7028)
Consolidate `CredentialsService.getMany()` in preparation for adding list query middleware to `GET /credentials`.
This commit is contained in:
@@ -1,16 +1,16 @@
|
||||
import express from 'express';
|
||||
import type { INodeCredentialTestResult } from 'n8n-workflow';
|
||||
import { deepCopy, LoggerProxy } from 'n8n-workflow';
|
||||
import { deepCopy } from 'n8n-workflow';
|
||||
import * as Db from '@/Db';
|
||||
import * as ResponseHelper from '@/ResponseHelper';
|
||||
import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||
|
||||
import type { CredentialRequest } from '@/requests';
|
||||
import { isSharingEnabled, rightDiff } from '@/UserManagement/UserManagementHelper';
|
||||
import { EECredentialsService as EECredentials } from './credentials.service.ee';
|
||||
import type { CredentialWithSharings } from './credentials.types';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
import { Container } from 'typedi';
|
||||
import { InternalHooks } from '@/InternalHooks';
|
||||
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
export const EECredentialsController = express.Router();
|
||||
@@ -25,27 +25,6 @@ EECredentialsController.use((req, res, next) => {
|
||||
next();
|
||||
});
|
||||
|
||||
/**
|
||||
* GET /credentials
|
||||
*/
|
||||
EECredentialsController.get(
|
||||
'/',
|
||||
ResponseHelper.send(async (req: CredentialRequest.GetAll): Promise<CredentialWithSharings[]> => {
|
||||
try {
|
||||
const allCredentials = await EECredentials.getAll(req.user, {
|
||||
relations: ['shared', 'shared.role', 'shared.user'],
|
||||
});
|
||||
|
||||
return allCredentials.map((credential: CredentialsEntity & CredentialWithSharings) =>
|
||||
EECredentials.addOwnerAndSharings(credential),
|
||||
);
|
||||
} catch (error) {
|
||||
LoggerProxy.error('Request to list credentials failed', error as Error);
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
/**
|
||||
* GET /credentials/:id
|
||||
*/
|
||||
@@ -59,7 +38,7 @@ EECredentialsController.get(
|
||||
let credential = (await EECredentials.get(
|
||||
{ id: credentialId },
|
||||
{ relations: ['shared', 'shared.role', 'shared.user'] },
|
||||
)) as CredentialsEntity & CredentialWithSharings;
|
||||
)) as CredentialsEntity;
|
||||
|
||||
if (!credential) {
|
||||
throw new ResponseHelper.NotFoundError(
|
||||
@@ -73,7 +52,7 @@ EECredentialsController.get(
|
||||
throw new ResponseHelper.UnauthorizedError('Forbidden.');
|
||||
}
|
||||
|
||||
credential = EECredentials.addOwnerAndSharings(credential);
|
||||
credential = Container.get(OwnershipService).addOwnedByAndSharedWith(credential);
|
||||
|
||||
if (!includeDecryptedData || !userSharing || userSharing.role.name !== 'owner') {
|
||||
const { data: _, ...rest } = credential;
|
||||
|
||||
@@ -35,8 +35,8 @@ credentialsController.use('/', EECredentialsController);
|
||||
*/
|
||||
credentialsController.get(
|
||||
'/',
|
||||
ResponseHelper.send(async (req: CredentialRequest.GetAll): Promise<ICredentialsDb[]> => {
|
||||
return CredentialsService.getAll(req.user, { roles: ['owner'] });
|
||||
ResponseHelper.send(async (req: CredentialRequest.GetAll) => {
|
||||
return CredentialsService.getMany(req.user);
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@ import { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||
import type { User } from '@db/entities/User';
|
||||
import { UserService } from '@/services/user.service';
|
||||
import { CredentialsService } from './credentials.service';
|
||||
import type { CredentialWithSharings } from './credentials.types';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import Container from 'typedi';
|
||||
|
||||
@@ -93,27 +92,4 @@ export class EECredentialsService extends CredentialsService {
|
||||
|
||||
return transaction.save(newSharedCredentials);
|
||||
}
|
||||
|
||||
static addOwnerAndSharings(
|
||||
credential: CredentialsEntity & CredentialWithSharings,
|
||||
): CredentialsEntity & CredentialWithSharings {
|
||||
credential.ownedBy = null;
|
||||
credential.sharedWith = [];
|
||||
|
||||
credential.shared?.forEach(({ user, role }) => {
|
||||
const { id, email, firstName, lastName } = user;
|
||||
|
||||
if (role.name === 'owner') {
|
||||
credential.ownedBy = { id, email, firstName, lastName };
|
||||
return;
|
||||
}
|
||||
|
||||
credential.sharedWith?.push({ id, email, firstName, lastName });
|
||||
});
|
||||
|
||||
// @ts-ignore
|
||||
delete credential.shared;
|
||||
|
||||
return credential;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import type { User } from '@db/entities/User';
|
||||
import type { CredentialRequest } from '@/requests';
|
||||
import { CredentialTypes } from '@/CredentialTypes';
|
||||
import { RoleService } from '@/services/role.service';
|
||||
import { OwnershipService } from '@/services/ownership.service';
|
||||
|
||||
export class CredentialsService {
|
||||
static async get(
|
||||
@@ -36,48 +37,58 @@ export class CredentialsService {
|
||||
});
|
||||
}
|
||||
|
||||
static async getAll(
|
||||
user: User,
|
||||
options?: { relations?: string[]; roles?: string[]; disableGlobalRole?: boolean },
|
||||
): Promise<ICredentialsDb[]> {
|
||||
const SELECT_FIELDS: Array<keyof ICredentialsDb> = [
|
||||
'id',
|
||||
'name',
|
||||
'type',
|
||||
'nodesAccess',
|
||||
'createdAt',
|
||||
'updatedAt',
|
||||
];
|
||||
static async getMany(user: User, options?: { disableGlobalRole: boolean }) {
|
||||
type Select = Array<keyof ICredentialsDb>;
|
||||
|
||||
// if instance owner, return all credentials
|
||||
const select: Select = ['id', 'name', 'type', 'nodesAccess', 'createdAt', 'updatedAt'];
|
||||
|
||||
if (user.globalRole.name === 'owner' && options?.disableGlobalRole !== true) {
|
||||
return Db.collections.Credentials.find({
|
||||
select: SELECT_FIELDS,
|
||||
relations: options?.relations,
|
||||
});
|
||||
const relations = ['shared', 'shared.role', 'shared.user'];
|
||||
|
||||
const returnAll = user.globalRole.name === 'owner' && options?.disableGlobalRole !== true;
|
||||
|
||||
const addOwnedByAndSharedWith = (c: CredentialsEntity) =>
|
||||
Container.get(OwnershipService).addOwnedByAndSharedWith(c);
|
||||
|
||||
if (returnAll) {
|
||||
const credentials = await Db.collections.Credentials.find({ select, relations });
|
||||
|
||||
return credentials.map(addOwnedByAndSharedWith);
|
||||
}
|
||||
|
||||
// if member, return credentials owned by or shared with member
|
||||
const userSharings = await Db.collections.SharedCredentials.find({
|
||||
where: {
|
||||
userId: user.id,
|
||||
...(options?.roles?.length ? { role: { name: In(options.roles) } } : {}),
|
||||
},
|
||||
relations: options?.roles?.length ? ['role'] : [],
|
||||
const ids = await CredentialsService.getAccessibleCredentials(user.id);
|
||||
|
||||
const credentials = await Db.collections.Credentials.find({
|
||||
select,
|
||||
relations,
|
||||
where: { id: In(ids) },
|
||||
});
|
||||
|
||||
return Db.collections.Credentials.find({
|
||||
select: SELECT_FIELDS,
|
||||
relations: options?.relations,
|
||||
where: {
|
||||
id: In(userSharings.map((x) => x.credentialsId)),
|
||||
},
|
||||
});
|
||||
return credentials.map(addOwnedByAndSharedWith);
|
||||
}
|
||||
|
||||
static async getMany(filter: FindManyOptions<ICredentialsDb>): Promise<ICredentialsDb[]> {
|
||||
return Db.collections.Credentials.find(filter);
|
||||
/**
|
||||
* Get the IDs of all credentials owned by or shared with a user.
|
||||
*/
|
||||
private static async getAccessibleCredentials(userId: string) {
|
||||
const sharings = await Db.collections.SharedCredentials.find({
|
||||
relations: ['role'],
|
||||
where: {
|
||||
userId,
|
||||
role: { name: In(['owner', 'user']), scope: 'credential' },
|
||||
},
|
||||
});
|
||||
|
||||
return sharings.map((s) => s.credentialsId);
|
||||
}
|
||||
|
||||
static async getManyByIds(ids: string[], { withSharings } = { withSharings: false }) {
|
||||
const options: FindManyOptions<CredentialsEntity> = { where: { id: In(ids) } };
|
||||
|
||||
if (withSharings) {
|
||||
options.relations = ['shared', 'shared.user', 'shared.role'];
|
||||
}
|
||||
|
||||
return Db.collections.Credentials.find(options);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
import type { IUser } from 'n8n-workflow';
|
||||
import type { ICredentialsDb } from '@/Interfaces';
|
||||
|
||||
export interface CredentialWithSharings extends ICredentialsDb {
|
||||
ownedBy?: IUser | null;
|
||||
sharedWith?: IUser[];
|
||||
}
|
||||
Reference in New Issue
Block a user