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