Files
twenty/packages/twenty-server/src/engine/workspace-datasource/workspace-datasource.service.ts
T
Félix Malfait c3dd6b25a6 fix: use canonical oxlint rule id in lint-disable directives (#21253)
## What

Many `oxlint-disable` / `eslint-disable` directives across the repo
carry a corrupted rule id — `@typescripttypescript/<rule>` — most likely
a find-and-replace accident that mangled the eslint-era
`@typescript-eslint/` prefix.

oxlint matches disable directives **loosely by rule name**, so these
still suppress in practice (not a silent no-op), but the id is malformed
and misleading.

## Change

Replace them with the **canonical oxlint id** `typescript/<rule>` —
matching the plugin name and rule keys declared in `.oxlintrc.json` —
**127 files, 262 directives**:

| rule | count |
| --- | ----- |
| `typescript/no-explicit-any` | 250 |
| `typescript/ban-ts-comment` | 6 |
| `typescript/no-misused-promises` | 4 |
| `typescript/no-empty-object-type` | 2 |

- `twenty-server`: 122 files
- `twenty-front`: 5 files

Comment-only — no code or runtime changes.

## Verification

`oxlint --type-aware -c .oxlintrc.json` reports **0 warnings / 0
errors** for both `twenty-server` and `twenty-front`. Every changed line
is exactly the id correction inside a disable directive (262 insertions
/ 262 deletions, no collateral edits).

> Addresses the cubic review, which flagged that the canonical oxlint id
is `typescript/...` (no `@`). Worth noting the original
`@typescripttypescript/` was not actually a silent no-op — oxlint
matches these directives loosely by rule name — but `typescript/` is the
correct, config-aligned id.
2026-06-05 13:52:32 +02:00

108 lines
3.3 KiB
TypeScript

import { Injectable } from '@nestjs/common';
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
import { msg } from '@lingui/core/macro';
import { isNonEmptyString } from '@sniptt/guards';
import { type DataSource, type EntityManager, Repository } from 'typeorm';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import {
PermissionsException,
PermissionsExceptionCode,
} from 'src/engine/metadata-modules/permissions/permissions.exception';
import {
WorkspaceDataSourceException,
WorkspaceDataSourceExceptionCode,
} from 'src/engine/workspace-datasource/exceptions/workspace-datasource.exception';
import { getWorkspaceSchemaName } from 'src/engine/workspace-datasource/utils/get-workspace-schema-name.util';
@Injectable()
export class WorkspaceDataSourceService {
constructor(
@InjectRepository(WorkspaceEntity)
private readonly workspaceRepository: Repository<WorkspaceEntity>,
@InjectDataSource()
private readonly coreDataSource: DataSource,
private readonly twentyConfigService: TwentyConfigService,
) {}
private assertDDLNotLocked(): void {
if (this.twentyConfigService.get('WORKSPACE_SCHEMA_DDL_LOCKED')) {
throw new WorkspaceDataSourceException({
message:
'Workspace schema DDL changes are locked. This is typically set during hot upgrades.',
code: WorkspaceDataSourceExceptionCode.DDL_LOCKED,
});
}
}
public async checkSchemaExists(workspaceId: string) {
const workspace = await this.workspaceRepository.findOne({
select: ['databaseSchema'],
where: { id: workspaceId },
});
return isNonEmptyString(workspace?.databaseSchema);
}
/**
*
* Create a new DB schema for a workspace
*
* @param workspaceId
* @returns
*/
public async createWorkspaceDBSchema(workspaceId: string): Promise<string> {
this.assertDDLNotLocked();
const schemaName = getWorkspaceSchemaName(workspaceId);
const queryRunner = this.coreDataSource.createQueryRunner();
try {
await queryRunner.createSchema(schemaName, true);
return schemaName;
} finally {
await queryRunner.release();
}
}
/**
*
* Delete a DB schema for a workspace
*
* @param workspaceId
* @returns
*/
public async deleteWorkspaceDBSchema(workspaceId: string): Promise<void> {
this.assertDDLNotLocked();
const schemaName = getWorkspaceSchemaName(workspaceId);
const queryRunner = this.coreDataSource.createQueryRunner();
try {
await queryRunner.dropSchema(schemaName, true, true);
} finally {
await queryRunner.release();
}
}
public async executeRawQuery(
_query: string,
// oxlint-disable-next-line typescript/no-explicit-any
_parameters: any[] = [],
_workspaceId: string,
_transactionManager?: EntityManager,
// oxlint-disable-next-line typescript/no-explicit-any
): Promise<any> {
throw new PermissionsException(
'Method not allowed as permissions are not handled at datasource level.',
PermissionsExceptionCode.METHOD_NOT_ALLOWED,
{
userFriendlyMessage: msg`This operation is not allowed. Please try a different approach or contact support if you need assistance.`,
},
);
}
}