-
-
Notifications
You must be signed in to change notification settings - Fork 473
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #5991 from logto-io/gao-reorg-org-routes
refactor(core): reorg organization routes
- Loading branch information
Showing
5 changed files
with
257 additions
and
234 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
117 changes: 117 additions & 0 deletions
117
packages/core/src/queries/organization/role-user-relations.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
import { | ||
Organizations, | ||
OrganizationRoles, | ||
OrganizationScopes, | ||
OrganizationRoleScopeRelations, | ||
Users, | ||
OrganizationRoleUserRelations, | ||
type OrganizationScope, | ||
type ResourceScopeEntity, | ||
Scopes, | ||
OrganizationRoleResourceScopeRelations, | ||
Resources, | ||
} from '@logto/schemas'; | ||
import { sql, type CommonQueryMethods } from '@silverhand/slonik'; | ||
|
||
import RelationQueries from '#src/utils/RelationQueries.js'; | ||
import { conditionalSql, convertToIdentifiers } from '#src/utils/sql.js'; | ||
|
||
export class RoleUserRelationQueries extends RelationQueries< | ||
[typeof Organizations, typeof OrganizationRoles, typeof Users] | ||
> { | ||
constructor(pool: CommonQueryMethods) { | ||
super(pool, OrganizationRoleUserRelations.table, Organizations, OrganizationRoles, Users); | ||
} | ||
|
||
/** Get the available scopes of a user in an organization. */ | ||
async getUserScopes( | ||
organizationId: string, | ||
userId: string | ||
): Promise<readonly OrganizationScope[]> { | ||
const { fields } = convertToIdentifiers(OrganizationRoleUserRelations, true); | ||
const roleScopeRelations = convertToIdentifiers(OrganizationRoleScopeRelations, true); | ||
const scopes = convertToIdentifiers(OrganizationScopes, true); | ||
|
||
return this.pool.any<OrganizationScope>(sql` | ||
select distinct on (${scopes.fields.id}) | ||
${sql.join(Object.values(scopes.fields), sql`, `)} | ||
from ${this.table} | ||
join ${roleScopeRelations.table} | ||
on ${roleScopeRelations.fields.organizationRoleId} = ${fields.organizationRoleId} | ||
join ${scopes.table} | ||
on ${scopes.fields.id} = ${roleScopeRelations.fields.organizationScopeId} | ||
where ${fields.organizationId} = ${organizationId} | ||
and ${fields.userId} = ${userId} | ||
`); | ||
} | ||
|
||
/** | ||
* Get the available resource scopes of a user in all organizations. | ||
* If `organizationId` is provided, it will only search in that organization. | ||
*/ | ||
async getUserResourceScopes( | ||
userId: string, | ||
resourceIndicator: string, | ||
organizationId?: string | ||
): Promise<readonly ResourceScopeEntity[]> { | ||
const { fields } = convertToIdentifiers(OrganizationRoleUserRelations, true); | ||
const roleScopeRelations = convertToIdentifiers(OrganizationRoleResourceScopeRelations, true); | ||
const scopes = convertToIdentifiers(Scopes, true); | ||
const resources = convertToIdentifiers(Resources, true); | ||
|
||
return this.pool.any<ResourceScopeEntity>(sql` | ||
select distinct on (${scopes.fields.id}) | ||
${scopes.fields.id}, ${scopes.fields.name} | ||
from ${this.table} | ||
join ${roleScopeRelations.table} | ||
on ${roleScopeRelations.fields.organizationRoleId} = ${fields.organizationRoleId} | ||
join ${scopes.table} | ||
on ${scopes.fields.id} = ${roleScopeRelations.fields.scopeId} | ||
join ${resources.table} | ||
on ${resources.fields.id} = ${scopes.fields.resourceId} | ||
where ${fields.userId} = ${userId} | ||
and ${resources.fields.indicator} = ${resourceIndicator} | ||
${conditionalSql(organizationId, (value) => sql`and ${fields.organizationId} = ${value}`)} | ||
`); | ||
} | ||
|
||
/** Replace the roles of a user in an organization. */ | ||
async replace(organizationId: string, userId: string, roleIds: string[]) { | ||
const users = convertToIdentifiers(Users); | ||
const relations = convertToIdentifiers(OrganizationRoleUserRelations); | ||
|
||
return this.pool.transaction(async (transaction) => { | ||
// Lock user | ||
await transaction.query(sql` | ||
select id | ||
from ${users.table} | ||
where ${users.fields.id} = ${userId} | ||
for update | ||
`); | ||
|
||
// Delete old relations | ||
await transaction.query(sql` | ||
delete from ${relations.table} | ||
where ${relations.fields.userId} = ${userId} | ||
and ${relations.fields.organizationId} = ${organizationId} | ||
`); | ||
|
||
// Insert new relations | ||
if (roleIds.length === 0) { | ||
return; | ||
} | ||
|
||
await transaction.query(sql` | ||
insert into ${relations.table} ( | ||
${relations.fields.userId}, | ||
${relations.fields.organizationId}, | ||
${relations.fields.organizationRoleId} | ||
) | ||
values ${sql.join( | ||
roleIds.map((roleId) => sql`(${userId}, ${organizationId}, ${roleId})`), | ||
sql`, ` | ||
)} | ||
`); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.