mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
feat: Add admin role to public API (no-changelog) (#7933)
## Summary Add the admin global role to the public API. This does not include porting over scopes. #### How to test the change: 1. ... ## Issues fixed Include links to Github issue or Community forum post or **Linear ticket**: > Important in order to close automatically and provide context to reviewers ... ## Review / Merge checklist - [ ] PR title and summary are descriptive. **Remember, the title automatically goes into the changelog. Use `(no-changelog)` otherwise.** ([conventions](https://github.com/n8n-io/n8n/blob/master/.github/pull_request_title_conventions.md)) - [ ] [Docs updated](https://github.com/n8n-io/n8n-docs) or follow-up ticket created. - [ ] Tests included. > A bug is not considered fixed, unless a test is added to prevent it from happening again. A feature is not complete without tests. > > *(internal)* You can use Slack commands to trigger [e2e tests](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#a39f9e5ba64a48b58a71d81c837e8227) or [deploy test instance](https://www.notion.so/n8n/How-to-use-Test-Instances-d65f49dfc51f441ea44367fb6f67eb0a?pvs=4#f6a177d32bde4b57ae2da0b8e454bfce) or [deploy early access version on Cloud](https://www.notion.so/n8n/Cloudbot-3dbe779836004972b7057bc989526998?pvs=4#fef2d36ab02247e1a0f65a74f6fb534e).
This commit is contained in:
parent
50e416d9ae
commit
4e55583715
|
@ -5,7 +5,7 @@ import Container from 'typedi';
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
generateAudit: [
|
generateAudit: [
|
||||||
authorize(['owner']),
|
authorize(['owner', 'admin']),
|
||||||
async (req: AuditRequest.Generate, res: Response): Promise<Response> => {
|
async (req: AuditRequest.Generate, res: Response): Promise<Response> => {
|
||||||
try {
|
try {
|
||||||
const { SecurityAuditService } = await import('@/security-audit/SecurityAudit.service');
|
const { SecurityAuditService } = await import('@/security-audit/SecurityAudit.service');
|
||||||
|
|
|
@ -23,7 +23,7 @@ import { Container } from 'typedi';
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
createCredential: [
|
createCredential: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
validCredentialType,
|
validCredentialType,
|
||||||
validCredentialsProperties,
|
validCredentialsProperties,
|
||||||
async (
|
async (
|
||||||
|
@ -47,7 +47,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
deleteCredential: [
|
deleteCredential: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (
|
async (
|
||||||
req: CredentialRequest.Delete,
|
req: CredentialRequest.Delete,
|
||||||
res: express.Response,
|
res: express.Response,
|
||||||
|
@ -55,7 +55,7 @@ export = {
|
||||||
const { id: credentialId } = req.params;
|
const { id: credentialId } = req.params;
|
||||||
let credential: CredentialsEntity | undefined;
|
let credential: CredentialsEntity | undefined;
|
||||||
|
|
||||||
if (req.user.globalRole.name !== 'owner') {
|
if (!['owner', 'admin'].includes(req.user.globalRole.name)) {
|
||||||
const shared = await getSharedCredentials(req.user.id, credentialId, [
|
const shared = await getSharedCredentials(req.user.id, credentialId, [
|
||||||
'credentials',
|
'credentials',
|
||||||
'role',
|
'role',
|
||||||
|
@ -78,7 +78,7 @@ export = {
|
||||||
],
|
],
|
||||||
|
|
||||||
getCredentialType: [
|
getCredentialType: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: CredentialTypeRequest.Get, res: express.Response): Promise<express.Response> => {
|
async (req: CredentialTypeRequest.Get, res: express.Response): Promise<express.Response> => {
|
||||||
const { credentialTypeName } = req.params;
|
const { credentialTypeName } = req.params;
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { ExecutionRepository } from '@db/repositories/execution.repository';
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
deleteExecution: [
|
deleteExecution: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: ExecutionRequest.Delete, res: express.Response): Promise<express.Response> => {
|
async (req: ExecutionRequest.Delete, res: express.Response): Promise<express.Response> => {
|
||||||
const sharedWorkflowsIds = await getSharedWorkflowIds(req.user);
|
const sharedWorkflowsIds = await getSharedWorkflowIds(req.user);
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
getExecution: [
|
getExecution: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: ExecutionRequest.Get, res: express.Response): Promise<express.Response> => {
|
async (req: ExecutionRequest.Get, res: express.Response): Promise<express.Response> => {
|
||||||
const sharedWorkflowsIds = await getSharedWorkflowIds(req.user);
|
const sharedWorkflowsIds = await getSharedWorkflowIds(req.user);
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
getExecutions: [
|
getExecutions: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
validCursor,
|
validCursor,
|
||||||
async (req: ExecutionRequest.GetAll, res: express.Response): Promise<express.Response> => {
|
async (req: ExecutionRequest.GetAll, res: express.Response): Promise<express.Response> => {
|
||||||
const {
|
const {
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { InternalHooks } from '@/InternalHooks';
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
pull: [
|
pull: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin']),
|
||||||
async (
|
async (
|
||||||
req: PublicSourceControlRequest.Pull,
|
req: PublicSourceControlRequest.Pull,
|
||||||
res: express.Response,
|
res: express.Response,
|
||||||
|
|
|
@ -15,7 +15,7 @@ import { InternalHooks } from '@/InternalHooks';
|
||||||
export = {
|
export = {
|
||||||
getUser: [
|
getUser: [
|
||||||
validLicenseWithUserQuota,
|
validLicenseWithUserQuota,
|
||||||
authorize(['owner']),
|
authorize(['owner', 'admin']),
|
||||||
async (req: UserRequest.Get, res: express.Response) => {
|
async (req: UserRequest.Get, res: express.Response) => {
|
||||||
const { includeRole = false } = req.query;
|
const { includeRole = false } = req.query;
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
|
@ -41,7 +41,7 @@ export = {
|
||||||
getUsers: [
|
getUsers: [
|
||||||
validLicenseWithUserQuota,
|
validLicenseWithUserQuota,
|
||||||
validCursor,
|
validCursor,
|
||||||
authorize(['owner']),
|
authorize(['owner', 'admin']),
|
||||||
async (req: UserRequest.Get, res: express.Response) => {
|
async (req: UserRequest.Get, res: express.Response) => {
|
||||||
const { offset = 0, limit = 100, includeRole = false } = req.query;
|
const { offset = 0, limit = 100, includeRole = false } = req.query;
|
||||||
|
|
||||||
|
|
|
@ -31,7 +31,7 @@ import { WorkflowHistoryService } from '@/workflows/workflowHistory/workflowHist
|
||||||
|
|
||||||
export = {
|
export = {
|
||||||
createWorkflow: [
|
createWorkflow: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: WorkflowRequest.Create, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.Create, res: express.Response): Promise<express.Response> => {
|
||||||
const workflow = req.body;
|
const workflow = req.body;
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
deleteWorkflow: [
|
deleteWorkflow: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: WorkflowRequest.Get, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.Get, res: express.Response): Promise<express.Response> => {
|
||||||
const { id: workflowId } = req.params;
|
const { id: workflowId } = req.params;
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
getWorkflow: [
|
getWorkflow: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: WorkflowRequest.Get, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.Get, res: express.Response): Promise<express.Response> => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
getWorkflows: [
|
getWorkflows: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
validCursor,
|
validCursor,
|
||||||
async (req: WorkflowRequest.GetAll, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.GetAll, res: express.Response): Promise<express.Response> => {
|
||||||
const { offset = 0, limit = 100, active = undefined, tags = undefined } = req.query;
|
const { offset = 0, limit = 100, active = undefined, tags = undefined } = req.query;
|
||||||
|
@ -104,7 +104,7 @@ export = {
|
||||||
...(active !== undefined && { active }),
|
...(active !== undefined && { active }),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (req.user.isOwner) {
|
if (['owner', 'admin'].includes(req.user.globalRole.name)) {
|
||||||
if (tags) {
|
if (tags) {
|
||||||
const workflowIds = await getWorkflowIdsViaTags(parseTagNames(tags));
|
const workflowIds = await getWorkflowIdsViaTags(parseTagNames(tags));
|
||||||
where.id = In(workflowIds);
|
where.id = In(workflowIds);
|
||||||
|
@ -152,7 +152,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
updateWorkflow: [
|
updateWorkflow: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: WorkflowRequest.Update, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.Update, res: express.Response): Promise<express.Response> => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
const updateData = new WorkflowEntity();
|
const updateData = new WorkflowEntity();
|
||||||
|
@ -214,7 +214,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
activateWorkflow: [
|
activateWorkflow: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: WorkflowRequest.Activate, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.Activate, res: express.Response): Promise<express.Response> => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ export = {
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
deactivateWorkflow: [
|
deactivateWorkflow: [
|
||||||
authorize(['owner', 'member']),
|
authorize(['owner', 'admin', 'member']),
|
||||||
async (req: WorkflowRequest.Activate, res: express.Response): Promise<express.Response> => {
|
async (req: WorkflowRequest.Activate, res: express.Response): Promise<express.Response> => {
|
||||||
const { id } = req.params;
|
const { id } = req.params;
|
||||||
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ function insertIf(condition: boolean, elements: string[]): string[] {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getSharedWorkflowIds(user: User): Promise<string[]> {
|
export async function getSharedWorkflowIds(user: User): Promise<string[]> {
|
||||||
const where = user.globalRole.name === 'owner' ? {} : { userId: user.id };
|
const where = ['owner', 'admin'].includes(user.globalRole.name) ? {} : { userId: user.id };
|
||||||
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
|
const sharedWorkflows = await Container.get(SharedWorkflowRepository).find({
|
||||||
where,
|
where,
|
||||||
select: ['workflowId'],
|
select: ['workflowId'],
|
||||||
|
@ -32,7 +32,7 @@ export async function getSharedWorkflow(
|
||||||
): Promise<SharedWorkflow | null> {
|
): Promise<SharedWorkflow | null> {
|
||||||
return Container.get(SharedWorkflowRepository).findOne({
|
return Container.get(SharedWorkflowRepository).findOne({
|
||||||
where: {
|
where: {
|
||||||
...(!user.isOwner && { userId: user.id }),
|
...(!['owner', 'admin'].includes(user.globalRole.name) && { userId: user.id }),
|
||||||
...(workflowId && { workflowId }),
|
...(workflowId && { workflowId }),
|
||||||
},
|
},
|
||||||
relations: [...insertIf(!config.getEnv('workflowTagsDisabled'), ['workflow.tags']), 'workflow'],
|
relations: [...insertIf(!config.getEnv('workflowTagsDisabled'), ['workflow.tags']), 'workflow'],
|
||||||
|
@ -48,7 +48,7 @@ export async function getSharedWorkflows(
|
||||||
): Promise<SharedWorkflow[]> {
|
): Promise<SharedWorkflow[]> {
|
||||||
return Container.get(SharedWorkflowRepository).find({
|
return Container.get(SharedWorkflowRepository).find({
|
||||||
where: {
|
where: {
|
||||||
...(!user.isOwner && { userId: user.id }),
|
...(!['owner', 'admin'].includes(user.globalRole.name) && { userId: user.id }),
|
||||||
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
|
...(options.workflowIds && { workflowId: In(options.workflowIds) }),
|
||||||
},
|
},
|
||||||
...(options.relations && { relations: options.relations }),
|
...(options.relations && { relations: options.relations }),
|
||||||
|
|
|
@ -6,11 +6,12 @@ import { Container } from 'typedi';
|
||||||
import type { AuthenticatedRequest, PaginatedRequest } from '../../../types';
|
import type { AuthenticatedRequest, PaginatedRequest } from '../../../types';
|
||||||
import { decodeCursor } from '../services/pagination.service';
|
import { decodeCursor } from '../services/pagination.service';
|
||||||
import { License } from '@/License';
|
import { License } from '@/License';
|
||||||
|
import type { RoleNames } from '@/databases/entities/Role';
|
||||||
|
|
||||||
const UNLIMITED_USERS_QUOTA = -1;
|
const UNLIMITED_USERS_QUOTA = -1;
|
||||||
|
|
||||||
export const authorize =
|
export const authorize =
|
||||||
(authorizedRoles: readonly string[]) =>
|
(authorizedRoles: readonly RoleNames[]) =>
|
||||||
(
|
(
|
||||||
req: AuthenticatedRequest,
|
req: AuthenticatedRequest,
|
||||||
res: express.Response,
|
res: express.Response,
|
||||||
|
|
Loading…
Reference in a new issue