Files
speckle-server/packages/server/modules/serverinvites/services/management.ts
T
Kristaps Fabians Geikins 6bfffca0a9 fix: various invite flow fixes & improvements (#2451)
* fix(fe2): show signup CTA for non-registered invitees [web-1144]

* fix: server invite signup error

* WIP project error access block

* feat(fe2): better 'no project access' error screens

* CR fix
2024-06-28 17:26:11 +02:00

100 lines
3.1 KiB
TypeScript

import { MaybeNullOrUndefined, Roles, ServerRoles, StreamRoles } from '@speckle/shared'
import {
MutationStreamInviteUseArgs,
ProjectInviteCreateInput,
ProjectInviteUseInput,
StreamInviteCreateInput
} from '@/modules/core/graph/generated/graphql'
import { InviteCreateValidationError } from '@/modules/serverinvites/errors'
import {
buildUserTarget,
ResourceTargets
} from '@/modules/serverinvites/helpers/inviteHelper'
import { has } from 'lodash'
import {
ContextResourceAccessRules,
isResourceAllowed
} from '@/modules/core/helpers/token'
import { StreamInvalidAccessError } from '@/modules/core/errors/stream'
import {
CreateAndSendInvite,
FinalizeStreamInvite
} from '@/modules/serverinvites/services/operations'
import { TokenResourceIdentifier } from '@/modules/core/domain/tokens/types'
type FullProjectInviteCreateInput = ProjectInviteCreateInput & { projectId: string }
const isStreamInviteCreateInput = (
i: StreamInviteCreateInput | FullProjectInviteCreateInput
): i is StreamInviteCreateInput => has(i, 'streamId')
export const createStreamInviteAndNotifyFactory =
({ createAndSendInvite }: { createAndSendInvite: CreateAndSendInvite }) =>
async (
input: StreamInviteCreateInput | FullProjectInviteCreateInput,
inviterId: string,
inviterResourceAccessRules: MaybeNullOrUndefined<TokenResourceIdentifier[]>
) => {
const { email, userId, role } = input
if (!email && !userId) {
throw new InviteCreateValidationError('Either email or userId must be specified')
}
const target = (userId ? buildUserTarget(userId) : email)!
await createAndSendInvite(
{
target,
inviterId,
resourceTarget: ResourceTargets.Streams,
resourceId: isStreamInviteCreateInput(input) ? input.streamId : input.projectId,
role: (role as StreamRoles) || Roles.Stream.Contributor,
message: isStreamInviteCreateInput(input)
? input.message || undefined
: undefined,
serverRole: (input.serverRole as ServerRoles) || undefined
},
inviterResourceAccessRules
)
}
const isStreamInviteUseArgs = (
i: MutationStreamInviteUseArgs | ProjectInviteUseInput
): i is MutationStreamInviteUseArgs => has(i, 'streamId')
export const useStreamInviteAndNotifyFactory =
({ finalizeStreamInvite }: { finalizeStreamInvite: FinalizeStreamInvite }) =>
async (
input: MutationStreamInviteUseArgs | ProjectInviteUseInput,
userId: string,
userResourceAccessRules: ContextResourceAccessRules
) => {
const { accept, token } = input
if (
!isResourceAllowed({
resourceId: isStreamInviteUseArgs(input) ? input.streamId : input.projectId,
resourceType: 'project',
resourceAccessRules: userResourceAccessRules
})
) {
throw new StreamInvalidAccessError(
'You are not allowed to process an invite for this stream',
{
info: {
userId,
userResourceAccessRules,
input
}
}
)
}
await finalizeStreamInvite(
accept,
isStreamInviteUseArgs(input) ? input.streamId : input.projectId,
token,
userId
)
}