@headless-lms/core 0.1.0 → 0.3.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 +90 -9
- package/dist/assets/events.js +19 -3
- package/dist/assets/events.js.map +1 -1
- package/dist/assets/file-urls.d.ts +20 -0
- package/dist/assets/file-urls.js +25 -0
- package/dist/assets/file-urls.js.map +1 -0
- package/dist/assets/index.d.ts +5 -4
- package/dist/assets/index.js +3 -2
- package/dist/assets/model.d.ts +2 -2
- package/dist/assets/ports.d.ts +45 -15
- package/dist/assets/service.d.ts +39 -7
- package/dist/assets/service.js +292 -37
- package/dist/assets/service.js.map +1 -1
- package/dist/automations/actions.d.ts +12 -15
- package/dist/automations/actions.js +188 -30
- package/dist/automations/actions.js.map +1 -1
- package/dist/automations/catalog.d.ts +5 -1
- package/dist/automations/catalog.js +514 -197
- package/dist/automations/catalog.js.map +1 -1
- package/dist/automations/community-derivations.d.ts +14 -0
- package/dist/automations/community-derivations.js +439 -0
- package/dist/automations/community-derivations.js.map +1 -0
- package/dist/automations/community-mail.d.ts +112 -0
- package/dist/automations/community-mail.js +90 -0
- package/dist/automations/community-mail.js.map +1 -0
- package/dist/automations/community-notifications.d.ts +16 -0
- package/dist/automations/community-notifications.js +84 -0
- package/dist/automations/community-notifications.js.map +1 -0
- package/dist/automations/events.d.ts +74 -24
- package/dist/automations/events.js +5 -5
- package/dist/automations/events.js.map +1 -1
- package/dist/automations/index.d.ts +7 -5
- package/dist/automations/index.js +3 -2
- package/dist/automations/model.d.ts +20 -3
- package/dist/automations/model.js +36 -3
- package/dist/automations/model.js.map +1 -1
- package/dist/automations/ports.d.ts +27 -8
- package/dist/automations/schedule.d.ts +6 -0
- package/dist/automations/schedule.js +41 -0
- package/dist/automations/schedule.js.map +1 -0
- package/dist/automations/seeds.d.ts +17 -0
- package/dist/automations/seeds.js +235 -0
- package/dist/automations/seeds.js.map +1 -0
- package/dist/automations/service.d.ts +41 -6
- package/dist/automations/service.js +542 -59
- package/dist/automations/service.js.map +1 -1
- package/dist/automations/types.d.ts +2 -2
- package/dist/automations/webhook-signing.d.ts +7 -0
- package/dist/automations/webhook-signing.js +22 -0
- package/dist/automations/webhook-signing.js.map +1 -0
- package/dist/content/events.d.ts +1013 -25
- package/dist/content/events.js +168 -19
- package/dist/content/events.js.map +1 -1
- package/dist/content/index.d.ts +5 -5
- package/dist/content/index.js +2 -2
- package/dist/content/model.d.ts +2 -2
- package/dist/content/ports.d.ts +109 -25
- package/dist/content/service.d.ts +68 -23
- package/dist/content/service.js +647 -60
- package/dist/content/service.js.map +1 -1
- package/dist/content/types.d.ts +2 -2
- package/dist/discussion/authors.d.ts +10 -0
- package/dist/discussion/authors.js +23 -0
- package/dist/discussion/authors.js.map +1 -0
- package/dist/discussion/chats.d.ts +104 -0
- package/dist/discussion/chats.js +798 -0
- package/dist/discussion/chats.js.map +1 -0
- package/dist/discussion/events.d.ts +633 -14
- package/dist/discussion/events.js +134 -5
- package/dist/discussion/events.js.map +1 -1
- package/dist/discussion/index.d.ts +7 -3
- package/dist/discussion/index.js +4 -1
- package/dist/discussion/model.d.ts +1 -2
- package/dist/discussion/ports.d.ts +288 -27
- package/dist/discussion/ports.js +6 -1
- package/dist/discussion/ports.js.map +1 -0
- package/dist/discussion/posts.d.ts +103 -0
- package/dist/discussion/posts.js +723 -0
- package/dist/discussion/posts.js.map +1 -0
- package/dist/discussion/service.d.ts +33 -11
- package/dist/discussion/service.js +297 -81
- package/dist/discussion/service.js.map +1 -1
- package/dist/entitlements/events.d.ts +264 -13
- package/dist/entitlements/events.js +49 -5
- package/dist/entitlements/events.js.map +1 -1
- package/dist/entitlements/index.d.ts +5 -4
- package/dist/entitlements/index.js +2 -1
- package/dist/entitlements/model.d.ts +3 -2
- package/dist/entitlements/ports.d.ts +124 -11
- package/dist/entitlements/rules.d.ts +12 -0
- package/dist/entitlements/rules.js +17 -0
- package/dist/entitlements/rules.js.map +1 -0
- package/dist/entitlements/service.d.ts +54 -3
- package/dist/entitlements/service.js +473 -2
- package/dist/entitlements/service.js.map +1 -1
- package/dist/identity/access.d.ts +6 -0
- package/dist/identity/access.js +7 -0
- package/dist/identity/access.js.map +1 -0
- package/dist/identity/events.d.ts +17 -3
- package/dist/identity/events.js +12 -2
- package/dist/identity/events.js.map +1 -1
- package/dist/identity/index.d.ts +6 -4
- package/dist/identity/index.js +3 -1
- package/dist/identity/model.d.ts +2 -1
- package/dist/identity/notifications.d.ts +27 -0
- package/dist/identity/notifications.js +101 -0
- package/dist/identity/notifications.js.map +1 -0
- package/dist/identity/ports.d.ts +76 -3
- package/dist/identity/service.d.ts +17 -3
- package/dist/identity/service.js +73 -5
- package/dist/identity/service.js.map +1 -1
- package/dist/integrations/events.d.ts +27 -3
- package/dist/integrations/events.js +15 -3
- package/dist/integrations/events.js.map +1 -1
- package/dist/integrations/model.js +1 -1
- package/dist/integrations/model.js.map +1 -1
- package/dist/integrations/service.js +2 -2
- package/dist/integrations/service.js.map +1 -1
- package/dist/organizations/access-scopes.d.ts +19 -0
- package/dist/organizations/access-scopes.js +89 -0
- package/dist/organizations/access-scopes.js.map +1 -0
- package/dist/organizations/events.d.ts +234 -25
- package/dist/organizations/events.js +58 -9
- package/dist/organizations/events.js.map +1 -1
- package/dist/organizations/index.d.ts +8 -7
- package/dist/organizations/index.js +4 -3
- package/dist/organizations/members.d.ts +8 -5
- package/dist/organizations/members.js.map +1 -1
- package/dist/organizations/ports.d.ts +20 -21
- package/dist/organizations/roles.d.ts +6 -10
- package/dist/organizations/roles.js +19 -7
- package/dist/organizations/roles.js.map +1 -1
- package/dist/organizations/service.d.ts +28 -14
- package/dist/organizations/service.js +274 -105
- package/dist/organizations/service.js.map +1 -1
- package/dist/organizations/types.d.ts +2 -11
- package/dist/progress/events.d.ts +34 -2
- package/dist/progress/events.js +15 -2
- package/dist/progress/events.js.map +1 -1
- package/dist/progress/index.d.ts +2 -2
- package/dist/progress/ports.d.ts +6 -1
- package/dist/progress/service.d.ts +5 -3
- package/dist/progress/service.js +9 -3
- package/dist/progress/service.js.map +1 -1
- package/dist/reporting/admin/index.d.ts +4 -0
- package/dist/reporting/admin/index.js +2 -0
- package/dist/reporting/admin/model.d.ts +108 -0
- package/dist/reporting/admin/ports.d.ts +27 -0
- package/dist/reporting/admin/service.d.ts +22 -0
- package/dist/reporting/admin/service.js +38 -0
- package/dist/reporting/admin/service.js.map +1 -0
- package/dist/reporting/member/index.d.ts +5 -0
- package/dist/reporting/member/index.js +2 -0
- package/dist/reporting/member/model.d.ts +124 -0
- package/dist/reporting/member/ports.d.ts +45 -0
- package/dist/reporting/member/service.d.ts +73 -0
- package/dist/reporting/member/service.js +286 -0
- package/dist/reporting/member/service.js.map +1 -0
- package/dist/shared/actor.d.ts +9 -0
- package/dist/shared/errors.d.ts +7 -1
- package/dist/shared/errors.js +10 -1
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/events.d.ts +5 -3
- package/dist/shared/events.js +1 -0
- package/dist/shared/events.js.map +1 -1
- package/dist/shared/id.d.ts +12 -0
- package/dist/shared/id.js +13 -1
- package/dist/shared/id.js.map +1 -1
- package/dist/shared/mailer.d.ts +6 -1
- package/dist/shared/mailer.js.map +1 -1
- package/dist/shared/network.d.ts +10 -0
- package/dist/shared/network.js +211 -0
- package/dist/shared/network.js.map +1 -0
- package/dist/shared/settings.js.map +1 -1
- package/dist/types/assets.d.ts +2 -2
- package/dist/types/automations.d.ts +21 -2
- package/dist/types/content.d.ts +2 -2
- package/dist/types/discussion.d.ts +12 -3
- package/dist/types/email-templates.d.ts +124 -1
- package/dist/types/entitlements.d.ts +2 -2
- package/dist/types/events.d.ts +3 -3
- package/dist/types/identity.d.ts +48 -2
- package/dist/types/index.d.ts +10 -10
- package/dist/types/organizations.d.ts +2 -2
- package/dist/types/ports.d.ts +7 -1
- package/dist/types/schemas/assets.d.ts +67 -36
- package/dist/types/schemas/assets.js +19 -13
- package/dist/types/schemas/assets.js.map +1 -1
- package/dist/types/schemas/automations.d.ts +88 -4
- package/dist/types/schemas/automations.js +46 -6
- package/dist/types/schemas/automations.js.map +1 -1
- package/dist/types/schemas/content.d.ts +385 -20
- package/dist/types/schemas/content.js +178 -15
- package/dist/types/schemas/content.js.map +1 -1
- package/dist/types/schemas/credentials.js.map +1 -1
- package/dist/types/schemas/discussion.d.ts +379 -4
- package/dist/types/schemas/discussion.js +209 -7
- package/dist/types/schemas/discussion.js.map +1 -1
- package/dist/types/schemas/entitlements.d.ts +44 -4
- package/dist/types/schemas/entitlements.js +32 -4
- package/dist/types/schemas/entitlements.js.map +1 -1
- package/dist/types/schemas/identity.d.ts +115 -5
- package/dist/types/schemas/identity.js +59 -6
- package/dist/types/schemas/identity.js.map +1 -1
- package/dist/types/schemas/index.d.ts +9 -9
- package/dist/types/schemas/index.js +9 -9
- package/dist/types/schemas/integrations.js.map +1 -1
- package/dist/types/schemas/organizations.d.ts +27 -5
- package/dist/types/schemas/organizations.js +14 -7
- package/dist/types/schemas/organizations.js.map +1 -1
- package/dist/types/schemas/outbox.d.ts +1 -0
- package/dist/types/schemas/outbox.js +1 -0
- package/dist/types/schemas/outbox.js.map +1 -1
- package/dist/types/schemas/progress.d.ts +1 -0
- package/dist/types/schemas/progress.js +1 -0
- package/dist/types/schemas/progress.js.map +1 -1
- package/dist/types/schemas/settings.js.map +1 -1
- package/dist/types/schemas/shared.d.ts +4 -1
- package/dist/types/schemas/shared.js +7 -1
- package/dist/types/schemas/shared.js.map +1 -1
- package/dist/types/shared.d.ts +1 -1
- package/package.json +2 -2
- package/dist/reporting/dashboard/index.d.ts +0 -4
- package/dist/reporting/dashboard/index.js +0 -2
- package/dist/reporting/dashboard/model.d.ts +0 -14
- package/dist/reporting/dashboard/ports.d.ts +0 -13
- package/dist/reporting/dashboard/service.d.ts +0 -19
- package/dist/reporting/dashboard/service.js +0 -20
- package/dist/reporting/dashboard/service.js.map +0 -1
- package/dist/reporting/learn/index.d.ts +0 -5
- package/dist/reporting/learn/index.js +0 -2
- package/dist/reporting/learn/model.d.ts +0 -23
- package/dist/reporting/learn/ports.d.ts +0 -42
- package/dist/reporting/learn/service.d.ts +0 -48
- package/dist/reporting/learn/service.js +0 -111
- package/dist/reporting/learn/service.js.map +0 -1
- package/dist/reporting/students/index.d.ts +0 -4
- package/dist/reporting/students/index.js +0 -2
- package/dist/reporting/students/model.d.ts +0 -31
- package/dist/reporting/students/ports.d.ts +0 -13
- package/dist/reporting/students/ports.js +0 -1
- package/dist/reporting/students/service.d.ts +0 -19
- package/dist/reporting/students/service.js +0 -20
- package/dist/reporting/students/service.js.map +0 -1
- /package/dist/reporting/{dashboard → admin}/model.js +0 -0
- /package/dist/reporting/{dashboard → admin}/ports.js +0 -0
- /package/dist/reporting/{learn → member}/model.js +0 -0
- /package/dist/reporting/{learn → member}/ports.js +0 -0
- /package/dist/{reporting/students/model.js → shared/actor.js} +0 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { ActivityView, CourseView, DownloadFile, DownloadView, Module } from "../../types/schemas/content.js";
|
|
2
|
+
import { NotificationKind } from "../../types/schemas/identity.js";
|
|
3
|
+
import "../../content/index.js";
|
|
4
|
+
import "../../identity/index.js";
|
|
5
|
+
//#region src/reporting/member/model.d.ts
|
|
6
|
+
/** Per-course progress for the student surface. Derived on read against the
|
|
7
|
+
* current published structure — never stored. */
|
|
8
|
+
interface DirectoryRow {
|
|
9
|
+
orgUserId: string;
|
|
10
|
+
userId: string;
|
|
11
|
+
role: string;
|
|
12
|
+
displayName: string | null;
|
|
13
|
+
headline: string | null;
|
|
14
|
+
bio: string | null;
|
|
15
|
+
imageAssetId: string | null;
|
|
16
|
+
}
|
|
17
|
+
interface DirectoryQuery {
|
|
18
|
+
page: number;
|
|
19
|
+
pageSize: number;
|
|
20
|
+
search?: string;
|
|
21
|
+
}
|
|
22
|
+
interface DirectoryEntry extends DirectoryRow {
|
|
23
|
+
imageUrl: string | null;
|
|
24
|
+
}
|
|
25
|
+
interface CommunityHomeLink {
|
|
26
|
+
id: string;
|
|
27
|
+
contentId: string;
|
|
28
|
+
type: 'course' | 'download' | 'community';
|
|
29
|
+
title: string;
|
|
30
|
+
}
|
|
31
|
+
interface CommunityHomeSpaceBase {
|
|
32
|
+
id: string;
|
|
33
|
+
name: string;
|
|
34
|
+
memberCount: number;
|
|
35
|
+
accessRule: 'all_members' | 'by_request' | 'by_invite';
|
|
36
|
+
standing: 'open' | 'member' | 'requested' | 'invited' | 'full' | 'none';
|
|
37
|
+
}
|
|
38
|
+
/** A space the viewer can see but not open: enough to request, accept or ask. */
|
|
39
|
+
interface LockedCommunitySpace extends CommunityHomeSpaceBase {
|
|
40
|
+
locked: true;
|
|
41
|
+
}
|
|
42
|
+
interface OpenCommunitySpace extends CommunityHomeSpaceBase {
|
|
43
|
+
locked: false;
|
|
44
|
+
description: string | null;
|
|
45
|
+
capacity: number | null;
|
|
46
|
+
settings: {
|
|
47
|
+
comments: boolean;
|
|
48
|
+
reactions: boolean;
|
|
49
|
+
requireReview: boolean;
|
|
50
|
+
};
|
|
51
|
+
topics: {
|
|
52
|
+
id: string;
|
|
53
|
+
name: string;
|
|
54
|
+
}[];
|
|
55
|
+
links: CommunityHomeLink[];
|
|
56
|
+
}
|
|
57
|
+
type CommunityHomeSpace = LockedCommunitySpace | OpenCommunitySpace;
|
|
58
|
+
interface CommunityHome {
|
|
59
|
+
communityId: string;
|
|
60
|
+
title: string;
|
|
61
|
+
description: string;
|
|
62
|
+
thumbnailUrl: string | null;
|
|
63
|
+
dm: {
|
|
64
|
+
enabled: boolean;
|
|
65
|
+
memberToMember: boolean;
|
|
66
|
+
memberToStaff: boolean;
|
|
67
|
+
staffToAnyone: boolean;
|
|
68
|
+
firstMessageIsRequest: boolean;
|
|
69
|
+
groupChats: boolean;
|
|
70
|
+
groupSize: number;
|
|
71
|
+
};
|
|
72
|
+
spaces: CommunityHomeSpace[];
|
|
73
|
+
}
|
|
74
|
+
interface CourseProgressView {
|
|
75
|
+
/** Keyed by activity id; absent key = not started. */
|
|
76
|
+
activities: Record<string, 'in-progress' | 'completed'>;
|
|
77
|
+
/** Integer 0–100: completed ÷ current published activities, rounded. */
|
|
78
|
+
percent: number;
|
|
79
|
+
/** The course target's own record says so. */
|
|
80
|
+
completed: boolean;
|
|
81
|
+
/** Per-activity reported state (the record's position map); absent key = none reported. */
|
|
82
|
+
positions: Record<string, unknown>;
|
|
83
|
+
}
|
|
84
|
+
/** One of the viewer's notifications, with the names of what it refers to.
|
|
85
|
+
* A post or chat the viewer can no longer see comes back null. */
|
|
86
|
+
interface NotificationView {
|
|
87
|
+
id: string;
|
|
88
|
+
kind: NotificationKind;
|
|
89
|
+
createdAt: Date;
|
|
90
|
+
readAt: Date | null;
|
|
91
|
+
actor: {
|
|
92
|
+
orgUserId: string;
|
|
93
|
+
displayName: string | null;
|
|
94
|
+
imageUrl: string | null;
|
|
95
|
+
} | null;
|
|
96
|
+
community: {
|
|
97
|
+
id: string;
|
|
98
|
+
title: string;
|
|
99
|
+
} | null;
|
|
100
|
+
space: {
|
|
101
|
+
id: string;
|
|
102
|
+
name: string;
|
|
103
|
+
} | null;
|
|
104
|
+
post: {
|
|
105
|
+
id: string;
|
|
106
|
+
title: string;
|
|
107
|
+
} | null;
|
|
108
|
+
commentId: string | null;
|
|
109
|
+
chat: {
|
|
110
|
+
id: string;
|
|
111
|
+
title: string;
|
|
112
|
+
} | null;
|
|
113
|
+
messageId: string | null;
|
|
114
|
+
}
|
|
115
|
+
interface NotificationsView {
|
|
116
|
+
rows: NotificationView[];
|
|
117
|
+
total: number;
|
|
118
|
+
page: number;
|
|
119
|
+
pageSize: number;
|
|
120
|
+
unreadCount: number;
|
|
121
|
+
}
|
|
122
|
+
//#endregion
|
|
123
|
+
export { type ActivityView, CommunityHome, CommunityHomeLink, CommunityHomeSpace, CourseProgressView, type CourseView, DirectoryEntry, DirectoryQuery, DirectoryRow, type DownloadFile, type DownloadView, LockedCommunitySpace, type Module, NotificationView, NotificationsView, OpenCommunitySpace };
|
|
124
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Page } from "../../types/shared.js";
|
|
2
|
+
import { ActivityView, CourseView, DownloadFile, DownloadView, Module } from "../../types/schemas/content.js";
|
|
3
|
+
import { Notification } from "../../types/schemas/identity.js";
|
|
4
|
+
import "../../types/index.js";
|
|
5
|
+
import { Actor } from "../../shared/actor.js";
|
|
6
|
+
import "../../identity/index.js";
|
|
7
|
+
import { CommunityHome, CommunityHomeSpace, CourseProgressView, DirectoryEntry, DirectoryQuery, DirectoryRow, NotificationView, NotificationsView } from "./model.js";
|
|
8
|
+
//#region src/reporting/member/ports.d.ts
|
|
9
|
+
interface MemberReportService {
|
|
10
|
+
listCourses(orgId: string, orgUserId: string): Promise<CourseView[]>;
|
|
11
|
+
getCourse(orgId: string, orgUserId: string, courseId: string): Promise<CourseView | null>;
|
|
12
|
+
listModules(orgId: string, orgUserId: string, courseId: string): Promise<Module[] | null>;
|
|
13
|
+
listActivities(orgId: string, orgUserId: string, courseId: string): Promise<ActivityView[] | null>;
|
|
14
|
+
courseProgress(orgId: string, orgUserId: string, courseId: string): Promise<CourseProgressView | null>;
|
|
15
|
+
listDownloads(orgId: string, orgUserId: string): Promise<DownloadView[]>;
|
|
16
|
+
getDownload(orgId: string, orgUserId: string, downloadId: string): Promise<{
|
|
17
|
+
download: DownloadView;
|
|
18
|
+
assets: DownloadFile[];
|
|
19
|
+
} | null>;
|
|
20
|
+
/** Signed URL of a course, download or community thumbnail: published, or staff. */
|
|
21
|
+
thumbnailFile(orgId: string, actor: Actor, owner: 'course' | 'download' | 'community', id: string): Promise<string | null>;
|
|
22
|
+
/** Signed URL of an asset the activity links, for a student who can open its course. */
|
|
23
|
+
activityFile(orgId: string, actor: Actor, activityId: string, assetId: string): Promise<string | null>;
|
|
24
|
+
/** Signed download URL of a file in a download the student can open. */
|
|
25
|
+
downloadFile(orgId: string, actor: Actor, downloadId: string, assetId: string): Promise<string | null>;
|
|
26
|
+
/** Signed URL of an org user's profile photo, when it belongs to this org. */
|
|
27
|
+
personImage(orgId: string, orgUserId: string): Promise<string | null>;
|
|
28
|
+
directory(orgId: string, actor: Actor, communityId: string, query: DirectoryQuery): Promise<Page<DirectoryEntry> | null>;
|
|
29
|
+
communityHome(orgId: string, actor: Actor, communityId: string): Promise<CommunityHome | null>;
|
|
30
|
+
communitySpace(orgId: string, actor: Actor, communityId: string, spaceId: string): Promise<CommunityHomeSpace | null>;
|
|
31
|
+
notifications(orgId: string, actor: Actor, userId: string, query: {
|
|
32
|
+
page: number;
|
|
33
|
+
pageSize: number;
|
|
34
|
+
}): Promise<NotificationsView>;
|
|
35
|
+
/** One notification the way `notifications` lists it. */
|
|
36
|
+
notificationView(orgId: string, actor: Actor, notification: Notification): Promise<NotificationView>;
|
|
37
|
+
}
|
|
38
|
+
interface MemberReportRepository {
|
|
39
|
+
directory(orgId: string, communityId: string, query: DirectoryQuery): Promise<Page<DirectoryRow>>;
|
|
40
|
+
spaceMemberCounts(orgId: string, communityId: string): Promise<Record<string, number>>;
|
|
41
|
+
people(orgId: string, orgUserIds: string[]): Promise<DirectoryRow[]>;
|
|
42
|
+
}
|
|
43
|
+
//#endregion
|
|
44
|
+
export { MemberReportRepository, MemberReportService };
|
|
45
|
+
//# sourceMappingURL=ports.d.ts.map
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { Page } from "../../types/shared.js";
|
|
2
|
+
import { ActivityView, CourseView, DownloadFile, DownloadView, Module } from "../../types/schemas/content.js";
|
|
3
|
+
import { Notification } from "../../types/schemas/identity.js";
|
|
4
|
+
import "../../types/index.js";
|
|
5
|
+
import { FileUrls } from "../../assets/file-urls.js";
|
|
6
|
+
import { AssetFiles } from "../../assets/ports.js";
|
|
7
|
+
import "../../assets/index.js";
|
|
8
|
+
import { Actor } from "../../shared/actor.js";
|
|
9
|
+
import { ContentService } from "../../content/ports.js";
|
|
10
|
+
import "../../content/index.js";
|
|
11
|
+
import { NotificationInbox } from "../../identity/ports.js";
|
|
12
|
+
import "../../identity/index.js";
|
|
13
|
+
import { EntitlementsService } from "../../entitlements/ports.js";
|
|
14
|
+
import "../../entitlements/index.js";
|
|
15
|
+
import { ChatService, PostService } from "../../discussion/ports.js";
|
|
16
|
+
import "../../discussion/index.js";
|
|
17
|
+
import { ProgressService } from "../../progress/ports.js";
|
|
18
|
+
import "../../progress/index.js";
|
|
19
|
+
import { CommunityHome, CommunityHomeSpace, CourseProgressView, DirectoryEntry, DirectoryQuery, NotificationView, NotificationsView } from "./model.js";
|
|
20
|
+
import { MemberReportRepository, MemberReportService } from "./ports.js";
|
|
21
|
+
//#region src/reporting/member/service.d.ts
|
|
22
|
+
type MemberAccess = Pick<EntitlementsService, 'isCommunityMember' | 'openSpaceIds' | 'spaceStandings' | 'hasAccess' | 'listAccessibleContent'>;
|
|
23
|
+
type MemberReportServiceParams = {
|
|
24
|
+
repo: MemberReportRepository;
|
|
25
|
+
content: ContentService;
|
|
26
|
+
progress: ProgressService;
|
|
27
|
+
files: Pick<AssetFiles, 'signFile'>;
|
|
28
|
+
fileUrls: FileUrls;
|
|
29
|
+
access: MemberAccess;
|
|
30
|
+
notifications: Pick<NotificationInbox, 'listNotifications'>;
|
|
31
|
+
posts: Pick<PostService, 'visibleTitles'>;
|
|
32
|
+
chats: Pick<ChatService, 'titlesFor'>;
|
|
33
|
+
};
|
|
34
|
+
declare class MemberReportServiceImpl implements MemberReportService {
|
|
35
|
+
private readonly repo;
|
|
36
|
+
private readonly content;
|
|
37
|
+
private readonly progress;
|
|
38
|
+
private readonly files;
|
|
39
|
+
private readonly fileUrls;
|
|
40
|
+
private readonly access;
|
|
41
|
+
private readonly inbox;
|
|
42
|
+
private readonly posts;
|
|
43
|
+
private readonly chats;
|
|
44
|
+
constructor(params: MemberReportServiceParams);
|
|
45
|
+
notifications(orgId: string, actor: Actor, userId: string, query: {
|
|
46
|
+
page: number;
|
|
47
|
+
pageSize: number;
|
|
48
|
+
}): Promise<NotificationsView>;
|
|
49
|
+
notificationView(orgId: string, actor: Actor, notification: Notification): Promise<NotificationView>;
|
|
50
|
+
private describeNotifications;
|
|
51
|
+
listCourses(orgId: string, orgUserId: string): Promise<CourseView[]>;
|
|
52
|
+
getCourse(orgId: string, orgUserId: string, courseId: string): Promise<CourseView | null>;
|
|
53
|
+
listModules(orgId: string, orgUserId: string, courseId: string): Promise<Module[] | null>;
|
|
54
|
+
listActivities(orgId: string, orgUserId: string, courseId: string): Promise<ActivityView[] | null>;
|
|
55
|
+
courseProgress(orgId: string, orgUserId: string, courseId: string): Promise<CourseProgressView | null>;
|
|
56
|
+
listDownloads(orgId: string, orgUserId: string): Promise<DownloadView[]>;
|
|
57
|
+
getDownload(orgId: string, orgUserId: string, downloadId: string): Promise<{
|
|
58
|
+
download: DownloadView;
|
|
59
|
+
assets: DownloadFile[];
|
|
60
|
+
} | null>;
|
|
61
|
+
thumbnailFile(orgId: string, actor: Actor, owner: 'course' | 'download' | 'community', id: string): Promise<string | null>;
|
|
62
|
+
activityFile(orgId: string, actor: Actor, activityId: string, assetId: string): Promise<string | null>;
|
|
63
|
+
downloadFile(orgId: string, actor: Actor, downloadId: string, assetId: string): Promise<string | null>;
|
|
64
|
+
personImage(orgId: string, orgUserId: string): Promise<string | null>;
|
|
65
|
+
directory(orgId: string, actor: Actor, communityId: string, query: DirectoryQuery): Promise<Page<DirectoryEntry> | null>;
|
|
66
|
+
communityHome(orgId: string, actor: Actor, communityId: string): Promise<CommunityHome | null>;
|
|
67
|
+
communitySpace(orgId: string, actor: Actor, communityId: string, spaceId: string): Promise<CommunityHomeSpace | null>;
|
|
68
|
+
private homeSpaces;
|
|
69
|
+
private linkViews;
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { MemberReportServiceImpl, MemberReportServiceParams };
|
|
73
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { isStaffRole } from "../../organizations/roles.js";
|
|
2
|
+
import { seesSpace } from "../../entitlements/rules.js";
|
|
3
|
+
//#region src/reporting/member/service.ts
|
|
4
|
+
function ref(id, names) {
|
|
5
|
+
const name = id ? names.get(id) : void 0;
|
|
6
|
+
return id && name !== void 0 ? {
|
|
7
|
+
id,
|
|
8
|
+
name
|
|
9
|
+
} : null;
|
|
10
|
+
}
|
|
11
|
+
function isActivityPublished(settings) {
|
|
12
|
+
return settings?.published !== false;
|
|
13
|
+
}
|
|
14
|
+
var MemberReportServiceImpl = class {
|
|
15
|
+
repo;
|
|
16
|
+
content;
|
|
17
|
+
progress;
|
|
18
|
+
files;
|
|
19
|
+
fileUrls;
|
|
20
|
+
access;
|
|
21
|
+
inbox;
|
|
22
|
+
posts;
|
|
23
|
+
chats;
|
|
24
|
+
constructor(params) {
|
|
25
|
+
this.repo = params.repo;
|
|
26
|
+
this.content = params.content;
|
|
27
|
+
this.progress = params.progress;
|
|
28
|
+
this.files = params.files;
|
|
29
|
+
this.fileUrls = params.fileUrls;
|
|
30
|
+
this.access = params.access;
|
|
31
|
+
this.inbox = params.notifications;
|
|
32
|
+
this.posts = params.posts;
|
|
33
|
+
this.chats = params.chats;
|
|
34
|
+
}
|
|
35
|
+
async notifications(orgId, actor, userId, query) {
|
|
36
|
+
const page = await this.inbox.listNotifications(orgId, userId, query);
|
|
37
|
+
return {
|
|
38
|
+
rows: await this.describeNotifications(orgId, actor, page.rows),
|
|
39
|
+
total: page.total,
|
|
40
|
+
page: page.page,
|
|
41
|
+
pageSize: page.pageSize,
|
|
42
|
+
unreadCount: page.unreadCount
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
async notificationView(orgId, actor, notification) {
|
|
46
|
+
const [view] = await this.describeNotifications(orgId, actor, [notification]);
|
|
47
|
+
return view;
|
|
48
|
+
}
|
|
49
|
+
async describeNotifications(orgId, actor, rows) {
|
|
50
|
+
const ids = (pick) => [...new Set(rows.flatMap((row) => pick(row) ?? []))];
|
|
51
|
+
const [people, postTitles, chatTitles, spaces, communities] = await Promise.all([
|
|
52
|
+
this.repo.people(orgId, ids((row) => row.actorOrgUserId)),
|
|
53
|
+
this.posts.visibleTitles(orgId, actor, ids((row) => row.postId)),
|
|
54
|
+
this.chats.titlesFor(orgId, actor, ids((row) => row.chatId)),
|
|
55
|
+
Promise.all(ids((row) => row.spaceId).map((id) => this.content.getSpace(orgId, id))),
|
|
56
|
+
Promise.all(ids((row) => row.communityId).map((id) => this.content.getCommunity(orgId, id)))
|
|
57
|
+
]);
|
|
58
|
+
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
|
+
return rows.map((row) => {
|
|
64
|
+
const person = row.actorOrgUserId ? personById.get(row.actorOrgUserId) : void 0;
|
|
65
|
+
const community = ref(row.communityId, communityById);
|
|
66
|
+
const space = ref(row.spaceId, spaceById);
|
|
67
|
+
const post = ref(row.postId, postById);
|
|
68
|
+
const chat = ref(row.chatId, chatById);
|
|
69
|
+
return {
|
|
70
|
+
id: row.id,
|
|
71
|
+
kind: row.kind,
|
|
72
|
+
createdAt: row.createdAt,
|
|
73
|
+
readAt: row.readAt,
|
|
74
|
+
actor: person ? {
|
|
75
|
+
orgUserId: person.orgUserId,
|
|
76
|
+
displayName: person.displayName,
|
|
77
|
+
imageUrl: person.imageAssetId ? this.fileUrls.personImage(person.orgUserId) : null
|
|
78
|
+
} : null,
|
|
79
|
+
community: community && {
|
|
80
|
+
id: community.id,
|
|
81
|
+
title: community.name
|
|
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
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
async listCourses(orgId, orgUserId) {
|
|
101
|
+
const ids = await this.access.listAccessibleContent(orgId, orgUserId, "course");
|
|
102
|
+
return (await Promise.all(ids.map((id) => this.content.getCourse(orgId, id)))).filter((c) => c !== null && c.status === "published");
|
|
103
|
+
}
|
|
104
|
+
async getCourse(orgId, orgUserId, courseId) {
|
|
105
|
+
if (!await this.access.hasAccess(orgId, orgUserId, courseId)) return null;
|
|
106
|
+
const course = await this.content.getCourse(orgId, courseId);
|
|
107
|
+
return course && course.status === "published" ? course : null;
|
|
108
|
+
}
|
|
109
|
+
async listModules(orgId, orgUserId, courseId) {
|
|
110
|
+
if (!await this.getCourse(orgId, orgUserId, courseId)) return null;
|
|
111
|
+
return this.content.listCourseModules(orgId, courseId);
|
|
112
|
+
}
|
|
113
|
+
async listActivities(orgId, orgUserId, courseId) {
|
|
114
|
+
if (!await this.getCourse(orgId, orgUserId, courseId)) return null;
|
|
115
|
+
return (await this.content.listCourseActivityViews(orgId, courseId)).filter((a) => isActivityPublished(a.settings));
|
|
116
|
+
}
|
|
117
|
+
async courseProgress(orgId, orgUserId, courseId) {
|
|
118
|
+
if (!await this.getCourse(orgId, orgUserId, courseId)) return null;
|
|
119
|
+
const ids = (await this.content.listCourseActivities(orgId, courseId)).filter((a) => isActivityPublished(a.settings)).map((a) => a.id);
|
|
120
|
+
const records = await this.progress.listByTargets(orgId, orgUserId, ids);
|
|
121
|
+
const activities = {};
|
|
122
|
+
const positions = {};
|
|
123
|
+
let done = 0;
|
|
124
|
+
for (const r of records) {
|
|
125
|
+
if (r.targetType !== "activity") continue;
|
|
126
|
+
activities[r.targetId] = r.completedAt ? "completed" : "in-progress";
|
|
127
|
+
if (r.completedAt) done += 1;
|
|
128
|
+
if (r.position != null) positions[r.targetId] = r.position;
|
|
129
|
+
}
|
|
130
|
+
const courseRecord = await this.progress.get(orgId, {
|
|
131
|
+
orgUserId,
|
|
132
|
+
targetType: "course",
|
|
133
|
+
targetId: courseId
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
activities,
|
|
137
|
+
percent: ids.length > 0 ? Math.round(done / ids.length * 100) : 0,
|
|
138
|
+
completed: courseRecord?.completedAt != null,
|
|
139
|
+
positions
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async listDownloads(orgId, orgUserId) {
|
|
143
|
+
const ids = await this.access.listAccessibleContent(orgId, orgUserId, "download");
|
|
144
|
+
return (await Promise.all(ids.map((id) => this.content.getDownload(orgId, id)))).filter((d) => d !== null && d.status === "published");
|
|
145
|
+
}
|
|
146
|
+
async getDownload(orgId, orgUserId, downloadId) {
|
|
147
|
+
if (!await this.access.hasAccess(orgId, orgUserId, downloadId)) return null;
|
|
148
|
+
const download = await this.content.getDownload(orgId, downloadId);
|
|
149
|
+
if (!download || download.status !== "published") return null;
|
|
150
|
+
return {
|
|
151
|
+
download,
|
|
152
|
+
assets: await this.content.listDownloadAssets(orgId, downloadId)
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
async thumbnailFile(orgId, actor, owner, id) {
|
|
156
|
+
const item = owner === "course" ? await this.content.getCourse(orgId, id) : owner === "download" ? await this.content.getDownload(orgId, id) : await this.content.getCommunity(orgId, id);
|
|
157
|
+
if (!item?.thumbnailAssetId || item.status !== "published" && !isStaffRole(actor.role)) return null;
|
|
158
|
+
return this.files.signFile(orgId, item.thumbnailAssetId);
|
|
159
|
+
}
|
|
160
|
+
async activityFile(orgId, actor, activityId, assetId) {
|
|
161
|
+
const activity = await this.content.getActivity(orgId, activityId);
|
|
162
|
+
if (!activity) return null;
|
|
163
|
+
if (!isStaffRole(actor.role)) {
|
|
164
|
+
if (!isActivityPublished(activity.settings) || !await this.getCourse(orgId, actor.id, activity.courseId)) return null;
|
|
165
|
+
}
|
|
166
|
+
if (!(await this.content.listCourseActivityAssets(orgId, activity.courseId)).some((link) => link.activityId === activityId && link.assetId === assetId)) return null;
|
|
167
|
+
return this.files.signFile(orgId, assetId);
|
|
168
|
+
}
|
|
169
|
+
async downloadFile(orgId, actor, downloadId, assetId) {
|
|
170
|
+
if (!isStaffRole(actor.role) && !await this.getDownload(orgId, actor.id, downloadId)) return null;
|
|
171
|
+
const file = (await this.content.listDownloadAssets(orgId, downloadId)).find((f) => f.assetId === assetId);
|
|
172
|
+
if (!file) return null;
|
|
173
|
+
return this.files.signFile(orgId, assetId, { saveAs: file.displayName ?? file.filename });
|
|
174
|
+
}
|
|
175
|
+
async personImage(orgId, orgUserId) {
|
|
176
|
+
const [person] = await this.repo.people(orgId, [orgUserId]);
|
|
177
|
+
if (!person?.imageAssetId) return null;
|
|
178
|
+
return this.files.signFile(orgId, person.imageAssetId);
|
|
179
|
+
}
|
|
180
|
+
async directory(orgId, actor, communityId, query) {
|
|
181
|
+
if (!await this.access.isCommunityMember(orgId, actor, communityId)) return null;
|
|
182
|
+
if (!await this.content.getCommunity(orgId, communityId)) return null;
|
|
183
|
+
const page = await this.repo.directory(orgId, communityId, query);
|
|
184
|
+
return {
|
|
185
|
+
...page,
|
|
186
|
+
rows: page.rows.map((row) => ({
|
|
187
|
+
...row,
|
|
188
|
+
imageUrl: row.imageAssetId ? this.fileUrls.personImage(row.orgUserId) : null
|
|
189
|
+
}))
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
async communityHome(orgId, actor, communityId) {
|
|
193
|
+
if (!await this.access.isCommunityMember(orgId, actor, communityId)) return null;
|
|
194
|
+
const community = await this.content.getCommunity(orgId, communityId);
|
|
195
|
+
if (!community) return null;
|
|
196
|
+
const spaces = await this.content.listSpaces(orgId, communityId);
|
|
197
|
+
return {
|
|
198
|
+
communityId,
|
|
199
|
+
title: community.title,
|
|
200
|
+
description: community.description,
|
|
201
|
+
thumbnailUrl: community.thumbnailUrl,
|
|
202
|
+
dm: community.settings.dm,
|
|
203
|
+
spaces: await this.homeSpaces(orgId, actor, communityId, spaces)
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
async communitySpace(orgId, actor, communityId, spaceId) {
|
|
207
|
+
if (!await this.access.isCommunityMember(orgId, actor, communityId)) return null;
|
|
208
|
+
const space = await this.content.getSpace(orgId, spaceId);
|
|
209
|
+
if (!space || space.communityId !== communityId) return null;
|
|
210
|
+
const [view] = await this.homeSpaces(orgId, actor, communityId, [space]);
|
|
211
|
+
return view ?? null;
|
|
212
|
+
}
|
|
213
|
+
async homeSpaces(orgId, actor, communityId, spaces) {
|
|
214
|
+
const [openIds, counts, standings] = await Promise.all([
|
|
215
|
+
this.access.openSpaceIds(orgId, actor, communityId),
|
|
216
|
+
this.repo.spaceMemberCounts(orgId, communityId),
|
|
217
|
+
this.access.spaceStandings(orgId, actor, communityId)
|
|
218
|
+
]);
|
|
219
|
+
const open = new Set(openIds);
|
|
220
|
+
const seen = spaces.filter((space) => seesSpace(actor.role, space.accessRule, standings[space.id]));
|
|
221
|
+
return Promise.all(seen.map(async (space) => {
|
|
222
|
+
const memberCount = counts[space.id] ?? 0;
|
|
223
|
+
const base = {
|
|
224
|
+
id: space.id,
|
|
225
|
+
name: space.name,
|
|
226
|
+
memberCount,
|
|
227
|
+
accessRule: space.accessRule,
|
|
228
|
+
standing: standingOf(space, open.has(space.id), memberCount, standings[space.id])
|
|
229
|
+
};
|
|
230
|
+
if (!open.has(space.id)) return {
|
|
231
|
+
...base,
|
|
232
|
+
locked: true
|
|
233
|
+
};
|
|
234
|
+
return {
|
|
235
|
+
...base,
|
|
236
|
+
locked: false,
|
|
237
|
+
description: space.description,
|
|
238
|
+
capacity: space.capacity,
|
|
239
|
+
settings: space.settings,
|
|
240
|
+
topics: space.topics.map((topic) => ({
|
|
241
|
+
id: topic.id,
|
|
242
|
+
name: topic.name
|
|
243
|
+
})),
|
|
244
|
+
links: await this.linkViews(orgId, actor, space.links)
|
|
245
|
+
};
|
|
246
|
+
}));
|
|
247
|
+
}
|
|
248
|
+
async linkViews(orgId, actor, links) {
|
|
249
|
+
const shown = (status) => status === "published" || isStaffRole(actor.role);
|
|
250
|
+
return (await Promise.all(links.map(async (link) => {
|
|
251
|
+
const course = await this.content.getCourse(orgId, link.contentId);
|
|
252
|
+
if (course) return shown(course.status) ? {
|
|
253
|
+
id: link.id,
|
|
254
|
+
contentId: link.contentId,
|
|
255
|
+
type: "course",
|
|
256
|
+
title: course.title
|
|
257
|
+
} : null;
|
|
258
|
+
const download = await this.content.getDownload(orgId, link.contentId);
|
|
259
|
+
if (download) return shown(download.status) ? {
|
|
260
|
+
id: link.id,
|
|
261
|
+
contentId: link.contentId,
|
|
262
|
+
type: "download",
|
|
263
|
+
title: download.title
|
|
264
|
+
} : null;
|
|
265
|
+
const community = await this.content.getCommunity(orgId, link.contentId);
|
|
266
|
+
if (community) return shown(community.status) ? {
|
|
267
|
+
id: link.id,
|
|
268
|
+
contentId: link.contentId,
|
|
269
|
+
type: "community",
|
|
270
|
+
title: community.title
|
|
271
|
+
} : null;
|
|
272
|
+
return null;
|
|
273
|
+
}))).filter((view) => view !== null);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
function standingOf(space, open, memberCount, status) {
|
|
277
|
+
if (space.accessRule === "all_members" || open && status !== "active") return "open";
|
|
278
|
+
if (status === "active") return "member";
|
|
279
|
+
if (status === "requested" || status === "invited") return status;
|
|
280
|
+
if (space.capacity !== null && memberCount >= space.capacity) return "full";
|
|
281
|
+
return "none";
|
|
282
|
+
}
|
|
283
|
+
//#endregion
|
|
284
|
+
export { MemberReportServiceImpl };
|
|
285
|
+
|
|
286
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","names":[],"sources":["../../../src/reporting/member/service.ts"],"sourcesContent":["import { type ContentServicePort, type SpaceDetail } from '../../content/index.js';\nimport { seesSpace, type EntitlementsService, type SpaceMember } from '../../entitlements/index.js';\nimport type { ProgressService } from '../../progress/index.js';\nimport type { AssetFiles, FileUrls } from '../../assets/index.js';\nimport { isStaffRole } from '../../organizations/index.js';\nimport type { ChatService, PostService } from '../../discussion/index.js';\nimport type { Notification, NotificationInbox } from '../../identity/index.js';\nimport type { Actor } from '../../shared/actor.js';\nimport type { Page } from '../../types/index.js';\nimport type {\n ActivityView,\n CommunityHome,\n CommunityHomeLink,\n CommunityHomeSpace,\n CourseProgressView,\n CourseView,\n DirectoryEntry,\n DirectoryQuery,\n DownloadFile,\n DownloadView,\n Module,\n NotificationView,\n NotificationsView,\n} from './model.js';\nimport type { MemberReportRepository, MemberReportService } from './ports.js';\n\nfunction ref(\n id: string | null,\n names: ReadonlyMap<string, string>,\n): { id: string; name: string } | null {\n const name = id ? names.get(id) : undefined;\n return id && name !== undefined ? { id, name } : null;\n}\n\nfunction isActivityPublished(settings: unknown): boolean {\n return (settings as { published?: boolean } | null)?.published !== false;\n}\n\ntype MemberAccess = Pick<\n EntitlementsService,\n 'isCommunityMember' | 'openSpaceIds' | 'spaceStandings' | 'hasAccess' | 'listAccessibleContent'\n>;\n\nexport type MemberReportServiceParams = {\n repo: MemberReportRepository;\n content: ContentServicePort;\n progress: ProgressService;\n files: Pick<AssetFiles, 'signFile'>;\n fileUrls: FileUrls;\n access: MemberAccess;\n notifications: Pick<NotificationInbox, 'listNotifications'>;\n posts: Pick<PostService, 'visibleTitles'>;\n chats: Pick<ChatService, 'titlesFor'>;\n};\n\nexport class MemberReportServiceImpl implements MemberReportService {\n private readonly repo: MemberReportRepository;\n private readonly content: ContentServicePort;\n private readonly progress: ProgressService;\n private readonly files: Pick<AssetFiles, 'signFile'>;\n private readonly fileUrls: FileUrls;\n private readonly access: MemberAccess;\n private readonly inbox: Pick<NotificationInbox, 'listNotifications'>;\n private readonly posts: Pick<PostService, 'visibleTitles'>;\n private readonly chats: Pick<ChatService, 'titlesFor'>;\n\n constructor(params: MemberReportServiceParams) {\n this.repo = params.repo;\n this.content = params.content;\n this.progress = params.progress;\n this.files = params.files;\n this.fileUrls = params.fileUrls;\n this.access = params.access;\n this.inbox = params.notifications;\n this.posts = params.posts;\n this.chats = params.chats;\n }\n\n async notifications(\n orgId: string,\n actor: Actor,\n userId: string,\n query: { page: number; pageSize: number },\n ): Promise<NotificationsView> {\n const page = await this.inbox.listNotifications(orgId, userId, query);\n return {\n rows: await this.describeNotifications(orgId, actor, page.rows),\n total: page.total,\n page: page.page,\n pageSize: page.pageSize,\n unreadCount: page.unreadCount,\n };\n }\n\n async notificationView(\n orgId: string,\n actor: Actor,\n notification: Notification,\n ): Promise<NotificationView> {\n const [view] = await this.describeNotifications(orgId, actor, [notification]);\n return view!;\n }\n\n private async describeNotifications(\n orgId: string,\n actor: Actor,\n rows: Notification[],\n ): Promise<NotificationView[]> {\n const ids = (pick: (row: Notification) => string | null): string[] => [\n ...new Set(rows.flatMap((row) => pick(row) ?? [])),\n ];\n const [people, postTitles, chatTitles, spaces, communities] = await Promise.all([\n this.repo.people(\n orgId,\n ids((row) => row.actorOrgUserId),\n ),\n this.posts.visibleTitles(\n orgId,\n actor,\n ids((row) => row.postId),\n ),\n this.chats.titlesFor(\n orgId,\n actor,\n ids((row) => row.chatId),\n ),\n Promise.all(ids((row) => row.spaceId).map((id) => this.content.getSpace(orgId, id))),\n Promise.all(ids((row) => row.communityId).map((id) => this.content.getCommunity(orgId, id))),\n ]);\n const personById = new Map(people.map((person) => [person.orgUserId, person]));\n const spaceById = new Map(spaces.flatMap((space) => (space ? [[space.id, space.name]] : [])));\n const communityById = new Map(\n communities.flatMap((community) => (community ? [[community.id, community.title]] : [])),\n );\n const postById = new Map(Object.entries(postTitles));\n const chatById = new Map(Object.entries(chatTitles));\n return rows.map((row) => {\n const person = row.actorOrgUserId ? personById.get(row.actorOrgUserId) : undefined;\n const community = ref(row.communityId, communityById);\n const space = ref(row.spaceId, spaceById);\n const post = ref(row.postId, postById);\n const chat = ref(row.chatId, chatById);\n return {\n id: row.id,\n kind: row.kind,\n createdAt: row.createdAt,\n readAt: row.readAt,\n actor: person\n ? {\n orgUserId: person.orgUserId,\n displayName: person.displayName,\n imageUrl: person.imageAssetId ? this.fileUrls.personImage(person.orgUserId) : null,\n }\n : null,\n community: community && { id: community.id, title: community.name },\n space: space && { id: space.id, name: space.name },\n post: post && { id: post.id, title: post.name },\n commentId: row.commentId,\n chat: chat && { id: chat.id, title: chat.name },\n messageId: row.messageId,\n };\n });\n }\n\n async listCourses(orgId: string, orgUserId: string): Promise<CourseView[]> {\n const ids = await this.access.listAccessibleContent(orgId, orgUserId, 'course');\n const courses = await Promise.all(ids.map((id) => this.content.getCourse(orgId, id)));\n return courses.filter((c): c is CourseView => c !== null && c.status === 'published');\n }\n\n async getCourse(orgId: string, orgUserId: string, courseId: string): Promise<CourseView | null> {\n if (!(await this.access.hasAccess(orgId, orgUserId, courseId))) {\n return null;\n }\n const course = await this.content.getCourse(orgId, courseId);\n return course && course.status === 'published' ? course : null;\n }\n\n async listModules(orgId: string, orgUserId: string, courseId: string): Promise<Module[] | null> {\n if (!(await this.getCourse(orgId, orgUserId, courseId))) {\n return null;\n }\n return this.content.listCourseModules(orgId, courseId);\n }\n\n async listActivities(\n orgId: string,\n orgUserId: string,\n courseId: string,\n ): Promise<ActivityView[] | null> {\n if (!(await this.getCourse(orgId, orgUserId, courseId))) {\n return null;\n }\n const activities = await this.content.listCourseActivityViews(orgId, courseId);\n return activities.filter((a) => isActivityPublished(a.settings));\n }\n\n async courseProgress(\n orgId: string,\n orgUserId: string,\n courseId: string,\n ): Promise<CourseProgressView | null> {\n if (!(await this.getCourse(orgId, orgUserId, courseId))) {\n return null;\n }\n const courseActivities = await this.content.listCourseActivities(orgId, courseId);\n const ids = courseActivities.filter((a) => isActivityPublished(a.settings)).map((a) => a.id);\n const records = await this.progress.listByTargets(orgId, orgUserId, ids);\n const activities: CourseProgressView['activities'] = {};\n const positions: CourseProgressView['positions'] = {};\n let done = 0;\n for (const r of records) {\n if (r.targetType !== 'activity') {\n continue;\n }\n activities[r.targetId] = r.completedAt ? 'completed' : 'in-progress';\n if (r.completedAt) {\n done += 1;\n }\n if (r.position != null) {\n positions[r.targetId] = r.position;\n }\n }\n const courseRecord = await this.progress.get(orgId, {\n orgUserId,\n targetType: 'course',\n targetId: courseId,\n });\n return {\n activities,\n percent: ids.length > 0 ? Math.round((done / ids.length) * 100) : 0,\n completed: courseRecord?.completedAt != null,\n positions,\n };\n }\n\n async listDownloads(orgId: string, orgUserId: string): Promise<DownloadView[]> {\n const ids = await this.access.listAccessibleContent(orgId, orgUserId, 'download');\n const rows = await Promise.all(ids.map((id) => this.content.getDownload(orgId, id)));\n return rows.filter((d): d is DownloadView => d !== null && d.status === 'published');\n }\n\n async getDownload(\n orgId: string,\n orgUserId: string,\n downloadId: string,\n ): Promise<{ download: DownloadView; assets: DownloadFile[] } | null> {\n if (!(await this.access.hasAccess(orgId, orgUserId, downloadId))) {\n return null;\n }\n const download = await this.content.getDownload(orgId, downloadId);\n if (!download || download.status !== 'published') {\n return null;\n }\n const assets = await this.content.listDownloadAssets(orgId, downloadId);\n return { download, assets };\n }\n\n async thumbnailFile(\n orgId: string,\n actor: Actor,\n owner: 'course' | 'download' | 'community',\n id: string,\n ): Promise<string | null> {\n const item =\n owner === 'course'\n ? await this.content.getCourse(orgId, id)\n : owner === 'download'\n ? await this.content.getDownload(orgId, id)\n : await this.content.getCommunity(orgId, id);\n if (!item?.thumbnailAssetId || (item.status !== 'published' && !isStaffRole(actor.role))) {\n return null;\n }\n return this.files.signFile(orgId, item.thumbnailAssetId);\n }\n\n async activityFile(\n orgId: string,\n actor: Actor,\n activityId: string,\n assetId: string,\n ): Promise<string | null> {\n const activity = await this.content.getActivity(orgId, activityId);\n if (!activity) {\n return null;\n }\n if (!isStaffRole(actor.role)) {\n if (\n !isActivityPublished(activity.settings) ||\n !(await this.getCourse(orgId, actor.id, activity.courseId))\n ) {\n return null;\n }\n }\n const links = await this.content.listCourseActivityAssets(orgId, activity.courseId);\n if (!links.some((link) => link.activityId === activityId && link.assetId === assetId)) {\n return null;\n }\n return this.files.signFile(orgId, assetId);\n }\n\n async downloadFile(\n orgId: string,\n actor: Actor,\n downloadId: string,\n assetId: string,\n ): Promise<string | null> {\n if (!isStaffRole(actor.role) && !(await this.getDownload(orgId, actor.id, downloadId))) {\n return null;\n }\n const files = await this.content.listDownloadAssets(orgId, downloadId);\n const file = files.find((f) => f.assetId === assetId);\n if (!file) {\n return null;\n }\n return this.files.signFile(orgId, assetId, { saveAs: file.displayName ?? file.filename });\n }\n\n async personImage(orgId: string, orgUserId: string): Promise<string | null> {\n const [person] = await this.repo.people(orgId, [orgUserId]);\n if (!person?.imageAssetId) {\n return null;\n }\n return this.files.signFile(orgId, person.imageAssetId);\n }\n\n async directory(\n orgId: string,\n actor: Actor,\n communityId: string,\n query: DirectoryQuery,\n ): Promise<Page<DirectoryEntry> | null> {\n if (!(await this.access.isCommunityMember(orgId, actor, communityId))) {\n return null;\n }\n const community = await this.content.getCommunity(orgId, communityId);\n if (!community) {\n return null;\n }\n const page = await this.repo.directory(orgId, communityId, query);\n return {\n ...page,\n rows: page.rows.map((row) => ({\n ...row,\n imageUrl: row.imageAssetId ? this.fileUrls.personImage(row.orgUserId) : null,\n })),\n };\n }\n\n async communityHome(\n orgId: string,\n actor: Actor,\n communityId: string,\n ): Promise<CommunityHome | null> {\n if (!(await this.access.isCommunityMember(orgId, actor, communityId))) {\n return null;\n }\n const community = await this.content.getCommunity(orgId, communityId);\n if (!community) {\n return null;\n }\n const spaces = await this.content.listSpaces(orgId, communityId);\n return {\n communityId,\n title: community.title,\n description: community.description,\n thumbnailUrl: community.thumbnailUrl,\n dm: community.settings.dm,\n spaces: await this.homeSpaces(orgId, actor, communityId, spaces),\n };\n }\n\n async communitySpace(\n orgId: string,\n actor: Actor,\n communityId: string,\n spaceId: string,\n ): Promise<CommunityHomeSpace | null> {\n if (!(await this.access.isCommunityMember(orgId, actor, communityId))) {\n return null;\n }\n const space = await this.content.getSpace(orgId, spaceId);\n if (!space || space.communityId !== communityId) {\n return null;\n }\n const [view] = await this.homeSpaces(orgId, actor, communityId, [space]);\n return view ?? null;\n }\n\n private async homeSpaces(\n orgId: string,\n actor: Actor,\n communityId: string,\n spaces: SpaceDetail[],\n ): Promise<CommunityHomeSpace[]> {\n const [openIds, counts, standings] = await Promise.all([\n this.access.openSpaceIds(orgId, actor, communityId),\n this.repo.spaceMemberCounts(orgId, communityId),\n this.access.spaceStandings(orgId, actor, communityId),\n ]);\n const open = new Set(openIds);\n const seen = spaces.filter((space) =>\n seesSpace(actor.role, space.accessRule, standings[space.id]),\n );\n return Promise.all(\n seen.map(async (space): Promise<CommunityHomeSpace> => {\n const memberCount = counts[space.id] ?? 0;\n const base = {\n id: space.id,\n name: space.name,\n memberCount,\n accessRule: space.accessRule,\n standing: standingOf(space, open.has(space.id), memberCount, standings[space.id]),\n };\n if (!open.has(space.id)) {\n return { ...base, locked: true };\n }\n return {\n ...base,\n locked: false,\n description: space.description,\n capacity: space.capacity,\n settings: space.settings,\n topics: space.topics.map((topic) => ({ id: topic.id, name: topic.name })),\n links: await this.linkViews(orgId, actor, space.links),\n };\n }),\n );\n }\n\n private async linkViews(\n orgId: string,\n actor: Actor,\n links: SpaceDetail['links'],\n ): Promise<CommunityHomeLink[]> {\n const shown = (status: string) => status === 'published' || isStaffRole(actor.role);\n const views = await Promise.all(\n links.map(async (link): Promise<CommunityHomeLink | null> => {\n const course = await this.content.getCourse(orgId, link.contentId);\n if (course) {\n return shown(course.status)\n ? { id: link.id, contentId: link.contentId, type: 'course', title: course.title }\n : null;\n }\n const download = await this.content.getDownload(orgId, link.contentId);\n if (download) {\n return shown(download.status)\n ? { id: link.id, contentId: link.contentId, type: 'download', title: download.title }\n : null;\n }\n const community = await this.content.getCommunity(orgId, link.contentId);\n if (community) {\n return shown(community.status)\n ? { id: link.id, contentId: link.contentId, type: 'community', title: community.title }\n : null;\n }\n return null;\n }),\n );\n return views.filter((view): view is CommunityHomeLink => view !== null);\n }\n}\n\nfunction standingOf(\n space: SpaceDetail,\n open: boolean,\n memberCount: number,\n status: SpaceMember['status'] | undefined,\n): CommunityHomeSpace['standing'] {\n if (space.accessRule === 'all_members' || (open && status !== 'active')) {\n return 'open';\n }\n if (status === 'active') {\n return 'member';\n }\n if (status === 'requested' || status === 'invited') {\n return status;\n }\n if (space.capacity !== null && memberCount >= space.capacity) {\n return 'full';\n }\n return 'none';\n}\n"],"mappings":"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"}
|
package/dist/shared/errors.d.ts
CHANGED
|
@@ -17,6 +17,12 @@ declare class ConflictError extends Error {
|
|
|
17
17
|
declare class ForbiddenError extends Error {
|
|
18
18
|
constructor(message: string);
|
|
19
19
|
}
|
|
20
|
+
/** The caller's own input breaks a rule, independent of existing state
|
|
21
|
+
* (wrong file type, too large, talking to yourself, …). The HTTP layer maps
|
|
22
|
+
* this to 400. */
|
|
23
|
+
declare class InvalidInputError extends Error {
|
|
24
|
+
constructor(message: string);
|
|
25
|
+
}
|
|
20
26
|
//#endregion
|
|
21
|
-
export { ConflictError, ForbiddenError, NotFoundError };
|
|
27
|
+
export { ConflictError, ForbiddenError, InvalidInputError, NotFoundError };
|
|
22
28
|
//# sourceMappingURL=errors.d.ts.map
|
package/dist/shared/errors.js
CHANGED
|
@@ -28,7 +28,16 @@ var ForbiddenError = class extends Error {
|
|
|
28
28
|
this.name = "ForbiddenError";
|
|
29
29
|
}
|
|
30
30
|
};
|
|
31
|
+
/** The caller's own input breaks a rule, independent of existing state
|
|
32
|
+
* (wrong file type, too large, talking to yourself, …). The HTTP layer maps
|
|
33
|
+
* this to 400. */
|
|
34
|
+
var InvalidInputError = class extends Error {
|
|
35
|
+
constructor(message) {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "InvalidInputError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
31
40
|
//#endregion
|
|
32
|
-
export { ConflictError, ForbiddenError, NotFoundError };
|
|
41
|
+
export { ConflictError, ForbiddenError, InvalidInputError, NotFoundError };
|
|
33
42
|
|
|
34
43
|
//# sourceMappingURL=errors.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"errors.js","names":[],"sources":["../../src/shared/errors.ts"],"sourcesContent":["// Cross-cutting domain errors. Like `../shared/ports.js`, this file is\n// importable from any context; the central HTTP error handler maps these to\n// status codes so routes never hand-roll error replies.\n\n/** A command's target does not exist in this org. Queries return null for the\n * same situation — a missing row is a normal answer to a question, but a\n * failed precondition for a command. */\nexport class NotFoundError extends Error {\n constructor(\n readonly resource: string,\n readonly id: string,\n ) {\n super(`${resource} not found`);\n this.name = 'NotFoundError';\n }\n}\n\n/** A command conflicts with existing state (duplicate email, already linked,\n * …). The HTTP layer maps this to 409. */\nexport class ConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConflictError';\n }\n}\n\n/** The caller is authenticated but not permitted to perform this command.\n * The HTTP layer maps this to 403. */\nexport class ForbiddenError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ForbiddenError';\n }\n}\n"],"mappings":";;;;AAOA,IAAa,gBAAb,cAAmC,MAAM;CAE5B;CACA;CAFX,YACE,UACA,IACA;EACA,MAAM,GAAG,SAAS,WAAW;EAHpB,KAAA,WAAA;EACA,KAAA,KAAA;EAGT,KAAK,OAAO;CACd;AACF;;;AAIA,IAAa,gBAAb,cAAmC,MAAM;CACvC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;;;AAIA,IAAa,iBAAb,cAAoC,MAAM;CACxC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"errors.js","names":[],"sources":["../../src/shared/errors.ts"],"sourcesContent":["// Cross-cutting domain errors. Like `../shared/ports.js`, this file is\n// importable from any context; the central HTTP error handler maps these to\n// status codes so routes never hand-roll error replies.\n\n/** A command's target does not exist in this org. Queries return null for the\n * same situation — a missing row is a normal answer to a question, but a\n * failed precondition for a command. */\nexport class NotFoundError extends Error {\n constructor(\n readonly resource: string,\n readonly id: string,\n ) {\n super(`${resource} not found`);\n this.name = 'NotFoundError';\n }\n}\n\n/** A command conflicts with existing state (duplicate email, already linked,\n * …). The HTTP layer maps this to 409. */\nexport class ConflictError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ConflictError';\n }\n}\n\n/** The caller is authenticated but not permitted to perform this command.\n * The HTTP layer maps this to 403. */\nexport class ForbiddenError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'ForbiddenError';\n }\n}\n\n/** The caller's own input breaks a rule, independent of existing state\n * (wrong file type, too large, talking to yourself, …). The HTTP layer maps\n * this to 400. */\nexport class InvalidInputError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'InvalidInputError';\n }\n}\n"],"mappings":";;;;AAOA,IAAa,gBAAb,cAAmC,MAAM;CAE5B;CACA;CAFX,YACE,UACA,IACA;EACA,MAAM,GAAG,SAAS,WAAW;EAHpB,KAAA,WAAA;EACA,KAAA,KAAA;EAGT,KAAK,OAAO;CACd;AACF;;;AAIA,IAAa,gBAAb,cAAmC,MAAM;CACvC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;;;AAIA,IAAa,iBAAb,cAAoC,MAAM;CACxC,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF;;;;AAKA,IAAa,oBAAb,cAAuC,MAAM;CAC3C,YAAY,SAAiB;EAC3B,MAAM,OAAO;EACb,KAAK,OAAO;CACd;AACF"}
|