From aa4eb8880b7ca12485e0dedb6ad5e85d933aaf1b Mon Sep 17 00:00:00 2001 From: Sohil Patel Date: Mon, 3 Aug 2026 18:58:33 +0530 Subject: [PATCH 1/2] feat: add createdAt field to PostChatterMessageDto and set default in service --- src/dtos/post-chatter-message.dto.ts | 6 +++++- src/services/chatter-message.service.ts | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/dtos/post-chatter-message.dto.ts b/src/dtos/post-chatter-message.dto.ts index c2b08e1a..e13f6161 100644 --- a/src/dtos/post-chatter-message.dto.ts +++ b/src/dtos/post-chatter-message.dto.ts @@ -1,4 +1,4 @@ -import { IsNotEmpty, IsNumber, IsString, IsOptional } from 'class-validator'; +import { IsNotEmpty, IsNumber, IsString, IsOptional, IsDate } from 'class-validator'; export class PostChatterMessageDto { @IsNumber() @@ -28,4 +28,8 @@ export class PostChatterMessageDto { @IsString() @IsOptional() status?: string; + + @IsDate() + @IsOptional() + createdAt?: Date; } \ No newline at end of file diff --git a/src/services/chatter-message.service.ts b/src/services/chatter-message.service.ts index 300a91a3..86ffe54c 100644 --- a/src/services/chatter-message.service.ts +++ b/src/services/chatter-message.service.ts @@ -404,6 +404,7 @@ export class ChatterMessageService extends CRUDService { chatterMessage.coModelEntityId = postDto.coModelEntityId; chatterMessage.coModelName = coModelName; chatterMessage.modelUserKey = postDto.modelUserKey ?? null; + chatterMessage.createdAt = postDto.createdAt ?? new Date(); const model = await this.modelMetadataRepo.findOne({ where: { singularName: coModelName }, From edc6149f89096c0c9a1c2708f0bef700b3b226a8 Mon Sep 17 00:00:00 2001 From: Oswald Rodrigues Date: Tue, 4 Aug 2026 14:49:26 +0530 Subject: [PATCH 2/2] changes to support passing an explicit createdAt while posting a chatter message --- src/dtos/post-chatter-message.dto.ts | 6 +----- src/services/chatter-message.service.ts | 24 ++++++++++++++++++++++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/dtos/post-chatter-message.dto.ts b/src/dtos/post-chatter-message.dto.ts index e13f6161..c2b08e1a 100644 --- a/src/dtos/post-chatter-message.dto.ts +++ b/src/dtos/post-chatter-message.dto.ts @@ -1,4 +1,4 @@ -import { IsNotEmpty, IsNumber, IsString, IsOptional, IsDate } from 'class-validator'; +import { IsNotEmpty, IsNumber, IsString, IsOptional } from 'class-validator'; export class PostChatterMessageDto { @IsNumber() @@ -28,8 +28,4 @@ export class PostChatterMessageDto { @IsString() @IsOptional() status?: string; - - @IsDate() - @IsOptional() - createdAt?: Date; } \ No newline at end of file diff --git a/src/services/chatter-message.service.ts b/src/services/chatter-message.service.ts index 86ffe54c..872c538b 100644 --- a/src/services/chatter-message.service.ts +++ b/src/services/chatter-message.service.ts @@ -37,6 +37,16 @@ interface ChatterMention { id?: string | number; } +/** + * Server-side-only overrides for `postMessage`. Not part of `PostChatterMessageDto`, so + * nothing here is settable over HTTP - only in-process callers such as migration or + * back-fill services can supply it. + */ +export interface PostChatterMessageOptions { + /** Backdate the message instead of stamping it with the current time. */ + createdAt?: Date; +} + @Injectable() export class ChatterMessageService extends CRUDService { private readonly _logger = new Logger(ChatterMessageService.name); @@ -389,7 +399,14 @@ export class ChatterMessageService extends CRUDService { return this.trimMessageUser(savedMessage); } - async postMessage(postDto: PostChatterMessageDto, files: Express.Multer.File[] = []) { + /** + * Post a chatter message. + * + * `options` is deliberately kept out of `PostChatterMessageDto` so it can only be supplied + * by server-side callers (migrations, back-fills). The controller binds the DTO alone, so + * an API client has no way to backdate a message. + */ + async postMessage(postDto: PostChatterMessageDto, files: Express.Multer.File[] = [], options: PostChatterMessageOptions = {}) { const coModelName = lowerFirst(postDto.coModelName); await this.assertRecordAccess(coModelName, postDto.coModelEntityId); @@ -404,7 +421,10 @@ export class ChatterMessageService extends CRUDService { chatterMessage.coModelEntityId = postDto.coModelEntityId; chatterMessage.coModelName = coModelName; chatterMessage.modelUserKey = postDto.modelUserKey ?? null; - chatterMessage.createdAt = postDto.createdAt ?? new Date(); + // Left unset otherwise, so the @CreateDateColumn default still applies. + if (options.createdAt) { + chatterMessage.createdAt = options.createdAt; + } const model = await this.modelMetadataRepo.findOne({ where: { singularName: coModelName },