File size: 3,553 Bytes
aec3094 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | import type { User } from '@n8n/db';
import { ProjectRelationRepository, SharedWorkflowRepository } from '@n8n/db';
import { Service } from '@n8n/di';
import {
hasGlobalScope,
rolesWithScope,
type ProjectRole,
type WorkflowSharingRole,
type Scope,
} from '@n8n/permissions';
// eslint-disable-next-line n8n-local-rules/misplaced-n8n-typeorm-import
import { In } from '@n8n/typeorm';
import { RoleService } from '@/services/role.service';
export type ShareWorkflowOptions =
| { scopes: Scope[]; projectId?: string }
| { projectRoles: ProjectRole[]; workflowRoles: WorkflowSharingRole[]; projectId?: string };
@Service()
export class WorkflowSharingService {
constructor(
private readonly sharedWorkflowRepository: SharedWorkflowRepository,
private readonly roleService: RoleService,
private readonly projectRelationRepository: ProjectRelationRepository,
) {}
/**
* Get the IDs of the workflows that have been shared with the user based on
* scope or roles.
* If `scopes` is passed the roles are inferred. Alternatively `projectRoles`
* and `workflowRoles` can be passed specifically.
*
* Returns all IDs if user has the 'workflow:read' global scope.
*/
async getSharedWorkflowIds(user: User, options: ShareWorkflowOptions): Promise<string[]> {
const { projectId } = options;
if (hasGlobalScope(user, 'workflow:read')) {
const sharedWorkflows = await this.sharedWorkflowRepository.find({
select: ['workflowId'],
...(projectId && { where: { projectId } }),
});
return sharedWorkflows.map(({ workflowId }) => workflowId);
}
const projectRoles =
'scopes' in options ? rolesWithScope('project', options.scopes) : options.projectRoles;
const workflowRoles =
'scopes' in options ? rolesWithScope('workflow', options.scopes) : options.workflowRoles;
const sharedWorkflows = await this.sharedWorkflowRepository.find({
where: {
role: In(workflowRoles),
project: {
projectRelations: {
userId: user.id,
role: In(projectRoles),
},
},
},
select: ['workflowId'],
});
return sharedWorkflows.map(({ workflowId }) => workflowId);
}
async getSharedWithMeIds(user: User) {
const sharedWithMeWorkflows = await this.sharedWorkflowRepository.find({
select: ['workflowId'],
where: {
role: 'workflow:editor',
project: {
projectRelations: {
userId: user.id,
role: 'project:personalOwner',
},
},
},
});
return sharedWithMeWorkflows.map(({ workflowId }) => workflowId);
}
async getSharedWorkflowScopes(
workflowIds: string[],
user: User,
): Promise<Array<[string, Scope[]]>> {
const projectRelations = await this.projectRelationRepository.findAllByUser(user.id);
const sharedWorkflows =
await this.sharedWorkflowRepository.getRelationsByWorkflowIdsAndProjectIds(
workflowIds,
projectRelations.map((p) => p.projectId),
);
return workflowIds.map((workflowId) => {
return [
workflowId,
this.roleService.combineResourceScopes(
'workflow',
user,
sharedWorkflows.filter((s) => s.workflowId === workflowId),
projectRelations,
),
];
});
}
async getOwnedWorkflowsInPersonalProject(user: User): Promise<string[]> {
const sharedWorkflows = await this.sharedWorkflowRepository.find({
select: ['workflowId'],
where: {
role: 'workflow:owner',
project: {
projectRelations: {
userId: user.id,
role: 'project:personalOwner',
},
},
},
});
return sharedWorkflows.map(({ workflowId }) => workflowId);
}
}
|