Files
speckle-server/packages/server/modules/activitystream/services/commentActivity.ts
T
2024-09-24 12:57:08 +03:00

252 lines
7.8 KiB
TypeScript

import { db } from '@/db/knex'
import { ActionTypes, ResourceTypes } from '@/modules/activitystream/helpers/types'
import { saveActivity } from '@/modules/activitystream/services'
import { ViewerResourceItem } from '@/modules/comments/domain/types'
import { CommentRecord } from '@/modules/comments/helpers/types'
import { getCommentsResourcesFactory } from '@/modules/comments/repositories/comments'
import {
CommentCreateInput,
CreateCommentInput,
CreateCommentReplyInput,
ProjectCommentsUpdatedMessageType,
ReplyCreateInput
} from '@/modules/core/graph/generated/graphql'
import {
getBranchLatestCommits,
getStreamBranchesByName
} from '@/modules/core/repositories/branches'
import {
getAllBranchCommits,
getCommitsAndTheirBranchIds,
getSpecificBranchCommits
} from '@/modules/core/repositories/commits'
import { getStreamObjects } from '@/modules/core/repositories/objects'
import {
getViewerResourceGroupsFactory,
getViewerResourceItemsUngroupedFactory,
getViewerResourcesForCommentFactory,
getViewerResourcesForCommentsFactory,
getViewerResourcesFromLegacyIdentifiersFactory
} from '@/modules/core/services/commit/viewerResources'
import { pubsub } from '@/modules/shared/utils/subscriptions'
import {
CommentSubscriptions,
ProjectSubscriptions,
publish
} from '@/modules/shared/utils/subscriptions'
import { MutationCommentArchiveArgs } from '@/test/graphql/generated/graphql'
import { has } from 'lodash'
type CommentCreatedActivityInput =
| CommentCreateInput
| (CreateCommentInput & { resolvedResourceItems?: ViewerResourceItem[] })
const isLegacyCommentCreateInput = (
i: CommentCreatedActivityInput
): i is CommentCreateInput => has(i, 'streamId')
export async function addCommentCreatedActivity(params: {
streamId: string
userId: string
input: CommentCreatedActivityInput
comment: CommentRecord
}) {
const { streamId, userId, input, comment } = params
const getViewerResourcesFromLegacyIdentifiers =
getViewerResourcesFromLegacyIdentifiersFactory({
getViewerResourcesForComments: getViewerResourcesForCommentsFactory({
getCommentsResources: getCommentsResourcesFactory({ db }),
getViewerResourcesFromLegacyIdentifiers: (...args) =>
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
}),
getCommitsAndTheirBranchIds,
getStreamObjects
})
const getViewerResourceItemsUngrouped = getViewerResourceItemsUngroupedFactory({
getViewerResourceGroups: getViewerResourceGroupsFactory({
getStreamObjects,
getBranchLatestCommits,
getStreamBranchesByName,
getSpecificBranchCommits,
getAllBranchCommits
})
})
let resourceIds: string
let resourceItems: ViewerResourceItem[]
if (isLegacyCommentCreateInput(input)) {
resourceIds = input.resources.map((res) => res?.resourceId).join(',')
const validResources = input.resources.filter(
(r): r is NonNullable<typeof r> => !!r
)
resourceItems = await getViewerResourcesFromLegacyIdentifiers(
streamId,
validResources
)
} else {
resourceItems =
input.resolvedResourceItems ||
(await getViewerResourceItemsUngrouped({
projectId: streamId,
resourceIdString: input.resourceIdString
}))
resourceIds = resourceItems.map((i) => i.versionId || i.objectId).join(',')
}
await Promise.all([
saveActivity({
resourceId: comment.id,
streamId,
resourceType: ResourceTypes.Comment,
actionType: ActionTypes.Comment.Create,
userId,
info: { input },
message: `Comment added: ${comment.id} (${input})`
}),
pubsub.publish(CommentSubscriptions.CommentActivity, {
commentActivity: {
type: 'comment-added',
comment
},
streamId,
resourceIds
}),
publish(ProjectSubscriptions.ProjectCommentsUpdated, {
projectCommentsUpdated: {
id: comment.id,
type: ProjectCommentsUpdatedMessageType.Created,
comment
},
projectId: streamId,
resourceItems
})
])
}
/**
* Add comment archived/unarchived activity
*/
export async function addCommentArchivedActivity(params: {
streamId: string
commentId: string
userId: string
input: MutationCommentArchiveArgs
comment: CommentRecord
}) {
const { streamId, commentId, userId, input, comment } = params
const isArchiving = !!input.archived
const getCommentsResources = getCommentsResourcesFactory({ db })
const getViewerResourcesFromLegacyIdentifiers =
getViewerResourcesFromLegacyIdentifiersFactory({
getViewerResourcesForComments: getViewerResourcesForCommentsFactory({
getCommentsResources: getCommentsResourcesFactory({ db }),
getViewerResourcesFromLegacyIdentifiers: (...args) =>
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
}),
getCommitsAndTheirBranchIds,
getStreamObjects
})
const getViewerResourcesForComment = getViewerResourcesForCommentFactory({
getCommentsResources,
getViewerResourcesFromLegacyIdentifiers
})
await Promise.all([
saveActivity({
streamId,
resourceType: ResourceTypes.Comment,
resourceId: commentId,
actionType: ActionTypes.Comment.Archive,
userId,
info: { input },
message: `Comment #${commentId} archived`
}),
pubsub.publish(CommentSubscriptions.CommentThreadActivity, {
commentThreadActivity: {
type: isArchiving ? 'comment-archived' : 'comment-added'
},
streamId: input.streamId,
commentId: input.commentId
}),
publish(ProjectSubscriptions.ProjectCommentsUpdated, {
projectCommentsUpdated: {
id: commentId,
type: isArchiving
? ProjectCommentsUpdatedMessageType.Archived
: ProjectCommentsUpdatedMessageType.Created,
comment: isArchiving ? null : comment
},
projectId: streamId,
resourceItems: await getViewerResourcesForComment(streamId, comment.id)
})
])
}
type ReplyCreatedActivityInput = ReplyCreateInput | CreateCommentReplyInput
const isLegacyReplyCreateInput = (
i: ReplyCreatedActivityInput
): i is ReplyCreateInput => has(i, 'streamId')
export async function addReplyAddedActivity(params: {
streamId: string
input: ReplyCreatedActivityInput
reply: CommentRecord
userId: string
}) {
const { streamId, input, reply, userId } = params
const getCommentsResources = getCommentsResourcesFactory({ db })
const getViewerResourcesFromLegacyIdentifiers =
getViewerResourcesFromLegacyIdentifiersFactory({
getViewerResourcesForComments: getViewerResourcesForCommentsFactory({
getCommentsResources: getCommentsResourcesFactory({ db }),
getViewerResourcesFromLegacyIdentifiers: (...args) =>
getViewerResourcesFromLegacyIdentifiers(...args) // recursive dep
}),
getCommitsAndTheirBranchIds,
getStreamObjects
})
const getViewerResourcesForComment = getViewerResourcesForCommentFactory({
getCommentsResources,
getViewerResourcesFromLegacyIdentifiers
})
const parentCommentId = isLegacyReplyCreateInput(input)
? input.parentComment
: input.threadId
await Promise.all([
saveActivity({
streamId,
resourceType: ResourceTypes.Comment,
resourceId: parentCommentId,
actionType: ActionTypes.Comment.Reply,
userId,
info: { input },
message: `Comment reply #${reply.id} created`
}),
pubsub.publish(CommentSubscriptions.CommentThreadActivity, {
commentThreadActivity: {
type: 'reply-added',
reply
},
streamId,
commentId: parentCommentId
}),
publish(ProjectSubscriptions.ProjectCommentsUpdated, {
projectCommentsUpdated: {
id: reply.id,
type: ProjectCommentsUpdatedMessageType.Created,
comment: reply
},
projectId: streamId,
resourceItems: await getViewerResourcesForComment(streamId, reply.id)
})
])
}