-
-
Notifications
You must be signed in to change notification settings - Fork 1.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
feat(core): Refactor how permissions get serialized for sessions into using a new strategy #3222
base: master
Are you sure you want to change the base?
Changes from all commits
2929b64
c3b269d
1f8438c
2ca5f29
30326ba
f70a352
0618ee3
d8120ce
b32642b
9fb95b9
a5a3b66
8262d7f
d9b3cdc
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 |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import { CreateAdministratorInput } from '@vendure/common/lib/generated-types'; | ||
import { ID } from '@vendure/common/lib/shared-types'; | ||
|
||
import { RequestContext } from '../../api'; | ||
import { EntityNotFoundError, Injector } from '../../common'; | ||
import { TransactionalConnection } from '../../connection'; | ||
import { Role, User } from '../../entity'; | ||
import { | ||
getChannelPermissions, | ||
UserChannelPermissions, | ||
} from '../../service/helpers/utils/get-user-channels-permissions'; | ||
|
||
import { ChannelRoleInput, RolePermissionResolverStrategy } from './role-permission-resolver-strategy'; | ||
|
||
export class DefaultRolePermissionResolverStrategy implements RolePermissionResolverStrategy { | ||
private connection: TransactionalConnection; | ||
|
||
async init(injector: Injector) { | ||
this.connection = injector.get(TransactionalConnection); | ||
} | ||
|
||
async getChannelIdsFromCreateAdministratorInput(ctx: RequestContext, input: CreateAdministratorInput) { | ||
const roles = await this.getRolesFromIds(ctx, input.roleIds); | ||
const channelRoles = []; | ||
for (const role of roles) { | ||
for (const channel of role.channels) { | ||
channelRoles.push({ roleId: role.id, channelId: channel.id }); | ||
} | ||
} | ||
return channelRoles; | ||
} | ||
|
||
/** | ||
* @description TODO | ||
*/ | ||
async persistUserAndTheirRoles( | ||
ctx: RequestContext, | ||
user: User, | ||
channelRoles: ChannelRoleInput[], | ||
): Promise<void> { | ||
const roleIds = channelRoles.map(channelRole => channelRole.roleId); | ||
const roles = await this.getRolesFromIds(ctx, roleIds); | ||
// Copy so as to not mutate the original user object when setting roles | ||
const userCopy = new User({ ...user, roles }); | ||
await this.connection.getRepository(ctx, User).save(userCopy, { reload: false }); | ||
} | ||
|
||
private async getRolesFromIds(ctx: RequestContext, roleIds: ID[]): Promise<Role[]> { | ||
const roles = | ||
// Empty array is important because that would return every row when used in the query | ||
roleIds.length === 0 | ||
? [] | ||
: await this.connection.getRepository(ctx, Role).findBy(roleIds.map(id => ({ id }))); | ||
for (const roleId of roleIds) { | ||
const foundRole = roles.find(role => role.id === roleId); | ||
if (!foundRole) throw new EntityNotFoundError('Role', roleId); | ||
} | ||
return roles; | ||
} | ||
|
||
async resolvePermissions(user: User): Promise<UserChannelPermissions[]> { | ||
return getChannelPermissions(user.roles); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { CreateAdministratorInput, UpdateAdministratorInput } from '@vendure/common/lib/generated-types'; | ||
import { ID } from '@vendure/common/lib/shared-types'; | ||
|
||
import { RequestContext } from '../../api'; | ||
import { InjectableStrategy } from '../../common'; | ||
import { User } from '../../entity'; | ||
import { UserChannelPermissions } from '../../service/helpers/utils/get-user-channels-permissions'; | ||
|
||
export type ChannelRoleInput = { channelId: ID; roleId: ID }; | ||
|
||
/** | ||
* @description TODO | ||
*/ | ||
export interface RolePermissionResolverStrategy extends InjectableStrategy { | ||
getChannelIdsFromCreateAdministratorInput<T extends CreateAdministratorInput | UpdateAdministratorInput>( | ||
ctx: RequestContext, | ||
input: T, | ||
): Promise<ChannelRoleInput[]>; | ||
|
||
/** | ||
* TODO | ||
*/ | ||
persistUserAndTheirRoles( | ||
ctx: RequestContext, | ||
user: User, | ||
channelRoles: ChannelRoleInput[], | ||
): Promise<void>; | ||
|
||
/** | ||
* @param user User for which you want to retrieve permissions | ||
*/ | ||
resolvePermissions(user: User): Promise<UserChannelPermissions[]>; | ||
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. Maybe a bit nitpicky, but more consistent with the rest of the codebase: 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, the |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import gql from 'graphql-tag'; | ||
import { VendurePlugin } from '../vendure-plugin'; | ||
import { ChannelRolePermissionResolverStrategy } from './config/channel-role-permission-resolver-strategy'; | ||
import { ChannelRole } from './entities/channel-role.entity'; | ||
import { ChannelRoleService } from './services/channel-role.service'; | ||
|
||
@VendurePlugin({ | ||
entities: [ChannelRole], | ||
providers: [ChannelRoleService], | ||
configuration: config => { | ||
config.authOptions.rolePermissionResolverStrategy = new ChannelRolePermissionResolverStrategy(); | ||
return config; | ||
}, | ||
adminApiExtensions: { | ||
schema: gql` | ||
input ChannelRoleInput { | ||
roleId: ID! | ||
channelId: ID! | ||
} | ||
extend input CreateAdministratorInput { | ||
channelIds: [ChannelRoleInput!]! | ||
} | ||
`, | ||
}, | ||
}) | ||
export class ChannelRolePlugin {} |
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.
I like it, thanks. 👍 Will add comments once we finalize the PR and everything is set.