@headless-lms/server 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -0
- package/dist/app/community-mail.d.ts +10 -10
- package/dist/app/community-mail.js +72 -28
- package/dist/app/community-mail.js.map +1 -1
- package/dist/app/container.d.ts +48 -10
- package/dist/app/container.js +268 -48
- package/dist/app/container.js.map +1 -1
- package/dist/app/notification-channels.d.ts +47 -0
- package/dist/app/notification-channels.js +175 -0
- package/dist/app/notification-channels.js.map +1 -0
- package/dist/app/notification-reads.d.ts +23 -0
- package/dist/app/notification-reads.js +74 -0
- package/dist/app/notification-reads.js.map +1 -0
- package/dist/app/platform.d.ts +14 -0
- package/dist/app/platform.js +14 -0
- package/dist/app/platform.js.map +1 -0
- package/dist/http/config.d.ts +4 -0
- package/dist/http/errors.d.ts +1 -0
- package/dist/http/errors.js +24 -4
- package/dist/http/errors.js.map +1 -1
- package/dist/http/fastify.d.ts +8 -0
- package/dist/http/mcp/catalogue.d.ts +11 -9
- package/dist/http/mcp/catalogue.js +15 -21
- package/dist/http/mcp/catalogue.js.map +1 -1
- package/dist/http/mcp/challenge.js +3 -3
- package/dist/http/mcp/challenge.js.map +1 -1
- package/dist/http/mcp/route.js +7 -7
- package/dist/http/mcp/route.js.map +1 -1
- package/dist/http/mcp/test-support.d.ts +6 -5
- package/dist/http/mcp/test-support.js +32 -11
- package/dist/http/mcp/test-support.js.map +1 -1
- package/dist/http/mcp/tool.d.ts +3 -9
- package/dist/http/mcp/tool.js +14 -6
- package/dist/http/mcp/tool.js.map +1 -1
- package/dist/http/mcp/tools/automations.js +10 -20
- package/dist/http/mcp/tools/automations.js.map +1 -1
- package/dist/http/mcp/tools/catalog.js +25 -42
- package/dist/http/mcp/tools/catalog.js.map +1 -1
- package/dist/http/mcp/tools/comments.js +9 -19
- package/dist/http/mcp/tools/comments.js.map +1 -1
- package/dist/http/mcp/tools/communities.js +16 -31
- package/dist/http/mcp/tools/communities.js.map +1 -1
- package/dist/http/mcp/tools/community-members.js +9 -16
- package/dist/http/mcp/tools/community-members.js.map +1 -1
- package/dist/http/mcp/tools/community-moderation.js +13 -25
- package/dist/http/mcp/tools/community-moderation.js.map +1 -1
- package/dist/http/mcp/tools/courses.js +11 -21
- package/dist/http/mcp/tools/courses.js.map +1 -1
- package/dist/http/mcp/tools/events.d.ts +6 -0
- package/dist/http/mcp/tools/events.js +170 -0
- package/dist/http/mcp/tools/events.js.map +1 -0
- package/dist/http/mcp/tools/index.d.ts +5 -1
- package/dist/http/mcp/tools/index.js +45 -10
- package/dist/http/mcp/tools/index.js.map +1 -1
- package/dist/http/mcp/tools/organization.d.ts +6 -0
- package/dist/http/mcp/tools/organization.js +214 -0
- package/dist/http/mcp/tools/organization.js.map +1 -0
- package/dist/http/mcp/tools/people.js +30 -49
- package/dist/http/mcp/tools/people.js.map +1 -1
- package/dist/http/plugins/auth.js +37 -8
- package/dist/http/plugins/auth.js.map +1 -1
- package/dist/http/plugins/error-handler.d.ts +5 -1
- package/dist/http/plugins/error-handler.js +13 -3
- package/dist/http/plugins/error-handler.js.map +1 -1
- package/dist/http/plugins/openapi.js +18 -2
- package/dist/http/plugins/openapi.js.map +1 -1
- package/dist/http/plugins/platform.d.ts +7 -0
- package/dist/http/plugins/platform.js +13 -0
- package/dist/http/plugins/platform.js.map +1 -0
- package/dist/http/routes/access.js +54 -36
- package/dist/http/routes/access.js.map +1 -1
- package/dist/http/routes/activities.js +45 -45
- package/dist/http/routes/activities.js.map +1 -1
- package/dist/http/routes/assets.js +30 -65
- package/dist/http/routes/assets.js.map +1 -1
- package/dist/http/routes/automations.js +37 -42
- package/dist/http/routes/automations.js.map +1 -1
- package/dist/http/routes/bundles.js +33 -36
- package/dist/http/routes/bundles.js.map +1 -1
- package/dist/http/routes/communities.js +144 -136
- package/dist/http/routes/communities.js.map +1 -1
- package/dist/http/routes/community-moderation.js +83 -137
- package/dist/http/routes/community-moderation.js.map +1 -1
- package/dist/http/routes/course-analytics.js +32 -15
- package/dist/http/routes/course-analytics.js.map +1 -1
- package/dist/http/routes/courses.js +25 -32
- package/dist/http/routes/courses.js.map +1 -1
- package/dist/http/routes/dashboard.js +9 -9
- package/dist/http/routes/dashboard.js.map +1 -1
- package/dist/http/routes/discussion.js +21 -39
- package/dist/http/routes/discussion.js.map +1 -1
- package/dist/http/routes/downloads.js +41 -47
- package/dist/http/routes/downloads.js.map +1 -1
- package/dist/http/routes/entitlements.js +19 -23
- package/dist/http/routes/entitlements.js.map +1 -1
- package/dist/http/routes/events.d.ts +7 -0
- package/dist/http/routes/events.js +333 -0
- package/dist/http/routes/events.js.map +1 -0
- package/dist/http/routes/integrations.js +40 -73
- package/dist/http/routes/integrations.js.map +1 -1
- package/dist/http/routes/member/assets.js +10 -13
- package/dist/http/routes/member/assets.js.map +1 -1
- package/dist/http/routes/member/chats.js +177 -75
- package/dist/http/routes/member/chats.js.map +1 -1
- package/dist/http/routes/member/comments.js +65 -26
- package/dist/http/routes/member/comments.js.map +1 -1
- package/dist/http/routes/member/community.js +68 -51
- package/dist/http/routes/member/community.js.map +1 -1
- package/dist/http/routes/member/courses.js +12 -19
- package/dist/http/routes/member/courses.js.map +1 -1
- package/dist/http/routes/member/devices.d.ts +7 -0
- package/dist/http/routes/member/devices.js +97 -0
- package/dist/http/routes/member/devices.js.map +1 -0
- package/dist/http/routes/member/downloads.js +6 -9
- package/dist/http/routes/member/downloads.js.map +1 -1
- package/dist/http/routes/member/events.d.ts +7 -0
- package/dist/http/routes/member/events.js +386 -0
- package/dist/http/routes/member/events.js.map +1 -0
- package/dist/http/routes/member/files.js +71 -46
- package/dist/http/routes/member/files.js.map +1 -1
- package/dist/http/routes/member/index.js +6 -0
- package/dist/http/routes/member/index.js.map +1 -1
- package/dist/http/routes/member/notification-settings.d.ts +7 -0
- package/dist/http/routes/member/notification-settings.js +100 -0
- package/dist/http/routes/member/notification-settings.js.map +1 -0
- package/dist/http/routes/member/notifications.js +69 -45
- package/dist/http/routes/member/notifications.js.map +1 -1
- package/dist/http/routes/member/org.js +5 -15
- package/dist/http/routes/member/org.js.map +1 -1
- package/dist/http/routes/member/posts.js +94 -95
- package/dist/http/routes/member/posts.js.map +1 -1
- package/dist/http/routes/member/profile.js +15 -6
- package/dist/http/routes/member/profile.js.map +1 -1
- package/dist/http/routes/member/progress.js +7 -11
- package/dist/http/routes/member/progress.js.map +1 -1
- package/dist/http/routes/organizations.js +415 -110
- package/dist/http/routes/organizations.js.map +1 -1
- package/dist/http/routes/platform.d.ts +7 -0
- package/dist/http/routes/platform.js +61 -0
- package/dist/http/routes/platform.js.map +1 -0
- package/dist/http/routes/students.js +12 -75
- package/dist/http/routes/students.js.map +1 -1
- package/dist/http/routes/webhooks.js +30 -39
- package/dist/http/routes/webhooks.js.map +1 -1
- package/dist/http/routes.js +9 -0
- package/dist/http/routes.js.map +1 -1
- package/dist/http/schemas/access.d.ts +346 -64
- package/dist/http/schemas/access.js +39 -12
- package/dist/http/schemas/access.js.map +1 -1
- package/dist/http/schemas/assets.d.ts +13 -8
- package/dist/http/schemas/assets.js +6 -5
- package/dist/http/schemas/assets.js.map +1 -1
- package/dist/http/schemas/automations.d.ts +4 -8
- package/dist/http/schemas/chats.d.ts +238 -36
- package/dist/http/schemas/chats.js +14 -7
- package/dist/http/schemas/chats.js.map +1 -1
- package/dist/http/schemas/community.d.ts +140 -33
- package/dist/http/schemas/community.js +25 -9
- package/dist/http/schemas/community.js.map +1 -1
- package/dist/http/schemas/course-analytics.d.ts +51 -1
- package/dist/http/schemas/course-analytics.js +19 -1
- package/dist/http/schemas/course-analytics.js.map +1 -1
- package/dist/http/schemas/dashboard.d.ts +1 -0
- package/dist/http/schemas/dashboard.js +2 -1
- package/dist/http/schemas/dashboard.js.map +1 -1
- package/dist/http/schemas/discussion.d.ts +45 -73
- package/dist/http/schemas/discussion.js +16 -4
- package/dist/http/schemas/discussion.js.map +1 -1
- package/dist/http/schemas/entitlements.d.ts +9 -12
- package/dist/http/schemas/entitlements.js +11 -5
- package/dist/http/schemas/entitlements.js.map +1 -1
- package/dist/http/schemas/events.d.ts +527 -0
- package/dist/http/schemas/events.js +64 -0
- package/dist/http/schemas/events.js.map +1 -0
- package/dist/http/schemas/files.d.ts +15 -5
- package/dist/http/schemas/files.js +10 -2
- package/dist/http/schemas/files.js.map +1 -1
- package/dist/http/schemas/index.d.ts +14 -12
- package/dist/http/schemas/index.js +14 -12
- package/dist/http/schemas/invites.d.ts +3 -47
- package/dist/http/schemas/invites.js +4 -25
- package/dist/http/schemas/invites.js.map +1 -1
- package/dist/http/schemas/member.d.ts +94 -7
- package/dist/http/schemas/member.js +7 -3
- package/dist/http/schemas/member.js.map +1 -1
- package/dist/http/schemas/members.d.ts +329 -65
- package/dist/http/schemas/members.js +67 -25
- package/dist/http/schemas/members.js.map +1 -1
- package/dist/http/schemas/notifications.d.ts +502 -175
- package/dist/http/schemas/notifications.js +148 -28
- package/dist/http/schemas/notifications.js.map +1 -1
- package/dist/http/schemas/platform.d.ts +37 -0
- package/dist/http/schemas/platform.js +19 -0
- package/dist/http/schemas/platform.js.map +1 -0
- package/dist/http/schemas/posts.d.ts +92 -38
- package/dist/http/schemas/posts.js +4 -4
- package/dist/http/schemas/posts.js.map +1 -1
- package/dist/http/schemas/profile.d.ts +1 -1
- package/dist/http/schemas/shared.d.ts +10 -13
- package/dist/http/schemas/shared.js +3 -11
- package/dist/http/schemas/shared.js.map +1 -1
- package/dist/http/schemas/students.d.ts +22 -0
- package/dist/http/schemas/students.js +3 -1
- package/dist/http/schemas/students.js.map +1 -1
- package/dist/http/scope.d.ts +9 -12
- package/dist/http/scope.js +30 -35
- package/dist/http/scope.js.map +1 -1
- package/dist/http/server.js +9 -0
- package/dist/http/server.js.map +1 -1
- package/dist/http/shutdown.d.ts +11 -0
- package/dist/http/shutdown.js +40 -0
- package/dist/http/shutdown.js.map +1 -0
- package/dist/http/sse.d.ts +19 -0
- package/dist/http/sse.js +104 -0
- package/dist/http/sse.js.map +1 -0
- package/dist/http/test-caller.d.ts +13 -0
- package/dist/http/test-caller.js +14 -0
- package/dist/http/test-caller.js.map +1 -0
- package/dist/http/well-known.js +2 -2
- package/dist/http/well-known.js.map +1 -1
- package/dist/index.d.ts +5 -2
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/packages/server/package.js +1 -1
- package/package.json +7 -6
- package/dist/http/routes/member/actor.d.ts +0 -14
- package/dist/http/routes/member/actor.js +0 -11
- package/dist/http/routes/member/actor.js.map +0 -1
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { PageQuery, refusals } from "../../schemas/shared.js";
|
|
2
|
+
import { resolveActor } from "../../scope.js";
|
|
3
|
+
import { AddEventAsset, AddEventAttendee, CreateEvent, Event, EventAssetParams, EventAttendeeParams, EventAttendeesPage, EventFile, EventIdParam, MemberEvent, MemberEventsPage, MemberEventsQuery, RenameEventAsset, ReorderEventAssets, UpdateEvent } from "../../schemas/events.js";
|
|
4
|
+
import "../../schemas/index.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/http/routes/member/events.ts
|
|
7
|
+
async function memberEventsRoutes(app, container) {
|
|
8
|
+
const r = app.withTypeProvider();
|
|
9
|
+
const content = container.content;
|
|
10
|
+
const member = container.reporting.member;
|
|
11
|
+
r.route({
|
|
12
|
+
method: "GET",
|
|
13
|
+
url: "/api/member/events",
|
|
14
|
+
preHandler: app.requireOrgSession,
|
|
15
|
+
schema: {
|
|
16
|
+
operationId: "listMemberEvents",
|
|
17
|
+
tags: ["Events"],
|
|
18
|
+
summary: "List the events you can see",
|
|
19
|
+
description: "For a member of the organization. The published `public` events, and the published and canceled events you attend; with `events:read`, every published and canceled event it covers. Each as the event read returns it.",
|
|
20
|
+
querystring: MemberEventsQuery,
|
|
21
|
+
response: {
|
|
22
|
+
200: MemberEventsPage,
|
|
23
|
+
...refusals(400, 403)
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
handler: async (req) => {
|
|
27
|
+
const actor = await resolveActor(container, req);
|
|
28
|
+
return member.listEvents(req.query, actor);
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
r.route({
|
|
32
|
+
method: "GET",
|
|
33
|
+
url: "/api/member/events/:eventId",
|
|
34
|
+
preHandler: app.requireOrgSession,
|
|
35
|
+
schema: {
|
|
36
|
+
operationId: "getMemberEvent",
|
|
37
|
+
tags: ["Events"],
|
|
38
|
+
summary: "Get an event, with what you can do with it",
|
|
39
|
+
description: "With `events:read` on the event or the org: the event in any status. As an attendee, directly or through a bundle: the published or canceled event, with the recording after the end when replay is on. Otherwise a published `public` event without its location, files and recording. 404 for anything else.",
|
|
40
|
+
params: EventIdParam,
|
|
41
|
+
response: {
|
|
42
|
+
200: MemberEvent,
|
|
43
|
+
...refusals(403, 404)
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
handler: async (req) => {
|
|
47
|
+
const actor = await resolveActor(container, req);
|
|
48
|
+
return member.getEvent(req.params.eventId, actor);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
r.route({
|
|
52
|
+
method: "GET",
|
|
53
|
+
url: "/api/member/events/:eventId/calendar",
|
|
54
|
+
preHandler: app.requireOrgSession,
|
|
55
|
+
schema: {
|
|
56
|
+
operationId: "getEventCalendar",
|
|
57
|
+
tags: ["Events"],
|
|
58
|
+
summary: "Download an event as a calendar file",
|
|
59
|
+
description: "An iCalendar file with the title, the times and the event page. The location and the meeting link are included when the event read returns them. 404 when the event read does.",
|
|
60
|
+
params: EventIdParam,
|
|
61
|
+
response: {
|
|
62
|
+
200: z.string().describe("`text/calendar`, one VEVENT"),
|
|
63
|
+
...refusals(403, 404)
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
handler: async (req, reply) => {
|
|
67
|
+
const actor = await resolveActor(container, req);
|
|
68
|
+
const body = await member.eventCalendar(req.params.eventId, actor);
|
|
69
|
+
return reply.header("content-type", "text/calendar; charset=utf-8").header("content-disposition", `attachment; filename="${req.params.eventId}.ics"`).send(body);
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
r.route({
|
|
73
|
+
method: "GET",
|
|
74
|
+
url: "/api/member/events/:eventId/attendees",
|
|
75
|
+
preHandler: app.requireOrgSession,
|
|
76
|
+
schema: {
|
|
77
|
+
operationId: "listMemberEventAttendees",
|
|
78
|
+
tags: ["Events"],
|
|
79
|
+
summary: "List the attendees of an event you run",
|
|
80
|
+
description: `Requires \`events:read\`. On the event or the org. The people attending, directly or through a bundle, by grant date. \`source\` is \`bundle\` for someone who attends only through a bundle.`,
|
|
81
|
+
params: EventIdParam,
|
|
82
|
+
querystring: PageQuery,
|
|
83
|
+
response: {
|
|
84
|
+
200: EventAttendeesPage,
|
|
85
|
+
...refusals(400, 403, 404)
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
handler: async (req) => {
|
|
89
|
+
const actor = await resolveActor(container, req);
|
|
90
|
+
return member.eventAttendees(req.params.eventId, req.query, actor);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
r.route({
|
|
94
|
+
method: "POST",
|
|
95
|
+
url: "/api/member/events",
|
|
96
|
+
preHandler: app.requireOrgSession,
|
|
97
|
+
schema: {
|
|
98
|
+
operationId: "createMemberEvent",
|
|
99
|
+
tags: ["Events"],
|
|
100
|
+
summary: "Create an event from the member app",
|
|
101
|
+
description: `Requires \`events:write\`. The event starts as a draft. 400 when it ends before it starts.`,
|
|
102
|
+
body: CreateEvent,
|
|
103
|
+
response: {
|
|
104
|
+
201: Event,
|
|
105
|
+
...refusals(400, 403)
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
handler: async (req, reply) => {
|
|
109
|
+
const actor = await resolveActor(container, req);
|
|
110
|
+
const event = await content.createEvent(req.body, actor);
|
|
111
|
+
return reply.code(201).send(event);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
r.route({
|
|
115
|
+
method: "PATCH",
|
|
116
|
+
url: "/api/member/events/:eventId",
|
|
117
|
+
preHandler: app.requireOrgSession,
|
|
118
|
+
schema: {
|
|
119
|
+
operationId: "updateMemberEvent",
|
|
120
|
+
tags: ["Events"],
|
|
121
|
+
summary: "Update an event you run",
|
|
122
|
+
description: `Requires \`events:write\`. Changes only the fields sent; \`status\` publishes or unpublishes it. \`thumbnailAssetId\` must be a ready library image (409 \`conflict\` otherwise); null clears it. A file it does not already use must be uploaded for it, or the caller needs \`media:read\` (403 otherwise). 409 \`canceled\` when the event is canceled.`,
|
|
123
|
+
params: EventIdParam,
|
|
124
|
+
body: UpdateEvent,
|
|
125
|
+
response: {
|
|
126
|
+
200: Event,
|
|
127
|
+
...refusals(400, 403, 404, 409)
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
handler: async (req) => {
|
|
131
|
+
const actor = await resolveActor(container, req);
|
|
132
|
+
return content.updateEvent(req.params.eventId, req.body, actor);
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
r.route({
|
|
136
|
+
method: "POST",
|
|
137
|
+
url: "/api/member/events/:eventId/cancel",
|
|
138
|
+
preHandler: app.requireOrgSession,
|
|
139
|
+
schema: {
|
|
140
|
+
operationId: "cancelMemberEvent",
|
|
141
|
+
tags: ["Events"],
|
|
142
|
+
summary: "Cancel an event you run",
|
|
143
|
+
description: `Requires \`events:write\`. Canceling is final. 409 \`canceled\` when it is already canceled.`,
|
|
144
|
+
params: EventIdParam,
|
|
145
|
+
response: {
|
|
146
|
+
200: Event,
|
|
147
|
+
...refusals(403, 404, 409)
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
handler: async (req) => {
|
|
151
|
+
const actor = await resolveActor(container, req);
|
|
152
|
+
return content.cancelEvent(req.params.eventId, actor);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
r.route({
|
|
156
|
+
method: "DELETE",
|
|
157
|
+
url: "/api/member/events/:eventId",
|
|
158
|
+
preHandler: app.requireOrgSession,
|
|
159
|
+
schema: {
|
|
160
|
+
operationId: "deleteMemberEvent",
|
|
161
|
+
tags: ["Events"],
|
|
162
|
+
summary: "Delete an event you can delete",
|
|
163
|
+
description: `Requires \`events:delete\`. Its attendees lose it; its library files survive.`,
|
|
164
|
+
params: EventIdParam,
|
|
165
|
+
response: {
|
|
166
|
+
204: z.void(),
|
|
167
|
+
...refusals(403, 404)
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
handler: async (req, reply) => {
|
|
171
|
+
const actor = await resolveActor(container, req);
|
|
172
|
+
await content.deleteEvent(req.params.eventId, actor);
|
|
173
|
+
return reply.code(204).send();
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
r.route({
|
|
177
|
+
method: "GET",
|
|
178
|
+
url: "/api/member/events/:eventId/assets",
|
|
179
|
+
preHandler: app.requireOrgSession,
|
|
180
|
+
schema: {
|
|
181
|
+
operationId: "listMemberEventAssets",
|
|
182
|
+
tags: ["Events"],
|
|
183
|
+
summary: "List the files of an event you run, in order",
|
|
184
|
+
description: "Requires `events:read`.",
|
|
185
|
+
params: EventIdParam,
|
|
186
|
+
response: {
|
|
187
|
+
200: z.array(EventFile),
|
|
188
|
+
...refusals(403, 404)
|
|
189
|
+
}
|
|
190
|
+
},
|
|
191
|
+
handler: async (req) => {
|
|
192
|
+
const actor = await resolveActor(container, req);
|
|
193
|
+
return content.listEventAssets(req.params.eventId, actor);
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
r.route({
|
|
197
|
+
method: "POST",
|
|
198
|
+
url: "/api/member/events/:eventId/assets",
|
|
199
|
+
preHandler: app.requireOrgSession,
|
|
200
|
+
schema: {
|
|
201
|
+
operationId: "addMemberEventAsset",
|
|
202
|
+
tags: ["Events"],
|
|
203
|
+
summary: "Attach a file to an event you run",
|
|
204
|
+
description: `Requires \`events:write\`. Added last. 409 when the file is not a ready library file or is already attached. A file not uploaded for the event needs \`media:read\` (403 otherwise). Returns the event's files.`,
|
|
205
|
+
params: EventIdParam,
|
|
206
|
+
body: AddEventAsset,
|
|
207
|
+
response: {
|
|
208
|
+
200: z.array(EventFile),
|
|
209
|
+
...refusals(403, 404, 409)
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
handler: async (req) => {
|
|
213
|
+
const actor = await resolveActor(container, req);
|
|
214
|
+
return content.addEventAsset(req.params.eventId, req.body, actor);
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
r.route({
|
|
218
|
+
method: "PUT",
|
|
219
|
+
url: "/api/member/events/:eventId/assets/order",
|
|
220
|
+
preHandler: app.requireOrgSession,
|
|
221
|
+
schema: {
|
|
222
|
+
operationId: "reorderMemberEventAssets",
|
|
223
|
+
tags: ["Events"],
|
|
224
|
+
summary: "Reorder the files of an event you run",
|
|
225
|
+
description: `Requires \`events:write\`. Send every attached file id exactly once (409 otherwise). Returns the event's files.`,
|
|
226
|
+
params: EventIdParam,
|
|
227
|
+
body: ReorderEventAssets,
|
|
228
|
+
response: {
|
|
229
|
+
200: z.array(EventFile),
|
|
230
|
+
...refusals(403, 404, 409)
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
handler: async (req) => {
|
|
234
|
+
const actor = await resolveActor(container, req);
|
|
235
|
+
return content.reorderEventAssets(req.params.eventId, req.body.assetIds, actor);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
r.route({
|
|
239
|
+
method: "PATCH",
|
|
240
|
+
url: "/api/member/events/:eventId/assets/:assetId",
|
|
241
|
+
preHandler: app.requireOrgSession,
|
|
242
|
+
schema: {
|
|
243
|
+
operationId: "renameMemberEventAsset",
|
|
244
|
+
tags: ["Events"],
|
|
245
|
+
summary: "Set a file's display name within an event you run",
|
|
246
|
+
description: `Requires \`events:write\`. Null falls back to the filename. Returns the event's files.`,
|
|
247
|
+
params: EventAssetParams,
|
|
248
|
+
body: RenameEventAsset,
|
|
249
|
+
response: {
|
|
250
|
+
200: z.array(EventFile),
|
|
251
|
+
...refusals(403, 404)
|
|
252
|
+
}
|
|
253
|
+
},
|
|
254
|
+
handler: async (req) => {
|
|
255
|
+
const actor = await resolveActor(container, req);
|
|
256
|
+
return content.renameEventAsset(req.params.eventId, req.params.assetId, req.body.displayName, actor);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
r.route({
|
|
260
|
+
method: "DELETE",
|
|
261
|
+
url: "/api/member/events/:eventId/assets/:assetId",
|
|
262
|
+
preHandler: app.requireOrgSession,
|
|
263
|
+
schema: {
|
|
264
|
+
operationId: "removeMemberEventAsset",
|
|
265
|
+
tags: ["Events"],
|
|
266
|
+
summary: "Remove a file from an event you run",
|
|
267
|
+
description: `Requires \`events:write\`. The library file itself survives. Returns the event's files.`,
|
|
268
|
+
params: EventAssetParams,
|
|
269
|
+
response: {
|
|
270
|
+
200: z.array(EventFile),
|
|
271
|
+
...refusals(403, 404)
|
|
272
|
+
}
|
|
273
|
+
},
|
|
274
|
+
handler: async (req) => {
|
|
275
|
+
const actor = await resolveActor(container, req);
|
|
276
|
+
return content.removeEventAsset(req.params.eventId, req.params.assetId, actor);
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
r.route({
|
|
280
|
+
method: "POST",
|
|
281
|
+
url: "/api/member/events/:eventId/register",
|
|
282
|
+
preHandler: app.requireOrgSession,
|
|
283
|
+
schema: {
|
|
284
|
+
operationId: "registerForEvent",
|
|
285
|
+
tags: ["Events"],
|
|
286
|
+
summary: "Register for an event",
|
|
287
|
+
description: "Any active member of the organization registers themselves for a published `public` event that has not started, with source `self`. 403 when the event is `private`; 404 when it does not exist or is not published; 409 `already_registered`, `started` or `full`.",
|
|
288
|
+
params: EventIdParam,
|
|
289
|
+
response: {
|
|
290
|
+
204: z.void(),
|
|
291
|
+
...refusals(403, 404, 409)
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
handler: async (req, reply) => {
|
|
295
|
+
const actor = await resolveActor(container, req);
|
|
296
|
+
await container.entitlements.grant({
|
|
297
|
+
orgUserId: actor.id,
|
|
298
|
+
contentId: req.params.eventId,
|
|
299
|
+
contentType: "event",
|
|
300
|
+
expiresAt: null
|
|
301
|
+
}, actor);
|
|
302
|
+
return reply.code(204).send();
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
r.route({
|
|
306
|
+
method: "POST",
|
|
307
|
+
url: "/api/member/events/:eventId/unregister",
|
|
308
|
+
preHandler: app.requireOrgSession,
|
|
309
|
+
schema: {
|
|
310
|
+
operationId: "cancelEventRegistration",
|
|
311
|
+
tags: ["Events"],
|
|
312
|
+
summary: "Cancel your registration for an event",
|
|
313
|
+
description: "Any active member of the organization revokes their own direct grant to the event, which frees the place. 404 when the caller has no direct active grant.",
|
|
314
|
+
params: EventIdParam,
|
|
315
|
+
response: {
|
|
316
|
+
204: z.void(),
|
|
317
|
+
...refusals(403, 404)
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
handler: async (req, reply) => {
|
|
321
|
+
const actor = await resolveActor(container, req);
|
|
322
|
+
await container.entitlements.revoke({
|
|
323
|
+
orgUserId: actor.id,
|
|
324
|
+
contentId: req.params.eventId,
|
|
325
|
+
contentType: "event"
|
|
326
|
+
}, actor);
|
|
327
|
+
return reply.code(204).send();
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
r.route({
|
|
331
|
+
method: "POST",
|
|
332
|
+
url: "/api/member/events/:eventId/attendees",
|
|
333
|
+
preHandler: app.requireOrgSession,
|
|
334
|
+
schema: {
|
|
335
|
+
operationId: "addMemberEventAttendee",
|
|
336
|
+
tags: ["Events"],
|
|
337
|
+
summary: "Add an attendee to an event you run",
|
|
338
|
+
description: "Requires `access:write`, or `events:write` on the event or the org. Grants the event to the person, with source `manual`. Adding someone who already attends changes nothing. 404 when the event or the person does not exist; 409 `not_published`, `ended` or `full`.",
|
|
339
|
+
params: EventIdParam,
|
|
340
|
+
body: AddEventAttendee,
|
|
341
|
+
response: {
|
|
342
|
+
204: z.void(),
|
|
343
|
+
...refusals(400, 403, 404, 409)
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
handler: async (req, reply) => {
|
|
347
|
+
const actor = await resolveActor(container, req);
|
|
348
|
+
await container.entitlements.grant({
|
|
349
|
+
orgUserId: req.body.orgUserId,
|
|
350
|
+
contentId: req.params.eventId,
|
|
351
|
+
contentType: "event",
|
|
352
|
+
expiresAt: null
|
|
353
|
+
}, actor);
|
|
354
|
+
return reply.code(204).send();
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
r.route({
|
|
358
|
+
method: "DELETE",
|
|
359
|
+
url: "/api/member/events/:eventId/attendees/:orgUserId",
|
|
360
|
+
preHandler: app.requireOrgSession,
|
|
361
|
+
schema: {
|
|
362
|
+
operationId: "removeMemberEventAttendee",
|
|
363
|
+
tags: ["Events"],
|
|
364
|
+
summary: "Remove an attendee from an event you run",
|
|
365
|
+
description: "Requires `access:write`, or `events:write` on the event or the org. Revokes the person's direct grant to the event. 404 when they have no direct active grant; someone who attends only through a bundle has none.",
|
|
366
|
+
params: EventAttendeeParams,
|
|
367
|
+
response: {
|
|
368
|
+
204: z.void(),
|
|
369
|
+
...refusals(403, 404)
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
handler: async (req, reply) => {
|
|
373
|
+
const actor = await resolveActor(container, req);
|
|
374
|
+
await container.entitlements.revoke({
|
|
375
|
+
orgUserId: req.params.orgUserId,
|
|
376
|
+
contentId: req.params.eventId,
|
|
377
|
+
contentType: "event"
|
|
378
|
+
}, actor);
|
|
379
|
+
return reply.code(204).send();
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
//#endregion
|
|
384
|
+
export { memberEventsRoutes };
|
|
385
|
+
|
|
386
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","names":[],"sources":["../../../../src/http/routes/member/events.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport {\n AddEventAsset,\n AddEventAttendee,\n CreateEvent,\n Event,\n EventAssetParams,\n EventAttendeeParams,\n EventAttendeesPage,\n EventFile,\n EventIdParam,\n MemberEvent,\n MemberEventsPage,\n MemberEventsQuery,\n PageQuery,\n RenameEventAsset,\n ReorderEventAssets,\n UpdateEvent,\n refusals,\n} from '../../schemas/index.js';\nimport type { Container } from '../../../app/container.js';\nimport { resolveActor } from '../../scope.js';\n\nexport async function memberEventsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const content = container.content;\n const member = container.reporting.member;\n\n r.route({\n method: 'GET',\n url: '/api/member/events',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberEvents',\n tags: ['Events'],\n summary: 'List the events you can see',\n description:\n 'For a member of the organization. The published `public` events, and the published and canceled events you attend; with `events:read`, every published and canceled event it covers. Each as the event read returns it.',\n querystring: MemberEventsQuery,\n response: { 200: MemberEventsPage, ...refusals(400, 403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.listEvents(req.query, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/events/:eventId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberEvent',\n tags: ['Events'],\n summary: 'Get an event, with what you can do with it',\n description:\n 'With `events:read` on the event or the org: the event in any status. As an attendee, directly or through a bundle: the published or canceled event, with the recording after the end when replay is on. Otherwise a published `public` event without its location, files and recording. 404 for anything else.',\n params: EventIdParam,\n response: { 200: MemberEvent, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.getEvent(req.params.eventId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/events/:eventId/calendar',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getEventCalendar',\n tags: ['Events'],\n summary: 'Download an event as a calendar file',\n description:\n 'An iCalendar file with the title, the times and the event page. The location and the meeting link are included when the event read returns them. 404 when the event read does.',\n params: EventIdParam,\n response: {\n 200: z.string().describe('`text/calendar`, one VEVENT'),\n ...refusals(403, 404),\n },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const body = await member.eventCalendar(req.params.eventId, actor);\n return reply\n .header('content-type', 'text/calendar; charset=utf-8')\n .header('content-disposition', `attachment; filename=\"${req.params.eventId}.ics\"`)\n .send(body);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/events/:eventId/attendees',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberEventAttendees',\n tags: ['Events'],\n summary: 'List the attendees of an event you run',\n description: `Requires \\`events:read\\`. On the event or the org. The people attending, directly or through a bundle, by grant date. \\`source\\` is \\`bundle\\` for someone who attends only through a bundle.`,\n params: EventIdParam,\n querystring: PageQuery,\n response: { 200: EventAttendeesPage, ...refusals(400, 403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.eventAttendees(req.params.eventId, req.query, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/events',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'createMemberEvent',\n tags: ['Events'],\n summary: 'Create an event from the member app',\n description: `Requires \\`events:write\\`. The event starts as a draft. 400 when it ends before it starts.`,\n body: CreateEvent,\n response: { 201: Event, ...refusals(400, 403) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const event = await content.createEvent(req.body, actor);\n return reply.code(201).send(event);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/member/events/:eventId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'updateMemberEvent',\n tags: ['Events'],\n summary: 'Update an event you run',\n description: `Requires \\`events:write\\`. Changes only the fields sent; \\`status\\` publishes or unpublishes it. \\`thumbnailAssetId\\` must be a ready library image (409 \\`conflict\\` otherwise); null clears it. A file it does not already use must be uploaded for it, or the caller needs \\`media:read\\` (403 otherwise). 409 \\`canceled\\` when the event is canceled.`,\n params: EventIdParam,\n body: UpdateEvent,\n response: { 200: Event, ...refusals(400, 403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.updateEvent(req.params.eventId, req.body, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/events/:eventId/cancel',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'cancelMemberEvent',\n tags: ['Events'],\n summary: 'Cancel an event you run',\n description: `Requires \\`events:write\\`. Canceling is final. 409 \\`canceled\\` when it is already canceled.`,\n params: EventIdParam,\n response: { 200: Event, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.cancelEvent(req.params.eventId, actor);\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/events/:eventId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'deleteMemberEvent',\n tags: ['Events'],\n summary: 'Delete an event you can delete',\n description: `Requires \\`events:delete\\`. Its attendees lose it; its library files survive.`,\n params: EventIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await content.deleteEvent(req.params.eventId, actor);\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/events/:eventId/assets',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberEventAssets',\n tags: ['Events'],\n summary: 'List the files of an event you run, in order',\n description: 'Requires `events:read`.',\n params: EventIdParam,\n response: { 200: z.array(EventFile), ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.listEventAssets(req.params.eventId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/events/:eventId/assets',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addMemberEventAsset',\n tags: ['Events'],\n summary: 'Attach a file to an event you run',\n description: `Requires \\`events:write\\`. Added last. 409 when the file is not a ready library file or is already attached. A file not uploaded for the event needs \\`media:read\\` (403 otherwise). Returns the event's files.`,\n params: EventIdParam,\n body: AddEventAsset,\n response: { 200: z.array(EventFile), ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.addEventAsset(req.params.eventId, req.body, actor);\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/events/:eventId/assets/order',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'reorderMemberEventAssets',\n tags: ['Events'],\n summary: 'Reorder the files of an event you run',\n description: `Requires \\`events:write\\`. Send every attached file id exactly once (409 otherwise). Returns the event's files.`,\n params: EventIdParam,\n body: ReorderEventAssets,\n response: { 200: z.array(EventFile), ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.reorderEventAssets(req.params.eventId, req.body.assetIds, actor);\n },\n });\n\n r.route({\n method: 'PATCH',\n url: '/api/member/events/:eventId/assets/:assetId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'renameMemberEventAsset',\n tags: ['Events'],\n summary: \"Set a file's display name within an event you run\",\n description: `Requires \\`events:write\\`. Null falls back to the filename. Returns the event's files.`,\n params: EventAssetParams,\n body: RenameEventAsset,\n response: { 200: z.array(EventFile), ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.renameEventAsset(\n req.params.eventId,\n req.params.assetId,\n req.body.displayName,\n actor,\n );\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/events/:eventId/assets/:assetId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeMemberEventAsset',\n tags: ['Events'],\n summary: 'Remove a file from an event you run',\n description: `Requires \\`events:write\\`. The library file itself survives. Returns the event's files.`,\n params: EventAssetParams,\n response: { 200: z.array(EventFile), ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return content.removeEventAsset(req.params.eventId, req.params.assetId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/events/:eventId/register',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'registerForEvent',\n tags: ['Events'],\n summary: 'Register for an event',\n description:\n 'Any active member of the organization registers themselves for a published `public` event that has not started, with source `self`. 403 when the event is `private`; 404 when it does not exist or is not published; 409 `already_registered`, `started` or `full`.',\n params: EventIdParam,\n response: { 204: z.void(), ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.entitlements.grant(\n {\n orgUserId: actor.id,\n contentId: req.params.eventId,\n contentType: 'event',\n expiresAt: null,\n },\n actor,\n );\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/events/:eventId/unregister',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'cancelEventRegistration',\n tags: ['Events'],\n summary: 'Cancel your registration for an event',\n description:\n 'Any active member of the organization revokes their own direct grant to the event, which frees the place. 404 when the caller has no direct active grant.',\n params: EventIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.entitlements.revoke(\n { orgUserId: actor.id, contentId: req.params.eventId, contentType: 'event' },\n actor,\n );\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/events/:eventId/attendees',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addMemberEventAttendee',\n tags: ['Events'],\n summary: 'Add an attendee to an event you run',\n description:\n 'Requires `access:write`, or `events:write` on the event or the org. Grants the event to the person, with source `manual`. Adding someone who already attends changes nothing. 404 when the event or the person does not exist; 409 `not_published`, `ended` or `full`.',\n params: EventIdParam,\n body: AddEventAttendee,\n response: { 204: z.void(), ...refusals(400, 403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.entitlements.grant(\n {\n orgUserId: req.body.orgUserId,\n contentId: req.params.eventId,\n contentType: 'event',\n expiresAt: null,\n },\n actor,\n );\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/events/:eventId/attendees/:orgUserId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeMemberEventAttendee',\n tags: ['Events'],\n summary: 'Remove an attendee from an event you run',\n description:\n \"Requires `access:write`, or `events:write` on the event or the org. Revokes the person's direct grant to the event. 404 when they have no direct active grant; someone who attends only through a bundle has none.\",\n params: EventAttendeeParams,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.entitlements.revoke(\n { orgUserId: req.params.orgUserId, contentId: req.params.eventId, contentType: 'event' },\n actor,\n );\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,29 +1,20 @@
|
|
|
1
1
|
import { refusals } from "../../schemas/shared.js";
|
|
2
|
-
import {
|
|
2
|
+
import { resolveActor } from "../../scope.js";
|
|
3
|
+
import { ActivityFileParams, CommunityThumbnailParams, CourseThumbnailParams, DownloadFileParams, DownloadThumbnailParams, EventFileParams, EventThumbnailParams, MessageAttachmentParams, PostAssetParams, PostCoverParams, UploadFileParams } from "../../schemas/files.js";
|
|
3
4
|
import "../../schemas/index.js";
|
|
4
|
-
import { actorOf } from "./actor.js";
|
|
5
5
|
import { z } from "zod";
|
|
6
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
6
|
//#region src/http/routes/member/files.ts
|
|
8
7
|
const tags = ["Files"];
|
|
9
8
|
const responses = {
|
|
10
9
|
302: z.void(),
|
|
11
10
|
...refusals(403, 404)
|
|
12
11
|
};
|
|
13
|
-
function redirect(reply, url
|
|
14
|
-
if (!url) throw new NotFoundError(what, id);
|
|
12
|
+
function redirect(reply, url) {
|
|
15
13
|
return reply.header("cache-control", "no-store").header("referrer-policy", "no-referrer").redirect(url, 302);
|
|
16
14
|
}
|
|
17
15
|
async function memberFileRoutes(app, container) {
|
|
18
16
|
const r = app.withTypeProvider();
|
|
19
17
|
const member = container.reporting.member;
|
|
20
|
-
async function actorOf$1(orgId, userId) {
|
|
21
|
-
const orgUser = await actorOf(container, orgId, userId);
|
|
22
|
-
return {
|
|
23
|
-
id: orgUser.id,
|
|
24
|
-
role: orgUser.role
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
18
|
r.route({
|
|
28
19
|
method: "GET",
|
|
29
20
|
url: "/api/member/courses/:courseId/thumbnail",
|
|
@@ -32,13 +23,47 @@ async function memberFileRoutes(app, container) {
|
|
|
32
23
|
operationId: "getCourseThumbnail",
|
|
33
24
|
tags,
|
|
34
25
|
summary: "Redirect to a course's thumbnail",
|
|
35
|
-
description: "
|
|
26
|
+
description: "For an unpublished course, which only a holder of `courses:read` on it may fetch: a published course carries a public `thumbnailUrl` instead. 404 when the course has no thumbnail.",
|
|
36
27
|
params: CourseThumbnailParams,
|
|
37
28
|
response: responses
|
|
38
29
|
},
|
|
39
30
|
handler: async (req, reply) => {
|
|
40
|
-
const actor = await
|
|
41
|
-
return redirect(reply, await member.thumbnailFile(
|
|
31
|
+
const actor = await resolveActor(container, req);
|
|
32
|
+
return redirect(reply, await member.thumbnailFile("course", req.params.courseId, actor));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
r.route({
|
|
36
|
+
method: "GET",
|
|
37
|
+
url: "/api/member/events/:eventId/thumbnail",
|
|
38
|
+
preHandler: app.requireOrgSession,
|
|
39
|
+
schema: {
|
|
40
|
+
operationId: "getEventThumbnail",
|
|
41
|
+
tags,
|
|
42
|
+
summary: "Redirect to an event's cover",
|
|
43
|
+
description: "For a draft event, which only a holder of `events:read` on it may fetch: a published or canceled event carries a public `thumbnailUrl` instead. 404 when the event read returns 404 or the event has no cover.",
|
|
44
|
+
params: EventThumbnailParams,
|
|
45
|
+
response: responses
|
|
46
|
+
},
|
|
47
|
+
handler: async (req, reply) => {
|
|
48
|
+
const actor = await resolveActor(container, req);
|
|
49
|
+
return redirect(reply, await member.thumbnailFile("event", req.params.eventId, actor));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
r.route({
|
|
53
|
+
method: "GET",
|
|
54
|
+
url: "/api/member/events/:eventId/assets/:assetId",
|
|
55
|
+
preHandler: app.requireOrgSession,
|
|
56
|
+
schema: {
|
|
57
|
+
operationId: "getEventFile",
|
|
58
|
+
tags,
|
|
59
|
+
summary: "Redirect to a file attached to an event",
|
|
60
|
+
description: "For a holder of `events:read` on the event or the org, or an attendee of the published or canceled event. Saved under its display name. 404 otherwise, or when the file is not attached to the event.",
|
|
61
|
+
params: EventFileParams,
|
|
62
|
+
response: responses
|
|
63
|
+
},
|
|
64
|
+
handler: async (req, reply) => {
|
|
65
|
+
const actor = await resolveActor(container, req);
|
|
66
|
+
return redirect(reply, await member.eventFile(req.params.eventId, req.params.assetId, actor));
|
|
42
67
|
}
|
|
43
68
|
});
|
|
44
69
|
r.route({
|
|
@@ -49,13 +74,13 @@ async function memberFileRoutes(app, container) {
|
|
|
49
74
|
operationId: "getDownloadThumbnail",
|
|
50
75
|
tags,
|
|
51
76
|
summary: "Redirect to a download's thumbnail",
|
|
52
|
-
description: "
|
|
77
|
+
description: "For an unpublished download, which only a holder of `downloads:read` on it may fetch: a published download carries a public `thumbnailUrl` instead. 404 when the download has no thumbnail.",
|
|
53
78
|
params: DownloadThumbnailParams,
|
|
54
79
|
response: responses
|
|
55
80
|
},
|
|
56
81
|
handler: async (req, reply) => {
|
|
57
|
-
const actor = await
|
|
58
|
-
return redirect(reply, await member.thumbnailFile(
|
|
82
|
+
const actor = await resolveActor(container, req);
|
|
83
|
+
return redirect(reply, await member.thumbnailFile("download", req.params.downloadId, actor));
|
|
59
84
|
}
|
|
60
85
|
});
|
|
61
86
|
r.route({
|
|
@@ -66,13 +91,13 @@ async function memberFileRoutes(app, container) {
|
|
|
66
91
|
operationId: "getCommunityThumbnail",
|
|
67
92
|
tags,
|
|
68
93
|
summary: "Redirect to a community's thumbnail",
|
|
69
|
-
description: "
|
|
94
|
+
description: "For an unpublished community, which only a holder of `communities:read` on it may fetch: a published community carries a public `thumbnailUrl` instead. 404 when the community has no thumbnail.",
|
|
70
95
|
params: CommunityThumbnailParams,
|
|
71
96
|
response: responses
|
|
72
97
|
},
|
|
73
98
|
handler: async (req, reply) => {
|
|
74
|
-
const actor = await
|
|
75
|
-
return redirect(reply, await member.thumbnailFile(
|
|
99
|
+
const actor = await resolveActor(container, req);
|
|
100
|
+
return redirect(reply, await member.thumbnailFile("community", req.params.communityId, actor));
|
|
76
101
|
}
|
|
77
102
|
});
|
|
78
103
|
r.route({
|
|
@@ -83,13 +108,13 @@ async function memberFileRoutes(app, container) {
|
|
|
83
108
|
operationId: "getActivityFile",
|
|
84
109
|
tags,
|
|
85
110
|
summary: "Redirect to a file used in a lesson",
|
|
86
|
-
description: "Served when the
|
|
111
|
+
description: "Served when the person can open the course, the course and the lesson are published, and the lesson lists the file. A holder of `courses:read` on the course may fetch any file a lesson lists. Use the URL as an img, video or audio src.",
|
|
87
112
|
params: ActivityFileParams,
|
|
88
113
|
response: responses
|
|
89
114
|
},
|
|
90
115
|
handler: async (req, reply) => {
|
|
91
|
-
const actor = await
|
|
92
|
-
return redirect(reply, await member.activityFile(req.
|
|
116
|
+
const actor = await resolveActor(container, req);
|
|
117
|
+
return redirect(reply, await member.activityFile(req.params.activityId, req.params.assetId, actor));
|
|
93
118
|
}
|
|
94
119
|
});
|
|
95
120
|
r.route({
|
|
@@ -100,13 +125,13 @@ async function memberFileRoutes(app, container) {
|
|
|
100
125
|
operationId: "getDownloadFile",
|
|
101
126
|
tags,
|
|
102
127
|
summary: "Redirect to a file in a download, saved under its display name",
|
|
103
|
-
description: "Served when the
|
|
128
|
+
description: "Served when the person can open the download, it is published, and it lists the file. A holder of `downloads:read` on the download may fetch it unpublished. The storage link lives DELIVERY_URL_EXPIRY seconds.",
|
|
104
129
|
params: DownloadFileParams,
|
|
105
130
|
response: responses
|
|
106
131
|
},
|
|
107
132
|
handler: async (req, reply) => {
|
|
108
|
-
const actor = await
|
|
109
|
-
return redirect(reply, await member.downloadFile(req.
|
|
133
|
+
const actor = await resolveActor(container, req);
|
|
134
|
+
return redirect(reply, await member.downloadFile(req.params.downloadId, req.params.assetId, actor));
|
|
110
135
|
}
|
|
111
136
|
});
|
|
112
137
|
r.route({
|
|
@@ -117,47 +142,47 @@ async function memberFileRoutes(app, container) {
|
|
|
117
142
|
operationId: "getPostCover",
|
|
118
143
|
tags,
|
|
119
144
|
summary: "Redirect to a post's cover image",
|
|
120
|
-
description: "
|
|
145
|
+
description: "For a post that is not published, served to whoever can read it: a published post carries a public `coverUrl` instead. 404 when the post has no cover.",
|
|
121
146
|
params: PostCoverParams,
|
|
122
147
|
response: responses
|
|
123
148
|
},
|
|
124
149
|
handler: async (req, reply) => {
|
|
125
|
-
const actor = await
|
|
126
|
-
return redirect(reply, await container.posts.coverFile(req.
|
|
150
|
+
const actor = await resolveActor(container, req);
|
|
151
|
+
return redirect(reply, await container.posts.coverFile(req.params.postId, actor));
|
|
127
152
|
}
|
|
128
153
|
});
|
|
129
154
|
r.route({
|
|
130
155
|
method: "GET",
|
|
131
|
-
url: "/api/member/
|
|
156
|
+
url: "/api/member/posts/:postId/assets/:assetId",
|
|
132
157
|
preHandler: app.requireOrgSession,
|
|
133
158
|
schema: {
|
|
134
|
-
operationId: "
|
|
159
|
+
operationId: "getPostAsset",
|
|
135
160
|
tags,
|
|
136
|
-
summary: "Redirect to
|
|
137
|
-
description: "Served to
|
|
138
|
-
params:
|
|
161
|
+
summary: "Redirect to a file in a post's body",
|
|
162
|
+
description: "Served to whoever can read the post while its body shows the file. Images, video, audio and PDFs open in place; any other file downloads under its name.",
|
|
163
|
+
params: PostAssetParams,
|
|
139
164
|
response: responses
|
|
140
165
|
},
|
|
141
166
|
handler: async (req, reply) => {
|
|
142
|
-
const actor = await
|
|
143
|
-
return redirect(reply, await container.
|
|
167
|
+
const actor = await resolveActor(container, req);
|
|
168
|
+
return redirect(reply, await container.posts.assetFile(req.params.postId, req.params.assetId, actor));
|
|
144
169
|
}
|
|
145
170
|
});
|
|
146
171
|
r.route({
|
|
147
172
|
method: "GET",
|
|
148
|
-
url: "/api/member/
|
|
173
|
+
url: "/api/member/chats/:chatId/messages/:messageId/attachments/:assetId",
|
|
149
174
|
preHandler: app.requireOrgSession,
|
|
150
175
|
schema: {
|
|
151
|
-
operationId: "
|
|
176
|
+
operationId: "getMessageAttachment",
|
|
152
177
|
tags,
|
|
153
|
-
summary: "Redirect to an
|
|
154
|
-
description: "Served to
|
|
155
|
-
params:
|
|
178
|
+
summary: "Redirect to an image attached to a chat message",
|
|
179
|
+
description: "Served to the chat's participants while the message stands, to holders of `communities:moderate` on the community also after it is deleted, and to them while the message is flagged.",
|
|
180
|
+
params: MessageAttachmentParams,
|
|
156
181
|
response: responses
|
|
157
182
|
},
|
|
158
183
|
handler: async (req, reply) => {
|
|
159
|
-
await
|
|
160
|
-
return redirect(reply, await
|
|
184
|
+
const actor = await resolveActor(container, req);
|
|
185
|
+
return redirect(reply, await container.chats.attachmentFile(req.params.chatId, req.params.messageId, req.params.assetId, actor));
|
|
161
186
|
}
|
|
162
187
|
});
|
|
163
188
|
r.route({
|
|
@@ -173,8 +198,8 @@ async function memberFileRoutes(app, container) {
|
|
|
173
198
|
response: responses
|
|
174
199
|
},
|
|
175
200
|
handler: async (req, reply) => {
|
|
176
|
-
const actor = await
|
|
177
|
-
return redirect(reply, await container.assets.ownUploadFile(req.
|
|
201
|
+
const actor = await resolveActor(container, req);
|
|
202
|
+
return redirect(reply, await container.assets.ownUploadFile(req.params.id, actor));
|
|
178
203
|
}
|
|
179
204
|
});
|
|
180
205
|
}
|