-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnewResponse.ts
More file actions
153 lines (132 loc) · 4.96 KB
/
Copy pathnewResponse.ts
File metadata and controls
153 lines (132 loc) · 4.96 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
import { stepInclude } from "@/core/flow/flowPrismaTypes";
import { ApolloServerErrorCode, CustomErrorCodes, GraphQLError } from "@graphql/errors";
import { MutationNewResponseArgs } from "@graphql/generated/resolver-types";
import { prisma } from "../../prisma/client";
import { getUserEntities } from "../entity/getUserEntities";
import { UserOrIdentityContextInterface } from "../entity/UserOrIdentityContext";
import { fieldAnswerInclude, fieldOptionSetInclude } from "../fields/fieldPrismaTypes";
import { newFieldAnswers } from "../fields/newFieldAnswers";
import { getEntityPermissions } from "../permission/getEntityPermissions";
import { finalizeStepResponses } from "../request/updateState/finalizeStepResponses";
import { newResultsForStep } from "../result/newResults/newResultsForStep";
interface NewResponseProps {
entityContext: UserOrIdentityContextInterface;
args: MutationNewResponseArgs;
}
// creates a new response for a given request step
// validates/creates field answers
export const newResponse = async ({ entityContext, args }: NewResponseProps): Promise<string> => {
const {
response: { answers, requestStepId },
} = args;
const responseId = await prisma.$transaction(async (transaction) => {
const requestStep = await transaction.requestStep.findUniqueOrThrow({
where: {
id: requestStepId,
},
include: {
Step: {
include: stepInclude,
},
Request: {
include: {
FlowVersion: true,
TriggerFieldAnswers: {
include: fieldAnswerInclude,
},
RequestDefinedOptionSets: {
include: {
FieldOptionSet: {
include: fieldOptionSetInclude,
},
},
},
},
},
},
});
if (requestStep.id !== requestStep.Request.currentRequestStepId)
throw new GraphQLError(
"User is trying to submit response for request step that is not the current request step.",
{
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
},
);
if (requestStep.responseFinal || requestStep.final || requestStep.Request.final)
throw new GraphQLError(
"Response received for reqeust step that is no longer accepting responses",
{
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
},
);
if (
!requestStep.Step.ResponseFieldSet ||
requestStep.Step.ResponseFieldSet.Fields.every((f) => f.isInternal)
)
throw new GraphQLError(
`Response received for request step that does not have response fields ${requestStepId}`,
{
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
},
);
if (!requestStep.Step.ResponseConfig)
throw new GraphQLError(
`Response received for request step that does not accept responses ${requestStepId}`,
{
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
},
);
const { allowMultipleResponses, ResponsePermissions } = requestStep.Step.ResponseConfig;
const hasRespondPermissions = await getEntityPermissions({
entityContext,
permission: ResponsePermissions,
transaction,
});
const { entityId, entityIds } = await getUserEntities({ entityContext, transaction });
if (!hasRespondPermissions) {
throw new GraphQLError("User does not have permission to respond", {
extensions: { code: CustomErrorCodes.InsufficientPermissions },
});
}
const existingUserResponse = await transaction.response.findFirst({
where: {
requestStepId,
creatorEntityId: { in: entityIds },
},
});
if (!allowMultipleResponses) {
if (existingUserResponse)
throw new GraphQLError(
`Response already exists for this request step. requestStepId: ${requestStepId}`,
{
extensions: { code: ApolloServerErrorCode.BAD_USER_INPUT },
},
);
}
const newResponse = await transaction.response.create({
data: {
id: args.response.responseId,
creatorEntityId: entityId,
requestStepId,
},
});
await newFieldAnswers({
type: "response",
fieldSet: requestStep.Step.ResponseFieldSet,
fieldAnswers: answers,
requestDefinedOptionSets: requestStep.Request.RequestDefinedOptionSets,
responseId: newResponse.id,
transaction,
});
return newResponse.id;
});
// perliminary results are determined after every response
// not running results and actions on the same transaction so that vote can be recorded if there is issue with action / result
// there is cron job to rerun stalled actions / results
const { endStepEarly } = await newResultsForStep({ requestStepId });
// const hasEarlyResult = await checkToEndResponseEarly({ requestStepId });
if (endStepEarly) {
await finalizeStepResponses({ requestStepId });
}
return responseId;
};