Skip to content

Commit 71a362c

Browse files
committed
imp(resolvers): add channels validation for rules in api resolvers
1 parent a18a198 commit 71a362c

1 file changed

Lines changed: 67 additions & 12 deletions

File tree

src/resolvers/projectNotifications.ts

Lines changed: 67 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,54 @@ function isChannelsEmpty(channels: NotificationsChannelsDBScheme): boolean {
8989
return notEmptyChannels.length === 0;
9090
}
9191

92+
/**
93+
* Returns true is threshold and threshold period are valid
94+
* @param threshold - threshold of the notification rule to be checked
95+
* @param thresholdPeriod - threshold period of the notification rule to be checked
96+
*/
97+
function validateNotificationsRuleTresholdAndPeriod(
98+
threshold: ProjectNotificationsRuleDBScheme['threshold'],
99+
thresholdPeriod: ProjectNotificationsRuleDBScheme['thresholdPeriod']
100+
): string | null {
101+
const validThresholdPeriods = [60_000, 3_600_000, 86_400_000, 604_800_000]
102+
103+
if (thresholdPeriod === undefined || !validThresholdPeriods.includes(thresholdPeriod)) {
104+
return'Threshold period should be one of the following: 60000, 3600000, 86400000, 604800000';
105+
}
106+
107+
if (threshold === undefined || threshold < 1) {
108+
return 'Threshold should be greater than 0';
109+
}
110+
111+
return null;
112+
}
113+
114+
115+
/**
116+
* Return true if all passed channels are filled with correct endpoints
117+
*/
118+
function validateNotificationsRuleChannels(channels: NotificationsChannelsDBScheme): string | null {
119+
if (channels.email!.isEnabled) {
120+
if (!/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/.test(channels.email!.endpoint)) {
121+
return 'Invalid email endpoint passed';
122+
}
123+
}
124+
125+
if (channels.slack!.isEnabled) {
126+
if (!/^https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9]+\/[A-Za-z0-9]+\/[A-Za-z0-9]+$/.test(channels.slack!.endpoint)) {
127+
return 'Invalid slack endpoint passed';
128+
}
129+
}
130+
131+
if (channels.telegram!.isEnabled) {
132+
if (!/^https:\/\/notify\.bot\.codex\.so\/u\/[A-Za-z0-9]+$/.test(channels.telegram!.endpoint)) {
133+
return 'Invalid telegram endpoint passed';
134+
}
135+
}
136+
137+
return null;
138+
}
139+
92140
/**
93141
* See all types and fields here {@see ../typeDefs/notify.graphql}
94142
*/
@@ -107,18 +155,23 @@ export default {
107155
{ user, factories }: ResolverContextWithUser
108156
): Promise<ProjectNotificationsRuleDBScheme> {
109157
const project = await factories.projectsFactory.findById(input.projectId);
110-
const validThresholdPeriods = [60_000, 3_600_000, 86_400_000, 604_800_000]
111158

112159
if (!project) {
113160
throw new ApolloError('No project with such id');
114161
}
115162

116-
if (isChannelsEmpty(input.channels)) {
117-
throw new UserInputError('At least one channel is required');
163+
const channelsValidationResult = validateNotificationsRuleChannels(input.channels);
164+
165+
if (channelsValidationResult !== null) {
166+
throw new UserInputError(channelsValidationResult);
118167
}
119168

120-
if (!validThresholdPeriods.includes(input.thresholdPeriod)) {
121-
throw new UserInputError('Threshold period should be one of the following: 60000, 3600000, 86400000, 604800000');
169+
if (input.whatToReceive === ReceiveTypes.SEEN_MORE) {
170+
const thresholdValidationResult = validateNotificationsRuleTresholdAndPeriod(input.threshold, input.thresholdPeriod);
171+
172+
if (thresholdValidationResult !== null) {
173+
throw new UserInputError(thresholdValidationResult);
174+
}
122175
}
123176

124177
return project.createNotificationsRule({
@@ -144,17 +197,19 @@ export default {
144197
if (!project) {
145198
throw new ApolloError('No project with such id');
146199
}
200+
201+
const channelsValidationResult = validateNotificationsRuleChannels(input.channels);
147202

148-
if (isChannelsEmpty(input.channels)) {
149-
throw new UserInputError('At least one channel is required');
203+
if (channelsValidationResult !== null) {
204+
throw new UserInputError(channelsValidationResult);
150205
}
151206

152-
if ((input.threshold !== undefined) !== (input.thresholdPeriod !== undefined)) {
153-
throw new UserInputError('Both threshold and thresholdPeriod should be set or unset');
154-
}
207+
if (input.whatToReceive === ReceiveTypes.SEEN_MORE) {
208+
const thresholdValidationResult = validateNotificationsRuleTresholdAndPeriod(input.threshold, input.thresholdPeriod);
155209

156-
if (input.threshold < 1) {
157-
throw new UserInputError('Threshold should be greater than 0');
210+
if (thresholdValidationResult !== null) {
211+
throw new UserInputError(thresholdValidationResult);
212+
}
158213
}
159214

160215
return project.updateNotificationsRule(input);

0 commit comments

Comments
 (0)