Improve Messaging Gmail experience (#14342)
In this PR, I'm solving several issues: 1) We were not checking if the currentWorkspaceMember was owning the message in the thread. It kind of worked before because the case of shared threads (with shared threads visibility restriction) was not happening that often. It seems that the bug has always been there 2) Re-implement orphan messages and threads deletion on messageChannel deletion. We used to brutally look for all orphans, we disabled it last week because it was too heavy on db. I've re-implemented it more carefully and "surgically" 3) Gmail sync was not handling folder synced correctly. It was leveraging labelIds which it shouldn't do (this is a AND AND parameter) in full sync 4) Added a command to clean orphan message threads manually if needed. Usually this is done when you remove a messageChannel, or change blocklist rules but it can be useful to have it to debug
This commit is contained in:
+23
-55
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { In, Not } from 'typeorm';
|
||||
import { In } from 'typeorm';
|
||||
|
||||
import { type TimelineThread } from 'src/engine/core-modules/messaging/dtos/timeline-thread.dto';
|
||||
import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager';
|
||||
@@ -94,6 +94,7 @@ export class TimelineMessagingService {
|
||||
await this.twentyORMManager.getRepository<MessageParticipantWorkspaceEntity>(
|
||||
'messageParticipant',
|
||||
);
|
||||
|
||||
const threadParticipants = await messageParticipantRepository
|
||||
.createQueryBuilder()
|
||||
.select('messageParticipant')
|
||||
@@ -183,32 +184,11 @@ export class TimelineMessagingService {
|
||||
'messageThread',
|
||||
);
|
||||
|
||||
const threadsWithoutWorkspaceMember = await messageThreadRepository.find({
|
||||
select: {
|
||||
id: true,
|
||||
},
|
||||
where: {
|
||||
id: In(messageThreadIds),
|
||||
messages: {
|
||||
messageChannelMessageAssociations: {
|
||||
messageChannel: {
|
||||
connectedAccount: {
|
||||
accountOwnerId: Not(workspaceMemberId),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const threadIdsWithoutWorkspaceMember = threadsWithoutWorkspaceMember.map(
|
||||
(thread) => thread.id,
|
||||
);
|
||||
|
||||
const threadVisibility = await messageThreadRepository
|
||||
.createQueryBuilder()
|
||||
.select('messageThread.id', 'id')
|
||||
.addSelect('messageChannel.visibility', 'visibility')
|
||||
.addSelect('connectedAccount.accountOwnerId', 'accountOwnerId')
|
||||
.leftJoin('messageThread.messages', 'message')
|
||||
.leftJoin(
|
||||
'message.messageChannelMessageAssociations',
|
||||
@@ -218,46 +198,34 @@ export class TimelineMessagingService {
|
||||
'messageChannelMessageAssociation.messageChannel',
|
||||
'messageChannel',
|
||||
)
|
||||
.leftJoin('messageChannel.connectedAccount', 'connectedAccount')
|
||||
.where('messageThread.id = ANY(:messageThreadIds)', {
|
||||
messageThreadIds: threadIdsWithoutWorkspaceMember,
|
||||
messageThreadIds: messageThreadIds,
|
||||
})
|
||||
.getRawMany();
|
||||
|
||||
const visibilityValues = Object.values(MessageChannelVisibility);
|
||||
|
||||
const threadVisibilityByThreadIdForWhichWorkspaceMemberIsNotOwner:
|
||||
| {
|
||||
[key: string]: MessageChannelVisibility;
|
||||
}
|
||||
| undefined = threadVisibility?.reduce(
|
||||
(threadVisibilityAcc, threadVisibility) => {
|
||||
threadVisibilityAcc[threadVisibility.id] =
|
||||
visibilityValues[
|
||||
Math.max(
|
||||
visibilityValues.indexOf(threadVisibility.visibility),
|
||||
visibilityValues.indexOf(
|
||||
threadVisibilityAcc[threadVisibility.id] ??
|
||||
MessageChannelVisibility.METADATA,
|
||||
),
|
||||
)
|
||||
];
|
||||
|
||||
return threadVisibilityAcc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
|
||||
const threadVisibilityByThreadId: {
|
||||
[key: string]: MessageChannelVisibility;
|
||||
} = messageThreadIds.reduce((threadVisibilityAcc, messageThreadId) => {
|
||||
// If the workspace member is not the owner of the thread, use the visibility value from the query
|
||||
// @ts-expect-error legacy noImplicitAny
|
||||
threadVisibilityAcc[messageThreadId] =
|
||||
threadIdsWithoutWorkspaceMember.includes(messageThreadId)
|
||||
? (threadVisibilityByThreadIdForWhichWorkspaceMemberIsNotOwner?.[
|
||||
messageThreadId
|
||||
] ?? MessageChannelVisibility.METADATA)
|
||||
: MessageChannelVisibility.SHARE_EVERYTHING;
|
||||
} = threadVisibility.reduce((threadVisibilityAcc, threadVisibility) => {
|
||||
if (threadVisibility.accountOwnerId === workspaceMemberId) {
|
||||
threadVisibilityAcc[threadVisibility.id] =
|
||||
MessageChannelVisibility.SHARE_EVERYTHING;
|
||||
|
||||
return threadVisibilityAcc;
|
||||
}
|
||||
|
||||
threadVisibilityAcc[threadVisibility.id] =
|
||||
visibilityValues[
|
||||
Math.max(
|
||||
visibilityValues.indexOf(threadVisibility.visibility),
|
||||
visibilityValues.indexOf(
|
||||
threadVisibilityAcc[threadVisibility.id] ??
|
||||
MessageChannelVisibility.METADATA,
|
||||
),
|
||||
)
|
||||
];
|
||||
|
||||
return threadVisibilityAcc;
|
||||
}, {});
|
||||
|
||||
Reference in New Issue
Block a user