-
Notifications
You must be signed in to change notification settings - Fork 7.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
refactor(core): Consolidate CredentialsService.getMany()
(no-changelog)
#7028
Changes from all commits
ea1a3c8
936a14c
c509bc3
be06c1f
d4506af
28c3cf1
294c890
61eb6ba
ac4c694
d242209
954b97d
b7e8eb3
160daa9
8ae8522
87e8d00
07b6fcd
9fb9cb5
22c8684
ed185c5
460b591
c023c83
b8e7253
d763fb4
a078178
e58f46e
bdf9ff0
89f72b3
69f57ba
5a875f4
f1cd686
e154504
b8af009
802c2af
e805ee1
006f2ff
b7fad9c
23af1ad
a3d282c
90ed65e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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', | ||||||
]; | ||||||
|
||||||
// if instance owner, return all credentials | ||||||
|
||||||
if (user.globalRole.name === 'owner' && options?.disableGlobalRole !== true) { | ||||||
return Db.collections.Credentials.find({ | ||||||
select: SELECT_FIELDS, | ||||||
relations: options?.relations, | ||||||
}); | ||||||
static async getMany(user: User, options?: { disableGlobalRole: boolean }) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There's a good bit of logic in this function, can we add some tests to it? We need to assert that the repository is called with the correct relations, select dolumns and the correct query is performed depending on the user types and arguments. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is covered in the followup: https://github.com/n8n-io/n8n/pull/7041/files#diff-39f41209012fda27b308597ac9471c22beab53d2d0975bc0bb87e91b597c7c94 |
||||||
type Select = Array<keyof ICredentialsDb>; | ||||||
|
||||||
const select: Select = ['id', 'name', 'type', 'nodesAccess', 'createdAt', 'updatedAt']; | ||||||
|
||||||
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 }); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can try to remove references to There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My reasoning for why this wasn't worth it is that, from what I understand, the root issue here is that |
||||||
|
||||||
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, | ||||||
return credentials.map(addOwnedByAndSharedWith); | ||||||
} | ||||||
|
||||||
/** | ||||||
* 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: { | ||||||
id: In(userSharings.map((x) => x.credentialsId)), | ||||||
userId, | ||||||
role: { name: In(['owner', 'user']), scope: 'credential' }, | ||||||
}, | ||||||
}); | ||||||
|
||||||
return sharings.map((s) => s.credentialsId); | ||||||
} | ||||||
|
||||||
static async getMany(filter: FindManyOptions<ICredentialsDb>): Promise<ICredentialsDb[]> { | ||||||
return Db.collections.Credentials.find(filter); | ||||||
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); | ||||||
} | ||||||
|
||||||
/** | ||||||
|
This file was deleted.
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -4,8 +4,9 @@ import { SharedWorkflowRepository } from '@/databases/repositories'; | |||||
import type { User } from '@/databases/entities/User'; | ||||||
import { RoleService } from './role.service'; | ||||||
import { UserService } from './user.service'; | ||||||
import type { ListQuery } from '@/requests'; | ||||||
import type { Credentials, ListQuery } from '@/requests'; | ||||||
import type { Role } from '@/databases/entities/Role'; | ||||||
import type { CredentialsEntity } from '@/databases/entities/CredentialsEntity'; | ||||||
|
||||||
@Service() | ||||||
export class OwnershipService { | ||||||
|
@@ -50,4 +51,25 @@ export class OwnershipService { | |||||
ownedBy: ownerId ? { id: ownerId } : null, | ||||||
}); | ||||||
} | ||||||
|
||||||
addOwnedByAndSharedWith(_credential: CredentialsEntity): Credentials.WithOwnedByAndSharedWith { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Simply because we might do the same for workflows, right? We have the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also can we add some unit tests covering this function? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I think this is clear from the typing? Different entities require different fields, and the caller cannot misuse the methods - the typing will block them if they try to.
Will do! Edit: Done! |
||||||
const { shared, ...rest } = _credential; | ||||||
|
||||||
const credential = rest as Credentials.WithOwnedByAndSharedWith; | ||||||
|
||||||
credential.ownedBy = null; | ||||||
credential.sharedWith = []; | ||||||
|
||||||
shared?.forEach(({ user, role }) => { | ||||||
const { id, email, firstName, lastName } = user; | ||||||
|
||||||
if (role.name === 'owner') { | ||||||
credential.ownedBy = { id, email, firstName, lastName }; | ||||||
} else { | ||||||
credential.sharedWith.push({ id, email, firstName, lastName }); | ||||||
} | ||||||
}); | ||||||
|
||||||
return credential; | ||||||
} | ||||||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, what do you mean? I don't see
CredentialsRepository
used in this file?