2021-03-11 22:51:58 +01:00
import { EventEmitter } from 'events' ;
2021-05-02 21:11:17 +02:00
import metricsHelper from '../util/metrics-helper' ;
2021-04-29 10:21:29 +02:00
import { DB_TIME } from '../metric-events' ;
2021-08-12 15:04:37 +02:00
import { Logger } from '../logger' ;
import {
2022-07-21 16:23:56 +02:00
IAccessInfo ,
2021-08-12 15:04:37 +02:00
IAccessStore ,
2023-08-17 09:43:43 +02:00
IProjectRoleUsage ,
2021-08-12 15:04:37 +02:00
IRole ,
2022-09-30 13:36:45 +02:00
IRoleWithProject ,
2021-08-12 15:04:37 +02:00
IUserPermission ,
2022-07-21 16:23:56 +02:00
IUserRole ,
2023-08-25 10:31:37 +02:00
IUserWithProjectRoles ,
2021-08-12 15:04:37 +02:00
} from '../types/stores/access-store' ;
2023-09-14 11:43:39 +02:00
import { IPermission , IUserAccessOverview } from '../types/model' ;
2022-01-13 11:14:17 +01:00
import NotFoundError from '../error/notfound-error' ;
import {
ENVIRONMENT_PERMISSION_TYPE ,
2023-08-25 10:31:37 +02:00
PROJECT_ROLE_TYPES ,
2022-01-13 11:14:17 +01:00
ROOT_PERMISSION_TYPE ,
} from '../util/constants' ;
2023-01-30 09:02:44 +01:00
import { Db } from './db' ;
2023-09-19 16:15:27 +02:00
import {
IdPermissionRef ,
NamePermissionRef ,
PermissionRef ,
} from 'lib/services/access-service' ;
2023-10-06 13:38:32 +02:00
import { inTransaction } from './transaction' ;
2021-03-11 22:51:58 +01:00
const T = {
ROLE_USER : 'role_user' ,
ROLES : 'roles' ,
2022-07-21 16:23:56 +02:00
GROUPS : 'groups' ,
GROUP_ROLE : 'group_role' ,
GROUP_USER : 'group_user' ,
2021-03-11 22:51:58 +01:00
ROLE_PERMISSION : 'role_permission' ,
2022-01-13 11:14:17 +01:00
PERMISSIONS : 'permissions' ,
PERMISSION_TYPES : 'permission_types' ,
2022-11-14 14:05:26 +01:00
CHANGE_REQUEST_SETTINGS : 'change_request_settings' ,
2022-11-23 08:30:54 +01:00
PERSONAL_ACCESS_TOKENS : 'personal_access_tokens' ,
PUBLIC_SIGNUP_TOKENS_USER : 'public_signup_tokens_user' ,
2021-03-11 22:51:58 +01:00
} ;
2022-01-13 11:14:17 +01:00
interface IPermissionRow {
id : number ;
permission : string ;
display_name : string ;
environment? : string ;
type : string ;
project? : string ;
role_id : number ;
}
2023-09-19 16:15:27 +02:00
type ResolvedPermission = {
id : number ;
name? : string ;
environment? : string ;
} ;
2021-08-12 15:04:37 +02:00
export class AccessStore implements IAccessStore {
private logger : Logger ;
2021-03-11 22:51:58 +01:00
private timer : Function ;
2023-01-30 09:02:44 +01:00
private db : Db ;
2021-03-11 22:51:58 +01:00
2023-01-30 09:02:44 +01:00
constructor ( db : Db , eventBus : EventEmitter , getLogger : Function ) {
2021-03-11 22:51:58 +01:00
this . db = db ;
2021-08-12 15:04:37 +02:00
this . logger = getLogger ( 'access-store.ts' ) ;
2021-03-11 22:51:58 +01:00
this . timer = ( action : string ) = >
metricsHelper . wrapTimer ( eventBus , DB_TIME , {
store : 'access-store' ,
action ,
} ) ;
}
2023-09-19 16:15:27 +02:00
private permissionHasId = ( permission : PermissionRef ) : boolean = > {
return ( permission as IdPermissionRef ) . id !== undefined ;
} ;
private permissionNamesToIds = async (
permissions : NamePermissionRef [ ] ,
) : Promise < ResolvedPermission [ ] > = > {
const permissionNames = ( permissions ? ? [ ] )
. filter ( ( p ) = > p . name !== undefined )
. map ( ( p ) = > p . name ) ;
if ( permissionNames . length === 0 ) {
return [ ] ;
}
const stopTimer = this . timer ( 'permissionNamesToIds' ) ;
const rows = await this . db
. select ( 'id' , 'permission' )
. from ( T . PERMISSIONS )
. whereIn ( 'permission' , permissionNames ) ;
const rowByPermissionName = rows . reduce ( ( acc , row ) = > {
acc [ row . permission ] = row ;
return acc ;
} , { } as Map < string , IPermissionRow > ) ;
const permissionsWithIds = permissions . map ( ( permission ) = > ( {
id : rowByPermissionName [ permission . name ] . id ,
. . . permission ,
} ) ) ;
stopTimer ( ) ;
return permissionsWithIds ;
} ;
resolvePermissions = async (
permissions : PermissionRef [ ] ,
) : Promise < ResolvedPermission [ ] > = > {
if ( permissions === undefined || permissions . length === 0 ) {
return [ ] ;
}
// permissions without ids (just names)
const permissionsWithoutIds = permissions . filter (
( p ) = > ! this . permissionHasId ( p ) ,
) as NamePermissionRef [ ] ;
const idPermissionsFromNamed = await this . permissionNamesToIds (
permissionsWithoutIds ,
) ;
if ( permissionsWithoutIds . length === permissions . length ) {
// all named permissions without ids
return idPermissionsFromNamed ;
} else if ( permissionsWithoutIds . length === 0 ) {
// all permissions have ids
return permissions as ResolvedPermission [ ] ;
}
// some permissions have ids, some don't (should not happen!)
return permissions . map ( ( permission ) = > {
if ( this . permissionHasId ( permission ) ) {
return permission as ResolvedPermission ;
} else {
return idPermissionsFromNamed . find (
( p ) = > p . name === ( permission as NamePermissionRef ) . name ,
) ! ;
}
} ) ;
} ;
2021-08-12 15:04:37 +02:00
async delete ( key : number ) : Promise < void > {
await this . db ( T . ROLES ) . where ( { id : key } ) . del ( ) ;
}
async deleteAll ( ) : Promise < void > {
await this . db ( T . ROLES ) . del ( ) ;
}
destroy ( ) : void { }
async exists ( key : number ) : Promise < boolean > {
const result = await this . db . raw (
2022-07-21 16:23:56 +02:00
` SELECT EXISTS(SELECT 1 FROM ${ T . ROLES } WHERE id = ?) AS present ` ,
2021-08-12 15:04:37 +02:00
[ key ] ,
) ;
const { present } = result . rows [ 0 ] ;
return present ;
}
async get ( key : number ) : Promise < IRole > {
2022-01-13 11:14:17 +01:00
const role = await this . db
2021-08-12 15:04:37 +02:00
. select ( [ 'id' , 'name' , 'type' , 'description' ] )
. where ( 'id' , key )
. first ( )
. from < IRole > ( T . ROLES ) ;
2022-01-13 11:14:17 +01:00
if ( ! role ) {
throw new NotFoundError ( ` Could not find role with id: ${ key } ` ) ;
}
return role ;
2021-08-12 15:04:37 +02:00
}
async getAll ( ) : Promise < IRole [ ] > {
return Promise . resolve ( [ ] ) ;
}
2022-01-13 11:14:17 +01:00
async getAvailablePermissions ( ) : Promise < IPermission [ ] > {
const rows = await this . db
. select ( [ 'id' , 'permission' , 'type' , 'display_name' ] )
. where ( 'type' , 'project' )
. orWhere ( 'type' , 'environment' )
2023-06-14 15:40:40 +02:00
. orWhere ( 'type' , 'root' )
2022-01-13 11:14:17 +01:00
. from ( ` ${ T . PERMISSIONS } as p ` ) ;
2023-06-30 12:15:11 +02:00
return rows . map ( this . mapPermission ) ;
2022-01-13 11:14:17 +01:00
}
mapPermission ( permission : IPermissionRow ) : IPermission {
return {
id : permission.id ,
name : permission.permission ,
displayName : permission.display_name ,
type : permission . type ,
} ;
}
2021-04-12 20:25:03 +02:00
async getPermissionsForUser ( userId : number ) : Promise < IUserPermission [ ] > {
2021-03-11 22:51:58 +01:00
const stopTimer = this . timer ( 'getPermissionsForUser' ) ;
2022-07-21 16:23:56 +02:00
let userPermissionQuery = this . db
2022-01-13 11:14:17 +01:00
. select (
'project' ,
'permission' ,
'environment' ,
'type' ,
'ur.role_id' ,
)
. from < IPermissionRow > ( ` ${ T . ROLE_PERMISSION } AS rp ` )
. join ( ` ${ T . ROLE_USER } AS ur ` , 'ur.role_id' , 'rp.role_id' )
. join ( ` ${ T . PERMISSIONS } AS p ` , 'p.id' , 'rp.permission_id' )
2021-04-12 20:25:03 +02:00
. where ( 'ur.user_id' , '=' , userId ) ;
2022-07-21 16:23:56 +02:00
2022-08-26 08:22:42 +02:00
userPermissionQuery = userPermissionQuery . union ( ( db ) = > {
db . select (
'project' ,
'permission' ,
'environment' ,
'p.type' ,
'gr.role_id' ,
)
. from < IPermissionRow > ( ` ${ T . GROUP_USER } AS gu ` )
. join ( ` ${ T . GROUPS } AS g ` , 'g.id' , 'gu.group_id' )
. join ( ` ${ T . GROUP_ROLE } AS gr ` , 'gu.group_id' , 'gr.group_id' )
. join ( ` ${ T . ROLE_PERMISSION } AS rp ` , 'rp.role_id' , 'gr.role_id' )
. join ( ` ${ T . PERMISSIONS } AS p ` , 'p.id' , 'rp.permission_id' )
2023-04-20 12:29:30 +02:00
. andWhere ( 'gu.user_id' , '=' , userId ) ;
2022-08-26 08:22:42 +02:00
} ) ;
2023-04-20 12:29:30 +02:00
userPermissionQuery = userPermissionQuery . union ( ( db ) = > {
db . select (
this . db . raw ( "'default' as project" ) ,
'permission' ,
'environment' ,
'p.type' ,
'g.root_role_id as role_id' ,
)
. from < IPermissionRow > ( ` ${ T . GROUP_USER } as gu ` )
. join ( ` ${ T . GROUPS } AS g ` , 'g.id' , 'gu.group_id' )
. join (
` ${ T . ROLE_PERMISSION } as rp ` ,
'rp.role_id' ,
'g.root_role_id' ,
)
. join ( ` ${ T . PERMISSIONS } as p ` , 'p.id' , 'rp.permission_id' )
. whereNotNull ( 'g.root_role_id' )
. andWhere ( 'gu.user_id' , '=' , userId ) ;
} ) ;
2022-07-21 16:23:56 +02:00
const rows = await userPermissionQuery ;
2021-03-11 22:51:58 +01:00
stopTimer ( ) ;
2022-01-13 11:14:17 +01:00
return rows . map ( this . mapUserPermission ) ;
2021-03-11 22:51:58 +01:00
}
2022-01-13 11:14:17 +01:00
mapUserPermission ( row : IPermissionRow ) : IUserPermission {
2023-06-14 15:40:40 +02:00
let project : string | undefined = undefined ;
2022-01-13 11:14:17 +01:00
// Since the editor should have access to the default project,
// we map the project to the project and environment specific
// permissions that are connected to the editor role.
if ( row . type !== ROOT_PERMISSION_TYPE ) {
project = row . project ;
}
2021-03-11 22:51:58 +01:00
2022-01-13 11:14:17 +01:00
const environment =
row . type === ENVIRONMENT_PERMISSION_TYPE
? row . environment
: undefined ;
2021-03-11 22:51:58 +01:00
2022-07-21 16:23:56 +02:00
return {
2022-01-13 11:14:17 +01:00
project ,
environment ,
permission : row.permission ,
} ;
2021-03-11 22:51:58 +01:00
}
2022-01-13 11:14:17 +01:00
async getPermissionsForRole ( roleId : number ) : Promise < IPermission [ ] > {
const stopTimer = this . timer ( 'getPermissionsForRole' ) ;
const rows = await this . db
. select (
'p.id' ,
'p.permission' ,
'rp.environment' ,
'p.display_name' ,
'p.type' ,
)
. from < IPermission > ( ` ${ T . ROLE_PERMISSION } as rp ` )
. join ( ` ${ T . PERMISSIONS } as p ` , 'p.id' , 'rp.permission_id' )
. where ( 'rp.role_id' , '=' , roleId ) ;
stopTimer ( ) ;
return rows . map ( ( permission ) = > {
return {
id : permission.id ,
name : permission.permission ,
environment : permission.environment ,
displayName : permission.display_name ,
type : permission . type ,
} ;
} ) ;
2021-03-11 22:51:58 +01:00
}
2022-01-13 11:14:17 +01:00
async addEnvironmentPermissionsToRole (
role_id : number ,
2023-09-19 16:15:27 +02:00
permissions : PermissionRef [ ] ,
2022-01-13 11:14:17 +01:00
) : Promise < void > {
2023-09-19 16:15:27 +02:00
const resolvedPermission = await this . resolvePermissions ( permissions ) ;
const rows = resolvedPermission . map ( ( permission ) = > {
2022-01-13 11:14:17 +01:00
return {
role_id ,
permission_id : permission.id ,
environment : permission.environment ,
} ;
} ) ;
2022-04-01 11:10:21 +02:00
await this . db . batchInsert ( T . ROLE_PERMISSION , rows ) ;
2021-04-09 13:46:53 +02:00
}
2022-01-13 11:14:17 +01:00
async unlinkUserRoles ( userId : number ) : Promise < void > {
return this . db ( T . ROLE_USER )
2021-03-11 22:51:58 +01:00
. where ( {
2022-01-13 11:14:17 +01:00
user_id : userId ,
2021-03-11 22:51:58 +01:00
} )
. delete ( ) ;
}
2022-11-23 08:30:54 +01:00
async unlinkUserGroups ( userId : number ) : Promise < void > {
return this . db ( T . GROUP_USER )
. where ( {
user_id : userId ,
} )
. delete ( ) ;
}
async clearUserPersonalAccessTokens ( userId : number ) : Promise < void > {
return this . db ( T . PERSONAL_ACCESS_TOKENS )
. where ( {
user_id : userId ,
} )
. delete ( ) ;
}
async clearPublicSignupUserTokens ( userId : number ) : Promise < void > {
return this . db ( T . PUBLIC_SIGNUP_TOKENS_USER )
. where ( {
user_id : userId ,
} )
. delete ( ) ;
}
2022-07-21 16:23:56 +02:00
async getProjectUsersForRole (
2022-01-13 11:14:17 +01:00
roleId : number ,
projectId? : string ,
2022-07-21 16:23:56 +02:00
) : Promise < IUserRole [ ] > {
2022-01-13 11:14:17 +01:00
const rows = await this . db
2022-07-21 16:23:56 +02:00
. select ( [ 'user_id' , 'ru.created_at' ] )
2022-01-13 11:14:17 +01:00
. from < IRole > ( ` ${ T . ROLE_USER } AS ru ` )
. join ( ` ${ T . ROLES } as r ` , 'ru.role_id' , 'id' )
. where ( 'r.id' , roleId )
. andWhere ( 'ru.project' , projectId ) ;
2022-07-21 16:23:56 +02:00
return rows . map ( ( r ) = > ( {
userId : r.user_id ,
addedAt : r.created_at ,
} ) ) ;
2022-01-13 11:14:17 +01:00
}
2023-08-25 10:31:37 +02:00
async getProjectUsers (
projectId? : string ,
) : Promise < IUserWithProjectRoles [ ] > {
const rows = await this . db
. select ( [ 'user_id' , 'ru.created_at' , 'ru.role_id' ] )
. from < IRole > ( ` ${ T . ROLE_USER } AS ru ` )
. join ( ` ${ T . ROLES } as r ` , 'ru.role_id' , 'id' )
. whereIn ( 'r.type' , PROJECT_ROLE_TYPES )
. andWhere ( 'ru.project' , projectId ) ;
return rows . reduce ( ( acc , row ) = > {
const existingUser = acc . find ( ( user ) = > user . id === row . user_id ) ;
if ( existingUser ) {
existingUser . roles . push ( row . role_id ) ;
} else {
acc . push ( {
id : row.user_id ,
addedAt : row.created_at ,
roleId : row.role_id ,
roles : [ row . role_id ] ,
} ) ;
}
return acc ;
} , [ ] ) ;
}
2022-09-30 13:36:45 +02:00
async getRolesForUserId ( userId : number ) : Promise < IRoleWithProject [ ] > {
2021-03-11 22:51:58 +01:00
return this . db
. select ( [ 'id' , 'name' , 'type' , 'project' , 'description' ] )
. from < IRole [ ] > ( T . ROLES )
. innerJoin ( ` ${ T . ROLE_USER } as ru ` , 'ru.role_id' , 'id' )
. where ( 'ru.user_id' , '=' , userId ) ;
}
2021-08-12 15:04:37 +02:00
async getUserIdsForRole ( roleId : number ) : Promise < number [ ] > {
2021-03-11 22:51:58 +01:00
const rows = await this . db
. select ( [ 'user_id' ] )
. from < IRole > ( T . ROLE_USER )
. where ( 'role_id' , roleId ) ;
2021-08-12 15:04:37 +02:00
return rows . map ( ( r ) = > r . user_id ) ;
2021-03-11 22:51:58 +01:00
}
2023-08-08 13:45:19 +02:00
async getGroupIdsForRole ( roleId : number ) : Promise < number [ ] > {
const rows = await this . db
. select ( [ 'group_id' ] )
. from < IRole > ( T . GROUP_ROLE )
. where ( 'role_id' , roleId ) ;
return rows . map ( ( r ) = > r . group_id ) ;
}
2023-08-17 09:43:43 +02:00
async getProjectUserAndGroupCountsForRole (
roleId : number ,
) : Promise < IProjectRoleUsage [ ] > {
const query = await this . db . raw (
`
2023-08-25 10:31:37 +02:00
SELECT
2023-08-17 09:43:43 +02:00
uq . project ,
sum ( uq . user_count ) AS user_count ,
sum ( uq . svc_account_count ) AS svc_account_count ,
sum ( uq . group_count ) AS group_count
FROM (
2023-08-25 10:31:37 +02:00
SELECT
2023-08-17 09:43:43 +02:00
project ,
0 AS user_count ,
0 AS svc_account_count ,
count ( project ) AS group_count
FROM group_role
WHERE role_id = ?
GROUP BY project
UNION SELECT
project ,
count ( us . id ) AS user_count ,
count ( svc . id ) AS svc_account_count ,
0 AS group_count
FROM role_user AS usr_r
LEFT OUTER JOIN public . users AS us ON us . id = usr_r . user_id AND us . is_service = 'false'
LEFT OUTER JOIN public . users AS svc ON svc . id = usr_r . user_id AND svc . is_service = 'true'
WHERE usr_r . role_id = ?
GROUP BY usr_r . project
) AS uq
GROUP BY uq . project
` ,
[ roleId , roleId ] ,
) ;
return query . rows . map ( ( r ) = > {
return {
project : r.project ,
role : roleId ,
userCount : Number ( r . user_count ) ,
groupCount : Number ( r . group_count ) ,
serviceAccountCount : Number ( r . svc_account_count ) ,
} ;
} ) ;
}
2022-01-13 11:14:17 +01:00
async addUserToRole (
userId : number ,
roleId : number ,
2022-07-21 16:23:56 +02:00
projectId? : string ,
2022-01-13 11:14:17 +01:00
) : Promise < void > {
2023-11-16 12:03:27 +01:00
await this . db ( T . ROLE_USER )
. insert ( {
user_id : userId ,
role_id : roleId ,
project : projectId ,
} )
. onConflict ( [ 'user_id' , 'role_id' , 'project' ] )
. ignore ( ) ;
2021-03-11 22:51:58 +01:00
}
2022-01-13 11:14:17 +01:00
async removeUserFromRole (
userId : number ,
roleId : number ,
projectId? : string ,
) : Promise < void > {
2021-03-11 22:51:58 +01:00
return this . db ( T . ROLE_USER )
. where ( {
user_id : userId ,
role_id : roleId ,
2022-01-13 11:14:17 +01:00
project : projectId ,
2021-03-11 22:51:58 +01:00
} )
. delete ( ) ;
}
2022-07-21 16:23:56 +02:00
async addGroupToRole (
groupId : number ,
roleId : number ,
createdBy : string ,
projectId? : string ,
) : Promise < void > {
return this . db ( T . GROUP_ROLE ) . insert ( {
group_id : groupId ,
role_id : roleId ,
project : projectId ,
created_by : createdBy ,
} ) ;
}
async removeGroupFromRole (
groupId : number ,
roleId : number ,
projectId? : string ,
) : Promise < void > {
return this . db ( T . GROUP_ROLE )
. where ( {
group_id : groupId ,
role_id : roleId ,
project : projectId ,
} )
. delete ( ) ;
}
2022-02-21 14:39:59 +01:00
async updateUserProjectRole (
userId : number ,
roleId : number ,
projectId : string ,
) : Promise < void > {
return this . db ( T . ROLE_USER )
. where ( {
user_id : userId ,
project : projectId ,
} )
2022-05-26 16:20:36 +02:00
. whereNotIn (
'role_id' ,
this . db ( T . ROLES ) . select ( 'id as role_id' ) . where ( 'type' , 'root' ) ,
)
2022-02-21 14:39:59 +01:00
. update ( 'role_id' , roleId ) ;
}
2022-07-21 16:23:56 +02:00
updateGroupProjectRole (
groupId : number ,
roleId : number ,
projectId : string ,
) : Promise < void > {
return this . db ( T . GROUP_ROLE )
. where ( {
group_id : groupId ,
project : projectId ,
} )
. whereNotIn (
'role_id' ,
this . db ( T . ROLES ) . select ( 'id as role_id' ) . where ( 'type' , 'root' ) ,
)
. update ( 'role_id' , roleId ) ;
}
2023-08-25 10:31:37 +02:00
async addRoleAccessToProject (
2022-07-21 16:23:56 +02:00
users : IAccessInfo [ ] ,
groups : IAccessInfo [ ] ,
projectId : string ,
roleId : number ,
createdBy : string ,
) : Promise < void > {
const userRows = users . map ( ( user ) = > {
return {
user_id : user.id ,
project : projectId ,
role_id : roleId ,
} ;
} ) ;
const groupRows = groups . map ( ( group ) = > {
return {
group_id : group.id ,
project : projectId ,
role_id : roleId ,
created_by : createdBy ,
} ;
} ) ;
2023-10-06 13:38:32 +02:00
await inTransaction ( this . db , async ( tx ) = > {
2022-07-21 16:23:56 +02:00
if ( userRows . length > 0 ) {
await tx ( T . ROLE_USER )
. insert ( userRows )
. onConflict ( [ 'project' , 'role_id' , 'user_id' ] )
. merge ( ) ;
}
if ( groupRows . length > 0 ) {
await tx ( T . GROUP_ROLE )
. insert ( groupRows )
. onConflict ( [ 'project' , 'role_id' , 'group_id' ] )
. merge ( ) ;
}
} ) ;
}
2023-08-25 10:31:37 +02:00
async addAccessToProject (
roles : number [ ] ,
groups : number [ ] ,
users : number [ ] ,
projectId : string ,
createdBy : string ,
) : Promise < void > {
const validatedProjectRoleIds = await this . db ( T . ROLES )
. select ( 'id' )
. whereIn ( 'id' , roles )
. whereIn ( 'type' , PROJECT_ROLE_TYPES )
. pluck ( 'id' ) ;
const groupRows = groups . flatMap ( ( group ) = >
validatedProjectRoleIds . map ( ( role ) = > ( {
group_id : group ,
project : projectId ,
role_id : role ,
created_by : createdBy ,
} ) ) ,
) ;
const userRows = users . flatMap ( ( user ) = >
validatedProjectRoleIds . map ( ( role ) = > ( {
user_id : user ,
project : projectId ,
role_id : role ,
} ) ) ,
) ;
2023-10-06 13:38:32 +02:00
await inTransaction ( this . db , async ( tx ) = > {
2023-08-25 10:31:37 +02:00
if ( groupRows . length > 0 ) {
await tx ( T . GROUP_ROLE )
. insert ( groupRows )
. onConflict ( [ 'project' , 'role_id' , 'group_id' ] )
. merge ( ) ;
}
if ( userRows . length > 0 ) {
await tx ( T . ROLE_USER )
. insert ( userRows )
. onConflict ( [ 'project' , 'role_id' , 'user_id' ] )
. merge ( ) ;
}
} ) ;
}
async setProjectRolesForUser (
projectId : string ,
userId : number ,
roles : number [ ] ,
) : Promise < void > {
const projectRoleIds = await this . db ( T . ROLES )
. select ( 'id' )
. whereIn ( 'type' , PROJECT_ROLE_TYPES )
. pluck ( 'id' ) ;
const projectRoleIdsSet = new Set ( projectRoleIds ) ;
const userRows = roles
. filter ( ( role ) = > projectRoleIdsSet . has ( role ) )
. map ( ( role ) = > ( {
user_id : userId ,
project : projectId ,
role_id : role ,
} ) ) ;
2023-10-06 13:38:32 +02:00
await inTransaction ( this . db , async ( tx ) = > {
2023-08-25 10:31:37 +02:00
await tx ( T . ROLE_USER )
. where ( 'project' , projectId )
. andWhere ( 'user_id' , userId )
. whereIn ( 'role_id' , projectRoleIds )
. delete ( ) ;
if ( userRows . length > 0 ) {
await tx ( T . ROLE_USER )
. insert ( userRows )
. onConflict ( [ 'project' , 'role_id' , 'user_id' ] )
. ignore ( ) ;
}
} ) ;
}
async getProjectRolesForUser (
projectId : string ,
userId : number ,
) : Promise < number [ ] > {
const rows = await this . db ( ` ${ T . ROLE_USER } as ru ` )
. join ( ` ${ T . ROLES } as r ` , 'ru.role_id' , 'r.id' )
. select ( 'ru.role_id' )
. where ( 'ru.project' , projectId )
. whereIn ( 'r.type' , PROJECT_ROLE_TYPES )
. andWhere ( 'ru.user_id' , userId ) ;
return rows . map ( ( r ) = > r . role_id as number ) ;
}
async setProjectRolesForGroup (
projectId : string ,
groupId : number ,
roles : number [ ] ,
createdBy : string ,
) : Promise < void > {
const projectRoleIds = await this . db ( T . ROLES )
. select ( 'id' )
. whereIn ( 'type' , PROJECT_ROLE_TYPES )
. pluck ( 'id' ) ;
const projectRoleIdsSet = new Set ( projectRoleIds ) ;
const groupRows = roles
. filter ( ( role ) = > projectRoleIdsSet . has ( role ) )
. map ( ( role ) = > ( {
group_id : groupId ,
project : projectId ,
role_id : role ,
created_by : createdBy ,
} ) ) ;
2023-10-06 13:38:32 +02:00
await inTransaction ( this . db , async ( tx ) = > {
2023-08-25 10:31:37 +02:00
await tx ( T . GROUP_ROLE )
. where ( 'project' , projectId )
. andWhere ( 'group_id' , groupId )
. whereIn ( 'role_id' , projectRoleIds )
. delete ( ) ;
if ( groupRows . length > 0 ) {
await tx ( T . GROUP_ROLE )
. insert ( groupRows )
. onConflict ( [ 'project' , 'role_id' , 'group_id' ] )
. ignore ( ) ;
}
} ) ;
}
async getProjectRolesForGroup (
projectId : string ,
groupId : number ,
) : Promise < number [ ] > {
const rows = await this . db ( ` ${ T . GROUP_ROLE } as gr ` )
. join ( ` ${ T . ROLES } as r ` , 'gr.role_id' , 'r.id' )
. select ( 'gr.role_id' )
. where ( 'gr.project' , projectId )
. whereIn ( 'r.type' , PROJECT_ROLE_TYPES )
. andWhere ( 'gr.group_id' , groupId ) ;
return rows . map ( ( row ) = > row . role_id as number ) ;
}
async removeUserAccess ( projectId : string , userId : number ) : Promise < void > {
return this . db ( T . ROLE_USER )
. where ( {
user_id : userId ,
project : projectId ,
} )
. whereIn (
'role_id' ,
this . db ( T . ROLES )
. select ( 'id as role_id' )
. whereIn ( 'type' , PROJECT_ROLE_TYPES ) ,
)
. delete ( ) ;
}
async removeGroupAccess ( projectId : string , groupId : number ) : Promise < void > {
return this . db ( T . GROUP_ROLE )
. where ( {
group_id : groupId ,
project : projectId ,
} )
. whereIn (
'role_id' ,
this . db ( T . ROLES )
. select ( 'id as role_id' )
. whereIn ( 'type' , PROJECT_ROLE_TYPES ) ,
)
. delete ( ) ;
}
2021-04-09 13:46:53 +02:00
async removeRolesOfTypeForUser (
userId : number ,
2023-06-14 15:40:40 +02:00
roleTypes : string [ ] ,
2021-04-09 13:46:53 +02:00
) : Promise < void > {
2023-11-06 14:38:12 +01:00
const rolesToRemove = await this . db ( T . ROLES )
2021-04-09 13:46:53 +02:00
. select ( 'id' )
2023-11-06 14:38:12 +01:00
. whereIn ( 'type' , roleTypes )
. pluck ( 'id' ) ;
2021-04-09 13:46:53 +02:00
return this . db ( T . ROLE_USER )
. where ( { user_id : userId } )
. whereIn ( 'role_id' , rolesToRemove )
. delete ( ) ;
}
2021-03-11 22:51:58 +01:00
async addPermissionsToRole (
role_id : number ,
2023-09-19 16:15:27 +02:00
permissions : PermissionRef [ ] | string [ ] ,
2022-01-13 11:14:17 +01:00
environment? : string ,
2021-03-11 22:51:58 +01:00
) : Promise < void > {
2023-09-19 16:15:27 +02:00
const permissionsAsRefs = ( permissions ? ? [ ] ) . map ( ( p ) = > {
if ( typeof p === 'string' ) {
return { name : p } ;
} else {
return p ;
}
} ) ;
// no need to pass down the environment in this particular case because it'll be overriden
const permissionsWithIds = await this . resolvePermissions (
permissionsAsRefs ,
) ;
2022-01-13 11:14:17 +01:00
2023-09-19 16:15:27 +02:00
const newRoles = permissionsWithIds . map ( ( p ) = > ( {
2021-03-11 22:51:58 +01:00
role_id ,
2022-01-13 11:14:17 +01:00
environment ,
2023-09-19 16:15:27 +02:00
permission_id : p.id ,
2021-03-11 22:51:58 +01:00
} ) ) ;
2022-01-13 11:14:17 +01:00
return this . db . batchInsert ( T . ROLE_PERMISSION , newRoles ) ;
2021-03-11 22:51:58 +01:00
}
async removePermissionFromRole (
2022-01-13 11:14:17 +01:00
role_id : number ,
2021-03-11 22:51:58 +01:00
permission : string ,
2022-01-13 11:14:17 +01:00
environment? : string ,
2021-03-11 22:51:58 +01:00
) : Promise < void > {
2022-01-13 11:14:17 +01:00
const rows = await this . db
. select ( 'id as permissionId' )
. from < number > ( T . PERMISSIONS )
. where ( 'permission' , permission ) ;
const permissionId = rows [ 0 ] . permissionId ;
2021-03-11 22:51:58 +01:00
return this . db ( T . ROLE_PERMISSION )
. where ( {
2022-01-13 11:14:17 +01:00
role_id ,
permission_id : permissionId ,
environment ,
2021-03-11 22:51:58 +01:00
} )
. delete ( ) ;
}
2021-04-09 13:46:53 +02:00
2022-01-13 11:14:17 +01:00
async wipePermissionsFromRole ( role_id : number ) : Promise < void > {
return this . db ( T . ROLE_PERMISSION )
. where ( {
role_id ,
} )
. delete ( ) ;
2021-04-09 13:46:53 +02:00
}
2022-10-28 11:27:11 +02:00
async cloneEnvironmentPermissions (
sourceEnvironment : string ,
destinationEnvironment : string ,
) : Promise < void > {
return this . db . raw (
` insert into role_permission
( role_id , permission_id , environment )
( select role_id , permission_id , ?
from $ { T . ROLE_PERMISSION } where environment = ? ) ` ,
[ destinationEnvironment , sourceEnvironment ] ,
) ;
}
2023-09-14 11:43:39 +02:00
async getUserAccessOverview ( ) : Promise < IUserAccessOverview [ ] > {
2023-09-29 14:18:21 +02:00
const result = await this . db . raw ( ` SELECT u.id, u.created_at, u.name, u.email, u.seen_at, up.p_array as projects, gr.p_array as groups, gp.p_array as group_projects, r.name as root_role
2023-09-14 11:43:39 +02:00
FROM users u , LATERAL (
SELECT ARRAY (
SELECT ru . project
FROM role_user ru
WHERE ru . user_id = u . id
) AS p_array
) up , LATERAL (
SELECT r . name
FROM role_user ru
2023-09-15 12:10:16 +02:00
INNER JOIN roles r on ru . role_id = r . id
WHERE ru . user_id = u . id and r . type = 'root'
2023-09-14 11:43:39 +02:00
) r , LATERAL (
SELECT ARRAY (
2023-09-15 12:10:16 +02:00
SELECT g . name FROM group_user gu
JOIN groups g on g . id = gu . group_id
2023-09-14 11:43:39 +02:00
WHERE gu . user_id = u . id
) AS p_array
2023-09-15 12:10:16 +02:00
) gr , LATERAL (
SELECT ARRAY (
SELECT gr . project
FROM group_user gu
JOIN group_role gr ON gu . group_id = gr . group_id
WHERE gu . user_id = u . id
)
AS p_array
) gp
2023-09-14 11:43:39 +02:00
order by u . id ; ` );
return result . rows . map ( ( row ) = > {
return {
userId : row.id ,
createdAt : row.created_at ,
userName : row.name ,
userEmail : row.email ,
lastSeen : row.seen_at ,
accessibleProjects : row.projects ,
groups : row.groups ,
rootRole : row.root_role ,
2023-09-15 12:10:16 +02:00
groupProjects : row.group_projects ,
2023-09-14 11:43:39 +02:00
} ;
} ) ;
}
2021-03-11 22:51:58 +01:00
}