From 3b47eaa04bb1b053e67e8159e54e8113f2572219 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 22 Apr 2025 21:10:39 +0530 Subject: [PATCH 01/12] init --- .../validators/tooljet-database.validator.ts | 13 ++++ server/src/modules/apps/module.ts | 2 +- server/src/modules/apps/repository.ts | 20 +++++ server/src/modules/apps/service.ts | 38 +-------- .../services/app-import-export.service.ts | 16 ++-- .../apps-import-export.util.service.ts | 1 + server/src/modules/apps/util.service.ts | 44 +++++++++++ .../guards/external-api-security.guard.ts | 20 ++--- .../external-apis/constants/feature.ts | 12 +++ .../modules/external-apis/constants/index.ts | 37 +++++++++ server/src/modules/external-apis/dto/index.ts | 77 ++++++++++++++++++- .../src/modules/external-apis/types/index.ts | 13 ++++ .../modules/licensing/configs/LicenseBase.ts | 1 + .../organizations/interfaces/IUtilService.ts | 3 + .../src/modules/organizations/util.service.ts | 18 +++++ .../versions/interfaces/IUtilService.ts | 1 + server/src/modules/versions/util.service.ts | 9 +++ 17 files changed, 268 insertions(+), 57 deletions(-) create mode 100644 server/src/modules/apps/util-services/apps-import-export.util.service.ts create mode 100644 server/src/modules/organizations/interfaces/IUtilService.ts create mode 100644 server/src/modules/organizations/util.service.ts diff --git a/server/src/dto/validators/tooljet-database.validator.ts b/server/src/dto/validators/tooljet-database.validator.ts index 6ebea6bd17..164087bd0e 100644 --- a/server/src/dto/validators/tooljet-database.validator.ts +++ b/server/src/dto/validators/tooljet-database.validator.ts @@ -10,6 +10,7 @@ import Ajv from 'ajv'; import * as path from 'path'; import * as fs from 'fs'; import { ImportResourcesDto } from '@dto/import-resources.dto'; +import { AppImportRequestDto } from '@modules/external-apis/dto'; const ajv = new Ajv({ allErrors: true, coerceTypes: true }); const logger = new Logger('TooljetDatabaseSchemaValidator'); @@ -109,3 +110,15 @@ export function ValidateTooljetDatabaseSchema(validationOptions?: ValidationOpti }); }; } + +export function ValidateTooljetDatabaseImportSchema(validationOptions?: ValidationOptions) { + return function (object: AppImportRequestDto, propertyName: string) { + registerDecorator({ + target: object.constructor, + propertyName: propertyName, + options: validationOptions, + constraints: [], + validator: ValidateTooljetDatabaseConstraint, + }); + }; +} diff --git a/server/src/modules/apps/module.ts b/server/src/modules/apps/module.ts index 93f7223e54..4f1daf97da 100644 --- a/server/src/modules/apps/module.ts +++ b/server/src/modules/apps/module.ts @@ -62,7 +62,7 @@ export class AppsModule { DataSourcesRepository, AppImportExportService, ], - exports: [AppsUtilService], + exports: [AppsUtilService, AppImportExportService], }; } } diff --git a/server/src/modules/apps/repository.ts b/server/src/modules/apps/repository.ts index 98c76b5634..172689e303 100644 --- a/server/src/modules/apps/repository.ts +++ b/server/src/modules/apps/repository.ts @@ -2,6 +2,7 @@ import { App } from '@entities/app.entity'; import { Injectable } from '@nestjs/common'; import { DataSource, Repository } from 'typeorm'; import { SessionAppData } from './types'; +import { WorkspaceAppsResponseDto } from '@modules/external-apis/dto'; @Injectable() export class AppsRepository extends Repository { @@ -63,4 +64,23 @@ export class AppsRepository extends Repository { }, }); } + + async findAllOrganizationApps(organizationId: string): Promise { + return await this.createQueryBuilder('app') + .select([ + 'app.id AS id', + 'app.name AS name', + 'app.slug AS slug', + 'app.created_at AS createdAt', + 'app.organization_id AS organizationId', + 'version.id AS versionId', + 'version.name AS versionName', + 'version.created_at AS versionCreatedAt', + ]) + .leftJoin('app_versions', 'version', 'version.app_id = app.id') + .where('app.organizationId = :organizationId', { organizationId }) + .orderBy('app.created_At', 'ASC') + .orderBy('version.created_at', 'ASC') + .getRawMany(); + } } diff --git a/server/src/modules/apps/service.ts b/server/src/modules/apps/service.ts index 58546f98ee..03e030470e 100644 --- a/server/src/modules/apps/service.ts +++ b/server/src/modules/apps/service.ts @@ -29,9 +29,6 @@ import { VersionRepository } from '@modules/versions/repository'; import { AppsRepository } from './repository'; import { FoldersUtilService } from '@modules/folders/util.service'; import { FolderAppsUtilService } from '@modules/folder-apps/util.service'; -import { DataQuery } from '@entities/data_query.entity'; -import { DataSource } from '@entities/data_source.entity'; -import { AppVersion } from '@entities/app_version.entity'; import { PageService } from './services/page.service'; import { EventsService } from './services/event.service'; import { LICENSE_FIELD } from '@modules/licensing/constants'; @@ -224,40 +221,7 @@ export class AppsService implements IAppsService { } async findTooljetDbTables(appId: string): Promise<{ table_id: string }[]> { - return await dbTransactionWrap(async (manager: EntityManager) => { - const tooljetDbDataQueries = await manager - .createQueryBuilder(DataQuery, 'data_queries') - .innerJoin(DataSource, 'data_sources', 'data_queries.data_source_id = data_sources.id') - .innerJoin(AppVersion, 'app_versions', 'app_versions.id = data_sources.app_version_id') - .where('app_versions.app_id = :appId', { appId }) - .andWhere('data_sources.kind = :kind', { kind: 'tooljetdb' }) - .getMany(); - - const uniqTableIds = new Set(); - tooljetDbDataQueries.forEach((dq) => { - if (dq.options?.operation === 'join_tables') { - const joinOptions = dq.options?.join_table?.joins ?? []; - (joinOptions || []).forEach((join) => { - const { table, conditions } = join; - if (table) uniqTableIds.add(table); - conditions?.conditionsList?.forEach((condition) => { - const { leftField, rightField } = condition; - if (leftField?.table) { - uniqTableIds.add(leftField?.table); - } - if (rightField?.table) { - uniqTableIds.add(rightField?.table); - } - }); - }); - } - if (dq.options.table_id) uniqTableIds.add(dq.options.table_id); - }); - - return [...uniqTableIds].map((table_id) => { - return { table_id }; - }); - }); + return await this.appsUtilService.findTooljetDbTables(appId); //moved to util } async getOne(app: App, user: User): Promise { diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index abc2abce3e..af18856250 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -1164,7 +1164,8 @@ export class AppImportExportService { manager: EntityManager, dataSource: DataSource, appVersionId: string, - user: User + user: User, + organizationId?: string ): Promise { const isDefaultDatasource = DefaultDataSourceNames.includes(dataSource.name as DefaultDataSourceName); const isPlugin = !!dataSource.pluginId; @@ -1189,7 +1190,7 @@ export class AppImportExportService { kind: dataSource.kind, type: DataSourceTypes.DEFAULT, scope: 'global', - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, }, }); }; @@ -1200,7 +1201,7 @@ export class AppImportExportService { kind: dataSource.kind, type: In([DataSourceTypes.DEFAULT, DataSourceTypes.SAMPLE]), scope: 'global', - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, }, }); }; @@ -1218,7 +1219,7 @@ export class AppImportExportService { if (plugin) { const newDataSource = manager.create(DataSource, { - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, name: dataSource.name, kind: dataSource.kind, type: DataSourceTypes.DEFAULT, @@ -1233,7 +1234,7 @@ export class AppImportExportService { const createNewGlobalDs = async (ds: DataSource): Promise => { const newDataSource = manager.create(DataSource, { - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, name: dataSource.name, kind: dataSource.kind, type: DataSourceTypes.DEFAULT, @@ -1318,12 +1319,13 @@ export class AppImportExportService { importedApp: App, appVersions: AppVersion[], appResourceMappings: AppResourceMappings, - isNormalizedAppDefinitionSchema: boolean + isNormalizedAppDefinitionSchema: boolean, + organizationId?: string ) { appResourceMappings = { ...appResourceMappings }; const { appVersionMapping, appDefaultEnvironmentMapping } = appResourceMappings; const organization: Organization = await manager.findOne(Organization, { - where: { id: user.organizationId }, + where: { id: user?.organizationId || organizationId }, relations: ['appEnvironments'], }); let currentEnvironmentId: string; diff --git a/server/src/modules/apps/util-services/apps-import-export.util.service.ts b/server/src/modules/apps/util-services/apps-import-export.util.service.ts new file mode 100644 index 0000000000..383ade1537 --- /dev/null +++ b/server/src/modules/apps/util-services/apps-import-export.util.service.ts @@ -0,0 +1 @@ +//to do ? idk diff --git a/server/src/modules/apps/util.service.ts b/server/src/modules/apps/util.service.ts index 36def10913..f17fa876a7 100644 --- a/server/src/modules/apps/util.service.ts +++ b/server/src/modules/apps/util.service.ts @@ -37,6 +37,9 @@ import { DataSourcesRepository } from '@modules/data-sources/repository'; import { IAppsUtilService } from './interfaces/IUtilService'; import { DataSourcesUtilService } from '@modules/data-sources/util.service'; import { AppVersionUpdateDto } from '@dto/app-version-update.dto'; +import { WorkspaceAppsResponseDto } from '@modules/external-apis/dto'; +import { DataQuery } from '@entities/data_query.entity'; +import { DataSource } from '@entities/data_source.entity'; @Injectable() export class AppsUtilService implements IAppsUtilService { @@ -522,4 +525,45 @@ export class AppsUtilService implements IAppsUtilService { return components; } + + async findAllOrganizationApps(organizationId: string): Promise { + return await this.appRepository.findAllOrganizationApps(organizationId); + } + + async findTooljetDbTables(appId: string): Promise<{ table_id: string }[]> { + return await dbTransactionWrap(async (manager: EntityManager) => { + const tooljetDbDataQueries = await manager + .createQueryBuilder(DataQuery, 'data_queries') + .innerJoin(DataSource, 'data_sources', 'data_queries.data_source_id = data_sources.id') + .innerJoin(AppVersion, 'app_versions', 'app_versions.id = data_sources.app_version_id') + .where('app_versions.app_id = :appId', { appId }) + .andWhere('data_sources.kind = :kind', { kind: 'tooljetdb' }) + .getMany(); + + const uniqTableIds = new Set(); + tooljetDbDataQueries.forEach((dq) => { + if (dq.options?.operation === 'join_tables') { + const joinOptions = dq.options?.join_table?.joins ?? []; + (joinOptions || []).forEach((join) => { + const { table, conditions } = join; + if (table) uniqTableIds.add(table); + conditions?.conditionsList?.forEach((condition) => { + const { leftField, rightField } = condition; + if (leftField?.table) { + uniqTableIds.add(leftField?.table); + } + if (rightField?.table) { + uniqTableIds.add(rightField?.table); + } + }); + }); + } + if (dq.options.table_id) uniqTableIds.add(dq.options.table_id); + }); + + return [...uniqTableIds].map((table_id) => { + return { table_id }; + }); + }); + } } diff --git a/server/src/modules/auth/guards/external-api-security.guard.ts b/server/src/modules/auth/guards/external-api-security.guard.ts index 0d6ab91863..27957fc73d 100644 --- a/server/src/modules/auth/guards/external-api-security.guard.ts +++ b/server/src/modules/auth/guards/external-api-security.guard.ts @@ -9,18 +9,18 @@ export class ExternalApiSecurityGuard implements CanActivate { const request = context.switchToHttp().getRequest(); // Check if external API is enabled - const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; - if (!isExternalApiEnabled) { - throw new ForbiddenException('External API is disabled'); - } + // const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; + // if (!isExternalApiEnabled) { + // throw new ForbiddenException('External API is disabled'); + // } - // Check the authorization header - const authHeader = request.headers['authorization']; - const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); + // // Check the authorization header + // const authHeader = request.headers['authorization']; + // const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); - if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { - throw new ForbiddenException('Unauthorized'); - } + // if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { + // throw new ForbiddenException('Unauthorized'); + // } return true; } diff --git a/server/src/modules/external-apis/constants/feature.ts b/server/src/modules/external-apis/constants/feature.ts index 6dcccf4e70..5551dd64e0 100644 --- a/server/src/modules/external-apis/constants/feature.ts +++ b/server/src/modules/external-apis/constants/feature.ts @@ -37,5 +37,17 @@ export const FEATURES: FeaturesConfig = { license: LICENSE_FIELD.EXTERNAL_API, isPublic: true, }, + [FEATURE_KEY.GET_ALL_WORKSPACE_APPS]: { + license: LICENSE_FIELD.EXTERNAL_API, + isPublic: true, + }, + [FEATURE_KEY.IMPORT_APP]: { + license: LICENSE_FIELD.EXTERNAL_API, + isPublic: true, + }, + [FEATURE_KEY.EXPORT_APP]: { + license: LICENSE_FIELD.EXTERNAL_API, + isPublic: true, + }, }, }; diff --git a/server/src/modules/external-apis/constants/index.ts b/server/src/modules/external-apis/constants/index.ts index 8fdca84235..97030f67a7 100644 --- a/server/src/modules/external-apis/constants/index.ts +++ b/server/src/modules/external-apis/constants/index.ts @@ -7,4 +7,41 @@ export enum FEATURE_KEY { UPDATE_USER_WORKSPACE = 'UPDATE_USER_WORKSPACE', GET_ALL_WORKSPACES = 'GET_ALL_WORKSPACES', UPDATE_USER_ROLE = 'UPDATE_USER_ROLE', + GET_ALL_WORKSPACE_APPS = 'GET_ALL_WORKSPACE_APPS', + IMPORT_APP = 'IMPORT_APP', + EXPORT_APP = 'EXPORT_APP', } + +export type DefaultDataSourceKind = 'restapi' | 'runjs' | 'runpy' | 'tooljetdb' | 'workflows'; +export type NewRevampedComponent = + | 'Text' + | 'TextInput' + | 'PasswordInput' + | 'NumberInput' + | 'Table' + | 'Button' + | 'Checkbox'; +export type DefaultDataSourceName = + | 'restapidefault' + | 'runjsdefault' + | 'runpydefault' + | 'tooljetdbdefault' + | 'workflowsdefault'; + +export const DefaultDataSourceKinds: DefaultDataSourceKind[] = ['restapi', 'runjs', 'runpy', 'tooljetdb', 'workflows']; +export const DefaultDataSourceNames: DefaultDataSourceName[] = [ + 'restapidefault', + 'runjsdefault', + 'runpydefault', + 'tooljetdbdefault', + 'workflowsdefault', +]; +export const NewRevampedComponents: NewRevampedComponent[] = [ + 'Text', + 'TextInput', + 'PasswordInput', + 'NumberInput', + 'Table', + 'Checkbox', + 'Button', +]; diff --git a/server/src/modules/external-apis/dto/index.ts b/server/src/modules/external-apis/dto/index.ts index 71fe51141b..9d8d6a0f9d 100644 --- a/server/src/modules/external-apis/dto/index.ts +++ b/server/src/modules/external-apis/dto/index.ts @@ -10,10 +10,13 @@ import { MaxLength, ValidateIf, IsNotEmpty, + IsDefined, + IsObject, } from 'class-validator'; -import { Type } from 'class-transformer'; +import { Transform, Type } from 'class-transformer'; import { USER_ROLE } from '@modules/group-permissions/constants'; - +import { TjdbSchemaToLatestVersion } from '@dto/transformers/resource-transformer'; +import { ValidateTooljetDatabaseImportSchema } from '@dto/validators/tooljet-database.validator'; export enum Status { ACTIVE = 'active', ARCHIVED = 'archived', @@ -131,3 +134,73 @@ export class UpdateUserWorkspaceDto { @IsOptional() groups?: GroupDto[]; } + +export class VersionDto { + id: string; + name: string; + createdAt?: Date; +} + +export class AppWithVersionsDto { + id: string; + name: string; + slug: string; + createdAt: Date; + organizationId: string; + versions: VersionDto[]; + versionCount: number; +} + +export class WorkspaceAppsResponseDto { + apps: AppWithVersionsDto[]; + total: number; +} + +export class AppImportRequestDto { + @IsString() + tooljet_version: string; + + // TODO: Add transformation and validation for app similar to tooljet_database + @IsOptional() + app: AppImportDto[]; + + // Optional parameter -> To be provided in import request to import app with custom name. + @IsOptional() + @IsString() + appName: string; + + // TJ-DB field + @IsOptional() + // Transform the input data to the latest schema version + // This should be applied first to ensure the data is in + // the correct format before validation + @Transform(TjdbSchemaToLatestVersion) + @ValidateNested({ each: true }) + // Ensure each item is properly instantiated as ImportTooljetDatabaseDto + // This is crucial for nested validation to work correctly + @Type(() => ImportTooljetDatabaseDto) + // Custom validator to check against the tooljet database schema + // This should be applied last to validate the transformed + // and instantiated data + @ValidateTooljetDatabaseImportSchema({ each: true }) + tooljet_database: ImportTooljetDatabaseDto[]; +} +export class AppImportDto { + @IsDefined() + @IsObject() + definition: any; +} + +export class ImportTooljetDatabaseDto { + @IsUUID() + id: string; + + @IsString() + table_name: string; + + @IsDefined() + schema: any; + + // @IsOptional() + // data: boolean; +} diff --git a/server/src/modules/external-apis/types/index.ts b/server/src/modules/external-apis/types/index.ts index 8c782681a6..5ed8d5c323 100644 --- a/server/src/modules/external-apis/types/index.ts +++ b/server/src/modules/external-apis/types/index.ts @@ -11,6 +11,9 @@ interface Features { [FEATURE_KEY.UPDATE_USER_WORKSPACE]: FeatureConfig; [FEATURE_KEY.GET_ALL_WORKSPACES]: FeatureConfig; [FEATURE_KEY.UPDATE_USER_ROLE]: FeatureConfig; + [FEATURE_KEY.GET_ALL_WORKSPACE_APPS]: FeatureConfig; + [FEATURE_KEY.IMPORT_APP]: FeatureConfig; + [FEATURE_KEY.EXPORT_APP]: FeatureConfig; } export interface FeaturesConfig { @@ -22,3 +25,13 @@ export interface ValidateEditUserGroupAdditionObject { groupsToAddIds: string[]; organizationId: string; } + +export interface AppResourceMappings { + defaultDataSourceIdMapping: Record; + dataQueryMapping: Record; + appVersionMapping: Record; + appEnvironmentMapping: Record; + appDefaultEnvironmentMapping: Record; + pagesMapping: Record; + componentsMapping: Record; +} diff --git a/server/src/modules/licensing/configs/LicenseBase.ts b/server/src/modules/licensing/configs/LicenseBase.ts index 5c62bedeaf..b014877f7d 100644 --- a/server/src/modules/licensing/configs/LicenseBase.ts +++ b/server/src/modules/licensing/configs/LicenseBase.ts @@ -275,6 +275,7 @@ export default class LicenseBase { } public get externalApis(): boolean { + return true; if (this.IsBasicPlan) { return !!BASIC_PLAN_TERMS.features?.externalApi; } diff --git a/server/src/modules/organizations/interfaces/IUtilService.ts b/server/src/modules/organizations/interfaces/IUtilService.ts new file mode 100644 index 0000000000..a6162c3cef --- /dev/null +++ b/server/src/modules/organizations/interfaces/IUtilService.ts @@ -0,0 +1,3 @@ +export interface IOrganizationUtilService { + validateWorkspaceExists(workspaceId: string): Promise; +} diff --git a/server/src/modules/organizations/util.service.ts b/server/src/modules/organizations/util.service.ts new file mode 100644 index 0000000000..9d501eb7f5 --- /dev/null +++ b/server/src/modules/organizations/util.service.ts @@ -0,0 +1,18 @@ +import { Injectable } from '@nestjs/common'; +import { OrganizationRepository } from './repository'; +import { BadRequestException } from '@nestjs/common'; +import { IOrganizationUtilService } from './interfaces/IUtilService'; + +@Injectable() +export class OrganizationsUtilService implements IOrganizationUtilService { + constructor(protected readonly organizationRepository: OrganizationRepository) {} + + async validateWorkspaceExists(workspaceId: string) { + const existingWorkspace = await this.organizationRepository.findOne({ + where: { id: workspaceId }, + }); + if (!existingWorkspace) { + throw new BadRequestException(`Invalid workspaceId: ${workspaceId}`); + } + } +} diff --git a/server/src/modules/versions/interfaces/IUtilService.ts b/server/src/modules/versions/interfaces/IUtilService.ts index 2b384ff789..768de2afdb 100644 --- a/server/src/modules/versions/interfaces/IUtilService.ts +++ b/server/src/modules/versions/interfaces/IUtilService.ts @@ -3,4 +3,5 @@ import { AppVersionUpdateDto } from '@dto/app-version-update.dto'; export interface IVersionUtilService { updateVersion(appVersion: AppVersion, appVersionUpdateDto: AppVersionUpdateDto): Promise; + fetchVersions(appId: string): Promise; } diff --git a/server/src/modules/versions/util.service.ts b/server/src/modules/versions/util.service.ts index f5723e0377..124a3c2ab3 100644 --- a/server/src/modules/versions/util.service.ts +++ b/server/src/modules/versions/util.service.ts @@ -72,4 +72,13 @@ export class VersionUtilService implements IVersionUtilService { await this.versionRepository.update(appVersion.id, editableParams); return; } + + async fetchVersions(appId: string): Promise { + return await this.versionRepository.find({ + where: { appId }, + order: { + createdAt: 'DESC', + }, + }); + } } From 01624a02d264d32a502c3af0ba8b693009022eec Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Wed, 23 Apr 2025 12:11:43 +0530 Subject: [PATCH 02/12] server --- .../apps/services/app-import-export.service.ts | 6 +++--- .../auth/guards/external-api-security.guard.ts | 18 +++++++++--------- server/src/modules/external-apis/module.ts | 13 ++++++++++++- server/src/modules/organizations/module.ts | 10 +++++++++- server/src/modules/versions/module.ts | 1 + 5 files changed, 34 insertions(+), 14 deletions(-) diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index af18856250..ace7cbe638 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -81,7 +81,7 @@ export class AppImportExportService { protected componentsService: ComponentsService ) {} - async export(user: User, id: string, searchParams: any = {}): Promise<{ appV2: App }> { + async export(user: User, id: string, searchParams: any = {}, organizationId?: string): Promise<{ appV2: App }> { // https://github.com/typeorm/typeorm/issues/3857 // Making use of query builder // filter by search params @@ -91,7 +91,7 @@ export class AppImportExportService { .createQueryBuilder(App, 'apps') .where('apps.id = :id AND apps.organization_id = :organizationId', { id, - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, }); const appToExport = await queryForAppToExport.getOne(); @@ -120,7 +120,7 @@ export class AppImportExportService { const appEnvironments = await manager .createQueryBuilder(AppEnvironment, 'app_environments') .where('app_environments.organizationId = :organizationId', { - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, }) .orderBy('app_environments.createdAt', 'ASC') .getMany(); diff --git a/server/src/modules/auth/guards/external-api-security.guard.ts b/server/src/modules/auth/guards/external-api-security.guard.ts index 27957fc73d..f6aced14d5 100644 --- a/server/src/modules/auth/guards/external-api-security.guard.ts +++ b/server/src/modules/auth/guards/external-api-security.guard.ts @@ -9,18 +9,18 @@ export class ExternalApiSecurityGuard implements CanActivate { const request = context.switchToHttp().getRequest(); // Check if external API is enabled - // const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; - // if (!isExternalApiEnabled) { - // throw new ForbiddenException('External API is disabled'); - // } + const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; + if (!isExternalApiEnabled) { + throw new ForbiddenException('External API is disabled'); + } // // Check the authorization header - // const authHeader = request.headers['authorization']; - // const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); + const authHeader = request.headers['authorization']; + const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); - // if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { - // throw new ForbiddenException('Unauthorized'); - // } + if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { + throw new ForbiddenException('Unauthorized'); + } return true; } diff --git a/server/src/modules/external-apis/module.ts b/server/src/modules/external-apis/module.ts index c4a209c0bc..c9b5197fc1 100644 --- a/server/src/modules/external-apis/module.ts +++ b/server/src/modules/external-apis/module.ts @@ -5,6 +5,10 @@ import { DynamicModule } from '@nestjs/common'; import { getImportPath } from '@modules/app/constants'; import { ExternalApiSecurityGuard } from './guards/external-api-security.guard'; import { RolesRepository } from '@modules/roles/repository'; +import { TooljetDbModule } from '@modules/tooljet-db/module'; +import { AppsModule } from '@modules/apps/module'; +import { OrganizationsModule } from '@modules/organizations/module'; +import { VersionModule } from '@modules/versions/module'; export class ExternalApiModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { const importPath = await getImportPath(configs?.IS_GET_CONTEXT); @@ -14,7 +18,14 @@ export class ExternalApiModule { return { module: ExternalApiModule, - imports: [await RolesModule.register(configs), await GroupPermissionsModule.register(configs)], + imports: [ + await RolesModule.register(configs), + await GroupPermissionsModule.register(configs), + await TooljetDbModule.register(configs), + await AppsModule.register(configs), + await OrganizationsModule.register(configs), + await VersionModule.register(configs), + ], providers: [ ExternalApiUtilService, ExternalApisService, diff --git a/server/src/modules/organizations/module.ts b/server/src/modules/organizations/module.ts index b7432d5e4c..e430ae78e5 100644 --- a/server/src/modules/organizations/module.ts +++ b/server/src/modules/organizations/module.ts @@ -10,12 +10,20 @@ export class OrganizationsModule { const { OrganizationsController } = await import(`${importPath}/organizations/controller`); const { FeatureAbilityFactory } = await import(`${importPath}/organizations/ability`); const { AppEnvironmentUtilService } = await import(`${importPath}/app-environments/util.service`); + const { OrganizationsUtilService } = await import(`${importPath}/organizations/util.service`); return { module: OrganizationsModule, imports: [await InstanceSettingsModule.register(configs)], controllers: [OrganizationsController], - providers: [OrganizationsService, OrganizationRepository, FeatureAbilityFactory, AppEnvironmentUtilService], + providers: [ + OrganizationsService, + OrganizationRepository, + FeatureAbilityFactory, + AppEnvironmentUtilService, + OrganizationsUtilService, + ], + exports: [OrganizationsUtilService], }; } } diff --git a/server/src/modules/versions/module.ts b/server/src/modules/versions/module.ts index 1f08dc76bb..261401a18d 100644 --- a/server/src/modules/versions/module.ts +++ b/server/src/modules/versions/module.ts @@ -51,6 +51,7 @@ export class VersionModule { VersionUtilService, FeatureAbilityFactory, ], + exports: [VersionUtilService], }; } } From 617688a985c572bec0f6b8d92fed1f404379f875 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Thu, 24 Apr 2025 19:57:16 +0530 Subject: [PATCH 03/12] param --- server/src/modules/apps/services/app-import-export.service.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index ace7cbe638..de4dc0a298 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -223,7 +223,8 @@ export class AppImportExportService { externalResourceMappings = {}, isGitApp = false, tooljetVersion = '', - cloning = false + cloning = false, + organizationId?: string ): Promise { if (typeof appParamsObj !== 'object') { throw new BadRequestException('Invalid params for app import'); From 7e52b6178cd21b761b2d39e0b1f239405a2b0319 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 29 Apr 2025 03:44:14 +0530 Subject: [PATCH 04/12] fix --- server/src/modules/apps/module.ts | 2 + .../services/app-import-export.service.ts | 78 +++++++++++++------ .../guards/external-api-security.guard.ts | 22 +++--- .../src/modules/external-apis/controller.ts | 2 +- .../guards/external-api-security.guard.ts | 27 ------- server/src/modules/external-apis/module.ts | 9 +-- server/src/modules/roles/service.ts | 29 +------ server/src/modules/roles/util.service.ts | 22 +++++- server/src/modules/users/module.ts | 1 + 9 files changed, 95 insertions(+), 97 deletions(-) delete mode 100644 server/src/modules/external-apis/guards/external-api-security.guard.ts diff --git a/server/src/modules/apps/module.ts b/server/src/modules/apps/module.ts index 4f1daf97da..580d37061a 100644 --- a/server/src/modules/apps/module.ts +++ b/server/src/modules/apps/module.ts @@ -19,6 +19,7 @@ import { FeatureAbilityFactory } from './ability'; import { DataSourcesModule } from '@modules/data-sources/module'; import { AppsSubscriber } from './subscribers/apps.subscriber'; import { AiModule } from '@modules/ai/module'; +import { UsersModule } from '@modules/users/module'; @Module({}) export class AppsModule { static async register(configs: { IS_GET_CONTEXT: boolean }): Promise { @@ -44,6 +45,7 @@ export class AppsModule { await AppEnvironmentsModule.register(configs), await DataSourcesModule.register(configs), await AiModule.register(configs), + await UsersModule.register(configs), ], controllers: [AppsController], providers: [ diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index de4dc0a298..4df309150b 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -33,6 +33,7 @@ import { DataSourcesUtilService } from '@modules/data-sources/util.service'; import { DataSourcesRepository } from '@modules/data-sources/repository'; import { AppEnvironmentUtilService } from '@modules/app-environments/util.service'; import { ComponentsService } from './component.service'; +import { UsersUtilService } from '@modules/users/util.service'; interface AppResourceMappings { defaultDataSourceIdMapping: Record; dataQueryMapping: Record; @@ -77,6 +78,7 @@ export class AppImportExportService { protected dataSourcesUtilService: DataSourcesUtilService, protected dataSourcesRepository: DataSourcesRepository, protected appEnvironmentUtilService: AppEnvironmentUtilService, + protected usersUtilService: UsersUtilService, protected readonly entityManager: EntityManager, protected componentsService: ComponentsService ) {} @@ -252,7 +254,13 @@ export class AppImportExportService { const currentTooljetVersion = !cloning ? tooljetVersion : null; - const importedApp = await this.createImportedAppForUser(this.entityManager, schemaUnifiedAppParams, user, isGitApp); + const importedApp = await this.createImportedAppForUser( + this.entityManager, //create new BC + schemaUnifiedAppParams, + user, + isGitApp, + organizationId + ); const resourceMapping = await this.setupImportedAppAssociations( this.entityManager, @@ -261,7 +269,8 @@ export class AppImportExportService { user, externalResourceMappings, isNormalizedAppDefinitionSchema, - currentTooljetVersion + currentTooljetVersion, + organizationId ); await this.updateEntityReferencesForImportedApp(this.entityManager, resourceMapping); @@ -334,12 +343,18 @@ export class AppImportExportService { } } - async createImportedAppForUser(manager: EntityManager, appParams: any, user: User, isGitApp = false): Promise { + async createImportedAppForUser( + manager: EntityManager, + appParams: any, + user: User, + isGitApp = false, + organizationId?: string + ): Promise { return await catchDbException(async () => { const importedApp = manager.create(App, { name: appParams.name, - organizationId: user.organizationId, - userId: user.id, + organizationId: user?.organizationId || organizationId, + userId: user.id, //fetch super admin user id for EE slug: null, icon: appParams.icon, creationMode: `${isGitApp ? 'GIT' : 'DEFAULT'}`, @@ -401,14 +416,22 @@ export class AppImportExportService { user: User, externalResourceMappings: Record, isNormalizedAppDefinitionSchema: boolean, - tooljetVersion: string | null + tooljetVersion: string | null, + organizationId?: string ) { // Old version without app version // Handle exports prior to 0.12.0 // TODO: have version based conditional based on app versions // isLessThanExportVersion(appParams.tooljet_version, 'v0.12.0') if (!appParams?.appVersions) { - await this.performLegacyAppImport(manager, importedApp, appParams, externalResourceMappings, user); + await this.performLegacyAppImport( + manager, + importedApp, + appParams, + externalResourceMappings, + user, + organizationId + ); return; } @@ -439,7 +462,8 @@ export class AppImportExportService { importedApp, importingAppVersions, appResourceMappings, - isNormalizedAppDefinitionSchema + isNormalizedAppDefinitionSchema, + organizationId ); appResourceMappings.appDefaultEnvironmentMapping = appDefaultEnvironmentMapping; appResourceMappings.appVersionMapping = appVersionMapping; @@ -465,7 +489,8 @@ export class AppImportExportService { importingPages, importingComponents, importingEvents, - tooljetVersion + tooljetVersion, + organizationId ); if (!isNormalizedAppDefinitionSchema) { @@ -672,7 +697,8 @@ export class AppImportExportService { importingPages: Page[], importingComponents: Component[], importingEvents: EventHandler[], - tooljetVersion: string | null + tooljetVersion: string | null, + organizationId?: string ): Promise { appResourceMappings = { ...appResourceMappings }; @@ -685,7 +711,8 @@ export class AppImportExportService { user, importingAppEnvironments, importingAppVersion, - appResourceMappings + appResourceMappings, + organizationId ); appResourceMappings.appEnvironmentMapping = appEnvironmentMapping; @@ -693,7 +720,8 @@ export class AppImportExportService { manager, importingAppVersion, user, - appResourceMappings + appResourceMappings, + organizationId ); appResourceMappings.defaultDataSourceIdMapping = defaultDataSourceIdMapping; @@ -712,7 +740,8 @@ export class AppImportExportService { manager, importingDataSource, appResourceMappings.appVersionMapping[importingAppVersion.id], - user + user, + organizationId ); // TODO: Have version based conditional based on app versions @@ -760,7 +789,7 @@ export class AppImportExportService { const { dataQueryMapping } = await this.createDataQueriesForAppVersion( manager, - user.organizationId, + user?.organizationId || organizationId, importingDataQueriesForAppVersion, importingDataSource, dataSourceForAppVersion, @@ -1148,10 +1177,11 @@ export class AppImportExportService { manager: EntityManager, appVersion: AppVersion, user: User, - appResourceMappings: AppResourceMappings + appResourceMappings: AppResourceMappings, + organizationId?: string ) { const defaultDataSourceIds = await this.createDefaultDataSourceForVersion( - user.organizationId, + user?.organizationId || organizationId, appResourceMappings.appVersionMapping[appVersion.id], DefaultDataSourceKinds, manager @@ -1259,11 +1289,12 @@ export class AppImportExportService { user: User, appEnvironments: Record[], appVersion: AppVersion, - appResourceMappings: AppResourceMappings + appResourceMappings: AppResourceMappings, + organizationId?: string ) { appResourceMappings = { ...appResourceMappings }; const currentOrgEnvironments = await this.appEnvironmentUtilService.getAll( - user.organizationId, + user?.organizationId || organizationId, appVersion.appId, manager ); @@ -1525,7 +1556,8 @@ export class AppImportExportService { importedApp: App, appParams: any, externalResourceMappings: any, - user: any + user: any, + organizationId?: string ) { const dataSourceMapping = {}; const dataQueryMapping = {}; @@ -1545,7 +1577,7 @@ export class AppImportExportService { // Create default data sources const defaultDataSourceIds = await this.createDefaultDataSourceForVersion( - user.organizationId, + user?.organizationId || organizationId, version.id, DefaultDataSourceKinds, manager @@ -1553,7 +1585,7 @@ export class AppImportExportService { let envIdArray: string[] = []; const organization: Organization = await manager.findOne(Organization, { - where: { id: user.organizationId }, + where: { id: user?.organizationId || organizationId }, relations: ['appEnvironments'], }); envIdArray = [...organization.appEnvironments.map((env) => env.id)]; @@ -1562,7 +1594,7 @@ export class AppImportExportService { await Promise.all( defaultAppEnvironments.map(async (en) => { const env = manager.create(AppEnvironment, { - organizationId: user.organizationId, + organizationId: user?.organizationId || organizationId, name: en.name, isDefault: en.isDefault, priority: en.priority, @@ -1629,7 +1661,7 @@ export class AppImportExportService { ? this.replaceTooljetDbTableIds( query.options, externalResourceMappings['tooljet_database'], - user.organizationId + user?.organizationId || organizationId ) : query.options, }); diff --git a/server/src/modules/auth/guards/external-api-security.guard.ts b/server/src/modules/auth/guards/external-api-security.guard.ts index f6aced14d5..30918b232b 100644 --- a/server/src/modules/auth/guards/external-api-security.guard.ts +++ b/server/src/modules/auth/guards/external-api-security.guard.ts @@ -8,19 +8,19 @@ export class ExternalApiSecurityGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const request = context.switchToHttp().getRequest(); - // Check if external API is enabled - const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; - if (!isExternalApiEnabled) { - throw new ForbiddenException('External API is disabled'); - } + // // Check if external API is enabled + // const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; + // if (!isExternalApiEnabled) { + // throw new ForbiddenException('External API is disabled'); + // } - // // Check the authorization header - const authHeader = request.headers['authorization']; - const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); + // // // Check the authorization header + // const authHeader = request.headers['authorization']; + // const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); - if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { - throw new ForbiddenException('Unauthorized'); - } + // if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { + // throw new ForbiddenException('Unauthorized'); + // } return true; } diff --git a/server/src/modules/external-apis/controller.ts b/server/src/modules/external-apis/controller.ts index 3a6f533243..7180ea23fb 100644 --- a/server/src/modules/external-apis/controller.ts +++ b/server/src/modules/external-apis/controller.ts @@ -1,8 +1,8 @@ import { Controller, Get, Param, UseGuards, Body, Patch, Post, Put, NotFoundException } from '@nestjs/common'; -import { ExternalApiSecurityGuard } from './guards/external-api-security.guard'; import { UpdateUserDto, WorkspaceDto, UpdateGivenWorkspaceDto, CreateUserDto } from './dto'; import { IExternalApisController } from './Interfaces/IController'; import { EditUserRoleDto } from '@modules/roles/dto'; +import { ExternalApiSecurityGuard } from '@modules/auth/guards/external-api-security.guard'; @Controller('ext') export class ExternalApisController implements IExternalApisController { diff --git a/server/src/modules/external-apis/guards/external-api-security.guard.ts b/server/src/modules/external-apis/guards/external-api-security.guard.ts deleted file mode 100644 index 0d6ab91863..0000000000 --- a/server/src/modules/external-apis/guards/external-api-security.guard.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { Injectable, CanActivate, ExecutionContext, ForbiddenException } from '@nestjs/common'; -import { ConfigService } from '@nestjs/config'; - -@Injectable() -export class ExternalApiSecurityGuard implements CanActivate { - constructor(protected configService: ConfigService) {} - - canActivate(context: ExecutionContext): boolean { - const request = context.switchToHttp().getRequest(); - - // Check if external API is enabled - const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; - if (!isExternalApiEnabled) { - throw new ForbiddenException('External API is disabled'); - } - - // Check the authorization header - const authHeader = request.headers['authorization']; - const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); - - if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { - throw new ForbiddenException('Unauthorized'); - } - - return true; - } -} diff --git a/server/src/modules/external-apis/module.ts b/server/src/modules/external-apis/module.ts index c9b5197fc1..042dc93662 100644 --- a/server/src/modules/external-apis/module.ts +++ b/server/src/modules/external-apis/module.ts @@ -3,7 +3,6 @@ import { GroupPermissionsModule } from '@modules/group-permissions/module'; import { RolesModule } from '@modules/roles/module'; import { DynamicModule } from '@nestjs/common'; import { getImportPath } from '@modules/app/constants'; -import { ExternalApiSecurityGuard } from './guards/external-api-security.guard'; import { RolesRepository } from '@modules/roles/repository'; import { TooljetDbModule } from '@modules/tooljet-db/module'; import { AppsModule } from '@modules/apps/module'; @@ -26,13 +25,7 @@ export class ExternalApiModule { await OrganizationsModule.register(configs), await VersionModule.register(configs), ], - providers: [ - ExternalApiUtilService, - ExternalApisService, - ExternalApiSecurityGuard, - FeatureAbilityFactory, - RolesRepository, - ], + providers: [ExternalApiUtilService, ExternalApisService, FeatureAbilityFactory, RolesRepository], controllers: [ExternalApisController], exports: [ExternalApiUtilService], }; diff --git a/server/src/modules/roles/service.ts b/server/src/modules/roles/service.ts index d638f10635..d67c7f9923 100644 --- a/server/src/modules/roles/service.ts +++ b/server/src/modules/roles/service.ts @@ -1,37 +1,14 @@ -import { BadRequestException, Injectable } from '@nestjs/common'; +import { Injectable } from '@nestjs/common'; import { EditUserRoleDto } from './dto'; import { RolesUtilService } from './util.service'; -import { ERROR_HANDLER } from '../group-permissions/constants/error'; -import { _ } from 'lodash'; -import { LicenseUserService } from '@modules/licensing/services/user.service'; -import { dbTransactionWrap } from '@helpers/database.helper'; -import { EntityManager } from 'typeorm'; import { RolesRepository } from './repository'; import { IRolesService } from './interfaces/IService'; @Injectable() export class RolesService implements IRolesService { - constructor( - protected rolesUtilService: RolesUtilService, - protected roleRepository: RolesRepository, - protected licenseUserService: LicenseUserService - ) {} + constructor(protected rolesUtilService: RolesUtilService, protected roleRepository: RolesRepository) {} async updateUserRole(organizationId: string, editRoleDto: EditUserRoleDto) { - const { userId, newRole } = editRoleDto; - await dbTransactionWrap(async (manager: EntityManager) => { - const userRole = await this.roleRepository.getUserRole(userId, organizationId, manager); - if (_.isEmpty(userRole)) { - throw new BadRequestException(ERROR_HANDLER.ADD_GROUP_USER_NON_EXISTING_USER); - } - - if (userRole.name == newRole) { - throw new BadRequestException(ERROR_HANDLER.DEFAULT_GROUP_ADD_USER_ROLE_EXIST(newRole)); - } - editRoleDto.currentRole = userRole; - await this.rolesUtilService.editDefaultGroupUserRole(organizationId, editRoleDto, manager); - - await this.licenseUserService.validateUser(manager); - }); + await this.rolesUtilService.updateUserRole(organizationId, editRoleDto); } } diff --git a/server/src/modules/roles/util.service.ts b/server/src/modules/roles/util.service.ts index 7a7bf6fdc1..6c596480f9 100644 --- a/server/src/modules/roles/util.service.ts +++ b/server/src/modules/roles/util.service.ts @@ -14,12 +14,14 @@ import { ERROR_HANDLER } from '@modules/group-permissions/constants/error'; import { RolesRepository } from './repository'; import { AddUserRoleObject } from '@modules/group-permissions/types'; import { IRolesUtilService } from './interfaces/IUtilService'; +import { LicenseUserService } from '@modules/licensing/services/user.service'; @Injectable() export class RolesUtilService implements IRolesUtilService { constructor( protected groupPermissionsRepository: GroupPermissionsRepository, - protected roleRepository: RolesRepository + protected roleRepository: RolesRepository, + protected licenseUserService: LicenseUserService ) {} async changeEndUserToEditor( @@ -194,4 +196,22 @@ export class RolesUtilService implements IRolesUtilService { return isBuilderLevelAppsPermission || isBuilderLevelDataSourcePermissions; }, manager); } + + async updateUserRole(organizationId: string, editRoleDto: EditUserRoleDto) { + const { userId, newRole } = editRoleDto; + await dbTransactionWrap(async (manager: EntityManager) => { + const userRole = await this.roleRepository.getUserRole(userId, organizationId, manager); + if (_.isEmpty(userRole)) { + throw new BadRequestException(ERROR_HANDLER.ADD_GROUP_USER_NON_EXISTING_USER); + } + + if (userRole.name == newRole) { + throw new BadRequestException(ERROR_HANDLER.DEFAULT_GROUP_ADD_USER_ROLE_EXIST(newRole)); + } + editRoleDto.currentRole = userRole; + await this.editDefaultGroupUserRole(organizationId, editRoleDto, manager); + + await this.licenseUserService.validateUser(manager); + }); + } } diff --git a/server/src/modules/users/module.ts b/server/src/modules/users/module.ts index bd91972dba..963eb08fca 100644 --- a/server/src/modules/users/module.ts +++ b/server/src/modules/users/module.ts @@ -16,6 +16,7 @@ export class UsersModule { imports: [await SessionModule.register(configs)], controllers: [UsersController], providers: [UsersService, UserRepository, UsersUtilService, FeatureAbilityFactory], + exports: [UsersUtilService], }; } } From 12f09f80d8e9d8d4fda24a125fa321baaafce012 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 6 May 2025 16:38:13 +0530 Subject: [PATCH 05/12] review --- .../apps-import-export.util.service.ts | 1 - .../guards/external-api-security.guard.ts | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) delete mode 100644 server/src/modules/apps/util-services/apps-import-export.util.service.ts diff --git a/server/src/modules/apps/util-services/apps-import-export.util.service.ts b/server/src/modules/apps/util-services/apps-import-export.util.service.ts deleted file mode 100644 index 383ade1537..0000000000 --- a/server/src/modules/apps/util-services/apps-import-export.util.service.ts +++ /dev/null @@ -1 +0,0 @@ -//to do ? idk diff --git a/server/src/modules/auth/guards/external-api-security.guard.ts b/server/src/modules/auth/guards/external-api-security.guard.ts index 30918b232b..19b0d197a4 100644 --- a/server/src/modules/auth/guards/external-api-security.guard.ts +++ b/server/src/modules/auth/guards/external-api-security.guard.ts @@ -9,18 +9,18 @@ export class ExternalApiSecurityGuard implements CanActivate { const request = context.switchToHttp().getRequest(); // // Check if external API is enabled - // const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; - // if (!isExternalApiEnabled) { - // throw new ForbiddenException('External API is disabled'); - // } + const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; + if (!isExternalApiEnabled) { + throw new ForbiddenException('External API is disabled'); + } - // // // Check the authorization header - // const authHeader = request.headers['authorization']; - // const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); + // // Check the authorization header + const authHeader = request.headers['authorization']; + const externalApiAccessToken = this.configService.get('EXTERNAL_API_ACCESS_TOKEN'); - // if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { - // throw new ForbiddenException('Unauthorized'); - // } + if (!authHeader || authHeader !== `Basic ${externalApiAccessToken}`) { + throw new ForbiddenException('Unauthorized'); + } return true; } From c7bca09dc659a243387611a9dd5f14adb5f34abc Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Thu, 8 May 2025 12:16:44 +0530 Subject: [PATCH 06/12] merge fix --- server/src/modules/app-permissions/module.ts | 11 ++++-- .../services/app-import-export.service.ts | 36 ++++++++++++------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/server/src/modules/app-permissions/module.ts b/server/src/modules/app-permissions/module.ts index 704c6c1374..dd2c1d905e 100644 --- a/server/src/modules/app-permissions/module.ts +++ b/server/src/modules/app-permissions/module.ts @@ -9,13 +9,18 @@ import { PageUsersRepository } from './repositories/page-users.repository'; import { PagePermissionsRepository } from './repositories/page-permissions.repository'; import { PageUser } from '@entities/page_users.entity'; import { PagePermission } from '@entities/page_permissions.entity'; +import { AppPermissionsController } from './controller'; +import { AppPermissionsService } from './service'; +import { AppPermissionsUtilService } from './util.service'; export class AppPermissionsModule { static async register(configs: { IS_GET_CONTEXT: boolean }): Promise { const importPath = await getImportPath(configs.IS_GET_CONTEXT); - const { AppPermissionsController } = await import(`${importPath}/app-permissions/controller`); - const { AppPermissionsService } = await import(`${importPath}/app-permissions/service`); - const { AppPermissionsUtilService } = await import(`${importPath}/app-permissions/util.service`); + // const { AppPermissionsController } = await import(`${importPath}/app-permissions/controller`); + // const { AppPermissionsService } = await import(`${importPath}/app-permissions/service`); + // const { AppPermissionsUtilService } = await import(`${importPath}/app-permissions/util.service`); + + //Please create EE Files for the above imports and remove static imports return { module: AppPermissionsModule, diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index 83c99e852e..b9914b0e8a 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -52,7 +52,17 @@ type DefaultDataSourceName = | 'tooljetdbdefault' | 'workflowsdefault'; -type NewRevampedComponent = 'Text' | 'TextInput' | 'PasswordInput' | 'NumberInput' | 'Table' | 'Button' | 'Checkbox' | 'Divider' | 'VerticalDivider' | 'Link'; +type NewRevampedComponent = + | 'Text' + | 'TextInput' + | 'PasswordInput' + | 'NumberInput' + | 'Table' + | 'Button' + | 'Checkbox' + | 'Divider' + | 'VerticalDivider' + | 'Link'; const DefaultDataSourceNames: DefaultDataSourceName[] = [ 'restapidefault', @@ -84,7 +94,7 @@ export class AppImportExportService { protected usersUtilService: UsersUtilService, protected readonly entityManager: EntityManager, protected componentsService: ComponentsService - ) { } + ) {} async export(user: User, id: string, searchParams: any = {}, organizationId?: string): Promise<{ appV2: App }> { // https://github.com/typeorm/typeorm/issues/3857 @@ -186,13 +196,13 @@ export class AppImportExportService { const components = pages.length > 0 ? await manager - .createQueryBuilder(Component, 'components') - .leftJoinAndSelect('components.layouts', 'layouts') - .where('components.pageId IN(:...pageId)', { - pageId: pages.map((v) => v.id), - }) - .orderBy('components.created_at', 'ASC') - .getMany() + .createQueryBuilder(Component, 'components') + .leftJoinAndSelect('components.layouts', 'layouts') + .where('components.pageId IN(:...pageId)', { + pageId: pages.map((v) => v.id), + }) + .orderBy('components.created_at', 'ASC') + .getMany() : []; const events = await manager @@ -1089,10 +1099,10 @@ export class AppImportExportService { const options = importingDataSource.kind === 'tooljetdb' ? this.replaceTooljetDbTableIds( - importingQuery.options, - externalResourceMappings['tooljet_database'], - organizationId - ) + importingQuery.options, + externalResourceMappings['tooljet_database'], + organizationId + ) : importingQuery.options; const newQuery = manager.create(DataQuery, { From 7af3812f5fe0ef4ce836977a3bee66a0b72495b2 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Mon, 12 May 2025 15:26:40 +0530 Subject: [PATCH 07/12] fix --- server/src/modules/app-permissions/module.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/server/src/modules/app-permissions/module.ts b/server/src/modules/app-permissions/module.ts index dd2c1d905e..704c6c1374 100644 --- a/server/src/modules/app-permissions/module.ts +++ b/server/src/modules/app-permissions/module.ts @@ -9,18 +9,13 @@ import { PageUsersRepository } from './repositories/page-users.repository'; import { PagePermissionsRepository } from './repositories/page-permissions.repository'; import { PageUser } from '@entities/page_users.entity'; import { PagePermission } from '@entities/page_permissions.entity'; -import { AppPermissionsController } from './controller'; -import { AppPermissionsService } from './service'; -import { AppPermissionsUtilService } from './util.service'; export class AppPermissionsModule { static async register(configs: { IS_GET_CONTEXT: boolean }): Promise { const importPath = await getImportPath(configs.IS_GET_CONTEXT); - // const { AppPermissionsController } = await import(`${importPath}/app-permissions/controller`); - // const { AppPermissionsService } = await import(`${importPath}/app-permissions/service`); - // const { AppPermissionsUtilService } = await import(`${importPath}/app-permissions/util.service`); - - //Please create EE Files for the above imports and remove static imports + const { AppPermissionsController } = await import(`${importPath}/app-permissions/controller`); + const { AppPermissionsService } = await import(`${importPath}/app-permissions/service`); + const { AppPermissionsUtilService } = await import(`${importPath}/app-permissions/util.service`); return { module: AppPermissionsModule, From 592447dc83fcdba8cab836668b6983449977c60d Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 13 May 2025 16:19:57 +0530 Subject: [PATCH 08/12] util-service --- .../guards/external-api-security.guard.ts | 2 +- server/src/modules/organizations/module.ts | 12 ++------ server/src/modules/roles/service.ts | 15 ++++++++-- server/src/modules/roles/util.service.ts | 30 +++++++------------ 4 files changed, 28 insertions(+), 31 deletions(-) diff --git a/server/src/modules/auth/guards/external-api-security.guard.ts b/server/src/modules/auth/guards/external-api-security.guard.ts index 19b0d197a4..f6aced14d5 100644 --- a/server/src/modules/auth/guards/external-api-security.guard.ts +++ b/server/src/modules/auth/guards/external-api-security.guard.ts @@ -8,7 +8,7 @@ export class ExternalApiSecurityGuard implements CanActivate { canActivate(context: ExecutionContext): boolean { const request = context.switchToHttp().getRequest(); - // // Check if external API is enabled + // Check if external API is enabled const isExternalApiEnabled = this.configService.get('ENABLE_EXTERNAL_API') === 'true'; if (!isExternalApiEnabled) { throw new ForbiddenException('External API is disabled'); diff --git a/server/src/modules/organizations/module.ts b/server/src/modules/organizations/module.ts index e430ae78e5..e533607557 100644 --- a/server/src/modules/organizations/module.ts +++ b/server/src/modules/organizations/module.ts @@ -2,6 +2,7 @@ import { DynamicModule } from '@nestjs/common'; import { getImportPath } from '@modules/app/constants'; import { InstanceSettingsModule } from '@modules/instance-settings/module'; import { OrganizationRepository } from './repository'; +import { AppEnvironmentsModule } from '@modules/app-environments/module'; export class OrganizationsModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { @@ -9,20 +10,13 @@ export class OrganizationsModule { const { OrganizationsService } = await import(`${importPath}/organizations/service`); const { OrganizationsController } = await import(`${importPath}/organizations/controller`); const { FeatureAbilityFactory } = await import(`${importPath}/organizations/ability`); - const { AppEnvironmentUtilService } = await import(`${importPath}/app-environments/util.service`); const { OrganizationsUtilService } = await import(`${importPath}/organizations/util.service`); return { module: OrganizationsModule, - imports: [await InstanceSettingsModule.register(configs)], + imports: [await InstanceSettingsModule.register(configs), await AppEnvironmentsModule.register(configs)], controllers: [OrganizationsController], - providers: [ - OrganizationsService, - OrganizationRepository, - FeatureAbilityFactory, - AppEnvironmentUtilService, - OrganizationsUtilService, - ], + providers: [OrganizationsService, OrganizationRepository, FeatureAbilityFactory, OrganizationsUtilService], exports: [OrganizationsUtilService], }; } diff --git a/server/src/modules/roles/service.ts b/server/src/modules/roles/service.ts index d67c7f9923..981f0e6f57 100644 --- a/server/src/modules/roles/service.ts +++ b/server/src/modules/roles/service.ts @@ -3,12 +3,23 @@ import { EditUserRoleDto } from './dto'; import { RolesUtilService } from './util.service'; import { RolesRepository } from './repository'; import { IRolesService } from './interfaces/IService'; +import { EntityManager } from 'typeorm'; +import { dbTransactionWrap } from '@helpers/database.helper'; +import { LicenseUserService } from '@modules/licensing/services/user.service'; @Injectable() export class RolesService implements IRolesService { - constructor(protected rolesUtilService: RolesUtilService, protected roleRepository: RolesRepository) {} + constructor( + protected rolesUtilService: RolesUtilService, + protected roleRepository: RolesRepository, + protected licenseUserService: LicenseUserService + ) {} async updateUserRole(organizationId: string, editRoleDto: EditUserRoleDto) { - await this.rolesUtilService.updateUserRole(organizationId, editRoleDto); + await dbTransactionWrap(async (manager: EntityManager) => { + await this.rolesUtilService.editDefaultGroupUserRole(organizationId, editRoleDto, manager); + + await this.licenseUserService.validateUser(manager); + }); } } diff --git a/server/src/modules/roles/util.service.ts b/server/src/modules/roles/util.service.ts index 6c596480f9..26733f07a1 100644 --- a/server/src/modules/roles/util.service.ts +++ b/server/src/modules/roles/util.service.ts @@ -57,8 +57,18 @@ export class RolesUtilService implements IRolesUtilService { editRoleDto: EditUserRoleDto, manager?: EntityManager ): Promise { - const { newRole, userId, updatingUserId: updatedAdmin, currentRole: userRole } = editRoleDto; + const { newRole, userId, updatingUserId: updatedAdmin } = editRoleDto; return await dbTransactionWrap(async (manager: EntityManager) => { + const userRole = await this.roleRepository.getUserRole(userId, organizationId, manager); + if (_.isEmpty(userRole)) { + throw new BadRequestException(ERROR_HANDLER.ADD_GROUP_USER_NON_EXISTING_USER); + } + + if (userRole.name == newRole) { + throw new BadRequestException(ERROR_HANDLER.DEFAULT_GROUP_ADD_USER_ROLE_EXIST(newRole)); + } + editRoleDto.currentRole = userRole; + // Removing an admin if (userRole.name == USER_ROLE.ADMIN) { const groupUsers = await this.groupPermissionsRepository.getUsersInGroup( @@ -196,22 +206,4 @@ export class RolesUtilService implements IRolesUtilService { return isBuilderLevelAppsPermission || isBuilderLevelDataSourcePermissions; }, manager); } - - async updateUserRole(organizationId: string, editRoleDto: EditUserRoleDto) { - const { userId, newRole } = editRoleDto; - await dbTransactionWrap(async (manager: EntityManager) => { - const userRole = await this.roleRepository.getUserRole(userId, organizationId, manager); - if (_.isEmpty(userRole)) { - throw new BadRequestException(ERROR_HANDLER.ADD_GROUP_USER_NON_EXISTING_USER); - } - - if (userRole.name == newRole) { - throw new BadRequestException(ERROR_HANDLER.DEFAULT_GROUP_ADD_USER_ROLE_EXIST(newRole)); - } - editRoleDto.currentRole = userRole; - await this.editDefaultGroupUserRole(organizationId, editRoleDto, manager); - - await this.licenseUserService.validateUser(manager); - }); - } } From 6e6b721fca8bf0790ec9b35d49d2e69c4811f5e1 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 13 May 2025 17:08:09 +0530 Subject: [PATCH 09/12] user-role --- server/src/modules/roles/service.ts | 14 +++++++++++++- server/src/modules/roles/util.service.ts | 12 +----------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/server/src/modules/roles/service.ts b/server/src/modules/roles/service.ts index 981f0e6f57..85bc6f87d7 100644 --- a/server/src/modules/roles/service.ts +++ b/server/src/modules/roles/service.ts @@ -1,4 +1,4 @@ -import { Injectable } from '@nestjs/common'; +import { BadRequestException, Injectable } from '@nestjs/common'; import { EditUserRoleDto } from './dto'; import { RolesUtilService } from './util.service'; import { RolesRepository } from './repository'; @@ -6,6 +6,8 @@ import { IRolesService } from './interfaces/IService'; import { EntityManager } from 'typeorm'; import { dbTransactionWrap } from '@helpers/database.helper'; import { LicenseUserService } from '@modules/licensing/services/user.service'; +import { ERROR_HANDLER } from '@modules/group-permissions/constants/error'; +import { _ } from 'lodash'; @Injectable() export class RolesService implements IRolesService { @@ -16,7 +18,17 @@ export class RolesService implements IRolesService { ) {} async updateUserRole(organizationId: string, editRoleDto: EditUserRoleDto) { + const { userId, newRole } = editRoleDto; await dbTransactionWrap(async (manager: EntityManager) => { + const userRole = await this.roleRepository.getUserRole(userId, organizationId, manager); + if (_.isEmpty(userRole)) { + throw new BadRequestException(ERROR_HANDLER.ADD_GROUP_USER_NON_EXISTING_USER); + } + + if (userRole.name == newRole) { + throw new BadRequestException(ERROR_HANDLER.DEFAULT_GROUP_ADD_USER_ROLE_EXIST(newRole)); + } + editRoleDto.currentRole = userRole; await this.rolesUtilService.editDefaultGroupUserRole(organizationId, editRoleDto, manager); await this.licenseUserService.validateUser(manager); diff --git a/server/src/modules/roles/util.service.ts b/server/src/modules/roles/util.service.ts index 26733f07a1..481f1c641a 100644 --- a/server/src/modules/roles/util.service.ts +++ b/server/src/modules/roles/util.service.ts @@ -57,18 +57,8 @@ export class RolesUtilService implements IRolesUtilService { editRoleDto: EditUserRoleDto, manager?: EntityManager ): Promise { - const { newRole, userId, updatingUserId: updatedAdmin } = editRoleDto; + const { newRole, userId, updatingUserId: updatedAdmin, currentRole: userRole } = editRoleDto; return await dbTransactionWrap(async (manager: EntityManager) => { - const userRole = await this.roleRepository.getUserRole(userId, organizationId, manager); - if (_.isEmpty(userRole)) { - throw new BadRequestException(ERROR_HANDLER.ADD_GROUP_USER_NON_EXISTING_USER); - } - - if (userRole.name == newRole) { - throw new BadRequestException(ERROR_HANDLER.DEFAULT_GROUP_ADD_USER_ROLE_EXIST(newRole)); - } - editRoleDto.currentRole = userRole; - // Removing an admin if (userRole.name == USER_ROLE.ADMIN) { const groupUsers = await this.groupPermissionsRepository.getUsersInGroup( From 29202a8e40508b3aef0816cd1995158cf2de29f1 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 13 May 2025 18:10:29 +0530 Subject: [PATCH 10/12] pass ws admin --- server/src/modules/external-apis/module.ts | 2 ++ server/src/modules/licensing/configs/LicenseBase.ts | 1 - server/src/modules/users/repository.ts | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/server/src/modules/external-apis/module.ts b/server/src/modules/external-apis/module.ts index 042dc93662..22621363e6 100644 --- a/server/src/modules/external-apis/module.ts +++ b/server/src/modules/external-apis/module.ts @@ -8,6 +8,7 @@ import { TooljetDbModule } from '@modules/tooljet-db/module'; import { AppsModule } from '@modules/apps/module'; import { OrganizationsModule } from '@modules/organizations/module'; import { VersionModule } from '@modules/versions/module'; +import { UsersModule } from '@modules/users/module'; export class ExternalApiModule { static async register(configs?: { IS_GET_CONTEXT: boolean }): Promise { const importPath = await getImportPath(configs?.IS_GET_CONTEXT); @@ -18,6 +19,7 @@ export class ExternalApiModule { return { module: ExternalApiModule, imports: [ + await UsersModule.register(configs), await RolesModule.register(configs), await GroupPermissionsModule.register(configs), await TooljetDbModule.register(configs), diff --git a/server/src/modules/licensing/configs/LicenseBase.ts b/server/src/modules/licensing/configs/LicenseBase.ts index f4aba87211..8153708a44 100644 --- a/server/src/modules/licensing/configs/LicenseBase.ts +++ b/server/src/modules/licensing/configs/LicenseBase.ts @@ -292,7 +292,6 @@ export default class LicenseBase { return this._isServerSideGlobal; } public get externalApis(): boolean { - return true; if (this.IsBasicPlan) { return !!this.BASIC_PLAN_TERMS.features?.externalApi; } diff --git a/server/src/modules/users/repository.ts b/server/src/modules/users/repository.ts index 236e8de8fa..e3417e5e50 100644 --- a/server/src/modules/users/repository.ts +++ b/server/src/modules/users/repository.ts @@ -18,6 +18,7 @@ import { Organization } from '@entities/organization.entity'; import { OrganizationUser } from '@entities/organization_user.entity'; import { isSuperAdmin } from '@helpers/utils.helper'; import * as uuid from 'uuid'; +import { USER_ROLE } from '@modules/group-permissions/constants'; type UserFilterOptions = { searchText?: string; status?: string; page?: number }; @@ -168,6 +169,18 @@ export class UserRepository extends Repository { await manager.upsert(UserDetails, updatableParams, conflictsPaths); } + async getUserWithAdminRole(organizationId: string, manager?: EntityManager): Promise { + return dbTransactionWrap((manager: EntityManager) => { + return manager + .createQueryBuilder(User, 'user') + .innerJoin('user.userGroups', 'groupUsers') + .innerJoin('groupUsers.group', 'group') + .where('group.name = :groupName', { groupName: USER_ROLE.ADMIN }) + .andWhere('group.organizationId = :organizationId', { organizationId }) + .getOne(); + }, manager || this.manager); + } + async findByEmail( email: string, organizationId?: string, From 01d73bd3f9ded044745a8a0ca792ddf29d12f044 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 13 May 2025 19:12:34 +0530 Subject: [PATCH 11/12] remove orgId --- .../apps/services/app-import-export.service.ts | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index b9914b0e8a..1e1c3008eb 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -96,7 +96,7 @@ export class AppImportExportService { protected componentsService: ComponentsService ) {} - async export(user: User, id: string, searchParams: any = {}, organizationId?: string): Promise<{ appV2: App }> { + async export(user: User, id: string, searchParams: any = {}): Promise<{ appV2: App }> { // https://github.com/typeorm/typeorm/issues/3857 // Making use of query builder // filter by search params @@ -106,7 +106,7 @@ export class AppImportExportService { .createQueryBuilder(App, 'apps') .where('apps.id = :id AND apps.organization_id = :organizationId', { id, - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, }); const appToExport = await queryForAppToExport.getOne(); @@ -135,7 +135,7 @@ export class AppImportExportService { const appEnvironments = await manager .createQueryBuilder(AppEnvironment, 'app_environments') .where('app_environments.organizationId = :organizationId', { - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, }) .orderBy('app_environments.createdAt', 'ASC') .getMany(); @@ -238,8 +238,7 @@ export class AppImportExportService { externalResourceMappings = {}, isGitApp = false, tooljetVersion = '', - cloning = false, - organizationId?: string + cloning = false ): Promise { if (typeof appParamsObj !== 'object') { throw new BadRequestException('Invalid params for app import'); @@ -271,8 +270,7 @@ export class AppImportExportService { this.entityManager, //create new BC schemaUnifiedAppParams, user, - isGitApp, - organizationId + isGitApp ); const resourceMapping = await this.setupImportedAppAssociations( @@ -282,8 +280,7 @@ export class AppImportExportService { user, externalResourceMappings, isNormalizedAppDefinitionSchema, - currentTooljetVersion, - organizationId + currentTooljetVersion ); await this.updateEntityReferencesForImportedApp(this.entityManager, resourceMapping); From dba41a8739645f26650cb9248b06e8eb626091a9 Mon Sep 17 00:00:00 2001 From: Rudra deep Biswas Date: Tue, 13 May 2025 22:04:31 +0530 Subject: [PATCH 12/12] cleanup --- .../services/app-import-export.service.ts | 86 ++++++------------- server/src/modules/roles/util.service.ts | 4 +- 2 files changed, 29 insertions(+), 61 deletions(-) diff --git a/server/src/modules/apps/services/app-import-export.service.ts b/server/src/modules/apps/services/app-import-export.service.ts index 1e1c3008eb..16fa8289f6 100644 --- a/server/src/modules/apps/services/app-import-export.service.ts +++ b/server/src/modules/apps/services/app-import-export.service.ts @@ -266,12 +266,7 @@ export class AppImportExportService { const currentTooljetVersion = !cloning ? tooljetVersion : null; - const importedApp = await this.createImportedAppForUser( - this.entityManager, //create new BC - schemaUnifiedAppParams, - user, - isGitApp - ); + const importedApp = await this.createImportedAppForUser(this.entityManager, schemaUnifiedAppParams, user, isGitApp); const resourceMapping = await this.setupImportedAppAssociations( this.entityManager, @@ -353,17 +348,11 @@ export class AppImportExportService { } } - async createImportedAppForUser( - manager: EntityManager, - appParams: any, - user: User, - isGitApp = false, - organizationId?: string - ): Promise { + async createImportedAppForUser(manager: EntityManager, appParams: any, user: User, isGitApp = false): Promise { return await catchDbException(async () => { const importedApp = manager.create(App, { name: appParams.name, - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, userId: user.id, //fetch super admin user id for EE slug: null, icon: appParams.icon, @@ -426,22 +415,14 @@ export class AppImportExportService { user: User, externalResourceMappings: Record, isNormalizedAppDefinitionSchema: boolean, - tooljetVersion: string | null, - organizationId?: string + tooljetVersion: string | null ) { // Old version without app version // Handle exports prior to 0.12.0 // TODO: have version based conditional based on app versions // isLessThanExportVersion(appParams.tooljet_version, 'v0.12.0') if (!appParams?.appVersions) { - await this.performLegacyAppImport( - manager, - importedApp, - appParams, - externalResourceMappings, - user, - organizationId - ); + await this.performLegacyAppImport(manager, importedApp, appParams, externalResourceMappings, user); return; } @@ -472,8 +453,7 @@ export class AppImportExportService { importedApp, importingAppVersions, appResourceMappings, - isNormalizedAppDefinitionSchema, - organizationId + isNormalizedAppDefinitionSchema ); appResourceMappings.appDefaultEnvironmentMapping = appDefaultEnvironmentMapping; appResourceMappings.appVersionMapping = appVersionMapping; @@ -499,8 +479,7 @@ export class AppImportExportService { importingPages, importingComponents, importingEvents, - tooljetVersion, - organizationId + tooljetVersion ); if (!isNormalizedAppDefinitionSchema) { @@ -707,8 +686,7 @@ export class AppImportExportService { importingPages: Page[], importingComponents: Component[], importingEvents: EventHandler[], - tooljetVersion: string | null, - organizationId?: string + tooljetVersion: string | null ): Promise { appResourceMappings = { ...appResourceMappings }; @@ -721,8 +699,7 @@ export class AppImportExportService { user, importingAppEnvironments, importingAppVersion, - appResourceMappings, - organizationId + appResourceMappings ); appResourceMappings.appEnvironmentMapping = appEnvironmentMapping; @@ -730,8 +707,7 @@ export class AppImportExportService { manager, importingAppVersion, user, - appResourceMappings, - organizationId + appResourceMappings ); appResourceMappings.defaultDataSourceIdMapping = defaultDataSourceIdMapping; @@ -750,8 +726,7 @@ export class AppImportExportService { manager, importingDataSource, appResourceMappings.appVersionMapping[importingAppVersion.id], - user, - organizationId + user ); // TODO: Have version based conditional based on app versions @@ -799,7 +774,7 @@ export class AppImportExportService { const { dataQueryMapping } = await this.createDataQueriesForAppVersion( manager, - user?.organizationId || organizationId, + user?.organizationId, importingDataQueriesForAppVersion, importingDataSource, dataSourceForAppVersion, @@ -1187,11 +1162,10 @@ export class AppImportExportService { manager: EntityManager, appVersion: AppVersion, user: User, - appResourceMappings: AppResourceMappings, - organizationId?: string + appResourceMappings: AppResourceMappings ) { const defaultDataSourceIds = await this.createDefaultDataSourceForVersion( - user?.organizationId || organizationId, + user?.organizationId, appResourceMappings.appVersionMapping[appVersion.id], DefaultDataSourceKinds, manager @@ -1205,8 +1179,7 @@ export class AppImportExportService { manager: EntityManager, dataSource: DataSource, appVersionId: string, - user: User, - organizationId?: string + user: User ): Promise { const isDefaultDatasource = DefaultDataSourceNames.includes(dataSource.name as DefaultDataSourceName); const isPlugin = !!dataSource.pluginId; @@ -1231,7 +1204,7 @@ export class AppImportExportService { kind: dataSource.kind, type: DataSourceTypes.DEFAULT, scope: 'global', - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, }, }); }; @@ -1242,7 +1215,7 @@ export class AppImportExportService { kind: dataSource.kind, type: In([DataSourceTypes.DEFAULT, DataSourceTypes.SAMPLE]), scope: 'global', - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, }, }); }; @@ -1260,7 +1233,7 @@ export class AppImportExportService { if (plugin) { const newDataSource = manager.create(DataSource, { - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, name: dataSource.name, kind: dataSource.kind, type: DataSourceTypes.DEFAULT, @@ -1275,7 +1248,7 @@ export class AppImportExportService { const createNewGlobalDs = async (ds: DataSource): Promise => { const newDataSource = manager.create(DataSource, { - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, name: dataSource.name, kind: dataSource.kind, type: DataSourceTypes.DEFAULT, @@ -1299,12 +1272,11 @@ export class AppImportExportService { user: User, appEnvironments: Record[], appVersion: AppVersion, - appResourceMappings: AppResourceMappings, - organizationId?: string + appResourceMappings: AppResourceMappings ) { appResourceMappings = { ...appResourceMappings }; const currentOrgEnvironments = await this.appEnvironmentUtilService.getAll( - user?.organizationId || organizationId, + user?.organizationId, appVersion.appId, manager ); @@ -1361,13 +1333,12 @@ export class AppImportExportService { importedApp: App, appVersions: AppVersion[], appResourceMappings: AppResourceMappings, - isNormalizedAppDefinitionSchema: boolean, - organizationId?: string + isNormalizedAppDefinitionSchema: boolean ) { appResourceMappings = { ...appResourceMappings }; const { appVersionMapping, appDefaultEnvironmentMapping } = appResourceMappings; const organization: Organization = await manager.findOne(Organization, { - where: { id: user?.organizationId || organizationId }, + where: { id: user?.organizationId }, relations: ['appEnvironments'], }); let currentEnvironmentId: string; @@ -1566,8 +1537,7 @@ export class AppImportExportService { importedApp: App, appParams: any, externalResourceMappings: any, - user: any, - organizationId?: string + user: any ) { const dataSourceMapping = {}; const dataQueryMapping = {}; @@ -1587,7 +1557,7 @@ export class AppImportExportService { // Create default data sources const defaultDataSourceIds = await this.createDefaultDataSourceForVersion( - user?.organizationId || organizationId, + user?.organizationId, version.id, DefaultDataSourceKinds, manager @@ -1595,7 +1565,7 @@ export class AppImportExportService { let envIdArray: string[] = []; const organization: Organization = await manager.findOne(Organization, { - where: { id: user?.organizationId || organizationId }, + where: { id: user?.organizationId }, relations: ['appEnvironments'], }); envIdArray = [...organization.appEnvironments.map((env) => env.id)]; @@ -1604,7 +1574,7 @@ export class AppImportExportService { await Promise.all( defaultAppEnvironments.map(async (en) => { const env = manager.create(AppEnvironment, { - organizationId: user?.organizationId || organizationId, + organizationId: user?.organizationId, name: en.name, isDefault: en.isDefault, priority: en.priority, @@ -1671,7 +1641,7 @@ export class AppImportExportService { ? this.replaceTooljetDbTableIds( query.options, externalResourceMappings['tooljet_database'], - user?.organizationId || organizationId + user?.organizationId ) : query.options, }); diff --git a/server/src/modules/roles/util.service.ts b/server/src/modules/roles/util.service.ts index 481f1c641a..7a7bf6fdc1 100644 --- a/server/src/modules/roles/util.service.ts +++ b/server/src/modules/roles/util.service.ts @@ -14,14 +14,12 @@ import { ERROR_HANDLER } from '@modules/group-permissions/constants/error'; import { RolesRepository } from './repository'; import { AddUserRoleObject } from '@modules/group-permissions/types'; import { IRolesUtilService } from './interfaces/IUtilService'; -import { LicenseUserService } from '@modules/licensing/services/user.service'; @Injectable() export class RolesUtilService implements IRolesUtilService { constructor( protected groupPermissionsRepository: GroupPermissionsRepository, - protected roleRepository: RolesRepository, - protected licenseUserService: LicenseUserService + protected roleRepository: RolesRepository ) {} async changeEndUserToEditor(