Enhance role-check system with stricter checks (#15392)
## Overview This PR strengthens our permission system by introducing more granular role-based access control across the platform. ## Changes ### New Permissions Added - **Applications** - Control who can install and manage applications - **Layouts** - Control who can customize page layouts and UI structure - **AI** - Control access to AI features and agents - **Upload File** - Separate permission for file uploads - **Download File** - Separate permission for file downloads (frontend visibility) ### Security Enhancements - Implemented whitelist-based validation for workspace field updates - Added explicit permission guards to core entity resolvers - Enhanced ESLint rule to enforce permission checks on all mutations - Created `CustomPermissionGuard` and `NoPermissionGuard` for better code documentation ### Affected Components - Core entity resolvers: webhooks, files, domains, applications, layouts, postgres credentials - Workspace update mutations now use whitelist validation - Settings UI updated with new permission controls ### Developer Experience - ESLint now catches missing permission guards during development - Explicit guard markers make permission requirements clear in code review - Comprehensive test coverage for new permission logic ## Testing - ✅ All TypeScript type checks pass - ✅ ESLint validation passes - ✅ New permission guards properly enforced - ✅ Frontend UI displays new permissions correctly ## Migration Notes Existing workspaces will need to assign the new permissions to roles as needed. By default, all new permissions are set to `false` for non-admin roles.
This commit is contained in:
+45
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewFieldPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args.input or args.inputs
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.viewId === 'string') {
|
||||
viewId = args.input.viewId;
|
||||
}
|
||||
|
||||
if (!viewId && Array.isArray(args?.inputs) && args.inputs.length > 0) {
|
||||
viewId =
|
||||
typeof args.inputs[0]?.viewId === 'string'
|
||||
? args.inputs[0].viewId
|
||||
: null;
|
||||
}
|
||||
|
||||
// For REST: extract from request body
|
||||
if (!viewId && typeof request.body?.viewId === 'string') {
|
||||
viewId = request.body.viewId;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewFilterGroupPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args.input
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.viewId === 'string') {
|
||||
viewId = args.input.viewId;
|
||||
}
|
||||
|
||||
// For REST: extract from request body
|
||||
if (!viewId && typeof request.body?.viewId === 'string') {
|
||||
viewId = request.body.viewId;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewFilterPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args.input
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.viewId === 'string') {
|
||||
viewId = args.input.viewId;
|
||||
}
|
||||
|
||||
// For REST: extract from request body
|
||||
if (!viewId && typeof request.body?.viewId === 'string') {
|
||||
viewId = request.body.viewId;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewGroupPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args.input or args.inputs
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.viewId === 'string') {
|
||||
viewId = args.input.viewId;
|
||||
}
|
||||
|
||||
if (!viewId && Array.isArray(args?.inputs) && args.inputs.length > 0) {
|
||||
viewId =
|
||||
typeof args.inputs[0]?.viewId === 'string'
|
||||
? args.inputs[0].viewId
|
||||
: null;
|
||||
}
|
||||
|
||||
// For REST: extract from request body
|
||||
if (!viewId && typeof request.body?.viewId === 'string') {
|
||||
viewId = request.body.viewId;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class CreateViewSortPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args.input
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.viewId === 'string') {
|
||||
viewId = args.input.viewId;
|
||||
}
|
||||
|
||||
// For REST: extract from request body
|
||||
if (!viewId && typeof request.body?.viewId === 'string') {
|
||||
viewId = request.body.viewId;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewFieldPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewField',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewFilterGroupPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
entityId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewFilterGroup',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewFilterPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewFilter',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewGroupPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewGroup',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
viewId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!viewId && typeof request.params?.id === 'string') {
|
||||
viewId = request.params.id;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyView(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteViewSortPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
entityId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewSort',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyViewFieldPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewField',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyViewFilterGroupPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
entityId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewFilterGroup',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyViewFilterPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewFilter',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyViewGroupPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewGroup',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyViewPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
viewId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!viewId && typeof request.params?.id === 'string') {
|
||||
viewId = request.params.id;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyView(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class DestroyViewSortPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
entityId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewSort',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewFieldPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewField',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewFilterGroupPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
entityId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewFilterGroup',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewFilterPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewFilter',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewGroupPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.input.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.input?.id === 'string') {
|
||||
entityId = args.input.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewGroup',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewPermissionGuard implements CanActivate {
|
||||
constructor(private readonly viewAccessService: ViewAccessService) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let viewId: string | null = null;
|
||||
|
||||
// For GraphQL: extract from args
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
viewId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!viewId && typeof request.params?.id === 'string') {
|
||||
viewId = request.params.id;
|
||||
}
|
||||
|
||||
return this.viewAccessService.canUserModifyView(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
import {
|
||||
Injectable,
|
||||
type CanActivate,
|
||||
type ExecutionContext,
|
||||
} from '@nestjs/common';
|
||||
import { GqlExecutionContext } from '@nestjs/graphql';
|
||||
|
||||
import { ViewAccessService } from 'src/engine/metadata-modules/view-permissions/services/view-access.service';
|
||||
import { ViewEntityLookupService } from 'src/engine/metadata-modules/view-permissions/services/view-entity-lookup.service';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateViewSortPermissionGuard implements CanActivate {
|
||||
constructor(
|
||||
private readonly viewAccessService: ViewAccessService,
|
||||
private readonly viewEntityLookupService: ViewEntityLookupService,
|
||||
) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const gqlContext = GqlExecutionContext.create(context);
|
||||
const request = gqlContext.getContext().req;
|
||||
|
||||
let entityId = '';
|
||||
|
||||
// For GraphQL: extract from args.id
|
||||
const args = gqlContext.getArgs();
|
||||
|
||||
if (typeof args?.id === 'string') {
|
||||
entityId = args.id;
|
||||
}
|
||||
|
||||
// For REST: extract from URL params
|
||||
if (!entityId && typeof request.params?.id === 'string') {
|
||||
entityId = request.params.id;
|
||||
}
|
||||
|
||||
const viewId = entityId
|
||||
? await this.viewEntityLookupService.findViewIdByEntityIdAndKind(
|
||||
'viewSort',
|
||||
entityId,
|
||||
request.workspace.id,
|
||||
)
|
||||
: null;
|
||||
|
||||
return this.viewAccessService.canUserModifyViewByChildEntity(
|
||||
viewId,
|
||||
request.userWorkspaceId,
|
||||
request.workspace.id,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user