@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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"community.js","names":[],"sources":["../../../../src/http/routes/member/community.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport type { Container } from '../../../app/container.js';\nimport { NotFoundError } from '@headless-lms/core/shared/errors';\nimport { actorOf } from './actor.js';\nimport {\n CommunityHome,\n CommunityHomeSpace,\n CommunityParam,\n CommunitySpaceParam,\n DirectoryPage,\n DirectoryQuery,\n OrgUserBody,\n PageQuery,\n SpaceMember,\n SpaceMemberParam,\n SpaceMembersPage,\n refusals,\n} from '../../schemas/index.js';\n\nexport async function memberCommunityRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const tags = ['Communities'];\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/home',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberCommunityHome',\n tags,\n summary: 'The spaces a member can see in a community',\n description:\n \"For a member of the community. Lists its spaces in order. Spaces the viewer can open come back in full; spaces they can see but not open come back locked, with only their name, count, rule and the viewer's standing. A by-invite space the viewer is not invited to or a member of is left out. 404 when the viewer is not a member.\",\n params: CommunityParam,\n response: { 200: CommunityHome, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const home = await container.reporting.member.communityHome(\n req.orgId,\n actor,\n req.params.communityId,\n );\n if (!home) {\n throw new NotFoundError('Community', req.params.communityId);\n }\n return home;\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/spaces/:spaceId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberSpace',\n tags,\n summary: 'One space as a member sees it',\n description:\n 'For a member of the community: the space with its topics, links, settings and where the viewer stands. A space the viewer cannot open comes back locked, without its content. 404 when the viewer is not a member, the space is not in the community, or it is a by-invite space the viewer is not invited to or a member of.',\n params: CommunitySpaceParam,\n response: { 200: CommunityHomeSpace, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const space = await container.reporting.member.communitySpace(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n );\n if (!space) {\n throw new NotFoundError('Space', req.params.spaceId);\n }\n return space;\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/directory',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberCommunityDirectory',\n tags,\n summary: 'People in a community',\n description:\n 'For a member of the community: everyone who holds it, with their public profile. 404 when the viewer is not a member.',\n params: CommunityParam,\n querystring: DirectoryQuery,\n response: { 200: DirectoryPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const page = await container.reporting.member.directory(\n req.orgId,\n actor,\n req.params.communityId,\n req.query,\n );\n if (!page) {\n throw new NotFoundError('Community', req.params.communityId);\n }\n return page;\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listSpaceMembers',\n tags,\n summary: 'List the members of a space',\n description:\n 'For anyone who can open the space. Members see the active members; moderators also see open requests and invitations.',\n params: CommunitySpaceParam,\n querystring: PageQuery,\n response: { 200: SpaceMembersPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.listSpaceMembers(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n req.query,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/requests',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'requestSpaceMembership',\n tags,\n summary: 'Ask to join a space',\n description:\n 'For a member of the community who is not staff. Opens a request on a `by_request` space for a moderator to approve. 409 when the space is not `by_request` or you are already placed in it.',\n params: CommunitySpaceParam,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const member = await container.entitlements.requestJoin(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/invites',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'inviteSpaceMember',\n tags,\n summary: 'Invite a person into a space you moderate',\n description:\n 'For a moderator who is a member of the community. Invites another member into a `by_invite` space; they join when they accept. 403 when the person is staff or does not hold the community; 409 when the space is not invite-only or the person is already placed.',\n params: CommunitySpaceParam,\n body: OrgUserBody,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const member = await container.entitlements.invite(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n req.body.orgUserId,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addSpaceMember',\n tags,\n summary: 'Add a person to a space you moderate',\n description:\n 'For a moderator who is a member of the community. Places another member straight into the space, with no request or invitation. 409 when the space is open to all members, the person is already placed, or the space is full.',\n params: CommunitySpaceParam,\n body: OrgUserBody,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n const member = await container.entitlements.addSpaceMember(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n req.body.orgUserId,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/acceptance',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'acceptSpaceInvite',\n tags,\n summary: 'Accept your invitation to a space',\n description:\n 'For a member of the community who is not staff. Makes you an active member. 409 when you have no open invitation, are already a member, or the space is full.',\n params: CommunitySpaceParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.accept(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members/:orgUserId/approval',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'approveSpaceRequest',\n tags,\n summary: \"Approve a person's request to join a space you moderate\",\n description:\n 'For a moderator who is a member of the community. Makes the requester an active member. 404 when the person has no open request; 409 when the space is full or they are already a member.',\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.approve(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members/:orgUserId/decline',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'declineSpaceRequest',\n tags,\n summary: \"Decline a person's request to join a space you moderate\",\n description:\n 'For a moderator who is a member of the community. Closes the open request. 404 when the person has no open request; 409 when they are already a member.',\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.decline(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/refusal',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'refuseSpaceInvite',\n tags,\n summary: 'Refuse your invitation to a space',\n description:\n 'For a member of the community who is not staff. 409 when you have no open invitation or are already a member.',\n params: CommunitySpaceParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.refuse(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/departure',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'leaveSpace',\n tags,\n summary: 'Leave a space',\n description:\n 'For a member of the community who is not staff. 409 when you are not a member of the space.',\n params: CommunitySpaceParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.leave(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members/:orgUserId/removal',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeSpaceMember',\n tags,\n summary: 'Remove a person from a space you moderate',\n description:\n 'For a moderator who is a member of the community. Revokes the placement, whether it is a membership, a request or an invitation. 409 when the space is open to all members or the placement is already revoked.',\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await actorOf(container, req.orgId, req.userId);\n return container.entitlements.remove(\n req.orgId,\n actor,\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n );\n },\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"community.js","names":[],"sources":["../../../../src/http/routes/member/community.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport type { Container } from '../../../app/container.js';\nimport { resolveActor } from '../../scope.js';\nimport {\n CommunityHome,\n CommunityHomeSpace,\n CommunityParam,\n CommunitySpaceParam,\n DirectoryPage,\n DirectoryQuery,\n OrgUserBody,\n PageQuery,\n SetMute,\n SpaceIdParam,\n SpaceMember,\n SpaceMemberParam,\n SpaceMembersPage,\n refusals,\n} from '../../schemas/index.js';\n\nexport async function memberCommunityRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const tags = ['Communities'];\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/home',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberCommunityHome',\n tags,\n summary: 'The spaces a member can see in a community',\n description:\n \"For a member of the community, through a grant or `communities:read` on it. Lists its spaces in order. Spaces the viewer can open come back in full; spaces they can see but not open come back locked, with only their name, count, rule and the viewer's standing. A by-invite space the viewer is not invited to or a member of is left out, unless the viewer opens every space. `viewer` carries the viewer's permissions on the community, whether they open every space, and their team flag and role name. 404 when the viewer is not a member.\",\n params: CommunityParam,\n response: { 200: CommunityHome, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.reporting.member.communityHome(req.params.communityId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/spaces/:spaceId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberSpace',\n tags,\n summary: 'One space as a member sees it',\n description:\n 'For a member of the community: the space with its topics, links, settings and where the viewer stands. A space the viewer cannot open comes back locked, without its content. 404 when the viewer is not a member, the space is not in the community, or it is a by-invite space the viewer is not invited to or a member of.',\n params: CommunitySpaceParam,\n response: { 200: CommunityHomeSpace, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.reporting.member.communitySpace(\n req.params.communityId,\n req.params.spaceId,\n actor,\n );\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/directory',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberCommunityDirectory',\n tags,\n summary: 'People in a community',\n description:\n 'For a member of the community: everyone who holds it or holds `communities:read` on it, with their public profile, whether they are team here and under which role name, and whether they open every space. 404 when the viewer is not a member.',\n params: CommunityParam,\n querystring: DirectoryQuery,\n response: { 200: DirectoryPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.reporting.member.directory(req.params.communityId, req.query, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listSpaceMembers',\n tags,\n summary: 'List the members of a space',\n description:\n 'For anyone who can open the space. Members see the active members; holders of `communities:moderate` on the community also see open requests and invitations. Who opens every space holds no place, and is left out.',\n params: CommunitySpaceParam,\n querystring: PageQuery,\n response: { 200: SpaceMembersPage, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.listSpaceMembers(\n req.params.communityId,\n req.params.spaceId,\n req.query,\n actor,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/requests',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'requestSpaceMembership',\n tags,\n summary: 'Ask to join a space',\n description:\n 'For a member of the community who does not open every space. Opens a request on a `by_request` space for a moderator to approve. 409 when the space is not `by_request` or you are already placed in it.',\n params: CommunitySpaceParam,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const member = await container.entitlements.requestJoin(\n req.params.communityId,\n req.params.spaceId,\n actor,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/invites',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'inviteSpaceMember',\n tags,\n summary: 'Invite a person into a space you moderate',\n description: `Requires \\`communities:moderate\\`. On the community, as its member. Invites another member into a \\`by_invite\\` space; they join when they accept. 403 when the person opens every space or is not a member of the community; 409 when the space is not invite-only or the person is already placed.`,\n params: CommunitySpaceParam,\n body: OrgUserBody,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const member = await container.entitlements.invite(\n req.params.communityId,\n req.params.spaceId,\n req.body.orgUserId,\n actor,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'addSpaceMember',\n tags,\n summary: 'Add a person to a space you moderate',\n description: `Requires \\`communities:moderate\\`. On the community, as its member. Places another member straight into the space, with no request or invitation. 403 when the person opens every space; 409 when the space is open to all members, the person is already placed, or the space is full.`,\n params: CommunitySpaceParam,\n body: OrgUserBody,\n response: { 201: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n const member = await container.entitlements.addSpaceMember(\n req.params.communityId,\n req.params.spaceId,\n req.body.orgUserId,\n actor,\n );\n return reply.code(201).send(member);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/accept',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'acceptSpaceInvite',\n tags,\n summary: 'Accept your invitation to a space',\n description:\n 'For a member of the community who does not open every space. Makes you an active member. 409 when you have no open invitation, are already a member, or the space is full.',\n params: CommunitySpaceParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.accept(req.params.communityId, req.params.spaceId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members/:orgUserId/approve',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'approveSpaceRequest',\n tags,\n summary: \"Approve a person's request to join a space you moderate\",\n description: `Requires \\`communities:moderate\\`. On the community, as its member. Makes the requester an active member. 404 when the person has no open request; 409 when the space is full or they are already a member.`,\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.approve(\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n actor,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members/:orgUserId/decline',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'declineSpaceRequest',\n tags,\n summary: \"Decline a person's request to join a space you moderate\",\n description: `Requires \\`communities:moderate\\`. On the community, as its member. Closes the open request. 404 when the person has no open request; 409 when they are already a member.`,\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.decline(\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n actor,\n );\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/refuse',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'refuseSpaceInvite',\n tags,\n summary: 'Refuse your invitation to a space',\n description:\n 'For a member of the community who does not open every space. 409 when you have no open invitation or are already a member.',\n params: CommunitySpaceParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.refuse(req.params.communityId, req.params.spaceId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/departure',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'leaveSpace',\n tags,\n summary: 'Leave a space',\n description:\n 'For a member of the community who does not open every space. 409 when you are not a member of the space.',\n params: CommunitySpaceParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.leave(req.params.communityId, req.params.spaceId, actor);\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/communities/:communityId/spaces/:spaceId/members/:orgUserId/remove',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeSpaceMember',\n tags,\n summary: 'Remove a person from a space you moderate',\n description: `Requires \\`communities:moderate\\`. On the community, as its member. Revokes the placement, whether it is a membership, a request or an invitation. 409 when the space is open to all members or the placement is already revoked.`,\n params: SpaceMemberParam,\n response: { 200: SpaceMember, ...refusals(403, 404, 409) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return container.entitlements.remove(\n req.params.communityId,\n req.params.spaceId,\n req.params.orgUserId,\n actor,\n );\n },\n });\n\n r.route({\n method: 'PUT',\n url: '/api/member/spaces/:spaceId/subscription',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'setSpaceSubscription',\n tags,\n summary: 'Mute a space, or clear your mute',\n description:\n 'For anyone who can open the space. `muted` stops its activity notifying you, until `mutedUntil` when given; mentions, actions on you and moderation work still notify. `none` clears the mute.',\n params: SpaceIdParam,\n body: SetMute,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n const actor = await resolveActor(container, req);\n await container.subscriptions.setSpace(req.params.spaceId, req.body, actor);\n return reply.code(204).send();\n },\n });\n}\n"],"mappings":"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"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { refusals } from "../../schemas/shared.js";
|
|
2
|
+
import { resolveActor } from "../../scope.js";
|
|
2
3
|
import { Course } from "../../schemas/content.js";
|
|
3
4
|
import { ActivityList } from "../../schemas/activities.js";
|
|
4
5
|
import { MemberCourseIdParam, MemberCourses, MemberModules } from "../../schemas/member.js";
|
|
5
6
|
import "../../schemas/index.js";
|
|
6
|
-
import { actorOf } from "./actor.js";
|
|
7
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
8
7
|
//#region src/http/routes/member/courses.ts
|
|
9
8
|
async function memberCoursesRoutes(app, container) {
|
|
10
9
|
const r = app.withTypeProvider();
|
|
@@ -24,8 +23,8 @@ async function memberCoursesRoutes(app, container) {
|
|
|
24
23
|
}
|
|
25
24
|
},
|
|
26
25
|
handler: async (req) => {
|
|
27
|
-
const
|
|
28
|
-
return member.listCourses(
|
|
26
|
+
const actor = await resolveActor(container, req);
|
|
27
|
+
return member.listCourses(actor);
|
|
29
28
|
}
|
|
30
29
|
});
|
|
31
30
|
r.route({
|
|
@@ -36,7 +35,7 @@ async function memberCoursesRoutes(app, container) {
|
|
|
36
35
|
operationId: "getMemberCourse",
|
|
37
36
|
tags: ["Content"],
|
|
38
37
|
summary: "Get one course you can open",
|
|
39
|
-
description: "For a member of the organization
|
|
38
|
+
description: "For a member of the organization who holds the course, or holds `courses:read` on it (which also opens it unpublished). 404 otherwise.",
|
|
40
39
|
params: MemberCourseIdParam,
|
|
41
40
|
response: {
|
|
42
41
|
200: Course,
|
|
@@ -44,10 +43,8 @@ async function memberCoursesRoutes(app, container) {
|
|
|
44
43
|
}
|
|
45
44
|
},
|
|
46
45
|
handler: async (req) => {
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
if (!course) throw new NotFoundError("Course", req.params.courseId);
|
|
50
|
-
return course;
|
|
46
|
+
const actor = await resolveActor(container, req);
|
|
47
|
+
return member.getCourse(req.params.courseId, actor);
|
|
51
48
|
}
|
|
52
49
|
});
|
|
53
50
|
r.route({
|
|
@@ -58,7 +55,7 @@ async function memberCoursesRoutes(app, container) {
|
|
|
58
55
|
operationId: "listMemberModules",
|
|
59
56
|
tags: ["Content"],
|
|
60
57
|
summary: "List the modules and activities of a course you can open",
|
|
61
|
-
description: "For a member of the organization
|
|
58
|
+
description: "For a member of the organization who holds the course, or holds `courses:read` on it. Published activities only. 404 otherwise.",
|
|
62
59
|
params: MemberCourseIdParam,
|
|
63
60
|
response: {
|
|
64
61
|
200: MemberModules,
|
|
@@ -66,10 +63,8 @@ async function memberCoursesRoutes(app, container) {
|
|
|
66
63
|
}
|
|
67
64
|
},
|
|
68
65
|
handler: async (req) => {
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
if (!modules) throw new NotFoundError("Course", req.params.courseId);
|
|
72
|
-
return modules;
|
|
66
|
+
const actor = await resolveActor(container, req);
|
|
67
|
+
return member.listModules(req.params.courseId, actor);
|
|
73
68
|
}
|
|
74
69
|
});
|
|
75
70
|
r.route({
|
|
@@ -80,7 +75,7 @@ async function memberCoursesRoutes(app, container) {
|
|
|
80
75
|
operationId: "listMemberActivities",
|
|
81
76
|
tags: ["Content"],
|
|
82
77
|
summary: "List the published activities of a course you can open",
|
|
83
|
-
description: "For a member of the organization
|
|
78
|
+
description: "For a member of the organization who holds the course, or holds `courses:read` on it. 404 otherwise.",
|
|
84
79
|
params: MemberCourseIdParam,
|
|
85
80
|
response: {
|
|
86
81
|
200: ActivityList,
|
|
@@ -88,10 +83,8 @@ async function memberCoursesRoutes(app, container) {
|
|
|
88
83
|
}
|
|
89
84
|
},
|
|
90
85
|
handler: async (req) => {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
if (!activities) throw new NotFoundError("Course", req.params.courseId);
|
|
94
|
-
return activities;
|
|
86
|
+
const actor = await resolveActor(container, req);
|
|
87
|
+
return member.listActivities(req.params.courseId, actor);
|
|
95
88
|
}
|
|
96
89
|
});
|
|
97
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"courses.js","names":[],"sources":["../../../../src/http/routes/member/courses.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n ActivityList,\n Course,\n MemberCourseIdParam,\n MemberCourses,\n MemberModules,\n refusals,\n} from '../../schemas/index.js';\nimport
|
|
1
|
+
{"version":3,"file":"courses.js","names":[],"sources":["../../../../src/http/routes/member/courses.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport {\n ActivityList,\n Course,\n MemberCourseIdParam,\n MemberCourses,\n MemberModules,\n refusals,\n} from '../../schemas/index.js';\nimport type { Container } from '../../../app/container.js';\nimport { resolveActor } from '../../scope.js';\n\nexport async function memberCoursesRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const member = container.reporting.member;\n\n r.route({\n method: 'GET',\n url: '/api/member/courses',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberCourses',\n tags: ['Content'],\n summary: 'List the courses you can open',\n description:\n 'For a member of the organization. Published courses you hold, directly or through a bundle.',\n response: { 200: MemberCourses, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.listCourses(actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/courses/:courseId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberCourse',\n tags: ['Content'],\n summary: 'Get one course you can open',\n description:\n 'For a member of the organization who holds the course, or holds `courses:read` on it (which also opens it unpublished). 404 otherwise.',\n params: MemberCourseIdParam,\n response: { 200: Course, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.getCourse(req.params.courseId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/courses/:courseId/modules',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberModules',\n tags: ['Content'],\n summary: 'List the modules and activities of a course you can open',\n description:\n 'For a member of the organization who holds the course, or holds `courses:read` on it. Published activities only. 404 otherwise.',\n params: MemberCourseIdParam,\n response: { 200: MemberModules, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.listModules(req.params.courseId, actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/courses/:courseId/activities',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberActivities',\n tags: ['Content'],\n summary: 'List the published activities of a course you can open',\n description:\n 'For a member of the organization who holds the course, or holds `courses:read` on it. 404 otherwise.',\n params: MemberCourseIdParam,\n response: { 200: ActivityList, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.listActivities(req.params.courseId, actor);\n },\n });\n}\n"],"mappings":";;;;;;;AAaA,eAAsB,oBACpB,KACA,WACe;CACf,MAAM,IAAI,IAAI,iBAAkC;CAChD,MAAM,SAAS,UAAU,UAAU;CAEnC,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAe,GAAG,SAAS,GAAG;GAAE;EACnD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,OAAO,YAAY,KAAK;EACjC;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK;IAAQ,GAAG,SAAS,KAAK,GAAG;GAAE;EACjD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,OAAO,UAAU,IAAI,OAAO,UAAU,KAAK;EACpD;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK;IAAe,GAAG,SAAS,KAAK,GAAG;GAAE;EACxD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,OAAO,YAAY,IAAI,OAAO,UAAU,KAAK;EACtD;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK;IAAc,GAAG,SAAS,KAAK,GAAG;GAAE;EACvD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,OAAO,eAAe,IAAI,OAAO,UAAU,KAAK;EACzD;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Container } from "../../../app/container.js";
|
|
2
|
+
import { FastifyInstance } from "fastify";
|
|
3
|
+
//#region src/http/routes/member/devices.d.ts
|
|
4
|
+
declare function memberDeviceRoutes(app: FastifyInstance, container: Container): Promise<void>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { memberDeviceRoutes };
|
|
7
|
+
//# sourceMappingURL=devices.d.ts.map
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { refusals } from "../../schemas/shared.js";
|
|
2
|
+
import { resolveActor, resolveCaller } from "../../scope.js";
|
|
3
|
+
import { Device, DeviceIdParam, DeviceList, PushConfigView, RegisterDevice } from "../../schemas/notifications.js";
|
|
4
|
+
import "../../schemas/index.js";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
//#region src/http/routes/member/devices.ts
|
|
7
|
+
async function memberDeviceRoutes(app, container) {
|
|
8
|
+
const r = app.withTypeProvider();
|
|
9
|
+
const tags = ["Notifications"];
|
|
10
|
+
async function memberOf(req) {
|
|
11
|
+
const caller = await resolveCaller(container, req);
|
|
12
|
+
return {
|
|
13
|
+
...caller.actor,
|
|
14
|
+
userId: caller.userId
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
r.route({
|
|
18
|
+
method: "GET",
|
|
19
|
+
url: "/api/member/devices",
|
|
20
|
+
preHandler: app.requireOrgSession,
|
|
21
|
+
schema: {
|
|
22
|
+
operationId: "listMemberDevices",
|
|
23
|
+
tags,
|
|
24
|
+
summary: "List the devices you registered for push notifications",
|
|
25
|
+
description: "For anyone signed in to the organization. Each app install or browser that registered, most recently seen first. A device not seen for 30 days receives no push until it registers again.",
|
|
26
|
+
response: {
|
|
27
|
+
200: DeviceList,
|
|
28
|
+
...refusals(403)
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
handler: async (req) => {
|
|
32
|
+
return container.devices.list(await memberOf(req));
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
r.route({
|
|
36
|
+
method: "POST",
|
|
37
|
+
url: "/api/member/devices",
|
|
38
|
+
preHandler: app.requireOrgSession,
|
|
39
|
+
schema: {
|
|
40
|
+
operationId: "registerMemberDevice",
|
|
41
|
+
tags,
|
|
42
|
+
summary: "Register this device for push notifications, or refresh it",
|
|
43
|
+
description: "For anyone signed in to the organization. Call it after sign-in and on every launch. A new token adds a device, a known token is refreshed, and a token another person registered moves to you. A browser sends its push subscription endpoint as `token` with its `keys`; an iOS app sends its bundle id as `appId` and its APNs `environment`. 422 when the provider is not configured, an `apns` `appId` is not one of the configured bundle ids, a `webpush` device has no `keys`, or `keys` or `environment` come with a provider they do not apply to.",
|
|
44
|
+
body: RegisterDevice,
|
|
45
|
+
response: {
|
|
46
|
+
200: Device,
|
|
47
|
+
...refusals(400, 403, 422)
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
handler: async (req) => {
|
|
51
|
+
return container.devices.register(req.body, await memberOf(req));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
r.route({
|
|
55
|
+
method: "DELETE",
|
|
56
|
+
url: "/api/member/devices/:deviceId",
|
|
57
|
+
preHandler: app.requireOrgSession,
|
|
58
|
+
schema: {
|
|
59
|
+
operationId: "removeMemberDevice",
|
|
60
|
+
tags,
|
|
61
|
+
summary: "Remove one of your devices",
|
|
62
|
+
description: "For the person who registered the device. Call it before signing out, so the next person on the device receives none of your pushes. 404 when the device is not yours.",
|
|
63
|
+
params: DeviceIdParam,
|
|
64
|
+
response: {
|
|
65
|
+
204: z.void(),
|
|
66
|
+
...refusals(403, 404)
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
handler: async (req, reply) => {
|
|
70
|
+
await container.devices.remove(req.params.deviceId, await memberOf(req));
|
|
71
|
+
return reply.code(204).send();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
r.route({
|
|
75
|
+
method: "GET",
|
|
76
|
+
url: "/api/member/push-config",
|
|
77
|
+
preHandler: app.requireOrgSession,
|
|
78
|
+
schema: {
|
|
79
|
+
operationId: "getMemberPushConfig",
|
|
80
|
+
tags,
|
|
81
|
+
summary: "Read what a browser needs to subscribe to push notifications",
|
|
82
|
+
description: "For anyone signed in to the organization. `vapidPublicKey` is the `applicationServerKey` for `pushManager.subscribe`, or null when Web Push is not configured.",
|
|
83
|
+
response: {
|
|
84
|
+
200: PushConfigView,
|
|
85
|
+
...refusals(403)
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
handler: async (req) => {
|
|
89
|
+
await resolveActor(container, req);
|
|
90
|
+
return container.devices.pushConfig();
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { memberDeviceRoutes };
|
|
96
|
+
|
|
97
|
+
//# sourceMappingURL=devices.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"devices.js","names":[],"sources":["../../../../src/http/routes/member/devices.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { z } from 'zod';\nimport type { Container } from '../../../app/container.js';\nimport type { FastifyRequest } from 'fastify';\nimport { resolveActor, resolveCaller } from '../../scope.js';\nimport {\n Device,\n DeviceIdParam,\n DeviceList,\n PushConfigView,\n RegisterDevice,\n refusals,\n} from '../../schemas/index.js';\n\nexport async function memberDeviceRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const tags = ['Notifications'];\n\n async function memberOf(req: FastifyRequest) {\n const caller = await resolveCaller(container, req);\n return { ...caller.actor, userId: caller.userId };\n }\n\n r.route({\n method: 'GET',\n url: '/api/member/devices',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberDevices',\n tags,\n summary: 'List the devices you registered for push notifications',\n description:\n 'For anyone signed in to the organization. Each app install or browser that registered, most recently seen first. A device not seen for 30 days receives no push until it registers again.',\n response: { 200: DeviceList, ...refusals(403) },\n },\n handler: async (req) => {\n return container.devices.list(await memberOf(req));\n },\n });\n\n r.route({\n method: 'POST',\n url: '/api/member/devices',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'registerMemberDevice',\n tags,\n summary: 'Register this device for push notifications, or refresh it',\n description:\n 'For anyone signed in to the organization. Call it after sign-in and on every launch. A new token adds a device, a known token is refreshed, and a token another person registered moves to you. A browser sends its push subscription endpoint as `token` with its `keys`; an iOS app sends its bundle id as `appId` and its APNs `environment`. 422 when the provider is not configured, an `apns` `appId` is not one of the configured bundle ids, a `webpush` device has no `keys`, or `keys` or `environment` come with a provider they do not apply to.',\n body: RegisterDevice,\n response: { 200: Device, ...refusals(400, 403, 422) },\n },\n handler: async (req) => {\n return container.devices.register(req.body, await memberOf(req));\n },\n });\n\n r.route({\n method: 'DELETE',\n url: '/api/member/devices/:deviceId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'removeMemberDevice',\n tags,\n summary: 'Remove one of your devices',\n description:\n 'For the person who registered the device. Call it before signing out, so the next person on the device receives none of your pushes. 404 when the device is not yours.',\n params: DeviceIdParam,\n response: { 204: z.void(), ...refusals(403, 404) },\n },\n handler: async (req, reply) => {\n await container.devices.remove(req.params.deviceId, await memberOf(req));\n return reply.code(204).send();\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/push-config',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberPushConfig',\n tags,\n summary: 'Read what a browser needs to subscribe to push notifications',\n description:\n 'For anyone signed in to the organization. `vapidPublicKey` is the `applicationServerKey` for `pushManager.subscribe`, or null when Web Push is not configured.',\n response: { 200: PushConfigView, ...refusals(403) },\n },\n handler: async (req) => {\n await resolveActor(container, req);\n return container.devices.pushConfig();\n },\n });\n}\n"],"mappings":";;;;;;AAeA,eAAsB,mBACpB,KACA,WACe;CACf,MAAM,IAAI,IAAI,iBAAkC;CAChD,MAAM,OAAO,CAAC,eAAe;CAE7B,eAAe,SAAS,KAAqB;EAC3C,MAAM,SAAS,MAAM,cAAc,WAAW,GAAG;EACjD,OAAO;GAAE,GAAG,OAAO;GAAO,QAAQ,OAAO;EAAO;CAClD;CAEA,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAY,GAAG,SAAS,GAAG;GAAE;EAChD;EACA,SAAS,OAAO,QAAQ;GACtB,OAAO,UAAU,QAAQ,KAAK,MAAM,SAAS,GAAG,CAAC;EACnD;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,MAAM;GACN,UAAU;IAAE,KAAK;IAAQ,GAAG,SAAS,KAAK,KAAK,GAAG;GAAE;EACtD;EACA,SAAS,OAAO,QAAQ;GACtB,OAAO,UAAU,QAAQ,SAAS,IAAI,MAAM,MAAM,SAAS,GAAG,CAAC;EACjE;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK,EAAE,KAAK;IAAG,GAAG,SAAS,KAAK,GAAG;GAAE;EACnD;EACA,SAAS,OAAO,KAAK,UAAU;GAC7B,MAAM,UAAU,QAAQ,OAAO,IAAI,OAAO,UAAU,MAAM,SAAS,GAAG,CAAC;GACvE,OAAO,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK;EAC9B;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb;GACA,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAgB,GAAG,SAAS,GAAG;GAAE;EACpD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,aAAa,WAAW,GAAG;GACjC,OAAO,UAAU,QAAQ,WAAW;EACtC;CACF,CAAC;AACH"}
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { refusals } from "../../schemas/shared.js";
|
|
2
|
+
import { resolveActor } from "../../scope.js";
|
|
2
3
|
import { DownloadIdParam } from "../../schemas/downloads.js";
|
|
3
4
|
import { MemberDownload, MemberDownloads } from "../../schemas/member.js";
|
|
4
5
|
import "../../schemas/index.js";
|
|
5
|
-
import { actorOf } from "./actor.js";
|
|
6
|
-
import { NotFoundError } from "@headless-lms/core/shared/errors";
|
|
7
6
|
//#region src/http/routes/member/downloads.ts
|
|
8
7
|
async function memberDownloadsRoutes(app, container) {
|
|
9
8
|
const r = app.withTypeProvider();
|
|
@@ -23,8 +22,8 @@ async function memberDownloadsRoutes(app, container) {
|
|
|
23
22
|
}
|
|
24
23
|
},
|
|
25
24
|
handler: async (req) => {
|
|
26
|
-
const
|
|
27
|
-
return member.listDownloads(
|
|
25
|
+
const actor = await resolveActor(container, req);
|
|
26
|
+
return member.listDownloads(actor);
|
|
28
27
|
}
|
|
29
28
|
});
|
|
30
29
|
r.route({
|
|
@@ -35,7 +34,7 @@ async function memberDownloadsRoutes(app, container) {
|
|
|
35
34
|
operationId: "getMemberDownload",
|
|
36
35
|
tags: ["Content"],
|
|
37
36
|
summary: "One download you can open, with its files in order",
|
|
38
|
-
description: "For a member of the organization
|
|
37
|
+
description: "For a member of the organization who holds the download, or holds `downloads:read` on it (which also opens it unpublished). 404 otherwise.",
|
|
39
38
|
params: DownloadIdParam,
|
|
40
39
|
response: {
|
|
41
40
|
200: MemberDownload,
|
|
@@ -43,10 +42,8 @@ async function memberDownloadsRoutes(app, container) {
|
|
|
43
42
|
}
|
|
44
43
|
},
|
|
45
44
|
handler: async (req) => {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
if (!result) throw new NotFoundError("Download", req.params.downloadId);
|
|
49
|
-
return result;
|
|
45
|
+
const actor = await resolveActor(container, req);
|
|
46
|
+
return member.getDownload(req.params.downloadId, actor);
|
|
50
47
|
}
|
|
51
48
|
});
|
|
52
49
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"downloads.js","names":[],"sources":["../../../../src/http/routes/member/downloads.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { DownloadIdParam, MemberDownload, MemberDownloads, refusals } from '../../schemas/index.js';\nimport
|
|
1
|
+
{"version":3,"file":"downloads.js","names":[],"sources":["../../../../src/http/routes/member/downloads.ts"],"sourcesContent":["import type { FastifyInstance } from 'fastify';\nimport type { ZodTypeProvider } from 'fastify-type-provider-zod';\nimport { DownloadIdParam, MemberDownload, MemberDownloads, refusals } from '../../schemas/index.js';\nimport type { Container } from '../../../app/container.js';\nimport { resolveActor } from '../../scope.js';\n\nexport async function memberDownloadsRoutes(\n app: FastifyInstance,\n container: Container,\n): Promise<void> {\n const r = app.withTypeProvider<ZodTypeProvider>();\n const member = container.reporting.member;\n\n r.route({\n method: 'GET',\n url: '/api/member/downloads',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'listMemberDownloads',\n tags: ['Content'],\n summary: 'List the downloads you can open',\n description:\n 'For a member of the organization. Published downloads you hold, directly or through a bundle.',\n response: { 200: MemberDownloads, ...refusals(403) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.listDownloads(actor);\n },\n });\n\n r.route({\n method: 'GET',\n url: '/api/member/downloads/:downloadId',\n preHandler: app.requireOrgSession,\n schema: {\n operationId: 'getMemberDownload',\n tags: ['Content'],\n summary: 'One download you can open, with its files in order',\n description:\n 'For a member of the organization who holds the download, or holds `downloads:read` on it (which also opens it unpublished). 404 otherwise.',\n params: DownloadIdParam,\n response: { 200: MemberDownload, ...refusals(403, 404) },\n },\n handler: async (req) => {\n const actor = await resolveActor(container, req);\n return member.getDownload(req.params.downloadId, actor);\n },\n });\n}\n"],"mappings":";;;;;;AAMA,eAAsB,sBACpB,KACA,WACe;CACf,MAAM,IAAI,IAAI,iBAAkC;CAChD,MAAM,SAAS,UAAU,UAAU;CAEnC,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aACE;GACF,UAAU;IAAE,KAAK;IAAiB,GAAG,SAAS,GAAG;GAAE;EACrD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,OAAO,cAAc,KAAK;EACnC;CACF,CAAC;CAED,EAAE,MAAM;EACN,QAAQ;EACR,KAAK;EACL,YAAY,IAAI;EAChB,QAAQ;GACN,aAAa;GACb,MAAM,CAAC,SAAS;GAChB,SAAS;GACT,aACE;GACF,QAAQ;GACR,UAAU;IAAE,KAAK;IAAgB,GAAG,SAAS,KAAK,GAAG;GAAE;EACzD;EACA,SAAS,OAAO,QAAQ;GACtB,MAAM,QAAQ,MAAM,aAAa,WAAW,GAAG;GAC/C,OAAO,OAAO,YAAY,IAAI,OAAO,YAAY,KAAK;EACxD;CACF,CAAC;AACH"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Container } from "../../../app/container.js";
|
|
2
|
+
import { FastifyInstance } from "fastify";
|
|
3
|
+
//#region src/http/routes/member/events.d.ts
|
|
4
|
+
declare function memberEventsRoutes(app: FastifyInstance, container: Container): Promise<void>;
|
|
5
|
+
//#endregion
|
|
6
|
+
export { memberEventsRoutes };
|
|
7
|
+
//# sourceMappingURL=events.d.ts.map
|