@headless-lms/core 0.3.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 +24 -18
- 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 +5 -4
- package/dist/assets/index.js +4 -3
- package/dist/assets/jobs.d.ts +15 -0
- package/dist/assets/jobs.js +30 -0
- package/dist/assets/jobs.js.map +1 -0
- package/dist/assets/ports.d.ts +37 -17
- package/dist/assets/service.d.ts +30 -15
- package/dist/assets/service.js +229 -59
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.js +2 -63
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +1 -2
- package/dist/automations/catalog.js +137 -65
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.js +20 -20
- package/dist/automations/community-derivations.js.map +1 -1
- package/dist/automations/community-mail.d.ts +36 -20
- package/dist/automations/community-mail.js +32 -24
- 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/events.d.ts +0 -10
- package/dist/automations/index.d.ts +12 -4
- package/dist/automations/index.js +9 -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.d.ts +25 -0
- package/dist/automations/notifications/debounce.js +93 -0
- package/dist/automations/notifications/debounce.js.map +1 -0
- package/dist/automations/notifications/defaults.d.ts +8 -0
- package/dist/automations/notifications/defaults.js +346 -0
- package/dist/automations/notifications/defaults.js.map +1 -0
- package/dist/automations/notifications/delivery.d.ts +28 -0
- package/dist/automations/notifications/delivery.js +88 -0
- package/dist/automations/notifications/delivery.js.map +1 -0
- package/dist/automations/notifications/processor.d.ts +64 -0
- package/dist/automations/notifications/processor.js +270 -0
- package/dist/automations/notifications/processor.js.map +1 -0
- package/dist/automations/notifications/rules/content.d.ts +6 -0
- package/dist/automations/notifications/rules/content.js +96 -0
- package/dist/automations/notifications/rules/content.js.map +1 -0
- package/dist/automations/notifications/rules/discussion.d.ts +7 -0
- package/dist/automations/notifications/rules/discussion.js +678 -0
- package/dist/automations/notifications/rules/discussion.js.map +1 -0
- package/dist/automations/notifications/rules/entitlements.d.ts +6 -0
- package/dist/automations/notifications/rules/entitlements.js +276 -0
- package/dist/automations/notifications/rules/entitlements.js.map +1 -0
- 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/index.d.ts +6 -0
- package/dist/automations/notifications/rules/index.js +15 -0
- package/dist/automations/notifications/rules/index.js.map +1 -0
- package/dist/automations/notifications/rules/organizations.d.ts +6 -0
- package/dist/automations/notifications/rules/organizations.js +35 -0
- package/dist/automations/notifications/rules/organizations.js.map +1 -0
- package/dist/automations/notifications/rules/recipients.d.ts +32 -0
- package/dist/automations/notifications/rules/recipients.js +98 -0
- package/dist/automations/notifications/rules/recipients.js.map +1 -0
- package/dist/automations/notifications/service.d.ts +29 -0
- package/dist/automations/notifications/service.js +45 -0
- package/dist/automations/notifications/service.js.map +1 -0
- package/dist/automations/notifications/types.d.ts +7 -0
- package/dist/automations/notifications/types.js +560 -0
- package/dist/automations/notifications/types.js.map +1 -0
- package/dist/automations/ports.d.ts +134 -21
- package/dist/automations/service.d.ts +30 -30
- package/dist/automations/service.js +111 -144
- 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 +437 -46
- package/dist/content/events.js +45 -1
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +8 -4
- package/dist/content/index.js +5 -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 +37 -0
- package/dist/content/notification-categories.js +73 -0
- package/dist/content/notification-categories.js.map +1 -0
- package/dist/content/ports.d.ts +132 -68
- package/dist/content/service.d.ts +100 -68
- package/dist/content/service.js +703 -146
- package/dist/content/service.js.map +1 -1
- package/dist/content/titles.d.ts +25 -0
- package/dist/content/titles.js +82 -0
- package/dist/content/titles.js.map +1 -0
- 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 +63 -39
- package/dist/discussion/chats.js +455 -190
- package/dist/discussion/chats.js.map +1 -1
- package/dist/discussion/digests.d.ts +24 -0
- package/dist/discussion/digests.js +104 -0
- package/dist/discussion/digests.js.map +1 -0
- package/dist/discussion/events.d.ts +227 -23
- package/dist/discussion/events.js +114 -19
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +12 -4
- package/dist/discussion/index.js +9 -2
- package/dist/discussion/jobs.d.ts +16 -0
- package/dist/discussion/jobs.js +40 -0
- package/dist/discussion/jobs.js.map +1 -0
- 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.d.ts +11 -0
- package/dist/discussion/mentions.js +35 -0
- package/dist/discussion/mentions.js.map +1 -0
- package/dist/discussion/ports.d.ts +279 -114
- package/dist/discussion/ports.js.map +1 -1
- package/dist/discussion/posts.d.ts +60 -44
- package/dist/discussion/posts.js +453 -287
- 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 +50 -35
- package/dist/discussion/service.js +333 -205
- package/dist/discussion/service.js.map +1 -1
- package/dist/discussion/subscriptions.d.ts +37 -0
- package/dist/discussion/subscriptions.js +115 -0
- package/dist/discussion/subscriptions.js.map +1 -0
- package/dist/discussion/titles.d.ts +28 -0
- package/dist/discussion/titles.js +98 -0
- package/dist/discussion/titles.js.map +1 -0
- package/dist/entitlements/events.d.ts +20 -20
- package/dist/entitlements/index.d.ts +5 -4
- package/dist/entitlements/index.js +3 -2
- package/dist/entitlements/jobs.d.ts +12 -0
- package/dist/entitlements/jobs.js +18 -0
- package/dist/entitlements/jobs.js.map +1 -0
- package/dist/entitlements/model.d.ts +2 -2
- package/dist/entitlements/ports.d.ts +68 -38
- 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 +43 -28
- package/dist/entitlements/service.js +387 -160
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/devices.d.ts +30 -0
- package/dist/identity/devices.js +109 -0
- package/dist/identity/devices.js.map +1 -0
- package/dist/identity/index.d.ts +6 -5
- package/dist/identity/index.js +4 -3
- package/dist/identity/model.d.ts +2 -2
- package/dist/identity/notification-settings.d.ts +28 -0
- package/dist/identity/notification-settings.js +114 -0
- package/dist/identity/notification-settings.js.map +1 -0
- package/dist/identity/ports.d.ts +80 -56
- 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/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 +15 -10
- package/dist/organizations/index.js +8 -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 +34 -0
- package/dist/organizations/notification-categories.js +66 -0
- package/dist/organizations/notification-categories.js.map +1 -0
- 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 +187 -65
- package/dist/organizations/service.d.ts +104 -35
- package/dist/organizations/service.js +1247 -323
- 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/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 +80 -26
- package/dist/reporting/member/ports.d.ts +50 -28
- package/dist/reporting/member/service.d.ts +81 -35
- package/dist/reporting/member/service.js +438 -145
- package/dist/reporting/member/service.js.map +1 -1
- package/dist/shared/actor.d.ts +22 -3
- package/dist/shared/errors.d.ts +15 -2
- package/dist/shared/errors.js +21 -2
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/id.d.ts +7 -0
- package/dist/shared/id.js +8 -1
- 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/mailer.d.ts +11 -1
- package/dist/shared/mailer.js +32 -5
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/notification-categories.d.ts +16 -0
- package/dist/shared/notification-categories.js +94 -0
- package/dist/shared/notification-categories.js.map +1 -0
- package/dist/shared/notification-settings.d.ts +14 -0
- package/dist/shared/notification-settings.js +61 -0
- package/dist/shared/notification-settings.js.map +1 -0
- package/dist/shared/ports.d.ts +68 -2
- package/dist/shared/settings.d.ts +2 -1
- package/dist/shared/settings.js +1 -0
- package/dist/shared/settings.js.map +1 -1
- package/dist/types/automations.d.ts +8 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +4 -5
- package/dist/types/email-templates.d.ts +119 -6
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/identity.d.ts +14 -17
- package/dist/types/index.d.ts +13 -12
- package/dist/types/index.js +2 -1
- package/dist/types/notifications.d.ts +157 -0
- package/dist/types/notifications.js +1 -0
- 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/automations.d.ts +1 -10
- package/dist/types/schemas/automations.js +1 -3
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +596 -11
- package/dist/types/schemas/content.js +225 -9
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +362 -66
- package/dist/types/schemas/discussion.js +123 -15
- 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/identity.d.ts +1 -85
- package/dist/types/schemas/identity.js +1 -42
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +8 -7
- package/dist/types/schemas/index.js +8 -7
- package/dist/types/schemas/notifications.d.ts +96 -0
- package/dist/types/schemas/notifications.js +57 -0
- package/dist/types/schemas/notifications.js.map +1 -0
- 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 +0 -1
- package/dist/types/schemas/progress.js +0 -1
- package/dist/types/schemas/progress.js.map +1 -1
- package/package.json +1 -1
- package/dist/automations/community-notifications.d.ts +0 -16
- package/dist/automations/community-notifications.js +0 -84
- package/dist/automations/community-notifications.js.map +0 -1
- package/dist/automations/seeds.d.ts +0 -17
- package/dist/automations/seeds.js +0 -235
- package/dist/automations/seeds.js.map +0 -1
- package/dist/identity/notifications.d.ts +0 -27
- package/dist/identity/notifications.js +0 -101
- package/dist/identity/notifications.js.map +0 -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,16 +1,45 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { PERMISSION_KEYS } from "../../types/schemas/organizations.js";
|
|
2
|
+
import { NotFoundError } from "../../shared/errors.js";
|
|
2
3
|
import { seesSpace } from "../../entitlements/rules.js";
|
|
4
|
+
import { channelOrder } from "../../shared/notification-categories.js";
|
|
5
|
+
import { eventSight } from "../../content/event-sight.js";
|
|
6
|
+
import { resolveChannels } from "../../shared/notification-settings.js";
|
|
7
|
+
import { applicableCategories } from "../../automations/notifications/applicable.js";
|
|
8
|
+
import { attendeeFace, attendeeView } from "../events/index.js";
|
|
9
|
+
import { eventCalendar } from "./calendar.js";
|
|
3
10
|
//#region src/reporting/member/service.ts
|
|
4
|
-
function ref
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
function refKey(ref) {
|
|
12
|
+
return `${ref.type}:${ref.id}`;
|
|
13
|
+
}
|
|
14
|
+
function itemView(ref, titles) {
|
|
15
|
+
const found = ref ? titles[refKey(ref)] : void 0;
|
|
16
|
+
if (!ref || !found) return null;
|
|
17
|
+
return found.excerpt !== void 0 ? {
|
|
18
|
+
type: ref.type,
|
|
19
|
+
id: ref.id,
|
|
20
|
+
excerpt: found.excerpt
|
|
21
|
+
} : {
|
|
22
|
+
type: ref.type,
|
|
23
|
+
id: ref.id,
|
|
24
|
+
title: found.title
|
|
25
|
+
};
|
|
10
26
|
}
|
|
11
27
|
function isActivityPublished(settings) {
|
|
12
28
|
return settings?.published !== false;
|
|
13
29
|
}
|
|
30
|
+
const READ_OF = {
|
|
31
|
+
course: "courses:read",
|
|
32
|
+
download: "downloads:read",
|
|
33
|
+
community: "communities:read",
|
|
34
|
+
event: "events:read"
|
|
35
|
+
};
|
|
36
|
+
const THUMBNAIL_OF = {
|
|
37
|
+
course: "Course thumbnail",
|
|
38
|
+
download: "Download thumbnail",
|
|
39
|
+
community: "Community thumbnail",
|
|
40
|
+
event: "Event thumbnail"
|
|
41
|
+
};
|
|
42
|
+
const EVENT_FACES = 10;
|
|
14
43
|
var MemberReportServiceImpl = class {
|
|
15
44
|
repo;
|
|
16
45
|
content;
|
|
@@ -18,9 +47,15 @@ var MemberReportServiceImpl = class {
|
|
|
18
47
|
files;
|
|
19
48
|
fileUrls;
|
|
20
49
|
access;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
50
|
+
people;
|
|
51
|
+
notificationList;
|
|
52
|
+
titles;
|
|
53
|
+
subscriptions;
|
|
54
|
+
notificationCategories;
|
|
55
|
+
notificationSettings;
|
|
56
|
+
channels;
|
|
57
|
+
studentPortalUrl;
|
|
58
|
+
now;
|
|
24
59
|
constructor(params) {
|
|
25
60
|
this.repo = params.repo;
|
|
26
61
|
this.content = params.content;
|
|
@@ -28,96 +63,197 @@ var MemberReportServiceImpl = class {
|
|
|
28
63
|
this.files = params.files;
|
|
29
64
|
this.fileUrls = params.fileUrls;
|
|
30
65
|
this.access = params.access;
|
|
31
|
-
this.
|
|
32
|
-
this.
|
|
33
|
-
this.
|
|
66
|
+
this.people = params.people;
|
|
67
|
+
this.notificationList = params.notifications;
|
|
68
|
+
this.titles = params.titles;
|
|
69
|
+
this.subscriptions = params.subscriptions;
|
|
70
|
+
this.notificationCategories = params.notificationCategories;
|
|
71
|
+
this.notificationSettings = params.notificationSettings;
|
|
72
|
+
this.channels = params.channels;
|
|
73
|
+
this.studentPortalUrl = params.studentPortalUrl.replace(/\/+$/, "");
|
|
74
|
+
this.now = params.now ?? (() => /* @__PURE__ */ new Date());
|
|
75
|
+
}
|
|
76
|
+
system(actor) {
|
|
77
|
+
return this.people.systemActor(actor.orgId);
|
|
78
|
+
}
|
|
79
|
+
viewer(actor) {
|
|
80
|
+
const role = actor.permissions.roleOn();
|
|
81
|
+
return {
|
|
82
|
+
orgUserId: actor.id,
|
|
83
|
+
orgRole: {
|
|
84
|
+
key: role.key,
|
|
85
|
+
name: role.name
|
|
86
|
+
},
|
|
87
|
+
permissions: PERMISSION_KEYS.filter((p) => actor.permissions.anywhere(p)),
|
|
88
|
+
orgPermissions: PERMISSION_KEYS.filter((p) => actor.permissions.has(p))
|
|
89
|
+
};
|
|
34
90
|
}
|
|
35
|
-
async
|
|
36
|
-
|
|
91
|
+
async communityNotificationSettings(communityId, actor) {
|
|
92
|
+
if (!await this.access.isCommunityMember(communityId, actor)) throw new NotFoundError("Community", communityId);
|
|
93
|
+
const orgId = actor.orgId;
|
|
94
|
+
const system = this.system(actor);
|
|
95
|
+
const [list, settings, spaceIds, spaces, community] = await Promise.all([
|
|
96
|
+
this.notificationCategories.community.get(communityId, system),
|
|
97
|
+
this.notificationSettings.get(orgId, actor.userId, { communityId }),
|
|
98
|
+
this.access.openSpaceIds(communityId, actor),
|
|
99
|
+
this.content.listSpaces(communityId, system),
|
|
100
|
+
this.content.findCommunity(communityId, system)
|
|
101
|
+
]);
|
|
102
|
+
const open = new Set(spaceIds);
|
|
37
103
|
return {
|
|
38
|
-
|
|
39
|
-
|
|
104
|
+
communityId,
|
|
105
|
+
digest: community?.settings.digest ?? null,
|
|
106
|
+
categories: this.settingsView(applicableCategories(list.categories, actor.permissions, { communityId }), settings, spaces.filter((space) => open.has(space.id)).map((space) => ({
|
|
107
|
+
spaceId: space.id,
|
|
108
|
+
name: space.name
|
|
109
|
+
})))
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
async orgNotificationSettings(actor) {
|
|
113
|
+
const orgId = actor.orgId;
|
|
114
|
+
const [list, settings] = await Promise.all([this.notificationCategories.org.get(orgId, this.system(actor)), this.notificationSettings.get(orgId, actor.userId, "org")]);
|
|
115
|
+
return { categories: this.settingsView(applicableCategories(list.categories, actor.permissions, "org"), settings, []) };
|
|
116
|
+
}
|
|
117
|
+
settingsView(categories, settings, spaces) {
|
|
118
|
+
const configured = channelOrder(this.channels.list());
|
|
119
|
+
const channelsAt = (category, spaceId) => {
|
|
120
|
+
const withoutLevel = settings.filter((setting) => setting.category !== category.key || setting.spaceId !== spaceId);
|
|
121
|
+
const fallback = new Map(resolveChannels(category, withoutLevel, spaceId, configured).map((resolved) => [resolved.channel, resolved.enabled]));
|
|
122
|
+
return resolveChannels(category, settings, spaceId, configured).map((resolved) => ({
|
|
123
|
+
...resolved,
|
|
124
|
+
default: fallback.get(resolved.channel) ?? resolved.enabled
|
|
125
|
+
}));
|
|
126
|
+
};
|
|
127
|
+
return categories.map((category) => {
|
|
128
|
+
const perSpace = category.perSpace === true;
|
|
129
|
+
const view = {
|
|
130
|
+
key: category.key,
|
|
131
|
+
perSpace,
|
|
132
|
+
channels: channelsAt(category, null)
|
|
133
|
+
};
|
|
134
|
+
if (perSpace) view.spaces = spaces.map(({ spaceId, name }) => ({
|
|
135
|
+
spaceId,
|
|
136
|
+
name,
|
|
137
|
+
channels: channelsAt(category, spaceId)
|
|
138
|
+
}));
|
|
139
|
+
return view;
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
async notifications(filter, page, actor) {
|
|
143
|
+
const listed = await this.notificationList.list(filter, page, actor);
|
|
144
|
+
return {
|
|
145
|
+
rows: await this.describeNotifications(actor, listed.items),
|
|
146
|
+
total: listed.total,
|
|
40
147
|
page: page.page,
|
|
41
148
|
pageSize: page.pageSize,
|
|
42
|
-
unreadCount:
|
|
149
|
+
unreadCount: listed.unreadCount
|
|
43
150
|
};
|
|
44
151
|
}
|
|
45
|
-
async
|
|
46
|
-
const
|
|
152
|
+
async notification(notificationId, actor) {
|
|
153
|
+
const found = await this.notificationList.get(notificationId, actor);
|
|
154
|
+
const [view] = found ? await this.describeNotifications(actor, [found]) : [];
|
|
155
|
+
if (!view) throw new NotFoundError("Notification", notificationId);
|
|
47
156
|
return view;
|
|
48
157
|
}
|
|
49
|
-
async
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
158
|
+
async notificationUnreadCounts(actor) {
|
|
159
|
+
const communityIds = await this.access.openCommunityIds(actor);
|
|
160
|
+
return this.notificationList.unreadCounts(communityIds, actor);
|
|
161
|
+
}
|
|
162
|
+
async describeNotifications(actor, rows) {
|
|
163
|
+
const orgId = actor.orgId;
|
|
164
|
+
const refs = rows.flatMap((row) => [
|
|
165
|
+
...row.subject ? [row.subject] : [],
|
|
166
|
+
...row.parent ? [row.parent] : [],
|
|
167
|
+
...row.communityId ? [{
|
|
168
|
+
type: "community",
|
|
169
|
+
id: row.communityId
|
|
170
|
+
}] : [],
|
|
171
|
+
...row.spaceId ? [{
|
|
172
|
+
type: "space",
|
|
173
|
+
id: row.spaceId
|
|
174
|
+
}] : []
|
|
175
|
+
]);
|
|
176
|
+
const actorIds = [...new Set(rows.flatMap((row) => row.actorId ?? []))];
|
|
177
|
+
const [people, discussionTitles, contentTitles] = await Promise.all([
|
|
178
|
+
this.repo.people(orgId, actorIds),
|
|
179
|
+
this.titles.discussion.titlesFor(refs, actor),
|
|
180
|
+
this.titles.content.titlesFor(refs, actor)
|
|
57
181
|
]);
|
|
182
|
+
const titles = {
|
|
183
|
+
...contentTitles,
|
|
184
|
+
...discussionTitles
|
|
185
|
+
};
|
|
58
186
|
const personById = new Map(people.map((person) => [person.orgUserId, person]));
|
|
59
|
-
const spaceById = new Map(spaces.flatMap((space) => space ? [[space.id, space.name]] : []));
|
|
60
|
-
const communityById = new Map(communities.flatMap((community) => community ? [[community.id, community.title]] : []));
|
|
61
|
-
const postById = new Map(Object.entries(postTitles));
|
|
62
|
-
const chatById = new Map(Object.entries(chatTitles));
|
|
63
187
|
return rows.map((row) => {
|
|
64
|
-
const person = row.
|
|
65
|
-
const community =
|
|
66
|
-
const space =
|
|
67
|
-
const post = ref(row.postId, postById);
|
|
68
|
-
const chat = ref(row.chatId, chatById);
|
|
188
|
+
const person = row.actorId ? personById.get(row.actorId) : void 0;
|
|
189
|
+
const community = row.communityId ? titles[`community:${row.communityId}`] : void 0;
|
|
190
|
+
const space = row.spaceId ? titles[`space:${row.spaceId}`] : void 0;
|
|
69
191
|
return {
|
|
70
192
|
id: row.id,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
193
|
+
type: row.type,
|
|
194
|
+
scope: row.scope,
|
|
195
|
+
reasons: row.reasons,
|
|
196
|
+
matchedReason: row.matchedReason,
|
|
197
|
+
category: row.category,
|
|
198
|
+
display: row.display,
|
|
199
|
+
community: row.communityId && community ? {
|
|
200
|
+
id: row.communityId,
|
|
201
|
+
title: community.title
|
|
202
|
+
} : null,
|
|
203
|
+
space: row.spaceId && space ? {
|
|
204
|
+
id: row.spaceId,
|
|
205
|
+
name: space.title
|
|
206
|
+
} : null,
|
|
74
207
|
actor: person ? {
|
|
75
208
|
orgUserId: person.orgUserId,
|
|
76
|
-
|
|
77
|
-
imageUrl: person.imageAssetId ? this.fileUrls.
|
|
209
|
+
name: person.displayName,
|
|
210
|
+
imageUrl: person.imageAssetId ? this.fileUrls.publicImage(orgId, person.orgUserId, person.imageAssetId) : null
|
|
78
211
|
} : null,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
space: space && {
|
|
84
|
-
id: space.id,
|
|
85
|
-
name: space.name
|
|
86
|
-
},
|
|
87
|
-
post: post && {
|
|
88
|
-
id: post.id,
|
|
89
|
-
title: post.name
|
|
90
|
-
},
|
|
91
|
-
commentId: row.commentId,
|
|
92
|
-
chat: chat && {
|
|
93
|
-
id: chat.id,
|
|
94
|
-
title: chat.name
|
|
95
|
-
},
|
|
96
|
-
messageId: row.messageId
|
|
212
|
+
subject: itemView(row.subject, titles),
|
|
213
|
+
parent: itemView(row.parent, titles),
|
|
214
|
+
createdAt: row.createdAt,
|
|
215
|
+
readAt: row.readAt
|
|
97
216
|
};
|
|
98
217
|
});
|
|
99
218
|
}
|
|
100
|
-
async
|
|
101
|
-
const
|
|
102
|
-
|
|
219
|
+
async opensCourse(courseId, actor) {
|
|
220
|
+
const reads = actor.permissions.has("courses:read", courseId);
|
|
221
|
+
if (!reads && !await this.access.hasAccess(actor.orgId, actor.id, courseId)) return null;
|
|
222
|
+
const course = await this.content.findCourse(courseId, this.system(actor));
|
|
223
|
+
return course && (reads || course.status === "published") ? course : null;
|
|
224
|
+
}
|
|
225
|
+
async opensDownload(downloadId, actor) {
|
|
226
|
+
const reads = actor.permissions.has("downloads:read", downloadId);
|
|
227
|
+
if (!reads && !await this.access.hasAccess(actor.orgId, actor.id, downloadId)) return null;
|
|
228
|
+
const download = await this.content.findDownload(downloadId, this.system(actor));
|
|
229
|
+
return download && (reads || download.status === "published") ? download : null;
|
|
230
|
+
}
|
|
231
|
+
async listCourses(actor) {
|
|
232
|
+
const ids = await this.access.listAccessibleContent(actor.orgId, actor.id, "course");
|
|
233
|
+
const system = this.system(actor);
|
|
234
|
+
return (await Promise.all(ids.map((id) => this.content.findCourse(id, system)))).filter((c) => c !== null && c.status === "published");
|
|
103
235
|
}
|
|
104
|
-
async
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
return course
|
|
236
|
+
async requireCourse(courseId, actor) {
|
|
237
|
+
const course = await this.opensCourse(courseId, actor);
|
|
238
|
+
if (!course) throw new NotFoundError("Course", courseId);
|
|
239
|
+
return course;
|
|
108
240
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
return this.content.listCourseModules(orgId, courseId);
|
|
241
|
+
getCourse(courseId, actor) {
|
|
242
|
+
return this.requireCourse(courseId, actor);
|
|
112
243
|
}
|
|
113
|
-
async
|
|
114
|
-
|
|
115
|
-
return
|
|
244
|
+
async listModules(courseId, actor) {
|
|
245
|
+
await this.requireCourse(courseId, actor);
|
|
246
|
+
return this.content.listCourseModules(courseId, this.system(actor));
|
|
116
247
|
}
|
|
117
|
-
async
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
248
|
+
async listActivities(courseId, actor) {
|
|
249
|
+
await this.requireCourse(courseId, actor);
|
|
250
|
+
return (await this.content.listCourseActivityViews(courseId, this.system(actor))).filter((a) => isActivityPublished(a.settings));
|
|
251
|
+
}
|
|
252
|
+
async courseProgress(courseId, actor) {
|
|
253
|
+
await this.requireCourse(courseId, actor);
|
|
254
|
+
const orgId = actor.orgId;
|
|
255
|
+
const ids = (await this.content.listCourseActivities(courseId, this.system(actor))).filter((a) => isActivityPublished(a.settings)).map((a) => a.id);
|
|
256
|
+
const records = await this.progress.listByTargets(orgId, actor.id, ids);
|
|
121
257
|
const activities = {};
|
|
122
258
|
const positions = {};
|
|
123
259
|
let done = 0;
|
|
@@ -128,7 +264,7 @@ var MemberReportServiceImpl = class {
|
|
|
128
264
|
if (r.position != null) positions[r.targetId] = r.position;
|
|
129
265
|
}
|
|
130
266
|
const courseRecord = await this.progress.get(orgId, {
|
|
131
|
-
orgUserId,
|
|
267
|
+
orgUserId: actor.id,
|
|
132
268
|
targetType: "course",
|
|
133
269
|
targetId: courseId
|
|
134
270
|
});
|
|
@@ -139,85 +275,236 @@ var MemberReportServiceImpl = class {
|
|
|
139
275
|
positions
|
|
140
276
|
};
|
|
141
277
|
}
|
|
142
|
-
async listDownloads(
|
|
143
|
-
const ids = await this.access.listAccessibleContent(orgId,
|
|
144
|
-
|
|
278
|
+
async listDownloads(actor) {
|
|
279
|
+
const ids = await this.access.listAccessibleContent(actor.orgId, actor.id, "download");
|
|
280
|
+
const system = this.system(actor);
|
|
281
|
+
return (await Promise.all(ids.map((id) => this.content.findDownload(id, system)))).filter((d) => d !== null && d.status === "published");
|
|
145
282
|
}
|
|
146
|
-
async getDownload(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (!download || download.status !== "published") return null;
|
|
283
|
+
async getDownload(downloadId, actor) {
|
|
284
|
+
const download = await this.opensDownload(downloadId, actor);
|
|
285
|
+
if (!download) throw new NotFoundError("Download", downloadId);
|
|
150
286
|
return {
|
|
151
287
|
download,
|
|
152
|
-
assets: await this.content.listDownloadAssets(
|
|
288
|
+
assets: await this.content.listDownloadAssets(downloadId, this.system(actor))
|
|
153
289
|
};
|
|
154
290
|
}
|
|
155
|
-
async thumbnailFile(
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
291
|
+
async thumbnailFile(owner, id, actor) {
|
|
292
|
+
const system = this.system(actor);
|
|
293
|
+
const item = owner === "event" ? (await this.seeEvents([id], actor))[0]?.event : owner === "course" ? await this.content.findCourse(id, system) : owner === "download" ? await this.content.findDownload(id, system) : await this.content.findCommunity(id, system);
|
|
294
|
+
if (!item?.thumbnailAssetId || owner !== "event" && item.status !== "published" && !actor.permissions.has(READ_OF[owner], id)) throw new NotFoundError(THUMBNAIL_OF[owner], id);
|
|
295
|
+
return signed(await this.files.signFile(actor.orgId, item.thumbnailAssetId), THUMBNAIL_OF[owner], id);
|
|
159
296
|
}
|
|
160
|
-
async activityFile(
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
if (!
|
|
164
|
-
|
|
297
|
+
async activityFile(activityId, assetId, actor) {
|
|
298
|
+
const system = this.system(actor);
|
|
299
|
+
const activity = await this.content.getActivity(activityId, system);
|
|
300
|
+
if (!activity) throw new NotFoundError("Lesson file", assetId);
|
|
301
|
+
if (!actor.permissions.has("courses:read", activity.courseId)) {
|
|
302
|
+
if (!isActivityPublished(activity.settings) || !await this.opensCourse(activity.courseId, actor)) throw new NotFoundError("Lesson file", assetId);
|
|
165
303
|
}
|
|
166
|
-
if (!(await this.content.listCourseActivityAssets(
|
|
167
|
-
return this.files.signFile(orgId, assetId);
|
|
168
|
-
}
|
|
169
|
-
async downloadFile(
|
|
170
|
-
if (!
|
|
171
|
-
const file = (await this.content.listDownloadAssets(
|
|
172
|
-
if (!file)
|
|
173
|
-
return this.files.signFile(orgId, assetId, { saveAs: file.displayName ?? file.filename });
|
|
174
|
-
}
|
|
175
|
-
async
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
304
|
+
if (!(await this.content.listCourseActivityAssets(activity.courseId, system)).some((link) => link.activityId === activityId && link.assetId === assetId)) throw new NotFoundError("Lesson file", assetId);
|
|
305
|
+
return signed(await this.files.signFile(actor.orgId, assetId), "Lesson file", assetId);
|
|
306
|
+
}
|
|
307
|
+
async downloadFile(downloadId, assetId, actor) {
|
|
308
|
+
if (!await this.opensDownload(downloadId, actor)) throw new NotFoundError("Download file", assetId);
|
|
309
|
+
const file = (await this.content.listDownloadAssets(downloadId, this.system(actor))).find((f) => f.assetId === assetId);
|
|
310
|
+
if (!file) throw new NotFoundError("Download file", assetId);
|
|
311
|
+
return signed(await this.files.signFile(actor.orgId, assetId, { saveAs: file.displayName ?? file.filename }), "Download file", assetId);
|
|
312
|
+
}
|
|
313
|
+
async seeEvents(ids, actor) {
|
|
314
|
+
if (ids.length === 0) return [];
|
|
315
|
+
const system = this.system(actor);
|
|
316
|
+
const [events, attended] = await Promise.all([this.content.findEvents(ids, system), ids.length === 1 ? this.access.hasAccess(actor.orgId, actor.id, ids[0]).then((attending) => attending ? [ids[0]] : []) : this.access.listAccessibleContent(actor.orgId, actor.id, "event")]);
|
|
317
|
+
const attending = new Set(attended);
|
|
318
|
+
const byId = new Map(events.map((event) => [event.id, event]));
|
|
319
|
+
return ids.flatMap((id) => {
|
|
320
|
+
const event = byId.get(id);
|
|
321
|
+
if (!event) return [];
|
|
322
|
+
const sight = eventSight(event, {
|
|
323
|
+
canRead: actor.permissions.has("events:read", id),
|
|
324
|
+
attending: attending.has(id)
|
|
325
|
+
});
|
|
326
|
+
return sight ? [{
|
|
327
|
+
event,
|
|
328
|
+
sight,
|
|
329
|
+
attending: attending.has(id)
|
|
330
|
+
}] : [];
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
async requireEvent(eventId, actor) {
|
|
334
|
+
const [seen] = await this.seeEvents([eventId], actor);
|
|
335
|
+
if (!seen) throw new NotFoundError("Event", eventId);
|
|
336
|
+
return seen;
|
|
337
|
+
}
|
|
338
|
+
async eventSummaries(seen, actor, now) {
|
|
339
|
+
const ids = seen.map((item) => item.event.id);
|
|
340
|
+
const attended = seen.filter((item) => item.attending).map((item) => item.event.id);
|
|
341
|
+
const [faces, direct] = await Promise.all([this.repo.eventFaces(actor.orgId, ids, EVENT_FACES), attended.length > 0 ? this.repo.directEventGrants(actor.orgId, actor.id, attended) : Promise.resolve([])]);
|
|
342
|
+
const leaves = new Set(direct);
|
|
343
|
+
return seen.map((item) => this.eventSummary(item, faces[item.event.id] ?? {
|
|
344
|
+
total: 0,
|
|
345
|
+
rows: []
|
|
346
|
+
}, leaves.has(item.event.id), actor, now));
|
|
347
|
+
}
|
|
348
|
+
eventSummary(seen, faces, canLeave, actor, now) {
|
|
349
|
+
const { event, sight, attending } = seen;
|
|
350
|
+
const id = event.id;
|
|
351
|
+
const canOpen = sight !== "public";
|
|
352
|
+
const capacity = event.settings.capacity;
|
|
353
|
+
const attendeeCount = faces.total;
|
|
354
|
+
const ended = event.endsAt.getTime() <= now.getTime();
|
|
355
|
+
const recording = sight === "read" || sight === "attendee" && ended && event.settings.replay ? event.recording : null;
|
|
356
|
+
const writes = actor.permissions.has("events:write", id);
|
|
357
|
+
const canManageAttendees = actor.permissions.has("access:write") || writes;
|
|
358
|
+
return {
|
|
359
|
+
orgId: event.orgId,
|
|
360
|
+
id,
|
|
361
|
+
type: event.type,
|
|
362
|
+
title: event.title,
|
|
363
|
+
thumbnailAssetId: event.thumbnailAssetId,
|
|
364
|
+
thumbnailUrl: event.thumbnailUrl,
|
|
365
|
+
status: event.status,
|
|
366
|
+
startsAt: event.startsAt,
|
|
367
|
+
endsAt: event.endsAt,
|
|
368
|
+
timeZone: event.timeZone,
|
|
369
|
+
location: canOpen ? event.location : null,
|
|
370
|
+
recording,
|
|
371
|
+
settings: {
|
|
372
|
+
type: event.settings.type,
|
|
373
|
+
capacity,
|
|
374
|
+
replay: event.settings.replay
|
|
375
|
+
},
|
|
376
|
+
attendeeCount,
|
|
377
|
+
attendees: faces.rows.map((row) => attendeeFace(actor.orgId, row, this.fileUrls)),
|
|
378
|
+
placesLeft: capacity === null ? null : Math.max(capacity - attendeeCount, 0),
|
|
379
|
+
viewer: {
|
|
380
|
+
attending,
|
|
381
|
+
canRegister: event.status === "published" && !attending && event.settings.type === "public" && event.startsAt.getTime() > now.getTime() && (capacity === null || attendeeCount < capacity),
|
|
382
|
+
canOpen,
|
|
383
|
+
canLeave,
|
|
384
|
+
canManageAttendees,
|
|
385
|
+
canAddAttendees: canManageAttendees && event.status === "published" && !ended,
|
|
386
|
+
canEdit: writes,
|
|
387
|
+
canCancel: writes,
|
|
388
|
+
canDelete: actor.permissions.has("events:delete", id)
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
async getEvent(eventId, actor) {
|
|
393
|
+
const seen = await this.requireEvent(eventId, actor);
|
|
394
|
+
const now = this.now();
|
|
395
|
+
const [[summary], files] = await Promise.all([this.eventSummaries([seen], actor, now), seen.sight === "public" ? Promise.resolve({}) : this.content.eventFilesFor([eventId], this.system(actor))]);
|
|
396
|
+
return {
|
|
397
|
+
...summary,
|
|
398
|
+
description: seen.event.description,
|
|
399
|
+
files: files[eventId] ?? []
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
async listEvents(query, actor) {
|
|
403
|
+
const now = this.now();
|
|
404
|
+
const reads = actor.permissions.where("events:read");
|
|
405
|
+
const page = await this.repo.events(actor.orgId, query, {
|
|
406
|
+
orgUserId: actor.id,
|
|
407
|
+
readAll: reads.org,
|
|
408
|
+
readIds: reads.content
|
|
409
|
+
}, now);
|
|
410
|
+
const rows = await this.eventSummaries(await this.seeEvents(page.rows, actor), actor, now);
|
|
184
411
|
return {
|
|
185
412
|
...page,
|
|
186
|
-
rows
|
|
187
|
-
...row,
|
|
188
|
-
imageUrl: row.imageAssetId ? this.fileUrls.personImage(row.orgUserId) : null
|
|
189
|
-
}))
|
|
413
|
+
rows
|
|
190
414
|
};
|
|
191
415
|
}
|
|
192
|
-
async
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
416
|
+
async eventCalendar(eventId, actor) {
|
|
417
|
+
const { event, sight } = await this.requireEvent(eventId, actor);
|
|
418
|
+
return eventCalendar(event, {
|
|
419
|
+
pageUrl: `${this.studentPortalUrl}/events/${encodeURIComponent(event.id)}`,
|
|
420
|
+
withLocation: sight !== "public",
|
|
421
|
+
now: this.now()
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
async eventAttendees(eventId, query, actor) {
|
|
425
|
+
actor.permissions.require("events:read", eventId);
|
|
426
|
+
if (!await this.content.findEvent(eventId, this.system(actor))) throw new NotFoundError("Event", eventId);
|
|
427
|
+
const page = await this.repo.eventAttendees(actor.orgId, eventId, query);
|
|
428
|
+
return {
|
|
429
|
+
...page,
|
|
430
|
+
rows: page.rows.map((row) => attendeeView(actor.orgId, row, this.fileUrls))
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
async eventFile(eventId, assetId, actor) {
|
|
434
|
+
const [seen] = await this.seeEvents([eventId], actor);
|
|
435
|
+
if (!seen || seen.sight === "public") throw new NotFoundError("Event file", assetId);
|
|
436
|
+
const file = (await this.content.eventFilesFor([eventId], this.system(actor)))[eventId]?.find((f) => f.assetId === assetId);
|
|
437
|
+
if (!file) throw new NotFoundError("Event file", assetId);
|
|
438
|
+
return signed(await this.files.signFile(actor.orgId, assetId, { saveAs: file.displayName ?? file.filename }), "Event file", assetId);
|
|
439
|
+
}
|
|
440
|
+
async directory(communityId, query, actor) {
|
|
441
|
+
if (!await this.access.isCommunityMember(communityId, actor)) throw new NotFoundError("Community", communityId);
|
|
442
|
+
const orgId = actor.orgId;
|
|
443
|
+
if (!await this.content.findCommunity(communityId, this.system(actor))) throw new NotFoundError("Community", communityId);
|
|
444
|
+
const readers = await this.people.holders(orgId, "communities:read", communityId);
|
|
445
|
+
const page = await this.repo.directory(orgId, communityId, query, readers);
|
|
446
|
+
const permissions = await this.people.permissionsOfMany(orgId, page.rows.map((row) => row.orgUserId));
|
|
447
|
+
return {
|
|
448
|
+
...page,
|
|
449
|
+
rows: page.rows.map((row) => {
|
|
450
|
+
const held = permissions.get(row.orgUserId);
|
|
451
|
+
const item = held?.roleOn(communityId);
|
|
452
|
+
const org = held?.roleOn();
|
|
453
|
+
return {
|
|
454
|
+
...row,
|
|
455
|
+
imageUrl: row.imageAssetId ? this.fileUrls.publicImage(orgId, row.orgUserId, row.imageAssetId) : null,
|
|
456
|
+
team: (item?.team ?? false) || (org?.team ?? false),
|
|
457
|
+
roleName: item?.team ? item.name : org?.team ? org.name : null,
|
|
458
|
+
opensEverySpace: (held?.has("communities:read", communityId) || held?.has("communities:moderate", communityId)) ?? false
|
|
459
|
+
};
|
|
460
|
+
})
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
async communityHome(communityId, actor) {
|
|
464
|
+
if (!await this.access.isCommunityMember(communityId, actor)) throw new NotFoundError("Community", communityId);
|
|
465
|
+
const system = this.system(actor);
|
|
466
|
+
const community = await this.content.findCommunity(communityId, system);
|
|
467
|
+
if (!community) throw new NotFoundError("Community", communityId);
|
|
468
|
+
const [spaces, everySpace] = await Promise.all([this.content.listSpaces(communityId, system), this.access.opensEverySpace(actor, communityId)]);
|
|
469
|
+
const itemRole = actor.permissions.roleOn(communityId);
|
|
470
|
+
const orgRole = actor.permissions.roleOn();
|
|
471
|
+
const role = itemRole.team || !orgRole.team ? itemRole : orgRole;
|
|
197
472
|
return {
|
|
198
473
|
communityId,
|
|
199
474
|
title: community.title,
|
|
200
475
|
description: community.description,
|
|
201
476
|
thumbnailUrl: community.thumbnailUrl,
|
|
202
477
|
dm: community.settings.dm,
|
|
203
|
-
spaces: await this.homeSpaces(
|
|
478
|
+
spaces: await this.homeSpaces(actor, communityId, spaces, everySpace),
|
|
479
|
+
viewer: {
|
|
480
|
+
permissions: PERMISSION_KEYS.filter((p) => actor.permissions.has(p, communityId)),
|
|
481
|
+
opensEverySpace: everySpace,
|
|
482
|
+
team: itemRole.team || orgRole.team,
|
|
483
|
+
roleName: role.name,
|
|
484
|
+
canCreateEvents: actor.permissions.has("events:write")
|
|
485
|
+
}
|
|
204
486
|
};
|
|
205
487
|
}
|
|
206
|
-
async communitySpace(
|
|
207
|
-
if (!await this.access.isCommunityMember(
|
|
208
|
-
const space = await this.content.getSpace(
|
|
209
|
-
if (!space || space.communityId !== communityId)
|
|
210
|
-
const
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
488
|
+
async communitySpace(communityId, spaceId, actor) {
|
|
489
|
+
if (!await this.access.isCommunityMember(communityId, actor)) throw new NotFoundError("Space", spaceId);
|
|
490
|
+
const space = await this.content.getSpace(spaceId, this.system(actor));
|
|
491
|
+
if (!space || space.communityId !== communityId) throw new NotFoundError("Space", spaceId);
|
|
492
|
+
const everySpace = await this.access.opensEverySpace(actor, communityId);
|
|
493
|
+
const [view] = await this.homeSpaces(actor, communityId, [space], everySpace);
|
|
494
|
+
if (!view) throw new NotFoundError("Space", spaceId);
|
|
495
|
+
return view;
|
|
496
|
+
}
|
|
497
|
+
async homeSpaces(actor, communityId, spaces, everySpace) {
|
|
498
|
+
const orgId = actor.orgId;
|
|
499
|
+
const excluding = await this.access.everySpaceOpeners(orgId, communityId);
|
|
500
|
+
const [openIds, counts, standings, subscribed] = await Promise.all([
|
|
501
|
+
this.access.openSpaceIds(communityId, actor),
|
|
502
|
+
this.repo.spaceMemberCounts(orgId, communityId, excluding),
|
|
503
|
+
this.access.spaceStandings(communityId, actor),
|
|
504
|
+
this.subscriptions.viewerSubscriptions(orgId, actor.id, "space", spaces.map((space) => space.id), /* @__PURE__ */ new Date())
|
|
218
505
|
]);
|
|
219
506
|
const open = new Set(openIds);
|
|
220
|
-
const seen = spaces.filter((space) => seesSpace(
|
|
507
|
+
const seen = spaces.filter((space) => seesSpace(everySpace, space.accessRule, standings[space.id]));
|
|
221
508
|
return Promise.all(seen.map(async (space) => {
|
|
222
509
|
const memberCount = counts[space.id] ?? 0;
|
|
223
510
|
const base = {
|
|
@@ -241,29 +528,31 @@ var MemberReportServiceImpl = class {
|
|
|
241
528
|
id: topic.id,
|
|
242
529
|
name: topic.name
|
|
243
530
|
})),
|
|
244
|
-
links: await this.linkViews(
|
|
531
|
+
links: await this.linkViews(actor, space.links),
|
|
532
|
+
subscription: subscribed[space.id] ?? null
|
|
245
533
|
};
|
|
246
534
|
}));
|
|
247
535
|
}
|
|
248
|
-
async linkViews(
|
|
249
|
-
const
|
|
536
|
+
async linkViews(actor, links) {
|
|
537
|
+
const system = this.system(actor);
|
|
538
|
+
const shown = (type, id, status) => status === "published" || actor.permissions.has(READ_OF[type], id);
|
|
250
539
|
return (await Promise.all(links.map(async (link) => {
|
|
251
|
-
const course = await this.content.
|
|
252
|
-
if (course) return shown(course.status) ? {
|
|
540
|
+
const course = await this.content.findCourse(link.contentId, system);
|
|
541
|
+
if (course) return shown("course", link.contentId, course.status) ? {
|
|
253
542
|
id: link.id,
|
|
254
543
|
contentId: link.contentId,
|
|
255
544
|
type: "course",
|
|
256
545
|
title: course.title
|
|
257
546
|
} : null;
|
|
258
|
-
const download = await this.content.
|
|
259
|
-
if (download) return shown(download.status) ? {
|
|
547
|
+
const download = await this.content.findDownload(link.contentId, system);
|
|
548
|
+
if (download) return shown("download", link.contentId, download.status) ? {
|
|
260
549
|
id: link.id,
|
|
261
550
|
contentId: link.contentId,
|
|
262
551
|
type: "download",
|
|
263
552
|
title: download.title
|
|
264
553
|
} : null;
|
|
265
|
-
const community = await this.content.
|
|
266
|
-
if (community) return shown(community.status) ? {
|
|
554
|
+
const community = await this.content.findCommunity(link.contentId, system);
|
|
555
|
+
if (community) return shown("community", link.contentId, community.status) ? {
|
|
267
556
|
id: link.id,
|
|
268
557
|
contentId: link.contentId,
|
|
269
558
|
type: "community",
|
|
@@ -273,6 +562,10 @@ var MemberReportServiceImpl = class {
|
|
|
273
562
|
}))).filter((view) => view !== null);
|
|
274
563
|
}
|
|
275
564
|
};
|
|
565
|
+
function signed(url, what, id) {
|
|
566
|
+
if (!url) throw new NotFoundError(what, id);
|
|
567
|
+
return url;
|
|
568
|
+
}
|
|
276
569
|
function standingOf(space, open, memberCount, status) {
|
|
277
570
|
if (space.accessRule === "all_members" || open && status !== "active") return "open";
|
|
278
571
|
if (status === "active") return "member";
|