d1d5984e30
* refactor(server emails): email transports module refactor to TypeScript * refactor(docker-compose deps): move local email server to common dev compose file * chore(server launch.json): add ts-node script running example * chore(server deps): add nodemailer types package * refactor(server activitystream): add strongly typed activity definitions * feat(server activitystream): add activity repository * feat(server info): add canonical url on the service level * feat(server): add static file serving route to server core * feat(server): add dependencies for periodical email digests * feat(server activity stream): call the initialization step from the activity stream module * feat(server activity digest): add WIP weekly email digest implementation * feat(server digest email): smul upgrades and fixes to the email template and its contents * just for Fabs to test * chore(root package.json): remove deleted docker-compose references * feat(frontend profile): add notification preferences panel * feat(server digest emails): set prod ready cron tab and timespan * refactor(server email digest): move templates into the email module * refactor(server activity digests): refactor to use notifications infrastructure * test(server activities): add tests and some refactor to activities and notification preferences * refactor(notification preferences): fix minor issues * test(server notification preferences test): fix describe nesting * fix(server activities): add missing action types * fix(server activities): fix errors after merging main * test(server activity notifications): add test coverage for activity notifications service * refactor(server activities): fixing tests and some cleanup * feat(server cli): add summary notification command to cli * chore(dev env db versions): upgrade local dev env versions * chore(server deps): upgrade local dev db to pg 14 * fix(docker-compose): bind maildev to localhost * process-scoped notifications test queues * test(activity tests): add sleep to fix flaky CI * feat(activity digests): add demo date for digest trigger * feat(activity digest): add UK timezone trigger date Co-authored-by: Iain Sproat <68657+iainsproat@users.noreply.github.com> Co-authored-by: Fabians <fabis94@live.com>
169 lines
4.7 KiB
TypeScript
169 lines
4.7 KiB
TypeScript
import { saveActivity } from '@/modules/activitystream/services'
|
|
import { ActionTypes, ResourceTypes } from '@/modules/activitystream/helpers/types'
|
|
import { StreamRoles } from '@/modules/core/helpers/mainConstants'
|
|
import { pubsub, StreamPubsubEvents } from '@/modules/shared'
|
|
|
|
/**
|
|
* Save "stream permissions granted to user" activity item
|
|
*/
|
|
export async function addStreamPermissionsAddedActivity(params: {
|
|
streamId: string
|
|
activityUserId: string
|
|
targetUserId: string
|
|
role: StreamRoles
|
|
}) {
|
|
const { streamId, activityUserId, targetUserId, role } = params
|
|
await Promise.all([
|
|
saveActivity({
|
|
streamId,
|
|
resourceType: ResourceTypes.Stream,
|
|
resourceId: streamId,
|
|
actionType: ActionTypes.Stream.PermissionsAdd,
|
|
userId: activityUserId,
|
|
info: { targetUser: targetUserId, role },
|
|
message: `Permission granted to user ${targetUserId} (${role})`
|
|
}),
|
|
pubsub.publish(StreamPubsubEvents.UserStreamAdded, {
|
|
userStreamAdded: {
|
|
id: streamId,
|
|
sharedBy: activityUserId
|
|
},
|
|
ownerId: targetUserId
|
|
})
|
|
])
|
|
}
|
|
|
|
/**
|
|
* Save "user accepted stream invite" activity item
|
|
*/
|
|
export async function addStreamInviteAcceptedActivity(params: {
|
|
streamId: string
|
|
inviteTargetId: string
|
|
inviterId: string
|
|
role: StreamRoles
|
|
}) {
|
|
const { streamId, inviteTargetId, inviterId, role } = params
|
|
await Promise.all([
|
|
saveActivity({
|
|
streamId,
|
|
resourceType: ResourceTypes.Stream,
|
|
resourceId: streamId,
|
|
actionType: ActionTypes.Stream.InviteAccepted,
|
|
userId: inviteTargetId,
|
|
info: { inviterUser: inviterId, role },
|
|
message: `User ${inviteTargetId} has accepted an invitation to become a ${role}`
|
|
}),
|
|
pubsub.publish(StreamPubsubEvents.UserStreamAdded, {
|
|
userStreamAdded: {
|
|
id: streamId,
|
|
sharedBy: inviterId
|
|
},
|
|
ownerId: inviteTargetId
|
|
})
|
|
])
|
|
}
|
|
|
|
/**
|
|
* Save "stream permissions revoked for user" activity item
|
|
*/
|
|
export async function addStreamPermissionsRevokedActivity(params: {
|
|
streamId: string
|
|
activityUserId: string
|
|
removedUserId: string
|
|
}) {
|
|
const { streamId, activityUserId, removedUserId } = params
|
|
const isVoluntaryLeave = activityUserId === removedUserId
|
|
|
|
await Promise.all([
|
|
saveActivity({
|
|
streamId,
|
|
resourceType: ResourceTypes.Stream,
|
|
resourceId: streamId,
|
|
actionType: ActionTypes.Stream.PermissionsRemove,
|
|
userId: activityUserId,
|
|
info: { targetUser: removedUserId },
|
|
message: isVoluntaryLeave
|
|
? `User ${removedUserId} left the stream`
|
|
: `Permission revoked for user ${removedUserId}`
|
|
}),
|
|
|
|
pubsub.publish(StreamPubsubEvents.UserStreamRemoved, {
|
|
userStreamRemoved: {
|
|
id: streamId,
|
|
revokedBy: activityUserId
|
|
},
|
|
ownerId: removedUserId
|
|
})
|
|
])
|
|
}
|
|
|
|
/**
|
|
* Save "user invited another user to stream" activity item
|
|
*/
|
|
export async function addStreamInviteSentOutActivity(params: {
|
|
streamId: string
|
|
inviteTargetId: string
|
|
inviterId: string
|
|
inviteTargetEmail: string
|
|
}) {
|
|
const { streamId, inviteTargetId, inviterId, inviteTargetEmail } = params
|
|
const targetDisplay = inviteTargetId || inviteTargetEmail
|
|
|
|
await saveActivity({
|
|
streamId,
|
|
resourceType: ResourceTypes.Stream,
|
|
resourceId: streamId,
|
|
actionType: ActionTypes.Stream.InviteSent,
|
|
userId: inviterId,
|
|
message: `User ${inviterId} has invited ${targetDisplay} to stream ${streamId}`,
|
|
info: { targetId: inviteTargetId || null, targetEmail: inviteTargetEmail || null }
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Save "user declined an invite" activity item
|
|
*/
|
|
export async function addStreamInviteDeclinedActivity(params: {
|
|
streamId: string
|
|
inviteTargetId: string
|
|
inviterId: string
|
|
}) {
|
|
const { streamId, inviteTargetId, inviterId } = params
|
|
await saveActivity({
|
|
streamId,
|
|
resourceType: ResourceTypes.Stream,
|
|
resourceId: streamId,
|
|
actionType: ActionTypes.Stream.InviteDeclined,
|
|
userId: inviteTargetId,
|
|
message: `User ${inviteTargetId} declined to join the stream ${streamId}`,
|
|
info: { targetId: inviteTargetId, inviterId }
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Save "user mentioned in stream comment" activity item
|
|
*/
|
|
export async function addStreamCommentMentionActivity(params: {
|
|
streamId: string
|
|
mentionAuthorId: string
|
|
mentionTargetId: string
|
|
commentId: string
|
|
threadId: string
|
|
}) {
|
|
const { streamId, mentionAuthorId, mentionTargetId, commentId, threadId } = params
|
|
await saveActivity({
|
|
streamId,
|
|
resourceType: ResourceTypes.Comment,
|
|
resourceId: commentId,
|
|
actionType: ActionTypes.Comment.Mention,
|
|
userId: mentionAuthorId,
|
|
message: `User ${mentionAuthorId} mentioned user ${mentionTargetId} in comment ${commentId}`,
|
|
info: {
|
|
mentionAuthorId,
|
|
mentionTargetId,
|
|
commentId,
|
|
threadId
|
|
}
|
|
})
|
|
}
|