@headless-lms/core 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/events.d.ts +27 -21
- package/dist/assets/file-urls.d.ts +11 -7
- package/dist/assets/file-urls.js +14 -4
- package/dist/assets/file-urls.js.map +1 -1
- package/dist/assets/index.d.ts +4 -4
- package/dist/assets/index.js +3 -3
- package/dist/assets/ports.d.ts +34 -15
- package/dist/assets/service.d.ts +30 -14
- package/dist/assets/service.js +230 -56
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.js +69 -4
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.js +16 -16
- package/dist/automations/community-derivations.js.map +1 -1
- package/dist/automations/community-mail.d.ts +34 -4
- package/dist/automations/community-mail.js +32 -4
- package/dist/automations/community-mail.js.map +1 -1
- package/dist/automations/event-permissions.d.ts +12 -0
- package/dist/automations/event-permissions.js +38 -0
- package/dist/automations/event-permissions.js.map +1 -0
- package/dist/automations/index.d.ts +2 -1
- package/dist/automations/index.js +2 -1
- package/dist/automations/notifications/applicable.d.ts +8 -0
- package/dist/automations/notifications/applicable.js +12 -0
- package/dist/automations/notifications/applicable.js.map +1 -0
- package/dist/automations/notifications/debounce.js +1 -1
- package/dist/automations/notifications/debounce.js.map +1 -1
- package/dist/automations/notifications/defaults.js +33 -3
- package/dist/automations/notifications/defaults.js.map +1 -1
- package/dist/automations/notifications/processor.js +3 -3
- package/dist/automations/notifications/processor.js.map +1 -1
- package/dist/automations/notifications/rules/content.js +60 -3
- package/dist/automations/notifications/rules/content.js.map +1 -1
- package/dist/automations/notifications/rules/discussion.js +29 -29
- package/dist/automations/notifications/rules/discussion.js.map +1 -1
- package/dist/automations/notifications/rules/entitlements.js +36 -9
- package/dist/automations/notifications/rules/entitlements.js.map +1 -1
- package/dist/automations/notifications/rules/events.d.ts +9 -0
- package/dist/automations/notifications/rules/events.js +27 -0
- package/dist/automations/notifications/rules/events.js.map +1 -0
- package/dist/automations/notifications/rules/organizations.js +17 -10
- package/dist/automations/notifications/rules/organizations.js.map +1 -1
- package/dist/automations/notifications/rules/recipients.js +0 -1
- package/dist/automations/notifications/rules/recipients.js.map +1 -1
- package/dist/automations/notifications/service.d.ts +8 -6
- package/dist/automations/notifications/service.js +13 -13
- package/dist/automations/notifications/service.js.map +1 -1
- package/dist/automations/notifications/types.js +94 -7
- package/dist/automations/notifications/types.js.map +1 -1
- package/dist/automations/ports.d.ts +30 -31
- package/dist/automations/service.d.ts +20 -17
- package/dist/automations/service.js +91 -62
- package/dist/automations/service.js.map +1 -1
- package/dist/content/event-sight.d.ts +11 -0
- package/dist/content/event-sight.js +11 -0
- package/dist/content/event-sight.js.map +1 -0
- package/dist/content/events.d.ts +413 -72
- package/dist/content/events.js +34 -1
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +6 -4
- package/dist/content/index.js +3 -1
- package/dist/content/jobs.d.ts +16 -0
- package/dist/content/jobs.js +37 -0
- package/dist/content/jobs.js.map +1 -0
- package/dist/content/model.d.ts +2 -2
- package/dist/content/notification-categories.d.ts +5 -4
- package/dist/content/notification-categories.js +15 -6
- package/dist/content/notification-categories.js.map +1 -1
- package/dist/content/ports.d.ts +113 -68
- package/dist/content/service.d.ts +99 -67
- package/dist/content/service.js +680 -139
- package/dist/content/service.js.map +1 -1
- package/dist/content/titles.d.ts +6 -3
- package/dist/content/titles.js +37 -24
- package/dist/content/titles.js.map +1 -1
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +4 -2
- package/dist/discussion/authors.js +9 -5
- package/dist/discussion/authors.js.map +1 -1
- package/dist/discussion/chats.d.ts +56 -37
- package/dist/discussion/chats.js +393 -161
- package/dist/discussion/chats.js.map +1 -1
- package/dist/discussion/events.d.ts +77 -39
- package/dist/discussion/events.js +41 -3
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +8 -5
- package/dist/discussion/index.js +5 -3
- package/dist/discussion/live.d.ts +106 -0
- package/dist/discussion/live.js +642 -0
- package/dist/discussion/live.js.map +1 -0
- package/dist/discussion/mentions.js +2 -2
- package/dist/discussion/mentions.js.map +1 -1
- package/dist/discussion/ports.d.ts +182 -100
- package/dist/discussion/ports.js.map +1 -1
- package/dist/discussion/posts.d.ts +45 -39
- package/dist/discussion/posts.js +268 -154
- package/dist/discussion/posts.js.map +1 -1
- package/dist/discussion/rules.d.ts +18 -0
- package/dist/discussion/rules.js +22 -0
- package/dist/discussion/rules.js.map +1 -0
- package/dist/discussion/service.d.ts +37 -31
- package/dist/discussion/service.js +252 -188
- package/dist/discussion/service.js.map +1 -1
- package/dist/discussion/subscriptions.d.ts +8 -8
- package/dist/discussion/subscriptions.js +29 -13
- package/dist/discussion/subscriptions.js.map +1 -1
- package/dist/discussion/titles.d.ts +4 -2
- package/dist/discussion/titles.js +27 -13
- package/dist/discussion/titles.js.map +1 -1
- package/dist/entitlements/events.d.ts +20 -20
- package/dist/entitlements/index.d.ts +4 -4
- package/dist/entitlements/index.js +2 -2
- package/dist/entitlements/model.d.ts +2 -2
- package/dist/entitlements/ports.d.ts +65 -39
- package/dist/entitlements/rules.d.ts +3 -6
- package/dist/entitlements/rules.js +5 -10
- package/dist/entitlements/rules.js.map +1 -1
- package/dist/entitlements/service.d.ts +40 -28
- package/dist/entitlements/service.js +370 -163
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/devices.d.ts +3 -3
- package/dist/identity/devices.js +7 -5
- package/dist/identity/devices.js.map +1 -1
- package/dist/identity/events.d.ts +2 -2
- package/dist/identity/index.d.ts +2 -2
- package/dist/identity/index.js +2 -2
- package/dist/identity/notification-settings.d.ts +1 -1
- package/dist/identity/notification-settings.js +3 -2
- package/dist/identity/notification-settings.js.map +1 -1
- package/dist/identity/ports.d.ts +7 -7
- package/dist/identity/service.d.ts +8 -7
- package/dist/identity/service.js +17 -13
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/events.d.ts +3 -3
- package/dist/integrations/ports.d.ts +9 -8
- package/dist/integrations/service.d.ts +9 -8
- package/dist/integrations/service.js +33 -16
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/default-roles.d.ts +22 -0
- package/dist/organizations/default-roles.js +89 -0
- package/dist/organizations/default-roles.js.map +1 -0
- package/dist/organizations/effective-permissions.d.ts +45 -0
- package/dist/organizations/effective-permissions.js +113 -0
- package/dist/organizations/effective-permissions.js.map +1 -0
- package/dist/organizations/events.d.ts +320 -181
- package/dist/organizations/events.js +90 -18
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +14 -10
- package/dist/organizations/index.js +7 -3
- package/dist/organizations/members.d.ts +66 -8
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/notification-catalog.d.ts +31 -0
- package/dist/organizations/notification-catalog.js +32 -0
- package/dist/organizations/notification-catalog.js.map +1 -0
- package/dist/organizations/notification-categories.d.ts +6 -4
- package/dist/organizations/notification-categories.js +25 -10
- package/dist/organizations/notification-categories.js.map +1 -1
- package/dist/organizations/org-roles.d.ts +33 -0
- package/dist/organizations/org-roles.js +49 -0
- package/dist/organizations/org-roles.js.map +1 -0
- package/dist/organizations/permissions.d.ts +311 -0
- package/dist/organizations/permissions.js +327 -0
- package/dist/organizations/permissions.js.map +1 -0
- package/dist/organizations/ports.d.ts +184 -65
- package/dist/organizations/service.d.ts +102 -35
- package/dist/organizations/service.js +1245 -328
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/testing.d.ts +18 -0
- package/dist/organizations/testing.js +37 -0
- package/dist/organizations/testing.js.map +1 -0
- package/dist/organizations/types.d.ts +5 -16
- package/dist/progress/events.d.ts +14 -14
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +11 -3
- package/dist/progress/service.d.ts +6 -5
- package/dist/progress/service.js +23 -8
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +6 -4
- package/dist/reporting/admin/model.d.ts +36 -3
- package/dist/reporting/admin/ports.d.ts +39 -14
- package/dist/reporting/admin/service.d.ts +32 -11
- package/dist/reporting/admin/service.js +102 -18
- package/dist/reporting/admin/service.js.map +1 -1
- package/dist/reporting/events/index.d.ts +27 -0
- package/dist/reporting/events/index.js +20 -0
- package/dist/reporting/events/index.js.map +1 -0
- package/dist/reporting/member/calendar.d.ts +11 -0
- package/dist/reporting/member/calendar.js +75 -0
- package/dist/reporting/member/calendar.js.map +1 -0
- package/dist/reporting/member/index.d.ts +3 -2
- package/dist/reporting/member/model.d.ts +26 -5
- package/dist/reporting/member/ports.d.ts +48 -29
- package/dist/reporting/member/service.d.ts +56 -29
- package/dist/reporting/member/service.js +328 -113
- package/dist/reporting/member/service.js.map +1 -1
- package/dist/shared/actor.d.ts +22 -3
- package/dist/shared/errors.d.ts +2 -1
- package/dist/shared/errors.js +3 -1
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/id.d.ts +4 -0
- package/dist/shared/id.js +4 -0
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/logger.d.ts +2 -1
- package/dist/shared/logger.js +10 -1
- package/dist/shared/logger.js.map +1 -1
- package/dist/shared/ports.d.ts +25 -5
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +4 -5
- package/dist/types/email-templates.d.ts +22 -3
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/identity.d.ts +13 -16
- package/dist/types/index.d.ts +9 -9
- package/dist/types/index.js +2 -1
- package/dist/types/notifications.d.ts +4 -4
- package/dist/types/organizations.d.ts +3 -2
- package/dist/types/ports.d.ts +8 -1
- package/dist/types/ports.js +7 -1
- package/dist/types/ports.js.map +1 -0
- package/dist/types/schemas/assets.d.ts +5 -5
- package/dist/types/schemas/assets.js +4 -3
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/content.d.ts +537 -13
- package/dist/types/schemas/content.js +201 -7
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +282 -59
- package/dist/types/schemas/discussion.js +77 -3
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +14 -1
- package/dist/types/schemas/entitlements.js +11 -4
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/index.d.ts +5 -5
- package/dist/types/schemas/index.js +5 -5
- package/dist/types/schemas/notifications.d.ts +13 -12
- package/dist/types/schemas/notifications.js +3 -2
- package/dist/types/schemas/notifications.js.map +1 -1
- package/dist/types/schemas/organizations.d.ts +96 -60
- package/dist/types/schemas/organizations.js +78 -27
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +3 -4
- package/dist/types/schemas/progress.js +0 -1
- package/dist/types/schemas/progress.js.map +1 -1
- package/package.json +1 -1
- package/dist/organizations/access-scopes.d.ts +0 -19
- package/dist/organizations/access-scopes.js +0 -89
- package/dist/organizations/access-scopes.js.map +0 -1
- package/dist/organizations/roles.d.ts +0 -19
- package/dist/organizations/roles.js +0 -82
- package/dist/organizations/roles.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content.js","names":[],"sources":["../../../../src/automations/notifications/rules/content.ts"],"sourcesContent":["import { contentEvents } from '../../../content/index.js';\nimport type { RecipientRule } from '../../ports.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\nconst activityPublished: RecipientRule = async (event, reads) => {\n const parsed = contentEvents.activityPublished.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { activityId, courseId } = parsed.data.data;\n const orgId = event.orgId;\n const activity = await reads.activity(orgId, activityId);\n if (!activity) {\n return [];\n }\n return listOf(\n {\n type: 'course.activity_added',\n scope: 'org',\n
|
|
1
|
+
{"version":3,"file":"content.js","names":[],"sources":["../../../../src/automations/notifications/rules/content.ts"],"sourcesContent":["import { contentEvents, type Event } from '../../../content/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport { previousStatusOf } from '../../community-mail.js';\nimport { eventBase, eventDisplay } from './events.js';\nimport { actorOr, eventAt, listOf, Reasons, recipientsOf } from './recipients.js';\n\nconst activityPublished: RecipientRule = async (event, reads) => {\n const parsed = contentEvents.activityPublished.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { activityId, courseId } = parsed.data.data;\n const orgId = event.orgId;\n const activity = await reads.activity(orgId, activityId);\n if (!activity) {\n return [];\n }\n return listOf(\n {\n type: 'course.activity_added',\n scope: 'org',\n actorId: actorOr(event, null),\n communityId: null,\n spaceId: null,\n subject: { type: 'activity', id: activityId },\n parent: { type: 'course', id: courseId },\n display: {\n courseTitle: activity.courseTitle,\n moduleTitle: activity.moduleTitle,\n activityTitle: activity.title,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.courseMembers(orgId, courseId), 'course_member'),\n { exclude: [actorOr(event, null)], at: eventAt(event) },\n ),\n );\n};\n\nconst LEAD_TEXT = { '1d': '1 day', '1h': '1 hour' } as const;\n\nfunction metadataText(event: DomainEvent, key: string): string | undefined {\n const value = event.metadata?.[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction whatChanged(\n event: DomainEvent,\n next: Event,\n): 'time' | 'location' | 'time_and_location' | null {\n const time =\n metadataText(event, 'previousStartsAt') !== next.startsAt.toISOString() ||\n metadataText(event, 'previousEndsAt') !== next.endsAt.toISOString();\n const location = event.metadata?.locationChanged === true;\n if (time && location) {\n return 'time_and_location';\n }\n return time ? 'time' : location ? 'location' : null;\n}\n\nasync function toAttendees(\n reads: NotificationReads,\n domainEvent: DomainEvent,\n event: Event,\n type: string,\n actorId: string | null,\n display: Record<string, string>,\n) {\n return listOf(\n { ...eventBase(type, event, actorId), display },\n await recipientsOf(\n reads,\n domainEvent.orgId,\n new Reasons().add(await reads.eventAttendees(domainEvent.orgId, event.id), 'event_member'),\n { exclude: [actorId], at: eventAt(domainEvent) },\n ),\n );\n}\n\nconst eventUpdated: RecipientRule = async (domainEvent, reads) => {\n const parsed = contentEvents.eventUpdated.safeParse(domainEvent);\n if (!parsed.success) {\n return [];\n }\n const next = parsed.data.data;\n const event = await reads.event(domainEvent.orgId, next.id);\n if (!event?.settings.notifications) {\n return [];\n }\n const actor = actorOr(domainEvent, null);\n const previousStatus = previousStatusOf(domainEvent);\n if (next.status === 'canceled' && previousStatus !== 'canceled') {\n return toAttendees(reads, domainEvent, event, 'event.canceled', actor, eventDisplay(next));\n }\n if (\n previousStatus !== 'published' ||\n next.status !== 'published' ||\n next.endsAt.getTime() <= eventAt(domainEvent).getTime()\n ) {\n return [];\n }\n const changed = whatChanged(domainEvent, next);\n if (!changed) {\n return [];\n }\n return toAttendees(reads, domainEvent, event, 'event.changed', actor, {\n ...eventDisplay(next),\n changed,\n });\n};\n\nconst eventStartingSoon: RecipientRule = async (domainEvent, reads) => {\n const parsed = contentEvents.eventStartingSoon.safeParse(domainEvent);\n if (!parsed.success) {\n return [];\n }\n const { eventId, lead } = parsed.data.data;\n const event = await reads.event(domainEvent.orgId, eventId);\n if (!event?.settings.notifications || event.status !== 'published') {\n return [];\n }\n return toAttendees(reads, domainEvent, event, 'event.starting_soon', null, {\n ...eventDisplay(event),\n leadText: LEAD_TEXT[lead],\n });\n};\n\nexport const CONTENT_RULES: Record<string, RecipientRule> = {\n 'content.course.activity.published': activityPublished,\n 'content.event.updated': eventUpdated,\n 'content.event.starting_soon': eventStartingSoon,\n};\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { discussionEvents } from "../../../discussion/events.js";
|
|
2
|
-
import { previousStatusOf } from "../../community-mail.js";
|
|
2
|
+
import { communityModerators, previousStatusOf } from "../../community-mail.js";
|
|
3
3
|
import { Reasons, actorOr, chatReach, chatTitle, eventAt, listOf, participantNames, recipientsOf, textExcerpt } from "./recipients.js";
|
|
4
4
|
//#region src/automations/notifications/rules/discussion.ts
|
|
5
5
|
const CHAT_STATUS = "chatStatus";
|
|
@@ -22,8 +22,8 @@ function courseReach(reads, orgId, courseId, exclude, at) {
|
|
|
22
22
|
exclude,
|
|
23
23
|
at,
|
|
24
24
|
canOpen: async (orgUserIds) => {
|
|
25
|
-
const [holders,
|
|
26
|
-
const open = /* @__PURE__ */ new Set([...holders, ...
|
|
25
|
+
const [holders, readers] = await Promise.all([reads.courseMembers(orgId, courseId), reads.holders(orgId, "courses:read", courseId)]);
|
|
26
|
+
const open = /* @__PURE__ */ new Set([...holders, ...readers]);
|
|
27
27
|
return orgUserIds.filter((orgUserId) => open.has(orgUserId));
|
|
28
28
|
}
|
|
29
29
|
};
|
|
@@ -55,7 +55,7 @@ function placeReach(reads, orgId, place, exclude, at) {
|
|
|
55
55
|
spaceId: place.post.spaceId
|
|
56
56
|
}, exclude, at) : courseReach(reads, orgId, place.activity.courseId, exclude, at);
|
|
57
57
|
}
|
|
58
|
-
function commentBase(type, place, commentId,
|
|
58
|
+
function commentBase(type, place, commentId, actorId, display) {
|
|
59
59
|
const subject = {
|
|
60
60
|
type: "comment",
|
|
61
61
|
id: commentId
|
|
@@ -63,7 +63,7 @@ function commentBase(type, place, commentId, actorOrgUserId, display) {
|
|
|
63
63
|
if (place.kind === "post") return {
|
|
64
64
|
type,
|
|
65
65
|
scope: "space",
|
|
66
|
-
|
|
66
|
+
actorId,
|
|
67
67
|
communityId: place.post.communityId,
|
|
68
68
|
spaceId: place.post.spaceId,
|
|
69
69
|
subject,
|
|
@@ -79,7 +79,7 @@ function commentBase(type, place, commentId, actorOrgUserId, display) {
|
|
|
79
79
|
return {
|
|
80
80
|
type,
|
|
81
81
|
scope: "org",
|
|
82
|
-
|
|
82
|
+
actorId,
|
|
83
83
|
communityId: null,
|
|
84
84
|
spaceId: null,
|
|
85
85
|
subject,
|
|
@@ -158,7 +158,7 @@ const postPublished = async (event, reads) => {
|
|
|
158
158
|
if (previousStatusOf(event) === "pending") lists.push(...listOf({
|
|
159
159
|
...base,
|
|
160
160
|
type: "post.approved",
|
|
161
|
-
|
|
161
|
+
actorId: actor,
|
|
162
162
|
display: {
|
|
163
163
|
postTitle: post.title,
|
|
164
164
|
spaceName: space.name
|
|
@@ -168,10 +168,10 @@ const postPublished = async (event, reads) => {
|
|
|
168
168
|
exclude: [actor]
|
|
169
169
|
})));
|
|
170
170
|
const authorName = await reads.displayName(orgId, post.orgUserId);
|
|
171
|
-
const text = await textExcerpt(reads, orgId, post.body || post.title, 280);
|
|
171
|
+
const text = await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280);
|
|
172
172
|
lists.push(...await mentionsOf(reads, orgId, {
|
|
173
173
|
...base,
|
|
174
|
-
|
|
174
|
+
actorId: post.orgUserId,
|
|
175
175
|
display: {
|
|
176
176
|
authorName,
|
|
177
177
|
excerpt: text,
|
|
@@ -181,7 +181,7 @@ const postPublished = async (event, reads) => {
|
|
|
181
181
|
lists.push({
|
|
182
182
|
...base,
|
|
183
183
|
type: "post.published",
|
|
184
|
-
|
|
184
|
+
actorId: post.orgUserId,
|
|
185
185
|
display: {
|
|
186
186
|
spaceName: space.name,
|
|
187
187
|
postTitle: post.title,
|
|
@@ -205,7 +205,7 @@ async function awaitingReview(event, reads, post) {
|
|
|
205
205
|
return listOf({
|
|
206
206
|
type: "post.awaiting_review",
|
|
207
207
|
scope: "space",
|
|
208
|
-
|
|
208
|
+
actorId: post.orgUserId,
|
|
209
209
|
communityId: post.communityId,
|
|
210
210
|
spaceId: post.spaceId,
|
|
211
211
|
subject: {
|
|
@@ -218,7 +218,7 @@ async function awaitingReview(event, reads, post) {
|
|
|
218
218
|
postTitle: post.title,
|
|
219
219
|
authorName: await reads.displayName(orgId, post.orgUserId)
|
|
220
220
|
}
|
|
221
|
-
}, await recipientsOf(reads, orgId, new Reasons().add(await reads
|
|
221
|
+
}, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, post.communityId), "moderator"), {
|
|
222
222
|
exclude: [actor, post.orgUserId],
|
|
223
223
|
at: eventAt(event),
|
|
224
224
|
canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds)
|
|
@@ -238,7 +238,7 @@ const postUpdated = async (event, reads) => {
|
|
|
238
238
|
const actor = actorOr(event, post.orgUserId);
|
|
239
239
|
lists.push(...await mentionsOf(reads, orgId, {
|
|
240
240
|
scope: "space",
|
|
241
|
-
|
|
241
|
+
actorId: post.orgUserId,
|
|
242
242
|
communityId: post.communityId,
|
|
243
243
|
spaceId: post.spaceId,
|
|
244
244
|
subject: {
|
|
@@ -248,7 +248,7 @@ const postUpdated = async (event, reads) => {
|
|
|
248
248
|
parent: null,
|
|
249
249
|
display: {
|
|
250
250
|
authorName: await reads.displayName(orgId, post.orgUserId),
|
|
251
|
-
excerpt: await textExcerpt(reads, orgId, post.body || post.title, 280),
|
|
251
|
+
excerpt: await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280),
|
|
252
252
|
postTitle: post.title
|
|
253
253
|
}
|
|
254
254
|
}, post.mentionedOrgUserIds, postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event))));
|
|
@@ -266,7 +266,7 @@ const postRemoved = async (event, reads) => {
|
|
|
266
266
|
return listOf({
|
|
267
267
|
type: "post.removed",
|
|
268
268
|
scope: "space",
|
|
269
|
-
|
|
269
|
+
actorId: remover,
|
|
270
270
|
communityId: post.communityId,
|
|
271
271
|
spaceId: post.spaceId,
|
|
272
272
|
subject: {
|
|
@@ -290,7 +290,7 @@ const postReacted = async (event, reads) => {
|
|
|
290
290
|
return listOf({
|
|
291
291
|
type: "post.reacted",
|
|
292
292
|
scope: "space",
|
|
293
|
-
|
|
293
|
+
actorId: reaction.orgUserId,
|
|
294
294
|
communityId: post.communityId,
|
|
295
295
|
spaceId: post.spaceId,
|
|
296
296
|
subject: {
|
|
@@ -366,7 +366,7 @@ const postReported = async (event, reads) => {
|
|
|
366
366
|
return listOf({
|
|
367
367
|
type: "content.flagged",
|
|
368
368
|
scope: "space",
|
|
369
|
-
|
|
369
|
+
actorId: flag.orgUserId,
|
|
370
370
|
communityId: flag.communityId,
|
|
371
371
|
spaceId: post.spaceId,
|
|
372
372
|
subject: {
|
|
@@ -376,10 +376,10 @@ const postReported = async (event, reads) => {
|
|
|
376
376
|
parent: null,
|
|
377
377
|
display: {
|
|
378
378
|
spaceName: space.name,
|
|
379
|
-
excerpt: await textExcerpt(reads, orgId, post.body || post.title, 280),
|
|
379
|
+
excerpt: await textExcerpt(reads, orgId, reads.postText(post.body) || post.title, 280),
|
|
380
380
|
reason: flag.reason
|
|
381
381
|
}
|
|
382
|
-
}, await recipientsOf(reads, orgId, new Reasons().add(await reads
|
|
382
|
+
}, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, flag.communityId), "moderator"), {
|
|
383
383
|
exclude: [actorOr(event, flag.orgUserId)],
|
|
384
384
|
at: eventAt(event),
|
|
385
385
|
canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds)
|
|
@@ -402,7 +402,7 @@ const commentReported = async (event, reads) => {
|
|
|
402
402
|
excerpt: text,
|
|
403
403
|
reason: flag.reason
|
|
404
404
|
}
|
|
405
|
-
}, await recipientsOf(reads, orgId, new Reasons().add(await reads
|
|
405
|
+
}, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, place.post.communityId), "moderator"), {
|
|
406
406
|
exclude: [actor],
|
|
407
407
|
at: eventAt(event),
|
|
408
408
|
canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds)
|
|
@@ -410,7 +410,7 @@ const commentReported = async (event, reads) => {
|
|
|
410
410
|
return listOf(commentBase("content.flagged", place, flag.commentId, actor, {
|
|
411
411
|
excerpt: text,
|
|
412
412
|
reason: flag.reason
|
|
413
|
-
}), await recipientsOf(reads, orgId, new Reasons().add(await reads.
|
|
413
|
+
}), await recipientsOf(reads, orgId, new Reasons().add(await reads.holders(orgId, "courses:moderate", place.activity.courseId), "moderator"), {
|
|
414
414
|
exclude: [actor],
|
|
415
415
|
at: eventAt(event)
|
|
416
416
|
}));
|
|
@@ -425,7 +425,7 @@ async function chatMentions(event, reads, message, mentioned) {
|
|
|
425
425
|
if (!chat || chatPending(event, chat.status)) return [];
|
|
426
426
|
return mentionsOf(reads, orgId, {
|
|
427
427
|
scope: "chat",
|
|
428
|
-
|
|
428
|
+
actorId: message.orgUserId,
|
|
429
429
|
communityId: chat.communityId,
|
|
430
430
|
spaceId: null,
|
|
431
431
|
subject: {
|
|
@@ -457,7 +457,7 @@ const messageSent = async (event, reads) => {
|
|
|
457
457
|
return [...listOf({
|
|
458
458
|
type: "message.sent",
|
|
459
459
|
scope: "chat",
|
|
460
|
-
|
|
460
|
+
actorId: message.orgUserId,
|
|
461
461
|
communityId: chat.communityId,
|
|
462
462
|
spaceId: null,
|
|
463
463
|
subject: {
|
|
@@ -493,7 +493,7 @@ const messageReacted = async (event, reads) => {
|
|
|
493
493
|
return listOf({
|
|
494
494
|
type: "message.reacted",
|
|
495
495
|
scope: "chat",
|
|
496
|
-
|
|
496
|
+
actorId: reaction.orgUserId,
|
|
497
497
|
communityId: chat.communityId,
|
|
498
498
|
spaceId: null,
|
|
499
499
|
subject: {
|
|
@@ -520,7 +520,7 @@ const messageReported = async (event, reads) => {
|
|
|
520
520
|
return listOf({
|
|
521
521
|
type: "message.flagged",
|
|
522
522
|
scope: "chat",
|
|
523
|
-
|
|
523
|
+
actorId: flag.orgUserId,
|
|
524
524
|
communityId: flag.communityId,
|
|
525
525
|
spaceId: null,
|
|
526
526
|
subject: {
|
|
@@ -532,7 +532,7 @@ const messageReported = async (event, reads) => {
|
|
|
532
532
|
id: message.chatId
|
|
533
533
|
} : null,
|
|
534
534
|
display: { reason: flag.reason }
|
|
535
|
-
}, await recipientsOf(reads, orgId, new Reasons().add(await reads.
|
|
535
|
+
}, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, flag.communityId), "moderator"), {
|
|
536
536
|
exclude: [actorOr(event, flag.orgUserId)],
|
|
537
537
|
at: eventAt(event)
|
|
538
538
|
}));
|
|
@@ -549,7 +549,7 @@ const chatCreated = async (event, reads) => {
|
|
|
549
549
|
return listOf({
|
|
550
550
|
type: "chat.request",
|
|
551
551
|
scope: "chat",
|
|
552
|
-
|
|
552
|
+
actorId: created.createdBy,
|
|
553
553
|
communityId: created.communityId,
|
|
554
554
|
spaceId: null,
|
|
555
555
|
subject: {
|
|
@@ -573,7 +573,7 @@ const chatParticipantAdded = async (event, reads) => {
|
|
|
573
573
|
return listOf({
|
|
574
574
|
type: "chat.added",
|
|
575
575
|
scope: "chat",
|
|
576
|
-
|
|
576
|
+
actorId: added.addedBy,
|
|
577
577
|
communityId: added.communityId,
|
|
578
578
|
spaceId: null,
|
|
579
579
|
subject: {
|
|
@@ -624,7 +624,7 @@ const digestDue = async (event, reads) => {
|
|
|
624
624
|
lists.push(...listOf({
|
|
625
625
|
type: "digest",
|
|
626
626
|
scope: "community",
|
|
627
|
-
|
|
627
|
+
actorId: null,
|
|
628
628
|
communityId,
|
|
629
629
|
spaceId: null,
|
|
630
630
|
subject: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discussion.js","names":[],"sources":["../../../../src/automations/notifications/rules/discussion.ts"],"sourcesContent":["import { discussionEvents } from '../../../discussion/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { JsonValue, RecipientList, SubjectRef } from '../../../types/index.js';\nimport { MESSAGE_EXCERPT, POST_EXCERPT, previousStatusOf } from '../../community-mail.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport {\n actorOr,\n chatReach,\n chatTitle,\n eventAt,\n listOf,\n participantNames,\n Reasons,\n recipientsOf,\n textExcerpt,\n type ListBase,\n type Reach,\n} from './recipients.js';\n\ntype Post = NonNullable<Awaited<ReturnType<NotificationReads['post']>>>;\ntype Activity = NonNullable<Awaited<ReturnType<NotificationReads['activity']>>>;\n\ntype Place =\n | { kind: 'post'; postId: string; post: Post; spaceName: string }\n | { kind: 'activity'; activityId: string; activity: Activity };\n\nconst CHAT_STATUS = 'chatStatus';\n\nfunction postReach(\n reads: NotificationReads,\n orgId: string,\n post: { id: string; spaceId: string },\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n mutedOn: [\n { type: 'post', id: post.id },\n { type: 'space', id: post.spaceId },\n ],\n };\n}\n\nfunction courseReach(\n reads: NotificationReads,\n orgId: string,\n courseId: string,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: async (orgUserIds) => {\n const [holders, staff] = await Promise.all([\n reads.courseHolders(orgId, courseId),\n reads.staffIds(orgId),\n ]);\n const open = new Set([...holders, ...staff]);\n return orgUserIds.filter((orgUserId) => open.has(orgUserId));\n },\n };\n}\n\nasync function placeOf(\n reads: NotificationReads,\n orgId: string,\n comment: { postId: string | null; activityId: string | null },\n): Promise<Place | null> {\n if (comment.postId) {\n const post = await reads.post(orgId, comment.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n return post && space\n ? { kind: 'post', postId: comment.postId, post, spaceName: space.name }\n : null;\n }\n if (comment.activityId) {\n const activity = await reads.activity(orgId, comment.activityId);\n return activity ? { kind: 'activity', activityId: comment.activityId, activity } : null;\n }\n return null;\n}\n\nfunction placeReach(\n reads: NotificationReads,\n orgId: string,\n place: Place,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return place.kind === 'post'\n ? postReach(reads, orgId, { id: place.postId, spaceId: place.post.spaceId }, exclude, at)\n : courseReach(reads, orgId, place.activity.courseId, exclude, at);\n}\n\nfunction commentBase(\n type: string,\n place: Place,\n commentId: string,\n actorOrgUserId: string | null,\n display: Record<string, JsonValue>,\n): ListBase {\n const subject: SubjectRef = { type: 'comment', id: commentId };\n if (place.kind === 'post') {\n return {\n type,\n scope: 'space',\n actorOrgUserId,\n communityId: place.post.communityId,\n spaceId: place.post.spaceId,\n subject,\n parent: { type: 'post', id: place.postId },\n display: { postTitle: place.post.title, ...display },\n };\n }\n return {\n type,\n scope: 'org',\n actorOrgUserId,\n communityId: null,\n spaceId: null,\n subject,\n parent: { type: 'activity', id: place.activityId },\n display: {\n activityTitle: place.activity.title,\n courseTitle: place.activity.courseTitle,\n courseId: place.activity.courseId,\n ...display,\n },\n };\n}\n\nasync function mentionsOf(\n reads: NotificationReads,\n orgId: string,\n base: Omit<ListBase, 'type'>,\n mentioned: string[],\n reach: Reach,\n): Promise<RecipientList[]> {\n if (mentioned.length === 0) {\n return [];\n }\n const recipients = await recipientsOf(\n reads,\n orgId,\n new Reasons().add(mentioned, 'mentioned'),\n reach,\n );\n return listOf({ ...base, type: 'mention' }, recipients);\n}\n\nasync function commentLists(\n event: DomainEvent,\n reads: NotificationReads,\n comment: {\n id: string;\n postId: string | null;\n activityId: string | null;\n parentId: string | null;\n orgUserId: string;\n body: string;\n mentionedOrgUserIds: string[];\n },\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n const at = eventAt(event);\n const exclude = [comment.orgUserId, actorOr(event, comment.orgUserId)];\n const reasons = new Reasons();\n if (place.kind === 'post') {\n reasons.add([place.post.orgUserId], 'post_author');\n }\n const parent = comment.parentId ? await reads.comment(orgId, comment.parentId) : null;\n reasons.add([parent?.orgUserId], 'comment_author');\n if (place.kind === 'post') {\n reasons.add(await reads.followerIds(orgId, place.postId), 'follower');\n }\n reasons.add(\n await reads.threadParticipants(\n orgId,\n place.kind === 'post'\n ? { type: 'post', id: place.postId }\n : { type: 'activity', id: place.activityId },\n ),\n 'thread_participant',\n );\n const name = await reads.displayName(orgId, comment.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n const created = listOf(\n commentBase('comment.created', place, comment.id, comment.orgUserId, {\n commenterName: name,\n excerpt: text,\n }),\n await recipientsOf(reads, orgId, reasons, placeReach(reads, orgId, place, exclude, at)),\n );\n const mentions = await mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: name,\n excerpt: text,\n }),\n comment.mentionedOrgUserIds,\n placeReach(reads, orgId, place, exclude, at),\n );\n return [...created, ...mentions];\n}\n\nconst postPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postPublished.safeParse(event);\n if (!parsed.success || previousStatusOf(event) === 'removed') {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const at = eventAt(event);\n const actor = actorOr(event, null);\n const exclude = [...new Set([post.orgUserId, ...(actor ? [actor] : [])])];\n const reach = postReach(reads, orgId, post, exclude, at);\n const base = {\n scope: 'space' as const,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post' as const, id: post.id },\n parent: null,\n };\n const lists: RecipientList[] = [];\n if (previousStatusOf(event) === 'pending') {\n lists.push(\n ...listOf(\n {\n ...base,\n type: 'post.approved',\n actorOrgUserId: actor,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], 'subject'), {\n ...reach,\n exclude: [actor],\n }),\n ),\n );\n }\n const authorName = await reads.displayName(orgId, post.orgUserId);\n const text = await textExcerpt(reads, orgId, post.body || post.title, POST_EXCERPT);\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n ...base,\n actorOrgUserId: post.orgUserId,\n display: { authorName, excerpt: text, postTitle: post.title },\n },\n post.mentionedOrgUserIds,\n reach,\n )),\n );\n lists.push({\n ...base,\n type: 'post.published',\n actorOrgUserId: post.orgUserId,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName,\n excerpt: text,\n },\n audience: { reason: 'space_member', spaceId: post.spaceId, exclude },\n });\n return lists;\n};\n\nasync function awaitingReview(\n event: DomainEvent,\n reads: NotificationReads,\n post: {\n id: string;\n communityId: string;\n spaceId: string;\n orgUserId: string;\n title: string;\n status: string;\n },\n): Promise<RecipientList[]> {\n if (post.status !== 'pending' || previousStatusOf(event) === 'pending') {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const actor = actorOr(event, post.orgUserId);\n return listOf(\n {\n type: 'post.awaiting_review',\n scope: 'space',\n actorOrgUserId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName: await reads.displayName(orgId, post.orgUserId),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.moderationAudience(orgId, post.communityId), 'moderator'),\n {\n exclude: [actor, post.orgUserId],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n}\n\nconst postCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postCreated.safeParse(event);\n return parsed.success ? awaitingReview(event, reads, parsed.data.data) : [];\n};\n\nconst postUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const lists = await awaitingReview(event, reads, post);\n if (post.mentionedOrgUserIds.length === 0) {\n return lists;\n }\n const actor = actorOr(event, post.orgUserId);\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n scope: 'space',\n actorOrgUserId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n authorName: await reads.displayName(orgId, post.orgUserId),\n excerpt: await textExcerpt(reads, orgId, post.body || post.title, POST_EXCERPT),\n postTitle: post.title,\n },\n },\n post.mentionedOrgUserIds,\n postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event)),\n )),\n );\n return lists;\n};\n\nconst postRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const remover = post.removedBy ?? actorOr(event, null);\n if (!remover || remover === post.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n return listOf(\n {\n type: 'post.removed',\n scope: 'space',\n actorOrgUserId: remover,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'subject'),\n postReach(reads, orgId, post, [remover], eventAt(event)),\n ),\n );\n};\n\nconst postReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, reaction.postId);\n if (!post) {\n return [];\n }\n return listOf(\n {\n type: 'post.reacted',\n scope: 'space',\n actorOrgUserId: reaction.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: reaction.postId },\n parent: null,\n display: {\n postTitle: post.title,\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'post_author'),\n postReach(\n reads,\n orgId,\n { id: reaction.postId, spaceId: post.spaceId },\n [reaction.orgUserId, actorOr(event, null)],\n eventAt(event),\n ),\n ),\n );\n};\n\nconst commentCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentCreated.safeParse(event);\n if (!parsed.success || parsed.data.data.status !== 'published') {\n return [];\n }\n return commentLists(event, reads, parsed.data.data);\n};\n\nconst commentPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentPublished.safeParse(event);\n return parsed.success ? commentLists(event, reads, parsed.data.data) : [];\n};\n\nconst commentUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n if (comment.status !== 'published' || comment.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: await reads.displayName(orgId, comment.orgUserId),\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n }),\n comment.mentionedOrgUserIds,\n placeReach(\n reads,\n orgId,\n place,\n [comment.orgUserId, actorOr(event, comment.orgUserId)],\n eventAt(event),\n ),\n );\n};\n\nconst commentRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n const remover = comment.removedBy ?? actorOr(event, null);\n if (!remover || remover === comment.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return listOf(\n commentBase('comment.removed', place, comment.id, remover, {}),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'subject'),\n placeReach(reads, orgId, place, [remover], eventAt(event)),\n ),\n );\n};\n\nconst commentReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, reaction.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n return listOf(\n commentBase('comment.reacted', place, reaction.commentId, reaction.orgUserId, {\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n }),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'comment_author'),\n placeReach(reads, orgId, place, [reaction.orgUserId, actorOr(event, null)], eventAt(event)),\n ),\n );\n};\n\nconst postReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, flag.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n if (!post || !space) {\n return [];\n }\n return listOf(\n {\n type: 'content.flagged',\n scope: 'space',\n actorOrgUserId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: flag.postId },\n parent: null,\n display: {\n spaceName: space.name,\n excerpt: await textExcerpt(reads, orgId, post.body || post.title, POST_EXCERPT),\n reason: flag.reason,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await reads.moderationAudience(orgId, flag.communityId), 'moderator'),\n {\n exclude: [actorOr(event, flag.orgUserId)],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n};\n\nconst commentReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, flag.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n const actor = actorOr(event, flag.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n if (place.kind === 'post') {\n return listOf(\n {\n ...commentBase('content.flagged', place, flag.commentId, actor, {}),\n display: { spaceName: place.spaceName, excerpt: text, reason: flag.reason },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n await reads.moderationAudience(orgId, place.post.communityId),\n 'moderator',\n ),\n {\n exclude: [actor],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds),\n },\n ),\n );\n }\n return listOf(\n commentBase('content.flagged', place, flag.commentId, actor, {\n excerpt: text,\n reason: flag.reason,\n }),\n await recipientsOf(reads, orgId, new Reasons().add(await reads.staffIds(orgId), 'staff'), {\n exclude: [actor],\n at: eventAt(event),\n }),\n );\n};\n\nfunction chatPending(event: DomainEvent, status: string): boolean {\n const value = event.metadata?.[CHAT_STATUS];\n return (typeof value === 'string' ? value : status) === 'pending';\n}\n\nasync function chatMentions(\n event: DomainEvent,\n reads: NotificationReads,\n message: { id: string; chatId: string; orgUserId: string; body: string },\n mentioned: string[],\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n {\n scope: 'chat',\n actorOrgUserId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n authorName: await reads.displayName(orgId, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n },\n },\n mentioned,\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n );\n}\n\nexport function messageSummary(count: number): string {\n return count === 1 ? '1 new message' : `${count} new messages`;\n}\n\nconst messageSent: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageSent.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const message = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n const senderName = await reads.displayName(orgId, message.orgUserId);\n const sent = listOf(\n {\n type: 'message.sent',\n scope: 'chat',\n actorOrgUserId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n senderName,\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n count: '1',\n summary: messageSummary(1),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n chat.participants.map((participant) => participant.orgUserId),\n 'participant',\n ),\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n ),\n );\n return [...sent, ...(await chatMentions(event, reads, message, message.mentionedOrgUserIds))];\n};\n\nconst messageUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageUpdated.safeParse(event);\n if (!parsed.success || parsed.data.data.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const message = parsed.data.data;\n return chatMentions(event, reads, message, message.mentionedOrgUserIds);\n};\n\nconst messageReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const [message, chat] = await Promise.all([\n reads.message(orgId, reaction.messageId),\n reads.chat(orgId, reaction.chatId),\n ]);\n if (!message || !chat) {\n return [];\n }\n return listOf(\n {\n type: 'message.reacted',\n scope: 'chat',\n actorOrgUserId: reaction.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: reaction.messageId },\n parent: { type: 'chat', id: reaction.chatId },\n display: {\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([message.orgUserId], 'message_author'),\n chatReach(reads, orgId, chat, reaction.chatId, reaction.orgUserId, eventAt(event)),\n ),\n );\n};\n\nconst messageReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const message = await reads.message(orgId, flag.messageId);\n return listOf(\n {\n type: 'message.flagged',\n scope: 'chat',\n actorOrgUserId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: null,\n subject: { type: 'message', id: flag.messageId },\n parent: message ? { type: 'chat', id: message.chatId } : null,\n display: { reason: flag.reason },\n },\n await recipientsOf(reads, orgId, new Reasons().add(await reads.staffIds(orgId), 'staff'), {\n exclude: [actorOr(event, flag.orgUserId)],\n at: eventAt(event),\n }),\n );\n};\n\nconst chatCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const created = parsed.data.data;\n if (created.kind !== 'direct' || created.status !== 'pending' || !created.createdBy) {\n return [];\n }\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, created.id);\n if (!chat) {\n return [];\n }\n const body = await reads.latestMessageBody(orgId, created.id);\n return listOf(\n {\n type: 'chat.request',\n scope: 'chat',\n actorOrgUserId: created.createdBy,\n communityId: created.communityId,\n spaceId: null,\n subject: { type: 'chat', id: created.id },\n parent: null,\n display: {\n senderName: await reads.displayName(orgId, created.createdBy),\n excerpt: await textExcerpt(reads, orgId, body ?? '', MESSAGE_EXCERPT),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(created.participantIds, 'participant'),\n chatReach(reads, orgId, chat, created.id, created.createdBy, eventAt(event)),\n ),\n );\n};\n\nconst chatParticipantAdded: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatParticipantAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const added = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, added.chatId);\n if (!chat) {\n return [];\n }\n return listOf(\n {\n type: 'chat.added',\n scope: 'chat',\n actorOrgUserId: added.addedBy,\n communityId: added.communityId,\n spaceId: null,\n subject: { type: 'chat', id: added.chatId },\n parent: null,\n display: {\n adderName: await reads.displayName(orgId, added.addedBy),\n participantNames: await participantNames(reads, orgId, chat),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([added.orgUserId], 'subject'),\n chatReach(reads, orgId, chat, added.chatId, added.addedBy, eventAt(event)),\n ),\n );\n};\n\nconst digestDue: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.digestDue.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { communityId, from, to } = parsed.data.data;\n const orgId = event.orgId;\n const posts = await reads.postsPublished(orgId, communityId, from, to);\n if (posts.length === 0) {\n return [];\n }\n const title = await reads.communityTitle(orgId, communityId);\n if (title === null) {\n return [];\n }\n const spaceIds = [...new Set(posts.map((post) => post.spaceId))];\n const openers = new Map<string, Set<string>>();\n for (const spaceId of spaceIds) {\n const open = await reads.spaceOpeners(orgId, spaceId);\n const muted = new Set(\n open.length > 0\n ? await reads.mutedAmong(orgId, { type: 'space', id: spaceId }, open, eventAt(event))\n : [],\n );\n openers.set(spaceId, new Set(open.filter((orgUserId) => !muted.has(orgUserId))));\n }\n const groups = new Map<string, { spaceIds: string[]; members: Reasons }>();\n for (const orgUserId of await reads.communityMembers(orgId, communityId)) {\n const open = spaceIds.filter((spaceId) => openers.get(spaceId)?.has(orgUserId));\n if (open.length === 0) {\n continue;\n }\n const key = open.join(' ');\n const group = groups.get(key) ?? { spaceIds: open, members: new Reasons() };\n group.members.add([orgUserId], 'community_member');\n groups.set(key, group);\n }\n const lists: RecipientList[] = [];\n for (const group of groups.values()) {\n const shown = posts.filter((post) => group.spaceIds.includes(post.spaceId));\n lists.push(\n ...listOf(\n {\n type: 'digest',\n scope: 'community',\n actorOrgUserId: null,\n communityId,\n spaceId: null,\n subject: { type: 'community', id: communityId },\n parent: null,\n display: {\n communityTitle: title,\n from: from.toISOString(),\n to: to.toISOString(),\n posts: shown.map((post) => ({\n postId: post.postId,\n title: post.title,\n authorName: post.authorName,\n spaceName: post.spaceName,\n commentCount: post.commentCount,\n })),\n },\n },\n await recipientsOf(reads, orgId, group.members, { exclude: [], at: eventAt(event) }),\n ),\n );\n }\n return lists;\n};\n\nexport const DISCUSSION_RULES: Record<string, RecipientRule> = {\n 'discussion.post.published': postPublished,\n 'discussion.post.created': postCreated,\n 'discussion.post.updated': postUpdated,\n 'discussion.post.removed': postRemoved,\n 'discussion.post.reaction.added': postReacted,\n 'discussion.comment.created': commentCreated,\n 'discussion.comment.published': commentPublished,\n 'discussion.comment.updated': commentUpdated,\n 'discussion.comment.removed': commentRemoved,\n 'discussion.comment.reaction.added': commentReacted,\n 'discussion.post.reported': postReported,\n 'discussion.comment.reported': commentReported,\n 'discussion.message.sent': messageSent,\n 'discussion.message.updated': messageUpdated,\n 'discussion.message.reaction.added': messageReacted,\n 'discussion.message.reported': messageReported,\n 'discussion.chat.created': chatCreated,\n 'discussion.chat.participant.added': chatParticipantAdded,\n 'discussion.digest.due': digestDue,\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"discussion.js","names":[],"sources":["../../../../src/automations/notifications/rules/discussion.ts"],"sourcesContent":["import { discussionEvents } from '../../../discussion/index.js';\nimport type { DomainEvent } from '../../../shared/ports.js';\nimport type { JsonValue, RecipientList, SubjectRef } from '../../../types/index.js';\nimport {\n communityModerators,\n MESSAGE_EXCERPT,\n POST_EXCERPT,\n previousStatusOf,\n} from '../../community-mail.js';\nimport type { NotificationReads, RecipientRule } from '../../ports.js';\nimport {\n actorOr,\n chatReach,\n chatTitle,\n eventAt,\n listOf,\n participantNames,\n Reasons,\n recipientsOf,\n textExcerpt,\n type ListBase,\n type Reach,\n} from './recipients.js';\n\ntype Post = NonNullable<Awaited<ReturnType<NotificationReads['post']>>>;\ntype Activity = NonNullable<Awaited<ReturnType<NotificationReads['activity']>>>;\n\ntype Place =\n | { kind: 'post'; postId: string; post: Post; spaceName: string }\n | { kind: 'activity'; activityId: string; activity: Activity };\n\nconst CHAT_STATUS = 'chatStatus';\n\nfunction postReach(\n reads: NotificationReads,\n orgId: string,\n post: { id: string; spaceId: string },\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n mutedOn: [\n { type: 'post', id: post.id },\n { type: 'space', id: post.spaceId },\n ],\n };\n}\n\nfunction courseReach(\n reads: NotificationReads,\n orgId: string,\n courseId: string,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return {\n exclude,\n at,\n canOpen: async (orgUserIds) => {\n const [holders, readers] = await Promise.all([\n reads.courseMembers(orgId, courseId),\n reads.holders(orgId, 'courses:read', courseId),\n ]);\n const open = new Set([...holders, ...readers]);\n return orgUserIds.filter((orgUserId) => open.has(orgUserId));\n },\n };\n}\n\nasync function placeOf(\n reads: NotificationReads,\n orgId: string,\n comment: { postId: string | null; activityId: string | null },\n): Promise<Place | null> {\n if (comment.postId) {\n const post = await reads.post(orgId, comment.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n return post && space\n ? { kind: 'post', postId: comment.postId, post, spaceName: space.name }\n : null;\n }\n if (comment.activityId) {\n const activity = await reads.activity(orgId, comment.activityId);\n return activity ? { kind: 'activity', activityId: comment.activityId, activity } : null;\n }\n return null;\n}\n\nfunction placeReach(\n reads: NotificationReads,\n orgId: string,\n place: Place,\n exclude: (string | null)[],\n at: Date,\n): Reach {\n return place.kind === 'post'\n ? postReach(reads, orgId, { id: place.postId, spaceId: place.post.spaceId }, exclude, at)\n : courseReach(reads, orgId, place.activity.courseId, exclude, at);\n}\n\nfunction commentBase(\n type: string,\n place: Place,\n commentId: string,\n actorId: string | null,\n display: Record<string, JsonValue>,\n): ListBase {\n const subject: SubjectRef = { type: 'comment', id: commentId };\n if (place.kind === 'post') {\n return {\n type,\n scope: 'space',\n actorId,\n communityId: place.post.communityId,\n spaceId: place.post.spaceId,\n subject,\n parent: { type: 'post', id: place.postId },\n display: { postTitle: place.post.title, ...display },\n };\n }\n return {\n type,\n scope: 'org',\n actorId,\n communityId: null,\n spaceId: null,\n subject,\n parent: { type: 'activity', id: place.activityId },\n display: {\n activityTitle: place.activity.title,\n courseTitle: place.activity.courseTitle,\n courseId: place.activity.courseId,\n ...display,\n },\n };\n}\n\nasync function mentionsOf(\n reads: NotificationReads,\n orgId: string,\n base: Omit<ListBase, 'type'>,\n mentioned: string[],\n reach: Reach,\n): Promise<RecipientList[]> {\n if (mentioned.length === 0) {\n return [];\n }\n const recipients = await recipientsOf(\n reads,\n orgId,\n new Reasons().add(mentioned, 'mentioned'),\n reach,\n );\n return listOf({ ...base, type: 'mention' }, recipients);\n}\n\nasync function commentLists(\n event: DomainEvent,\n reads: NotificationReads,\n comment: {\n id: string;\n postId: string | null;\n activityId: string | null;\n parentId: string | null;\n orgUserId: string;\n body: string;\n mentionedOrgUserIds: string[];\n },\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n const at = eventAt(event);\n const exclude = [comment.orgUserId, actorOr(event, comment.orgUserId)];\n const reasons = new Reasons();\n if (place.kind === 'post') {\n reasons.add([place.post.orgUserId], 'post_author');\n }\n const parent = comment.parentId ? await reads.comment(orgId, comment.parentId) : null;\n reasons.add([parent?.orgUserId], 'comment_author');\n if (place.kind === 'post') {\n reasons.add(await reads.followerIds(orgId, place.postId), 'follower');\n }\n reasons.add(\n await reads.threadParticipants(\n orgId,\n place.kind === 'post'\n ? { type: 'post', id: place.postId }\n : { type: 'activity', id: place.activityId },\n ),\n 'thread_participant',\n );\n const name = await reads.displayName(orgId, comment.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n const created = listOf(\n commentBase('comment.created', place, comment.id, comment.orgUserId, {\n commenterName: name,\n excerpt: text,\n }),\n await recipientsOf(reads, orgId, reasons, placeReach(reads, orgId, place, exclude, at)),\n );\n const mentions = await mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: name,\n excerpt: text,\n }),\n comment.mentionedOrgUserIds,\n placeReach(reads, orgId, place, exclude, at),\n );\n return [...created, ...mentions];\n}\n\nconst postPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postPublished.safeParse(event);\n if (!parsed.success || previousStatusOf(event) === 'removed') {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const at = eventAt(event);\n const actor = actorOr(event, null);\n const exclude = [...new Set([post.orgUserId, ...(actor ? [actor] : [])])];\n const reach = postReach(reads, orgId, post, exclude, at);\n const base = {\n scope: 'space' as const,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post' as const, id: post.id },\n parent: null,\n };\n const lists: RecipientList[] = [];\n if (previousStatusOf(event) === 'pending') {\n lists.push(\n ...listOf(\n {\n ...base,\n type: 'post.approved',\n actorId: actor,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(reads, orgId, new Reasons().add([post.orgUserId], 'subject'), {\n ...reach,\n exclude: [actor],\n }),\n ),\n );\n }\n const authorName = await reads.displayName(orgId, post.orgUserId);\n const text = await textExcerpt(\n reads,\n orgId,\n reads.postText(post.body) || post.title,\n POST_EXCERPT,\n );\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n ...base,\n actorId: post.orgUserId,\n display: { authorName, excerpt: text, postTitle: post.title },\n },\n post.mentionedOrgUserIds,\n reach,\n )),\n );\n lists.push({\n ...base,\n type: 'post.published',\n actorId: post.orgUserId,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName,\n excerpt: text,\n },\n audience: { reason: 'space_member', spaceId: post.spaceId, exclude },\n });\n return lists;\n};\n\nasync function awaitingReview(\n event: DomainEvent,\n reads: NotificationReads,\n post: {\n id: string;\n communityId: string;\n spaceId: string;\n orgUserId: string;\n title: string;\n status: string;\n },\n): Promise<RecipientList[]> {\n if (post.status !== 'pending' || previousStatusOf(event) === 'pending') {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n const actor = actorOr(event, post.orgUserId);\n return listOf(\n {\n type: 'post.awaiting_review',\n scope: 'space',\n actorId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n spaceName: space.name,\n postTitle: post.title,\n authorName: await reads.displayName(orgId, post.orgUserId),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, post.communityId), 'moderator'),\n {\n exclude: [actor, post.orgUserId],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n}\n\nconst postCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postCreated.safeParse(event);\n return parsed.success ? awaitingReview(event, reads, parsed.data.data) : [];\n};\n\nconst postUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const orgId = event.orgId;\n const lists = await awaitingReview(event, reads, post);\n if (post.mentionedOrgUserIds.length === 0) {\n return lists;\n }\n const actor = actorOr(event, post.orgUserId);\n lists.push(\n ...(await mentionsOf(\n reads,\n orgId,\n {\n scope: 'space',\n actorId: post.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: {\n authorName: await reads.displayName(orgId, post.orgUserId),\n excerpt: await textExcerpt(\n reads,\n orgId,\n reads.postText(post.body) || post.title,\n POST_EXCERPT,\n ),\n postTitle: post.title,\n },\n },\n post.mentionedOrgUserIds,\n postReach(reads, orgId, post, [actor, post.orgUserId], eventAt(event)),\n )),\n );\n return lists;\n};\n\nconst postRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const post = parsed.data.data;\n const remover = post.removedBy ?? actorOr(event, null);\n if (!remover || remover === post.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const space = await reads.space(orgId, post.spaceId);\n if (!space) {\n return [];\n }\n return listOf(\n {\n type: 'post.removed',\n scope: 'space',\n actorId: remover,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: post.id },\n parent: null,\n display: { postTitle: post.title, spaceName: space.name },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'subject'),\n postReach(reads, orgId, post, [remover], eventAt(event)),\n ),\n );\n};\n\nconst postReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, reaction.postId);\n if (!post) {\n return [];\n }\n return listOf(\n {\n type: 'post.reacted',\n scope: 'space',\n actorId: reaction.orgUserId,\n communityId: post.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: reaction.postId },\n parent: null,\n display: {\n postTitle: post.title,\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([post.orgUserId], 'post_author'),\n postReach(\n reads,\n orgId,\n { id: reaction.postId, spaceId: post.spaceId },\n [reaction.orgUserId, actorOr(event, null)],\n eventAt(event),\n ),\n ),\n );\n};\n\nconst commentCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentCreated.safeParse(event);\n if (!parsed.success || parsed.data.data.status !== 'published') {\n return [];\n }\n return commentLists(event, reads, parsed.data.data);\n};\n\nconst commentPublished: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentPublished.safeParse(event);\n return parsed.success ? commentLists(event, reads, parsed.data.data) : [];\n};\n\nconst commentUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentUpdated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n if (comment.status !== 'published' || comment.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n commentBase('mention', place, comment.id, comment.orgUserId, {\n authorName: await reads.displayName(orgId, comment.orgUserId),\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n }),\n comment.mentionedOrgUserIds,\n placeReach(\n reads,\n orgId,\n place,\n [comment.orgUserId, actorOr(event, comment.orgUserId)],\n eventAt(event),\n ),\n );\n};\n\nconst commentRemoved: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentRemoved.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const comment = parsed.data.data;\n const remover = comment.removedBy ?? actorOr(event, null);\n if (!remover || remover === comment.orgUserId) {\n return [];\n }\n const orgId = event.orgId;\n const place = await placeOf(reads, orgId, comment);\n if (!place) {\n return [];\n }\n return listOf(\n commentBase('comment.removed', place, comment.id, remover, {}),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'subject'),\n placeReach(reads, orgId, place, [remover], eventAt(event)),\n ),\n );\n};\n\nconst commentReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, reaction.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n return listOf(\n commentBase('comment.reacted', place, reaction.commentId, reaction.orgUserId, {\n excerpt: await textExcerpt(reads, orgId, comment.body, POST_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n }),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([comment.orgUserId], 'comment_author'),\n placeReach(reads, orgId, place, [reaction.orgUserId, actorOr(event, null)], eventAt(event)),\n ),\n );\n};\n\nconst postReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.postReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const post = await reads.post(orgId, flag.postId);\n const space = post ? await reads.space(orgId, post.spaceId) : null;\n if (!post || !space) {\n return [];\n }\n return listOf(\n {\n type: 'content.flagged',\n scope: 'space',\n actorId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: post.spaceId,\n subject: { type: 'post', id: flag.postId },\n parent: null,\n display: {\n spaceName: space.name,\n excerpt: await textExcerpt(\n reads,\n orgId,\n reads.postText(post.body) || post.title,\n POST_EXCERPT,\n ),\n reason: flag.reason,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, flag.communityId), 'moderator'),\n {\n exclude: [actorOr(event, flag.orgUserId)],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, post.spaceId, orgUserIds),\n },\n ),\n );\n};\n\nconst commentReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.commentReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const comment = await reads.comment(orgId, flag.commentId);\n const place = comment ? await placeOf(reads, orgId, comment) : null;\n if (!comment || !place) {\n return [];\n }\n const actor = actorOr(event, flag.orgUserId);\n const text = await textExcerpt(reads, orgId, comment.body, POST_EXCERPT);\n if (place.kind === 'post') {\n return listOf(\n {\n ...commentBase('content.flagged', place, flag.commentId, actor, {}),\n display: { spaceName: place.spaceName, excerpt: text, reason: flag.reason },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n await communityModerators(reads, orgId, place.post.communityId),\n 'moderator',\n ),\n {\n exclude: [actor],\n at: eventAt(event),\n canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, place.post.spaceId, orgUserIds),\n },\n ),\n );\n }\n return listOf(\n commentBase('content.flagged', place, flag.commentId, actor, {\n excerpt: text,\n reason: flag.reason,\n }),\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n await reads.holders(orgId, 'courses:moderate', place.activity.courseId),\n 'moderator',\n ),\n { exclude: [actor], at: eventAt(event) },\n ),\n );\n};\n\nfunction chatPending(event: DomainEvent, status: string): boolean {\n const value = event.metadata?.[CHAT_STATUS];\n return (typeof value === 'string' ? value : status) === 'pending';\n}\n\nasync function chatMentions(\n event: DomainEvent,\n reads: NotificationReads,\n message: { id: string; chatId: string; orgUserId: string; body: string },\n mentioned: string[],\n): Promise<RecipientList[]> {\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n return mentionsOf(\n reads,\n orgId,\n {\n scope: 'chat',\n actorId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n authorName: await reads.displayName(orgId, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n },\n },\n mentioned,\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n );\n}\n\nexport function messageSummary(count: number): string {\n return count === 1 ? '1 new message' : `${count} new messages`;\n}\n\nconst messageSent: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageSent.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const message = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, message.chatId);\n if (!chat || chatPending(event, chat.status)) {\n return [];\n }\n const senderName = await reads.displayName(orgId, message.orgUserId);\n const sent = listOf(\n {\n type: 'message.sent',\n scope: 'chat',\n actorId: message.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: message.id },\n parent: { type: 'chat', id: message.chatId },\n display: {\n senderName,\n chatTitle: await chatTitle(reads, orgId, chat, message.orgUserId),\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n count: '1',\n summary: messageSummary(1),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(\n chat.participants.map((participant) => participant.orgUserId),\n 'participant',\n ),\n chatReach(reads, orgId, chat, message.chatId, message.orgUserId, eventAt(event)),\n ),\n );\n return [...sent, ...(await chatMentions(event, reads, message, message.mentionedOrgUserIds))];\n};\n\nconst messageUpdated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageUpdated.safeParse(event);\n if (!parsed.success || parsed.data.data.mentionedOrgUserIds.length === 0) {\n return [];\n }\n const message = parsed.data.data;\n return chatMentions(event, reads, message, message.mentionedOrgUserIds);\n};\n\nconst messageReacted: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReactionAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const reaction = parsed.data.data;\n const orgId = event.orgId;\n const [message, chat] = await Promise.all([\n reads.message(orgId, reaction.messageId),\n reads.chat(orgId, reaction.chatId),\n ]);\n if (!message || !chat) {\n return [];\n }\n return listOf(\n {\n type: 'message.reacted',\n scope: 'chat',\n actorId: reaction.orgUserId,\n communityId: chat.communityId,\n spaceId: null,\n subject: { type: 'message', id: reaction.messageId },\n parent: { type: 'chat', id: reaction.chatId },\n display: {\n excerpt: await textExcerpt(reads, orgId, message.body, MESSAGE_EXCERPT),\n reactorName: await reads.displayName(orgId, reaction.orgUserId),\n reaction: reaction.reaction,\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([message.orgUserId], 'message_author'),\n chatReach(reads, orgId, chat, reaction.chatId, reaction.orgUserId, eventAt(event)),\n ),\n );\n};\n\nconst messageReported: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.messageReported.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const flag = parsed.data.data;\n const orgId = event.orgId;\n const message = await reads.message(orgId, flag.messageId);\n return listOf(\n {\n type: 'message.flagged',\n scope: 'chat',\n actorId: flag.orgUserId,\n communityId: flag.communityId,\n spaceId: null,\n subject: { type: 'message', id: flag.messageId },\n parent: message ? { type: 'chat', id: message.chatId } : null,\n display: { reason: flag.reason },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(await communityModerators(reads, orgId, flag.communityId), 'moderator'),\n { exclude: [actorOr(event, flag.orgUserId)], at: eventAt(event) },\n ),\n );\n};\n\nconst chatCreated: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatCreated.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const created = parsed.data.data;\n if (created.kind !== 'direct' || created.status !== 'pending' || !created.createdBy) {\n return [];\n }\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, created.id);\n if (!chat) {\n return [];\n }\n const body = await reads.latestMessageBody(orgId, created.id);\n return listOf(\n {\n type: 'chat.request',\n scope: 'chat',\n actorId: created.createdBy,\n communityId: created.communityId,\n spaceId: null,\n subject: { type: 'chat', id: created.id },\n parent: null,\n display: {\n senderName: await reads.displayName(orgId, created.createdBy),\n excerpt: await textExcerpt(reads, orgId, body ?? '', MESSAGE_EXCERPT),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add(created.participantIds, 'participant'),\n chatReach(reads, orgId, chat, created.id, created.createdBy, eventAt(event)),\n ),\n );\n};\n\nconst chatParticipantAdded: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.chatParticipantAdded.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const added = parsed.data.data;\n const orgId = event.orgId;\n const chat = await reads.chat(orgId, added.chatId);\n if (!chat) {\n return [];\n }\n return listOf(\n {\n type: 'chat.added',\n scope: 'chat',\n actorId: added.addedBy,\n communityId: added.communityId,\n spaceId: null,\n subject: { type: 'chat', id: added.chatId },\n parent: null,\n display: {\n adderName: await reads.displayName(orgId, added.addedBy),\n participantNames: await participantNames(reads, orgId, chat),\n },\n },\n await recipientsOf(\n reads,\n orgId,\n new Reasons().add([added.orgUserId], 'subject'),\n chatReach(reads, orgId, chat, added.chatId, added.addedBy, eventAt(event)),\n ),\n );\n};\n\nconst digestDue: RecipientRule = async (event, reads) => {\n const parsed = discussionEvents.digestDue.safeParse(event);\n if (!parsed.success) {\n return [];\n }\n const { communityId, from, to } = parsed.data.data;\n const orgId = event.orgId;\n const posts = await reads.postsPublished(orgId, communityId, from, to);\n if (posts.length === 0) {\n return [];\n }\n const title = await reads.communityTitle(orgId, communityId);\n if (title === null) {\n return [];\n }\n const spaceIds = [...new Set(posts.map((post) => post.spaceId))];\n const openers = new Map<string, Set<string>>();\n for (const spaceId of spaceIds) {\n const open = await reads.spaceOpeners(orgId, spaceId);\n const muted = new Set(\n open.length > 0\n ? await reads.mutedAmong(orgId, { type: 'space', id: spaceId }, open, eventAt(event))\n : [],\n );\n openers.set(spaceId, new Set(open.filter((orgUserId) => !muted.has(orgUserId))));\n }\n const groups = new Map<string, { spaceIds: string[]; members: Reasons }>();\n for (const orgUserId of await reads.communityMembers(orgId, communityId)) {\n const open = spaceIds.filter((spaceId) => openers.get(spaceId)?.has(orgUserId));\n if (open.length === 0) {\n continue;\n }\n const key = open.join(' ');\n const group = groups.get(key) ?? { spaceIds: open, members: new Reasons() };\n group.members.add([orgUserId], 'community_member');\n groups.set(key, group);\n }\n const lists: RecipientList[] = [];\n for (const group of groups.values()) {\n const shown = posts.filter((post) => group.spaceIds.includes(post.spaceId));\n lists.push(\n ...listOf(\n {\n type: 'digest',\n scope: 'community',\n actorId: null,\n communityId,\n spaceId: null,\n subject: { type: 'community', id: communityId },\n parent: null,\n display: {\n communityTitle: title,\n from: from.toISOString(),\n to: to.toISOString(),\n posts: shown.map((post) => ({\n postId: post.postId,\n title: post.title,\n authorName: post.authorName,\n spaceName: post.spaceName,\n commentCount: post.commentCount,\n })),\n },\n },\n await recipientsOf(reads, orgId, group.members, { exclude: [], at: eventAt(event) }),\n ),\n );\n }\n return lists;\n};\n\nexport const DISCUSSION_RULES: Record<string, RecipientRule> = {\n 'discussion.post.published': postPublished,\n 'discussion.post.created': postCreated,\n 'discussion.post.updated': postUpdated,\n 'discussion.post.removed': postRemoved,\n 'discussion.post.reaction.added': postReacted,\n 'discussion.comment.created': commentCreated,\n 'discussion.comment.published': commentPublished,\n 'discussion.comment.updated': commentUpdated,\n 'discussion.comment.removed': commentRemoved,\n 'discussion.comment.reaction.added': commentReacted,\n 'discussion.post.reported': postReported,\n 'discussion.comment.reported': commentReported,\n 'discussion.message.sent': messageSent,\n 'discussion.message.updated': messageUpdated,\n 'discussion.message.reaction.added': messageReacted,\n 'discussion.message.reported': messageReported,\n 'discussion.chat.created': chatCreated,\n 'discussion.chat.participant.added': chatParticipantAdded,\n 'discussion.digest.due': digestDue,\n};\n"],"mappings":"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"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { entitlementEvents } from "../../../entitlements/events.js";
|
|
2
|
-
import { previousStatusOf } from "../../community-mail.js";
|
|
2
|
+
import { communityModerators, previousStatusOf } from "../../community-mail.js";
|
|
3
3
|
import { Reasons, actorOr, eventAt, listOf, recipientsOf } from "./recipients.js";
|
|
4
|
+
import { eventBase, eventDisplay } from "./events.js";
|
|
4
5
|
//#region src/automations/notifications/rules/entitlements.ts
|
|
5
6
|
function seatsLeft(capacity, active) {
|
|
6
7
|
return capacity == null ? "No cap" : String(Math.max(capacity - active, 0));
|
|
@@ -50,7 +51,7 @@ async function membershipEnded(event, reads, grant, ref) {
|
|
|
50
51
|
return listOf({
|
|
51
52
|
type: "community.membership_ended",
|
|
52
53
|
scope: "org",
|
|
53
|
-
|
|
54
|
+
actorId: actorOr(event, null),
|
|
54
55
|
communityId: null,
|
|
55
56
|
spaceId: null,
|
|
56
57
|
subject: ref,
|
|
@@ -58,14 +59,14 @@ async function membershipEnded(event, reads, grant, ref) {
|
|
|
58
59
|
display: { communities }
|
|
59
60
|
}, await subjectOnly(event, reads, grant.orgUserId));
|
|
60
61
|
}
|
|
61
|
-
async function spaceBase(reads, orgId, member, type,
|
|
62
|
+
async function spaceBase(reads, orgId, member, type, actorId) {
|
|
62
63
|
const space = await reads.space(orgId, member.spaceId);
|
|
63
64
|
return space ? {
|
|
64
65
|
space,
|
|
65
66
|
base: {
|
|
66
67
|
type,
|
|
67
68
|
scope: "space",
|
|
68
|
-
|
|
69
|
+
actorId,
|
|
69
70
|
communityId: member.communityId,
|
|
70
71
|
spaceId: member.spaceId,
|
|
71
72
|
subject: {
|
|
@@ -93,7 +94,7 @@ const spaceMemberCreated = async (event, reads) => {
|
|
|
93
94
|
memberName: await reads.displayName(orgId, member.orgUserId),
|
|
94
95
|
seatsLeft: seatsLeft(found.space.capacity, active)
|
|
95
96
|
}
|
|
96
|
-
}, await recipientsOf(reads, orgId, new Reasons().add(await reads
|
|
97
|
+
}, await recipientsOf(reads, orgId, new Reasons().add(await communityModerators(reads, orgId, member.communityId), "moderator"), {
|
|
97
98
|
exclude: [member.orgUserId, actorOr(event, null)],
|
|
98
99
|
at: eventAt(event),
|
|
99
100
|
canOpen: (orgUserIds) => reads.spaceOpenersAmong(orgId, member.spaceId, orgUserIds)
|
|
@@ -141,12 +142,26 @@ const spaceMemberDeleted = async (event, reads) => {
|
|
|
141
142
|
}
|
|
142
143
|
}, await subjectOnly(event, reads, member.orgUserId)) : [];
|
|
143
144
|
};
|
|
145
|
+
async function grantedEvent(reads, orgId, grant) {
|
|
146
|
+
return grant.contentId ? reads.event(orgId, grant.contentId) : null;
|
|
147
|
+
}
|
|
144
148
|
const entitlementCreated = async (event, reads) => {
|
|
145
149
|
const parsed = entitlementEvents.entitlementCreated.safeParse(event);
|
|
146
150
|
if (!parsed.success) return [];
|
|
147
151
|
const grant = parsed.data.data;
|
|
148
152
|
const orgId = event.orgId;
|
|
149
153
|
const actor = actorOr(event, null);
|
|
154
|
+
const granted = await grantedEvent(reads, orgId, grant);
|
|
155
|
+
if (granted) {
|
|
156
|
+
if (!granted.settings.notifications) return [];
|
|
157
|
+
return listOf({
|
|
158
|
+
...eventBase("event.granted", granted, actor),
|
|
159
|
+
display: eventDisplay(granted)
|
|
160
|
+
}, await recipientsOf(reads, orgId, new Reasons().add([grant.orgUserId], "event_member"), {
|
|
161
|
+
exclude: [],
|
|
162
|
+
at: eventAt(event)
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
150
165
|
const subject = await subjectOnly(event, reads, grant.orgUserId);
|
|
151
166
|
if (subject.length === 0) return [];
|
|
152
167
|
const lists = [];
|
|
@@ -154,7 +169,7 @@ const entitlementCreated = async (event, reads) => {
|
|
|
154
169
|
if (target) lists.push(...listOf({
|
|
155
170
|
type: "access.granted",
|
|
156
171
|
scope: "org",
|
|
157
|
-
|
|
172
|
+
actorId: actor,
|
|
158
173
|
communityId: null,
|
|
159
174
|
spaceId: null,
|
|
160
175
|
subject: target.ref,
|
|
@@ -170,7 +185,7 @@ const entitlementCreated = async (event, reads) => {
|
|
|
170
185
|
lists.push(...listOf({
|
|
171
186
|
type: "community.welcome",
|
|
172
187
|
scope: "community",
|
|
173
|
-
|
|
188
|
+
actorId: actor,
|
|
174
189
|
communityId,
|
|
175
190
|
spaceId: null,
|
|
176
191
|
subject: {
|
|
@@ -195,7 +210,7 @@ const entitlementEndingSoon = async (event, reads) => {
|
|
|
195
210
|
return listOf({
|
|
196
211
|
type: "community.ending_soon",
|
|
197
212
|
scope: "community",
|
|
198
|
-
|
|
213
|
+
actorId: null,
|
|
199
214
|
communityId: grant.communityId,
|
|
200
215
|
spaceId: null,
|
|
201
216
|
subject: {
|
|
@@ -213,6 +228,18 @@ const entitlementDeleted = async (event, reads) => {
|
|
|
213
228
|
const parsed = entitlementEvents.entitlementDeleted.safeParse(event);
|
|
214
229
|
if (!parsed.success) return [];
|
|
215
230
|
const grant = parsed.data.data;
|
|
231
|
+
const revokedFrom = await grantedEvent(reads, event.orgId, grant);
|
|
232
|
+
if (revokedFrom) {
|
|
233
|
+
if (!revokedFrom.settings.notifications || !(await reads.contentLostBy(event.orgId, grant)).includes(revokedFrom.id)) return [];
|
|
234
|
+
const actor = actorOr(event, null);
|
|
235
|
+
return listOf({
|
|
236
|
+
...eventBase("event.revoked", revokedFrom, actor),
|
|
237
|
+
display: eventDisplay(revokedFrom)
|
|
238
|
+
}, await recipientsOf(reads, event.orgId, new Reasons().add([grant.orgUserId], "event_member"), {
|
|
239
|
+
exclude: [actor],
|
|
240
|
+
at: eventAt(event)
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
216
243
|
const target = await grantSubject(reads, event.orgId, grant);
|
|
217
244
|
const ended = await membershipEnded(event, reads, grant, target?.ref ?? null);
|
|
218
245
|
if (ended) return ended;
|
|
@@ -220,7 +247,7 @@ const entitlementDeleted = async (event, reads) => {
|
|
|
220
247
|
return listOf({
|
|
221
248
|
type: "access.revoked",
|
|
222
249
|
scope: "org",
|
|
223
|
-
|
|
250
|
+
actorId: actorOr(event, null),
|
|
224
251
|
communityId: null,
|
|
225
252
|
spaceId: null,
|
|
226
253
|
subject: target.ref,
|