Skip to main content
Version: 0.13.0 (Previous)

🛣️ Organization routes

Organization routes are SDK composers, not Express middleware. Mount their matching feature or organizationService; each detail links schema, validators, pipeline, and response contract.

Inventory

RouteMethod / protocolPathSchemaValidatorsSuccess status
createOrganizationRoutePOST / HTTP/organizationscreateOrganizationSchemaisAuthenticated(), checkIdentityType(['admin'])200
getOrganizationRouteGET / HTTP/organizations/:organizationIdgetOrganizationSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin', 'member'], ['params', 'requestParams', 'organizationId'] ) )200
findOrganizationsRouteGET / HTTP/organizationsfindOrganizationsSchemaisAuthenticated(), checkIdentityType(['admin'])200
updateOrganizationRoutePATCH / HTTP/organizations/:organizationIdupdateOrganizationSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )200
updateOrganizationAsAdminRoutePATCH / HTTP/admin/organizations/:organizationId/updateOrganizationAsAdminSchemaisAuthenticated(), checkIdentityType(['admin'])200
deleteOrganizationRouteDELETE / HTTP/organizations/:organizationIddeleteOrganizationSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )204
getOrganizationMemberRoleRouteGET / HTTP/organizations/:organizationId/members/:identityId/rolegetOrganizationMemberRoleSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ) )200
checkOrganizationMemberExistenceRouteGET / HTTP/organizations/:organizationId/members/check-existencecheckOrganizationMemberExistenceSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ) )200
findOrganizationMembersRouteGET / HTTP/organizations/:organizationId/membersfindOrganizationMembersSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ) )200
upsertOrganizationMembersRoutePATCH / HTTP/organizations/:organizationId/membersupsertOrganizationMembersSchemaisAuthenticated(), some( checkIdentityType(['admin']), all( hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ), hasOrgRoleAssignmentPermission( ['params', 'requestParams', 'organizationId'], ['params', 'requestBody'] ) ) ), hasOrgOwnerRemainingAfterMembersUpsert( ['params', 'requestParams', 'organizationId'], ['params', 'requestBody'] )204
deleteOrganizationMemberRouteDELETE / HTTP/organizations/:organizationId/members/:identityIddeleteOrganizationMemberSchemaisAuthenticated(), some( checkIdentityType(['admin']), all( hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ), hasOrgRoleSameOrAbove( ['params', 'requestParams', 'organizationId'], ['params', 'requestParams', 'identityId'] ) ) ), hasOrgOwnerRemainingAfterMemberRemoval( ['params', 'requestParams', 'organizationId'], ['params', 'requestParams', 'identityId'] )204
findOrganizationsForMemberRouteGET / HTTP/organizations/members/:identityIdfindOrganizationsForMemberSchemaisAuthenticated(), some( checkIdentityType(['admin']), isSelf(['params', 'requestParams', 'identityId']) )200
findOrganizationDescendantsRouteGET / HTTP/organizations/:organizationId/descendantsfindOrganizationDescendantsSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole( ['owner', 'admin'], ['params', 'requestParams', 'organizationId'] ) )200
getLogoUploadUrlRouteGET / HTTP/organizations/:organizationId/logo-upload-urlgetSignedImageUploadUrlSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )200
getCertificateUploadUrlRouteGET / HTTP/organizations/:organizationId/certificate-upload-urlgetCertificateUploadUrlSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )200
createChangeRequestRoutePOST / HTTP/organizations/:organizationId/change-requestscreateChangeRequestSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )204
findChangeRequestsForOrganizationRouteGET / HTTP/organizations/:organizationId/change-requestsfindChangeRequestsForOrganizationSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )200
getOrganizationFollowersRouteGET / HTTP/organizations/:organizationId/followersgetOrganizationFollowersSchemaisAuthenticated(), some( checkIdentityType(['admin']), hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId']) )200

Details

createOrganizationRoute

Implementation

Endpoint: POST /organizations

Creates a new organization via POST /organizations with parent/ancestor and logo normalization.

Access: The source executes this validator chain in order: isAuthenticatedcheckIdentityType.

Request: createOrganizationSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdcalculateChildAncestorsnoopcreateOrganizationnormalizeLogoOfOwnernormalizeOrganizationTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const createOrganizationRoute = withRoute({
handler: compose(
ifElse(
match(Boolean, ['params', 'requestBody', 'parentId']),
compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestBody', 'parentId'],
],
'parentOrganization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
calculateChildAncestors,
[['context', 'data', 'parentOrganization']],
'ancestors'
)
)
)
),
applyPayloadArgs(noop, [[]])
),
withLogging(
flatMapAsync(
applyPayloadArgs(
createOrganization,
[
['context', 'db', 'organizations'],
['params', 'requestBody', 'ownerId'],
['params', 'requestBody', 'organization'],
['params', 'requestBody', 'parentId'],
['context', 'data', 'ancestors'],
],
'organizationId'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['context', 'data', 'organizationId'],
],
'rawOrganization'
)
)
),
// TODO: once we remove terminators, these 'normalizeX' functions should be replaced by a single normalizer
flatMapAsync(
applyPayloadArgs(
normalizeLogoOfOwner,
[
['context', 'fileStorageDriver'],
['context', 'data', 'rawOrganization'],
],
'organization'
)
),
// TODO: replace terminator (because we are using old terminator, the function directly before it has to append "organization" to context.data)
lift(withLogging(normalizeOrganizationTerminator))
),
method: 'POST',
path: '/organizations',
validators: [isAuthenticated(), checkIdentityType(['admin'])],
});

getOrganizationRoute

Implementation

Endpoint: GET /organizations/:organizationId

Retrieves a specific organization via GET /organizations/:organizationId with logo normalization and access control.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: getOrganizationSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdnormalizeCertificateImagenormalizeLogoOfOwnernormalizeOrganizationTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const getOrganizationRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'rawOrganization'
)
),

// TODO: once we remove terminators, these 'normalizeX' functions should be replaced by a single normalizer
flatMapAsync(
applyPayloadArgs(
normalizeCertificateImage,
[
['context', 'fileStorageDriver'],
['context', 'data', 'rawOrganization'],
],
'organizationWithCertificateImage'
)
),

flatMapAsync(
applyPayloadArgs(
normalizeLogoOfOwner,
[
['context', 'fileStorageDriver'],
['context', 'data', 'organizationWithCertificateImage'],
],
'organization'
)
),
// TODO: replace terminator (because we are using old terminator, the function directly before it has to append "organization" to context.data)
lift(withLogging(normalizeOrganizationTerminator))
),
method: 'GET',
path: '/organizations/:organizationId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(
['owner', 'admin', 'member'],
['params', 'requestParams', 'organizationId']
)
),
],
});

findOrganizationsRoute

Implementation

Endpoint: GET /organizations

Retrieves paginated organizations list via GET /organizations with certificate and logo normalization for admin users.

Access: The source executes this validator chain in order: isAuthenticatedcheckIdentityType.

Request: findOrganizationsSchema defines the path, query, header, and JSON-body contract.

Pipeline: findOrganizationsnormalizeCertificateImagesnormalizeLogosOfOwnersapplySpecnormalizeOrganizationsListTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const findOrganizationsRoute = withRoute({
handler: compose(
withPagination(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['params', 'requestQuery'],
],
'paginatedOrganizations'
)
)
),
// TODO: once we remove terminators, these 'normalizeX' functions should be replaced by a single normalizer
flatMapAsync(
applyPayloadArgs(
normalizeCertificateImages,
[
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedOrganizations', 'data'],
],
'organizationsWithCertificateImages'
)
),
flatMapAsync(
applyPayloadArgs(
normalizeLogosOfOwners,
[
['context', 'fileStorageDriver'],
['context', 'data', 'organizationsWithCertificateImages'],
],
'normalizedOrganizations'
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({
data: nthArg(0),
metadata: nthArg(1),
}),
[
['context', 'data', 'normalizedOrganizations'],
['context', 'data', 'paginatedOrganizations', 'metadata'],
],
'organizations'
)
),
// TODO: replace terminator (because we are using old terminator, the function directly before it has to append "organizations" to context.data)
lift(withLogging(normalizeOrganizationsListTerminator))
),
method: 'GET',
path: '/organizations',
validators: [isAuthenticated(), checkIdentityType(['admin'])],
});

updateOrganizationRoute

Implementation

Endpoint: PATCH /organizations/:organizationId

Updates an existing organization via PATCH /organizations/:organizationId with logo normalization and access control.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: updateOrganizationSchema defines the path, query, header, and JSON-body contract.

Pipeline: updateOrganizationgetOrganizationByIdnormalizeCertificateImagenormalizeLogoOfOwnernormalizeOrganizationTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const updateOrganizationRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
updateOrganization,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
['params', 'requestBody'],
],
'hasUpdatedOrganization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'rawOrganization'
)
)
),

// TODO: once we remove terminators, these 'normalizeX' functions should be replaced by a single normalizer
flatMapAsync(
applyPayloadArgs(
normalizeCertificateImage,
[
['context', 'fileStorageDriver'],
['context', 'data', 'rawOrganization'],
],
'organizationWithCertificateImage'
)
),
flatMapAsync(
applyPayloadArgs(
normalizeLogoOfOwner,
[
['context', 'fileStorageDriver'],
['context', 'data', 'organizationWithCertificateImage'],
],
'organization'
)
),
// TODO: replace terminator (because we are using old terminator, the function directly before it has to append "organization" to context.data)
lift(withLogging(normalizeOrganizationTerminator))
),
method: 'PATCH',
path: '/organizations/:organizationId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});

updateOrganizationAsAdminRoute

Implementation

Endpoint: PATCH /admin/organizations/:organizationId/

Updates an organization as admin via PATCH /admin/organizations/:organizationId/.

Access: The source executes this validator chain in order: isAuthenticatedcheckIdentityType.

Request: updateOrganizationAsAdminSchema defines the path, query, header, and JSON-body contract.

Pipeline: validateAuditStatusupdateOrganizationgetOrganizationByIdnormalizeCertificateImagenormalizeLogoOfOwnernormalizeOrganizationTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const updateOrganizationAsAdminRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
validateAuditStatus,
[['params', 'requestBody', 'auditStatus']],
'isValidAuditStatus'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
updateOrganization,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
['params', 'requestBody'],
],
'hasUpdatedOrganization'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'rawOrganization'
)
)
),

// TODO: once we remove terminators, these 'normalizeX' functions should be replaced by a single normalizer
flatMapAsync(
applyPayloadArgs(
normalizeCertificateImage,
[
['context', 'fileStorageDriver'],
['context', 'data', 'rawOrganization'],
],
'organizationWithCertificateImage'
)
),

flatMapAsync(
applyPayloadArgs(
normalizeLogoOfOwner,
[
['context', 'fileStorageDriver'],
['context', 'data', 'organizationWithCertificateImage'],
],
'organization'
)
),
// TODO: replace terminator (because we are using old terminator, the function directly before it has to append "organization" to context.data)
lift(withLogging(normalizeOrganizationTerminator))
),
method: 'PATCH',
path: '/admin/organizations/:organizationId/',
validators: [isAuthenticated(), checkIdentityType(['admin'])],
});

deleteOrganizationRoute

Implementation

Endpoint: DELETE /organizations/:organizationId

Deletes an organization and its logo via DELETE /organizations/:organizationId.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: deleteOrganizationSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIddeleteLogoOfOwnerdeleteOrganizationdeleteOrganizationTerminator.

Success: 204; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const deleteOrganizationRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organization'
)
),

flatMapAsync(
applyPayloadArgs(
deleteLogoOfOwner,
[
['context', 'fileStorageDriver'],
['context', 'data', 'organization'],
],
'logoOfOwnerDeleted'
)
),

// TODO: there is currently no way to delete certificates

flatMapAsync(
withLogging(
applyPayloadArgs(
deleteOrganization,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'hasDeletedOrganization'
)
)
),
// TODO: replace terminator
lift(withLogging(deleteOrganizationTerminator))
),
method: 'DELETE',
path: '/organizations/:organizationId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});

getOrganizationMemberRoleRoute

Implementation

Endpoint: GET /organizations/:organizationId/members/:identityId/role

Retrieves the role of a specific member within an organization via GET /organizations/:organizationId/members/:identityId/role.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: getOrganizationMemberRoleSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdbuildOrganizationsForMemberByIdsQueryfindOrganizationscalculateMemberRole.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const getOrganizationMemberRoleRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildOrganizationsForMemberByIdsQuery,
[
['params', 'requestParams', 'identityId'],
['context', 'data', 'organization', 'ancestors'],
],
'ancestorOrganizationsQuery'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['context', 'data', 'ancestorOrganizationsQuery'],
],
'ancestorOrganizations'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
calculateMemberRole,
[
['context', 'data', 'organization'],
['context', 'data', 'ancestorOrganizations'],
['params', 'requestParams', 'identityId'],
],
'memberRole'
)
)
),
lift(
orThrow(
[
[OrganizationMemberNotFoundError, 404],
[OrganizationMemberRoleNotFoundError, 404],
[OrganizationDbError, 500],
],
[['context', 'data', 'memberRole'], 200]
)
)
),
method: 'GET',
path: '/organizations/:organizationId/members/:identityId/role',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
)
),
],
});

checkOrganizationMemberExistenceRoute

Implementation

Endpoint: GET /organizations/:organizationId/members/check-existence

Checks if a given identity exists as a member within an organization via GET /organizations/:organizationId/members/check-existence.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: checkOrganizationMemberExistenceSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdcheckOrganizationMemberExistencenormalizeOrganizationMemberExistenceTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const checkOrganizationMemberExistenceRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
checkOrganizationMemberExistence,
[
['context', 'data', 'organization', 'members'],
['params', 'requestQuery', 'identityId'],
],
'isMemberOfOrganization'
)
)
),
// TODO: replace terminator
lift(withLogging(normalizeOrganizationMemberExistenceTerminator))
),
method: 'GET',
path: '/organizations/:organizationId/members/check-existence',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
)
),
],
});

findOrganizationMembersRoute

Implementation

Endpoint: GET /organizations/:organizationId/members

Retrieves all members within an organization via GET /organizations/:organizationId/members.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: findOrganizationMembersSchema defines the path, query, header, and JSON-body contract.

Pipeline: findOrganizationMembersnormalizeOrganizationMembersListTerminator.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const findOrganizationMembersRoute = withRoute({
handler: compose(
withPaginatedProperty(
withLogging(
applyPayloadArgs(
findOrganizationMembers,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organizationMembers'
)
),
['members']
),
// TODO: replace terminator
lift(withLogging(normalizeOrganizationMembersListTerminator))
),
method: 'GET',
path: '/organizations/:organizationId/members',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
)
),
],
});

upsertOrganizationMembersRoute

Implementation

Endpoint: PATCH /organizations/:organizationId/members

Upserts members within an organization via PATCH /organizations/:organizationId/members.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypeallhasOrgRolehasOrgRoleAssignmentPermissionhasOrgOwnerRemainingAfterMembersUpsert.

Request: upsertOrganizationMembersSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdupsertOrganizationMembersupsertOrganizationMembersTerminator.

Success: 204; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const upsertOrganizationMembersRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
upsertOrganizationMembers,
[
['context', 'db', 'organizations'],
['context', 'data', 'organization', 'members'],
['params', 'requestParams', 'organizationId'],
['params', 'requestBody'],
],
'hasUpsertedOrganizationMembers'
)
)
),
// TODO: replace terminator
lift(withLogging(upsertOrganizationMembersTerminator))
),
method: 'PATCH',
path: '/organizations/:organizationId/members',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
all(
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
),
hasOrgRoleAssignmentPermission(
['params', 'requestParams', 'organizationId'],
['params', 'requestBody']
)
)
),
hasOrgOwnerRemainingAfterMembersUpsert(
['params', 'requestParams', 'organizationId'],
['params', 'requestBody']
),
],
});

deleteOrganizationMemberRoute

Implementation

Endpoint: DELETE /organizations/:organizationId/members/:identityId

Removes a member from an organization via DELETE /organizations/:organizationId/members/:identityId.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypeallhasOrgRolehasOrgRoleSameOrAbovehasOrgOwnerRemainingAfterMemberRemoval.

Request: deleteOrganizationMemberSchema defines the path, query, header, and JSON-body contract.

Pipeline: deleteOrganizationMemberdeleteOrganizationMemberTerminator.

Success: 204; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const deleteOrganizationMemberRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
deleteOrganizationMember,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
['params', 'requestParams', 'identityId'],
],
'hasDeletedOrganizationMember'
)
),
// TODO: replace terminator
lift(withLogging(deleteOrganizationMemberTerminator))
),
method: 'DELETE',
path: '/organizations/:organizationId/members/:identityId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
all(
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
),
hasOrgRoleSameOrAbove(
['params', 'requestParams', 'organizationId'],
['params', 'requestParams', 'identityId']
)
)
),
hasOrgOwnerRemainingAfterMemberRemoval(
['params', 'requestParams', 'organizationId'],
['params', 'requestParams', 'identityId']
),
],
});

findOrganizationsForMemberRoute

Implementation

Endpoint: GET /organizations/members/:identityId

Retrieves all organizations for a specific member, including direct and inherited roles, via GET /organizations/members/:identityId.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypeisSelf.

Request: findOrganizationsForMemberSchema defines the path, query, header, and JSON-body contract.

Pipeline: buildOrganizationsForMemberByRoleQueryfindOrganizationsnormalizeCertificateImagesnormalizeLogosOfOwnersbuildOrganizationsWithDescendantsQueryextractAncestorsbuildOrganizationsForMemberByIdsQuerycalculateMemberRoleForOrganizationsnormalizeOrganizationsForMember.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const findOrganizationsForMemberRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
buildOrganizationsForMemberByRoleQuery,
[
['params', 'requestParams', 'identityId'],
['params', 'requestQuery', 'roles'],
],
'organizationsForMemberQuery'
)
),
flatMapAsync(
ifElse(
match(equals('true'), ['params', 'requestQuery', 'includeInherited']),
compose(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['context', 'data', 'organizationsForMemberQuery'],
],
'organizationsForMember'
)
),
flatMapAsync(
applyPayloadArgs(
normalizeCertificateImages,
[
['context', 'fileStorageDriver'],
['context', 'data', 'organizationsForMember'],
],
'organizationsForMemberWithCertificateImages'
)
),
flatMapAsync(
applyPayloadArgs(
normalizeLogosOfOwners,
[
['context', 'fileStorageDriver'],
[
'context',
'data',
'organizationsForMemberWithCertificateImages',
],
],
'organizationsForMemberWithCertificateImagesAndLogos'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildOrganizationsWithDescendantsQuery,
[
[
'context',
'data',
'organizationsForMemberWithCertificateImagesAndLogos',
],
],
'organizationsWithDescendantsQuery'
)
)
),
flatMapAsync(
// TODO: comment out withPagination for now due to the issue with the database patching
// withPagination(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['context', 'data', 'organizationsWithDescendantsQuery'],
],
'organizationsWithDescendants'
)
)
// )
),
flatMapAsync(
withLogging(
applyPayloadArgs(
extractAncestors,
[['context', 'data', 'organizationsWithDescendants']],
'concatenatedAncestors'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildOrganizationsForMemberByIdsQuery,
[
['params', 'requestParams', 'identityId'],
['context', 'data', 'concatenatedAncestors'],
],
'ancestorOrganizationsQuery'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['context', 'data', 'ancestorOrganizationsQuery'],
],
'ancestorOrganizations'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
calculateMemberRoleForOrganizations,
[
['context', 'data', 'organizationsWithDescendants'],
['context', 'data', 'ancestorOrganizations'],
['params', 'requestParams', 'identityId'],
],
'organizationWithMemberRoles'
)
)
)
),
compose(
withPagination(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['context', 'data', 'organizationsForMemberQuery'],
],
'paginatedOrganizationsForMember'
)
)
),
flatMapAsync(
applyPayloadArgs(
normalizeCertificateImages,
[
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedOrganizationsForMember', 'data'],
],
'organizationsForMemberWithCertificateImages'
)
),
flatMapAsync(
applyPayloadArgs(
normalizeLogosOfOwners,
[
['context', 'fileStorageDriver'],
[
'context',
'data',
'organizationsForMemberWithCertificateImages',
],
],
'organizationsForMemberWithCertificateImagesAndLogos'
)
),
flatMapAsync(
withLogging(applyPayloadArgs(() => [], [], 'ancestorOrganizations'))
),
flatMapAsync(
withLogging(
applyPayloadArgs(
calculateMemberRoleForOrganizations,
[
[
'context',
'data',
'organizationsForMemberWithCertificateImagesAndLogos',
],
['context', 'data', 'ancestorOrganizations'],
['params', 'requestParams', 'identityId'],
],
'organizationWithMemberRoles'
)
)
)
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeOrganizationsForMember,
[['context', 'data', 'organizationWithMemberRoles']],
'normalizedOrganizationsForMember'
)
)
),
lift(
orThrow(
[
[OrganizationMemberNotFoundError, 404],
[OrganizationMemberRoleNotFoundError, 404],
[OrganizationDbError, 500],
],
[['context', 'data', 'normalizedOrganizationsForMember'], 200]
)
)
),
method: 'GET',
path: '/organizations/members/:identityId',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
isSelf(['params', 'requestParams', 'identityId'])
),
],
});

findOrganizationDescendantsRoute

Implementation

Endpoint: GET /organizations/:organizationId/descendants

Organization descendants retrieval route with pagination and normalization.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: findOrganizationDescendantsSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdbuildDescendantsQueryfindOrganizationsnormalizeOrganizationsapplySpec.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const findOrganizationDescendantsRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildDescendantsQuery,
[
['context', 'data', 'organization'],
['params', 'requestQuery', 'depth'],
],
'descendantsQuery'
)
)
),
flatMapAsync(
withPagination(
withLogging(
applyPayloadArgs(
findOrganizations,
[
['context', 'db', 'organizations'],
['context', 'data', 'descendantsQuery'],
],
'paginatedOrganizationDescendants'
)
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeOrganizations,
[['context', 'data', 'paginatedOrganizationDescendants', 'data']],
'normalizedOrganizations'
)
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedOrganizations'],
['context', 'data', 'paginatedOrganizationDescendants', 'metadata'],
],
'normalizedOrganizationsWithPagination'
)
),
lift(
orThrow(
[
[OrganizationInvalidQueryError, 400],
[OrganizationDbError, 500],
],
[['context', 'data', 'normalizedOrganizationsWithPagination'], 200]
)
)
),
method: 'GET',
path: '/organizations/:organizationId/descendants',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(
['owner', 'admin'],
['params', 'requestParams', 'organizationId']
)
),
],
});

getLogoUploadUrlRoute

Implementation

Endpoint: GET /organizations/:organizationId/logo-upload-url

Generates a signed upload URL for an organization logo via GET /organizations/:organizationId/logo-upload-url.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: getSignedImageUploadUrlSchema defines the path, query, header, and JSON-body contract.

Pipeline: generateFileUploadUrl.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const getLogoUploadUrlRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(generateFileUploadUrl, [
['context', 'fileStorageDriver'],
['params', 'requestQuery', 'contentType'],
['params', 'requestQuery', 'contentLength'],
])
),
lift(orThrow([[FileStorageServiceError, 500]], [['context', 'data'], 200]))
),
method: 'GET',
path: '/organizations/:organizationId/logo-upload-url',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});

getCertificateUploadUrlRoute

Implementation

Endpoint: GET /organizations/:organizationId/certificate-upload-url

Generates a signed upload URL for an organization certificate via GET /organizations/:organizationId/certificate-upload-url.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: getCertificateUploadUrlSchema defines the path, query, header, and JSON-body contract.

Pipeline: generateFileUploadUrl.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const getCertificateUploadUrlRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(generateFileUploadUrl, [
['context', 'fileStorageDriver'],
['params', 'requestQuery', 'contentType'],
['params', 'requestQuery', 'contentLength'],
])
),
lift(orThrow([[FileStorageServiceError, 500]], [['context', 'data'], 200]))
),
method: 'GET',
path: '/organizations/:organizationId/certificate-upload-url',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});

createChangeRequestRoute

Implementation

Endpoint: POST /organizations/:organizationId/change-requests

Creates organization change request via POST /organizations/:organizationId/change-requests.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: createChangeRequestSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdvalidateOrganizationNamenoopextractTokenFromAuthorizationHeadercheckTokencreateChangeRequestbuildUpdateOrganizationAfterNewChangeRequestPayloadupdateOrganizationnormalizeEmptyBody.

Success: 204; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const createChangeRequestRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'rawOrganization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
validateOrganizationName,
[
['context', 'db', 'organizations'],
['context', 'data', 'rawOrganization'],
['params', 'requestParams', 'organizationId'],
['params', 'requestBody', 'name'],
],
'isValidOrganizationName'
)
)
),
flatMapAsync(
withLogging(
whenCookieAuth(
withLogging(
applyPayloadArgs(
noop,
[['context', 'request', 'cookies', 'accessToken']],
'accessToken'
)
),
withLogging(
applyPayloadArgs(
extractTokenFromAuthorizationHeader,
[['context', 'request', 'headers', 'authorization']],
'accessToken'
)
)
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
checkToken,
[
['context', 'db', 'onetimetokens'],
['context', 'configuration', 'authSecrets'],
['context', 'request'],
['context', 'data', 'accessToken'],
],
'checkTokenResult'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
createChangeRequest,
[
['context', 'db', 'organizationChangeRequests'],
['params', 'requestParams', 'organizationId'],
['context', 'data', 'checkTokenResult', 'tokenInfo', 'identityId'],
['params', 'requestBody'],
],
'changeRequestId'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildUpdateOrganizationAfterNewChangeRequestPayload,
[],
'organizationFieldsToUpdate'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
updateOrganization,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
['context', 'data', 'organizationFieldsToUpdate'],
],
'hasUpdatedOrganization'
)
)
),
flatMapAsync(
withLogging(applyPayloadArgs(normalizeEmptyBody, [], 'normalizedBody'))
),
lift(
withLogging(
orThrow(
[
[OrganizationBadRequestError, 400],
[OrganizationDbError, 500],
[AuthenticationBadRequestError, 400],
[AuthenticationUnauthorizedError, 401],
[AuthenticationInvalidTokenError, 400],
[AuthenticationUnexpectedDBError, 500],
[FileStorageServiceError, 500],
[OrganizationChangeRequestDbError, 500],
],
[['context', 'data', 'normalizedBody'], 204]
)
)
)
),
method: 'POST',
path: '/organizations/:organizationId/change-requests',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});

findChangeRequestsForOrganizationRoute

Implementation

Endpoint: GET /organizations/:organizationId/change-requests

Retrieves change requests for a specific organization via GET /organizations/:organizationId/change-requests.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: findChangeRequestsForOrganizationSchema defines the path, query, header, and JSON-body contract.

Pipeline: findChangeRequestsnormalizeChangeRequestsapplySpec.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const findChangeRequestsForOrganizationRoute = withRoute({
handler: compose(
withLogging(
withPagination(
applyPayloadArgs(
findChangeRequests,
[
['context', 'db', 'organizationChangeRequests'],
['params', 'requestParams', 'organizationId'],
],
'changeRequests'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeChangeRequests,
[
['context', 'fileStorageDriver'],
['context', 'data', 'changeRequests', 'data'],
],
'normalizedChangeRequests'
)
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedChangeRequests'],
['context', 'data', 'changeRequests', 'metadata'],
],
'normalizedBody'
)
),

lift(
withLogging(
orThrow(
[
[OrganizationChangeRequestDbError, 500],
[OrganizationChangeRequestError, 500],
],
[['context', 'data', 'normalizedBody'], 200]
)
)
)
),
method: 'GET',
path: '/organizations/:organizationId/change-requests',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});

getOrganizationFollowersRoute

Implementation

Endpoint: GET /organizations/:organizationId/followers

Retrieves organization followers via GET /organizations/:organizationId/followers.

Access: The source executes this validator chain in order: isAuthenticatedsomecheckIdentityTypehasOrgRole.

Request: getOrganizationFollowersSchema defines the path, query, header, and JSON-body contract.

Pipeline: getOrganizationByIdbuildOrganizationFollowersByFollowOrganizationIdQuerybuildWithoutMongoIdFindOptionsfindProfilesnormalizeFollowersapplySpec.

Success: 200; the complete source shows the final ordinary value, terminator, or orThrow response descriptor.

Failure: Validator failures occur before the pipeline; source-mapped block errors and status mappings are preserved in the complete definition below.

View complete source
export const getOrganizationFollowersRoute = withRoute({
handler: compose(
withLogging(
applyPayloadArgs(
getOrganizationById,
[
['context', 'db', 'organizations'],
['params', 'requestParams', 'organizationId'],
],
'organization'
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
buildOrganizationFollowersByFollowOrganizationIdQuery,
[['params', 'requestParams', 'organizationId']],
'filter'
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(buildWithoutMongoIdFindOptions, [], 'options')
)
),
flatMapAsync(
withPagination(
withLogging(
applyPayloadArgs(
findProfiles,
[
['context', 'db', 'profiles'],
['context', 'data', 'filter'],
['context', 'data', 'options'],
],
'paginatedFollowers'
)
)
)
),
flatMapAsync(
withLogging(
applyPayloadArgs(
normalizeFollowers,
[
['context', 'fileStorageDriver'],
['context', 'data', 'paginatedFollowers', 'data'],
],
'normalizedFollowers'
)
)
),
flatMapAsync(
applyPayloadArgs(
applySpec({ data: nthArg(0), metadata: { pagination: nthArg(1) } }),
[
['context', 'data', 'normalizedFollowers'],
['context', 'data', 'paginatedFollowers', 'metadata'],
],
'normalizedBody'
)
),
lift(
orThrow(
[
[OrganizationNotFoundError, 404],
[OrganizationDbError, 500],
[AvatarBlockError, 500],
[ProfileDbBlockError, 500],
],
[['context', 'data', 'normalizedBody'], 200]
)
)
),
method: 'GET',
path: '/organizations/:organizationId/followers',
validators: [
isAuthenticated(),
some(
checkIdentityType(['admin']),
hasOrgRole(['owner'], ['params', 'requestParams', 'organizationId'])
),
],
});