-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnewRequest.ts
More file actions
175 lines (153 loc) · 5.62 KB
/
Copy pathnewRequest.ts
File metadata and controls
175 lines (153 loc) · 5.62 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
import { createFlowInclude } from "@/core/flow/flowPrismaTypes";
import { prisma } from "@/prisma/client";
import { ApolloServerErrorCode, CustomErrorCodes, GraphQLError } from "@graphql/errors";
import { FlowType, MutationNewRequestArgs } from "@graphql/generated/resolver-types";
import { createRequestDefinedOptionSet } from "./createRequestDefinedOptionSet";
import { finalizeStepResponses } from "./updateState/finalizeStepResponses";
import { canEndRequestStepWithResponse } from "./utils/endRequestStepWithoutResponse";
import { entityInclude } from "../entity/entityPrismaTypes";
import { getUserEntities } from "../entity/getUserEntities";
import { updateEntityWatchFlows } from "../entity/updateEntityWatchFlow";
import { UserOrIdentityContextInterface } from "../entity/UserOrIdentityContext";
import { FieldPrismaType } from "../fields/fieldPrismaTypes";
import { newFieldAnswers } from "../fields/newFieldAnswers";
import { sendNewStepNotifications } from "../notification/sendNewStepNotifications";
import { getEntityPermissions } from "../permission/getEntityPermissions";
import { newResultsForStep } from "../result/newResults/newResultsForStep";
// creates a new request for a flow, starting with the request's first step
// validates/creates request fields and request defined options
export const newRequest = async ({
args,
entityContext,
// proposed flow version id is used when creating an evolution request
proposedFlowVersionId,
}: {
args: MutationNewRequestArgs;
entityContext: UserOrIdentityContextInterface;
proposedFlowVersionId?: string;
}): Promise<string> => {
const {
request: { requestDefinedOptions, requestFields, flowId, requestId },
} = args;
const { entityId, entityIds } = await getUserEntities({ entityContext });
const flow = await prisma.flow.findUniqueOrThrow({
where: {
id: flowId,
},
include: createFlowInclude(entityIds),
});
if (!flow.CurrentFlowVersion)
throw new GraphQLError("Missing current version of flow", {
extensions: { code: ApolloServerErrorCode.INTERNAL_SERVER_ERROR },
});
if (flow.type === FlowType.Evolve && !proposedFlowVersionId)
throw new GraphQLError(
`Request for evolve flow id ${flow.id} is missing proposedFlowVersionId`,
{
extensions: { code: ApolloServerErrorCode.INTERNAL_SERVER_ERROR },
},
);
const step = flow.CurrentFlowVersion.Steps[0];
const flowVersionId = flow.CurrentFlowVersion.id;
const hasRequestPermission = await getEntityPermissions({
entityContext,
permission: flow.CurrentFlowVersion.TriggerPermissions,
});
if (!hasRequestPermission)
throw new GraphQLError("User does not have permission to request", {
extensions: { code: CustomErrorCodes.InsufficientPermissions },
});
const { requestStepId, responseComplete } = await prisma.$transaction(async (transaction) => {
const request = await transaction.request.create({
include: {
CreatorEntity: {
include: entityInclude,
},
},
data: {
id: requestId,
name: args.request.name,
flowVersionId: flowVersionId,
creatorEntityId: entityId,
proposedFlowVersionId,
final: false,
},
});
if (args.request.watch) {
await updateEntityWatchFlows({ entityId, flowIds: [flowId], watch: true, transaction });
}
const responseComplete = canEndRequestStepWithResponse({ step });
const requestStep = await transaction.requestStep.create({
data: {
expirationDate: new Date(
new Date().getTime() + (step.ResponseConfig?.expirationSeconds ?? 0) * 1000,
),
responseFinal: responseComplete,
Request: {
connect: {
id: request.id,
},
},
Step: {
connect: {
id: step.id,
},
},
CurrentStepParent: {
connect: {
id: request.id,
},
},
},
});
await Promise.all(
requestDefinedOptions.map(async (r) => {
let field: FieldPrismaType | undefined = undefined;
for (const step of flow.CurrentFlowVersion?.Steps ?? []) {
field = step.ResponseFieldSet?.Fields.find((f) => f.id === r.fieldId);
if (field) break;
}
if (!field)
throw new GraphQLError("Cannot find field for trigger defined options", {
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
});
const triggerOptionsType = field.FieldOptionsConfig?.triggerOptionsType;
if (!triggerOptionsType)
throw new GraphQLError(`Field does not allow trigger defined options: ${field.id}`, {
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
});
return await createRequestDefinedOptionSet({
type: "trigger",
valueType: triggerOptionsType,
requestId: request.id,
newOptionArgs: r.options,
fieldId: r.fieldId,
transaction,
});
}),
);
// TODO: if auto approve, just create the result
if (flow.CurrentFlowVersion?.TriggerFieldSet) {
await newFieldAnswers({
type: "request",
fieldSet: flow.CurrentFlowVersion?.TriggerFieldSet,
fieldAnswers: requestFields,
requestId: request.id,
transaction,
});
}
return {
requestId: request.id,
requestStepId: requestStep.id,
responseComplete,
};
});
if (responseComplete) {
await newResultsForStep({ requestStepId });
await finalizeStepResponses({ requestStepId });
}
await sendNewStepNotifications({
requestStepId,
});
return requestId;
};