4150 i should be able to view my emails even if ive set my account visibility to metadata (#4156)
* improve timeline messaging to allow users to view the threads to which they participated * working * improvement * improvements * improvements * fix * remove unnecessary type
This commit is contained in:
@ -3,9 +3,9 @@ import { Module } from '@nestjs/common';
|
|||||||
import { TimelineMessagingResolver } from 'src/core/messaging/timeline-messaging.resolver';
|
import { TimelineMessagingResolver } from 'src/core/messaging/timeline-messaging.resolver';
|
||||||
import { TimelineMessagingService } from 'src/core/messaging/timeline-messaging.service';
|
import { TimelineMessagingService } from 'src/core/messaging/timeline-messaging.service';
|
||||||
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
import { WorkspaceDataSourceModule } from 'src/workspace/workspace-datasource/workspace-datasource.module';
|
||||||
|
import { UserModule } from 'src/core/user/user.module';
|
||||||
@Module({
|
@Module({
|
||||||
imports: [WorkspaceDataSourceModule],
|
imports: [WorkspaceDataSourceModule, UserModule],
|
||||||
exports: [],
|
exports: [],
|
||||||
providers: [TimelineMessagingResolver, TimelineMessagingService],
|
providers: [TimelineMessagingResolver, TimelineMessagingService],
|
||||||
})
|
})
|
||||||
|
|||||||
@ -17,6 +17,9 @@ import { AuthWorkspace } from 'src/decorators/auth/auth-workspace.decorator';
|
|||||||
import { TimelineMessagingService } from 'src/core/messaging/timeline-messaging.service';
|
import { TimelineMessagingService } from 'src/core/messaging/timeline-messaging.service';
|
||||||
import { TIMELINE_THREADS_MAX_PAGE_SIZE } from 'src/core/messaging/constants/messaging.constants';
|
import { TIMELINE_THREADS_MAX_PAGE_SIZE } from 'src/core/messaging/constants/messaging.constants';
|
||||||
import { TimelineThreadsWithTotal } from 'src/core/messaging/dtos/timeline-threads-with-total.dto';
|
import { TimelineThreadsWithTotal } from 'src/core/messaging/dtos/timeline-threads-with-total.dto';
|
||||||
|
import { AuthUser } from 'src/decorators/auth/auth-user.decorator';
|
||||||
|
import { UserService } from 'src/core/user/services/user.service';
|
||||||
|
import { User } from 'src/core/user/user.entity';
|
||||||
|
|
||||||
@ArgsType()
|
@ArgsType()
|
||||||
class GetTimelineThreadsFromPersonIdArgs {
|
class GetTimelineThreadsFromPersonIdArgs {
|
||||||
@ -49,15 +52,24 @@ class GetTimelineThreadsFromCompanyIdArgs {
|
|||||||
export class TimelineMessagingResolver {
|
export class TimelineMessagingResolver {
|
||||||
constructor(
|
constructor(
|
||||||
private readonly timelineMessagingService: TimelineMessagingService,
|
private readonly timelineMessagingService: TimelineMessagingService,
|
||||||
|
private readonly userService: UserService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@Query(() => TimelineThreadsWithTotal)
|
@Query(() => TimelineThreadsWithTotal)
|
||||||
async getTimelineThreadsFromPersonId(
|
async getTimelineThreadsFromPersonId(
|
||||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||||
|
@AuthUser() user: User,
|
||||||
@Args() { personId, page, pageSize }: GetTimelineThreadsFromPersonIdArgs,
|
@Args() { personId, page, pageSize }: GetTimelineThreadsFromPersonIdArgs,
|
||||||
) {
|
) {
|
||||||
|
const workspaceMember = await this.userService.loadWorkspaceMember(user);
|
||||||
|
|
||||||
|
if (!workspaceMember) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const timelineThreads =
|
const timelineThreads =
|
||||||
await this.timelineMessagingService.getMessagesFromPersonIds(
|
await this.timelineMessagingService.getMessagesFromPersonIds(
|
||||||
|
workspaceMember.id,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
[personId],
|
[personId],
|
||||||
page,
|
page,
|
||||||
@ -70,10 +82,18 @@ export class TimelineMessagingResolver {
|
|||||||
@Query(() => TimelineThreadsWithTotal)
|
@Query(() => TimelineThreadsWithTotal)
|
||||||
async getTimelineThreadsFromCompanyId(
|
async getTimelineThreadsFromCompanyId(
|
||||||
@AuthWorkspace() { id: workspaceId }: Workspace,
|
@AuthWorkspace() { id: workspaceId }: Workspace,
|
||||||
|
@AuthUser() user: User,
|
||||||
@Args() { companyId, page, pageSize }: GetTimelineThreadsFromCompanyIdArgs,
|
@Args() { companyId, page, pageSize }: GetTimelineThreadsFromCompanyIdArgs,
|
||||||
) {
|
) {
|
||||||
|
const workspaceMember = await this.userService.loadWorkspaceMember(user);
|
||||||
|
|
||||||
|
if (!workspaceMember) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const timelineThreads =
|
const timelineThreads =
|
||||||
await this.timelineMessagingService.getMessagesFromCompanyId(
|
await this.timelineMessagingService.getMessagesFromCompanyId(
|
||||||
|
workspaceMember.id,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
companyId,
|
companyId,
|
||||||
page,
|
page,
|
||||||
|
|||||||
@ -21,6 +21,7 @@ export class TimelineMessagingService {
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
async getMessagesFromPersonIds(
|
async getMessagesFromPersonIds(
|
||||||
|
workspaceMemberId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
personIds: string[],
|
personIds: string[],
|
||||||
page: number = 1,
|
page: number = 1,
|
||||||
@ -178,13 +179,14 @@ export class TimelineMessagingService {
|
|||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
const threadMessagesFromActiveParticipants:
|
const threadMessagesParticipants:
|
||||||
| {
|
| {
|
||||||
id: string;
|
id: string;
|
||||||
messageId: string;
|
messageId: string;
|
||||||
receivedAt: Date;
|
receivedAt: Date;
|
||||||
body: string;
|
body: string;
|
||||||
subject: string;
|
subject: string;
|
||||||
|
role: string;
|
||||||
personId: string;
|
personId: string;
|
||||||
workspaceMemberId: string;
|
workspaceMemberId: string;
|
||||||
handle: string;
|
handle: string;
|
||||||
@ -203,6 +205,7 @@ export class TimelineMessagingService {
|
|||||||
message."receivedAt",
|
message."receivedAt",
|
||||||
message.text,
|
message.text,
|
||||||
message."subject",
|
message."subject",
|
||||||
|
"messageParticipant"."role",
|
||||||
"messageParticipant"."personId",
|
"messageParticipant"."personId",
|
||||||
"messageParticipant"."workspaceMemberId",
|
"messageParticipant"."workspaceMemberId",
|
||||||
"messageParticipant".handle,
|
"messageParticipant".handle,
|
||||||
@ -216,7 +219,7 @@ export class TimelineMessagingService {
|
|||||||
FROM
|
FROM
|
||||||
${dataSourceSchema}."message" message
|
${dataSourceSchema}."message" message
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
(SELECT * FROM ${dataSourceSchema}."messageParticipant" WHERE "messageParticipant".role = 'from') "messageParticipant" ON "messageParticipant"."messageId" = message.id
|
${dataSourceSchema}."messageParticipant" "messageParticipant" ON "messageParticipant"."messageId" = message.id
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
${dataSourceSchema}."person" person ON person."id" = "messageParticipant"."personId"
|
${dataSourceSchema}."person" person ON person."id" = "messageParticipant"."personId"
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
@ -230,6 +233,11 @@ export class TimelineMessagingService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const threadMessagesFromActiveParticipants =
|
||||||
|
threadMessagesParticipants?.filter(
|
||||||
|
(threadMessage) => threadMessage.role === 'from',
|
||||||
|
);
|
||||||
|
|
||||||
const totalNumberOfThreads =
|
const totalNumberOfThreads =
|
||||||
await this.workspaceDataSourceService.executeRawQuery(
|
await this.workspaceDataSourceService.executeRawQuery(
|
||||||
`
|
`
|
||||||
@ -245,14 +253,14 @@ export class TimelineMessagingService {
|
|||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const threadParticipantsByThreadId: {
|
const threadActiveParticipantsByThreadId: {
|
||||||
[key: string]: TimelineThreadParticipant[];
|
[key: string]: TimelineThreadParticipant[];
|
||||||
} = messageThreadIds.reduce((messageThreadIdAcc, messageThreadId) => {
|
} = messageThreadIds.reduce((messageThreadIdAcc, messageThreadId) => {
|
||||||
const threadMessages = threadMessagesFromActiveParticipants?.filter(
|
const threadMessages = threadMessagesFromActiveParticipants?.filter(
|
||||||
(threadMessage) => threadMessage.id === messageThreadId,
|
(threadMessage) => threadMessage.id === messageThreadId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const threadParticipants = threadMessages?.reduce(
|
const threadActiveParticipants = threadMessages?.reduce(
|
||||||
(
|
(
|
||||||
threadMessageAcc,
|
threadMessageAcc,
|
||||||
threadMessage,
|
threadMessage,
|
||||||
@ -296,13 +304,36 @@ export class TimelineMessagingService {
|
|||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
messageThreadIdAcc[messageThreadId] = threadParticipants
|
messageThreadIdAcc[messageThreadId] = threadActiveParticipants
|
||||||
? Object.values(threadParticipants)
|
? Object.values(threadActiveParticipants)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
return messageThreadIdAcc;
|
return messageThreadIdAcc;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
|
const messageThreadIdsForWhichWorkspaceMemberIsNotInParticipants =
|
||||||
|
messageThreadIds.reduce(
|
||||||
|
(
|
||||||
|
messageThreadIdsForWhichWorkspaceMemberIsInNotParticipantsAcc: string[],
|
||||||
|
messageThreadId,
|
||||||
|
) => {
|
||||||
|
const threadMessagesWithWorkspaceMemberInParticipants =
|
||||||
|
threadMessagesParticipants?.filter(
|
||||||
|
(threadMessage) =>
|
||||||
|
threadMessage.id === messageThreadId &&
|
||||||
|
threadMessage.workspaceMemberId === workspaceMemberId,
|
||||||
|
) ?? [];
|
||||||
|
|
||||||
|
if (threadMessagesWithWorkspaceMemberInParticipants.length === 0)
|
||||||
|
messageThreadIdsForWhichWorkspaceMemberIsInNotParticipantsAcc.push(
|
||||||
|
messageThreadId,
|
||||||
|
);
|
||||||
|
|
||||||
|
return messageThreadIdsForWhichWorkspaceMemberIsInNotParticipantsAcc;
|
||||||
|
},
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
const threadVisibility:
|
const threadVisibility:
|
||||||
| {
|
| {
|
||||||
id: string;
|
id: string;
|
||||||
@ -322,13 +353,13 @@ export class TimelineMessagingService {
|
|||||||
WHERE
|
WHERE
|
||||||
message."messageThreadId" = ANY($1)
|
message."messageThreadId" = ANY($1)
|
||||||
`,
|
`,
|
||||||
[messageThreadIds],
|
[messageThreadIdsForWhichWorkspaceMemberIsNotInParticipants],
|
||||||
workspaceId,
|
workspaceId,
|
||||||
);
|
);
|
||||||
|
|
||||||
const visibilityValues = ['metadata', 'subject', 'share_everything'];
|
const visibilityValues = ['metadata', 'subject', 'share_everything'];
|
||||||
|
|
||||||
const threadVisibilityByThreadId:
|
const threadVisibilityByThreadIdForWhichWorkspaceMemberIsNotInParticipants:
|
||||||
| {
|
| {
|
||||||
[key: string]: 'metadata' | 'subject' | 'share_everything';
|
[key: string]: 'metadata' | 'subject' | 'share_everything';
|
||||||
}
|
}
|
||||||
@ -349,13 +380,30 @@ export class TimelineMessagingService {
|
|||||||
{},
|
{},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const threadVisibilityByThreadId: {
|
||||||
|
[key: string]: 'metadata' | 'subject' | 'share_everything';
|
||||||
|
} = messageThreadIds.reduce((threadVisibilityAcc, messageThreadId) => {
|
||||||
|
// If the workspace member is not in the participants of the thread, use the visibility value from the query
|
||||||
|
threadVisibilityAcc[messageThreadId] =
|
||||||
|
messageThreadIdsForWhichWorkspaceMemberIsNotInParticipants.includes(
|
||||||
|
messageThreadId,
|
||||||
|
)
|
||||||
|
? threadVisibilityByThreadIdForWhichWorkspaceMemberIsNotInParticipants?.[
|
||||||
|
messageThreadId
|
||||||
|
] ?? 'metadata'
|
||||||
|
: 'share_everything';
|
||||||
|
|
||||||
|
return threadVisibilityAcc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
const timelineThreads = messageThreadIds.map((messageThreadId) => {
|
const timelineThreads = messageThreadIds.map((messageThreadId) => {
|
||||||
const threadParticipants = threadParticipantsByThreadId[messageThreadId];
|
const threadActiveParticipants =
|
||||||
|
threadActiveParticipantsByThreadId[messageThreadId];
|
||||||
|
|
||||||
const firstParticipant = threadParticipants[0];
|
const firstParticipant = threadActiveParticipants[0];
|
||||||
|
|
||||||
const threadParticipantsWithoutFirstParticipant =
|
const threadActiveParticipantsWithoutFirstParticipant =
|
||||||
threadParticipants.filter(
|
threadActiveParticipants.filter(
|
||||||
(threadParticipant) =>
|
(threadParticipant) =>
|
||||||
threadParticipant.handle !== firstParticipant.handle,
|
threadParticipant.handle !== firstParticipant.handle,
|
||||||
);
|
);
|
||||||
@ -363,20 +411,22 @@ export class TimelineMessagingService {
|
|||||||
const lastTwoParticipants: TimelineThreadParticipant[] = [];
|
const lastTwoParticipants: TimelineThreadParticipant[] = [];
|
||||||
|
|
||||||
const lastParticipant =
|
const lastParticipant =
|
||||||
threadParticipantsWithoutFirstParticipant.slice(-1)[0];
|
threadActiveParticipantsWithoutFirstParticipant.slice(-1)[0];
|
||||||
|
|
||||||
if (lastParticipant) {
|
if (lastParticipant) {
|
||||||
lastTwoParticipants.push(lastParticipant);
|
lastTwoParticipants.push(lastParticipant);
|
||||||
|
|
||||||
const threadParticipantsWithoutFirstAndLastParticipants =
|
const threadActiveParticipantsWithoutFirstAndLastParticipants =
|
||||||
threadParticipantsWithoutFirstParticipant.filter(
|
threadActiveParticipantsWithoutFirstParticipant.filter(
|
||||||
(threadParticipant) =>
|
(threadParticipant) =>
|
||||||
threadParticipant.handle !== lastParticipant.handle,
|
threadParticipant.handle !== lastParticipant.handle,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (threadParticipantsWithoutFirstAndLastParticipants.length > 0)
|
if (threadActiveParticipantsWithoutFirstAndLastParticipants.length > 0)
|
||||||
lastTwoParticipants.push(
|
lastTwoParticipants.push(
|
||||||
threadParticipantsWithoutFirstAndLastParticipants.slice(-1)[0],
|
threadActiveParticipantsWithoutFirstAndLastParticipants.slice(
|
||||||
|
-1,
|
||||||
|
)[0],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,7 +449,7 @@ export class TimelineMessagingService {
|
|||||||
visibility: threadVisibilityByThreadId?.[messageThreadId] ?? 'metadata',
|
visibility: threadVisibilityByThreadId?.[messageThreadId] ?? 'metadata',
|
||||||
subject: threadSubject,
|
subject: threadSubject,
|
||||||
numberOfMessagesInThread: numberOfMessages,
|
numberOfMessagesInThread: numberOfMessages,
|
||||||
participantCount: threadParticipants.length,
|
participantCount: threadActiveParticipants.length,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -410,6 +460,7 @@ export class TimelineMessagingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async getMessagesFromCompanyId(
|
async getMessagesFromCompanyId(
|
||||||
|
workspaceMemberId: string,
|
||||||
workspaceId: string,
|
workspaceId: string,
|
||||||
companyId: string,
|
companyId: string,
|
||||||
page: number = 1,
|
page: number = 1,
|
||||||
@ -443,6 +494,7 @@ export class TimelineMessagingService {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const messageThreads = await this.getMessagesFromPersonIds(
|
const messageThreads = await this.getMessagesFromPersonIds(
|
||||||
|
workspaceMemberId,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
formattedPersonIds,
|
formattedPersonIds,
|
||||||
page,
|
page,
|
||||||
|
|||||||
Reference in New Issue
Block a user