Fix empty user id clickhouse (#18238)

- Fixes:
- Make Workspace User select work; previously, it didn't work as we were
not fetching the workspace users correctly
  - Send Object Events with valid record id and object id

## Audit logs demo


https://github.com/user-attachments/assets/92437037-d253-4810-a138-7c709550755d
This commit is contained in:
Baptiste Devessier
2026-02-27 16:58:44 +01:00
committed by GitHub
parent 86fbf69e95
commit cfad24da48
29 changed files with 146 additions and 171 deletions
@@ -11,7 +11,7 @@ export class EventLogRecord {
timestamp: Date;
@Field(() => String, { nullable: true })
userWorkspaceId?: string;
userId?: string;
@Field(() => GraphQLJSON, { nullable: true })
properties?: Record<string, unknown>;
@@ -1,10 +1,12 @@
/* @license Enterprise */
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ClickHouseModule } from 'src/database/clickHouse/clickHouse.module';
import { BillingModule } from 'src/engine/core-modules/billing/billing.module';
import { GuardRedirectModule } from 'src/engine/core-modules/guard-redirect/guard-redirect.module';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permissions.module';
import { EventLogsResolver } from './event-logs.resolver';
@@ -16,6 +18,7 @@ import { EventLogsService } from './event-logs.service';
PermissionsModule,
BillingModule,
GuardRedirectModule,
TypeOrmModule.forFeature([UserWorkspaceEntity]),
],
providers: [EventLogsResolver, EventLogsService],
exports: [EventLogsService],
@@ -1,14 +1,17 @@
/* @license Enterprise */
import { BadRequestException, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { EventLogTable } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { Repository } from 'typeorm';
import { ClickHouseService } from 'src/database/clickHouse/clickHouse.service';
import { formatDateForClickHouse } from 'src/database/clickHouse/clickHouse.util';
import { BillingEntitlementKey } from 'src/engine/core-modules/billing/enums/billing-entitlement-key.enum';
import { BillingService } from 'src/engine/core-modules/billing/services/billing.service';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import {
EventLogsException,
@@ -26,7 +29,7 @@ type ClickHouseEventRecord = {
event?: string;
name?: string;
timestamp: string;
userWorkspaceId?: string;
userId?: string;
properties?: Record<string, unknown>;
recordId?: string;
objectMetadataId?: string;
@@ -47,6 +50,8 @@ export class EventLogsService {
constructor(
private readonly clickHouseService: ClickHouseService,
private readonly billingService: BillingService,
@InjectRepository(UserWorkspaceEntity)
private readonly userWorkspaceRepository: Repository<UserWorkspaceEntity>,
) {}
async queryEventLogs(
@@ -67,7 +72,7 @@ export class EventLogsService {
const whereClauses: string[] = ['"workspaceId" = {workspaceId:String}'];
const params: Record<string, unknown> = { workspaceId };
this.applyFilters(
await this.applyFilters(
whereClauses,
params,
input.filters,
@@ -155,13 +160,13 @@ export class EventLogsService {
}
}
private applyFilters(
private async applyFilters(
whereClauses: string[],
params: Record<string, unknown>,
filters: EventLogFiltersInput | undefined,
eventFieldName: string,
table: EventLogTable,
): void {
): Promise<void> {
if (!isDefined(filters)) {
return;
}
@@ -174,8 +179,15 @@ export class EventLogsService {
}
if (isDefined(filters.userWorkspaceId)) {
whereClauses.push('"userWorkspaceId" = {userWorkspaceId:String}');
params.userWorkspaceId = filters.userWorkspaceId;
const userWorkspace = await this.userWorkspaceRepository.findOne({
where: { id: filters.userWorkspaceId },
select: ['userId'],
});
if (isDefined(userWorkspace)) {
whereClauses.push('"userId" = {userId:String}');
params.userId = userWorkspace.userId;
}
}
if (isDefined(filters.dateRange?.start)) {
@@ -222,7 +234,7 @@ export class EventLogsService {
return {
event: eventName,
timestamp: new Date(record.timestamp),
userWorkspaceId: record.userWorkspaceId,
userId: record.userId,
properties: record.properties,
recordId: record.recordId,
objectMetadataId: record.objectMetadataId,