Skip to content

Commit b630a3b

Browse files
author
amazon-meaisiah
authored
Merge pull request awslabs#377 from awslabs/bugfix
Fix bugs with email validation and catalog visibility listings, remove aws-sdk from catalog updater
2 parents a9034db + b28d52b commit b630a3b

File tree

2,628 files changed

+191
-803740
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

2,628 files changed

+191
-803740
lines changed

dev-portal/src/pages/Admin/Accounts/PendingInvites.jsx

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { useCallback, useEffect, useMemo, useState } from 'react'
1+
import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'
22
import {
33
Button,
44
Container,
@@ -179,25 +179,53 @@ const TableActions = ({
179179
</Button.Group>
180180
)
181181

182+
// Pulled from https://html.spec.whatwg.org/multipage/input.html#e-mail-state-(type%3Demail) and
183+
// optimized in a few ways for size:
184+
// - Classes of `[A-Za-z0-9]` were shortened to the equivalent `[^_\W]`.
185+
// - Other instances of `0-9` in classes were converted to the shorthand `\d`.
186+
// - The whole regexp was made case-insensitive to avoid the need for `A-Za-z` in classes.
187+
// - As we're only testing, I replaced all the non-capturing groups with capturing ones.
188+
const validEmailRegex =
189+
/^[\w.!#$%&'*+\/=?^`{|}~-]+@[^_\W]([a-z\d-]{0,61}[^_\W])?(\.[^_\W]([a-z\d-]{0,61}[^_\W])?)*$/i
190+
182191
/*
183192
* Note: `onConfirm` should return a boolean indicating whether the creation
184193
* succeeded.
185194
*/
186195
const CreateInviteModal = ({ onConfirm, open, onClose, messages }) => {
187196
const [email, setEmail] = useState('')
188197
const [loading, setLoading] = useState(false)
189-
const isEmailValid = useMemo(() => /^[^@\s]+@[^@\s]+$/.test(email), [email])
198+
const isEmailValid = useMemo(() => validEmailRegex.test(email), [email])
190199
const onChangeEmailAddress = useCallback(
191200
(_event, { value }) => setEmail(value),
192201
[],
193202
)
194203
const onClickCreate = useCallback(async () => {
195204
setLoading(true)
196-
if (await onConfirm(email)) {
197-
setEmail('')
205+
try {
206+
if (await onConfirm(email)) {
207+
setEmail('')
208+
}
209+
} finally {
210+
setLoading(false)
198211
}
199-
setLoading(false)
200212
}, [onConfirm, email])
213+
214+
// If the user stops typing, but the email is invalid, show the invalid email message as a hint
215+
// for why they can't proceed. Don't make the timeout so short that it'd annoy a slow typer,
216+
// though.
217+
const [needsAssistance, setNeedsAssistance] = useState(false)
218+
const emailEverSet = useRef(false)
219+
220+
useEffect(() => {
221+
if (email) emailEverSet.current = true
222+
if (isEmailValid) {
223+
setNeedsAssistance(false)
224+
} else if (!needsAssistance && emailEverSet.current) {
225+
const timer = setTimeout(() => { setNeedsAssistance(true) }, 3000 /* ms */)
226+
return () => { clearTimeout(timer) }
227+
}
228+
}, [email, needsAssistance])
201229

202230
return (
203231
<Modal open={open} onClose={onClose} size={'small'}>
@@ -208,7 +236,7 @@ const CreateInviteModal = ({ onConfirm, open, onClose, messages }) => {
208236
send an invitation to create an account.
209237
</p>
210238
<MessageList.MessageList messages={messages} />
211-
<Message hidden={isEmailValid || loading} warning>
239+
<Message hidden={!needsAssistance || isEmailValid || loading} warning>
212240
Please enter a valid email address.
213241
</Message>
214242
<Input

lambdas/backend/__tests__/routes/admin/catalog/visibility.js

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,140 @@ describe('GET /admin/catalog/visibility', () => {
246246
}
247247
})
248248
})
249+
250+
test('includes unsubscribable API Gateway-managed APIs with subscribable ones', async () => {
251+
util.catalog.mockReturnValue(Promise.resolve({
252+
apiGateway: [
253+
{
254+
id: 'aaaaaa',
255+
name: 'basic usage plan',
256+
apis: [
257+
{
258+
apiId: 'a1b2c3',
259+
apiStage: 'prod',
260+
swagger: {}
261+
}
262+
]
263+
}
264+
],
265+
generic: [
266+
{
267+
apiId: 'd1e2f3',
268+
apiStage: 'prod',
269+
swagger: {}
270+
}
271+
]
272+
}))
273+
274+
util.apigateway.getRestApis = jest.fn().mockReturnValue(promiser({
275+
items: [
276+
{
277+
id: 'a1b2c3',
278+
name: 'first'
279+
},
280+
{
281+
id: 'd1e2f3',
282+
name: 'second'
283+
}
284+
]
285+
}))
286+
287+
util.apigateway.getStages = jest.fn()
288+
.mockReturnValueOnce(promiser({
289+
item: [
290+
{
291+
id: 'a1b2c3',
292+
name: 'first',
293+
stageName: 'prod'
294+
},
295+
{
296+
id: 'a1b2c3',
297+
name: 'first',
298+
stageName: 'exclude'
299+
}
300+
]
301+
}))
302+
.mockReturnValueOnce(promiser({
303+
item: [
304+
{
305+
id: 'd1e3f3',
306+
name: 'second',
307+
stageName: 'prod'
308+
},
309+
{
310+
id: 'd1e3f3',
311+
name: 'second',
312+
stageName: 'exclude'
313+
}
314+
]
315+
}))
316+
317+
util.apigateway.getUsagePlans = jest.fn()
318+
.mockReturnValue(promiser({
319+
items: [
320+
{
321+
id: 'z1x2c3',
322+
name: 'basic',
323+
apiStages: [
324+
{
325+
apiId: 'a1b2c3',
326+
stage: 'prod'
327+
},
328+
{
329+
apiId: 'a1b2c3',
330+
stage: 'exclude'
331+
}
332+
]
333+
}
334+
]
335+
}))
336+
337+
await adminCatalogVisibility.get(generateRequestContext(), mockResponseObject)
338+
339+
expect(util.apigateway.getRestApis).toHaveBeenCalledTimes(1)
340+
expect(util.apigateway.getStages).toHaveBeenCalledTimes(2)
341+
expect(mockResponseObject.status).toHaveBeenCalledWith(200)
342+
expect(mockResponseObject.json).toHaveBeenCalledWith({
343+
apiGateway: [
344+
{
345+
id: 'a1b2c3',
346+
stage: 'prod',
347+
visibility: true,
348+
subscribable: true,
349+
name: 'first',
350+
usagePlanId: 'z1x2c3',
351+
usagePlanName: 'basic',
352+
sdkGeneration: false
353+
},
354+
{
355+
id: 'a1b2c3',
356+
stage: 'exclude',
357+
visibility: false,
358+
subscribable: true,
359+
name: 'first',
360+
usagePlanId: 'z1x2c3',
361+
usagePlanName: 'basic',
362+
sdkGeneration: false
363+
},
364+
{
365+
id: 'd1e2f3',
366+
stage: 'prod',
367+
visibility: true,
368+
subscribable: false,
369+
name: 'second',
370+
sdkGeneration: false
371+
},
372+
{
373+
id: 'd1e2f3',
374+
stage: 'exclude',
375+
visibility: false,
376+
subscribable: false,
377+
name: 'second',
378+
sdkGeneration: false
379+
}
380+
]
381+
})
382+
})
249383
})
250384

251385
describe('POST /admin/catalog/visibility', () => {

lambdas/backend/routes/admin/catalog/visibility.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,15 @@ exports.get = async (req, res) => {
8080

8181
// mark every api in the generic catalog as visible
8282
catalogObject.generic.forEach((catalogEntry) => {
83+
// Unlike in the catalog and elsewhere, the visibility's `apiGateway` contains *all* API
84+
// Gateway-managed APIs, and only unmanaged APIs are in `visibility.generic`.
85+
if (catalogEntry.apiId != null) {
86+
const target = visibility.apiGateway.find((api) =>
87+
api.id === catalogEntry.apiId && api.stage === catalogEntry.apiStage
88+
)
89+
if (target != null) { target.visibility = true; return }
90+
}
91+
8392
if (!visibility.generic) {
8493
visibility.generic = {}
8594
}
@@ -89,8 +98,6 @@ exports.get = async (req, res) => {
8998
name: (catalogEntry.swagger && catalogEntry.swagger.info && catalogEntry.swagger.info.title) || 'Untitled'
9099
}
91100

92-
if (catalogEntry.stage) { visibility.generic[catalogEntry.id].stage = catalogEntry.stage }
93-
if (catalogEntry.apiId) { visibility.generic[catalogEntry.id].apiId = catalogEntry.apiId }
94101
if (catalogEntry.sdkGeneration !== undefined) {
95102
console.log(`catalogEntry: ${inspect(catalogEntry)}`)
96103
visibility.apiGateway.map((api) => {

lambdas/catalog-updater/node_modules/.bin/uuid

Lines changed: 0 additions & 1 deletion
This file was deleted.

lambdas/catalog-updater/node_modules/argparse/package.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lambdas/catalog-updater/node_modules/aws-sdk/.changes/2.10.0.json

Lines changed: 0 additions & 17 deletions
This file was deleted.

lambdas/catalog-updater/node_modules/aws-sdk/.changes/2.100.0.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

lambdas/catalog-updater/node_modules/aws-sdk/.changes/2.101.0.json

Lines changed: 0 additions & 12 deletions
This file was deleted.

lambdas/catalog-updater/node_modules/aws-sdk/.changes/2.102.0.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

lambdas/catalog-updater/node_modules/aws-sdk/.changes/2.103.0.json

Lines changed: 0 additions & 7 deletions
This file was deleted.

0 commit comments

Comments
 (0)