-
-
Notifications
You must be signed in to change notification settings - Fork 28
Feat: Expand User type #55
Feat: Expand User type #55
Conversation
package.json
Outdated
"start": "serverless offline start --skipCacheInvalidation", | ||
"test": "snyk test" | ||
"start": "DEBUG=fcc:* serverless offline start --skipCacheInvalidation", | ||
"test": "jest", |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
I'll need a little more time to review this, I can do that on my Monday, your Sunday. |
90befaa
to
8dc081d
Compare
.travis.yml
Outdated
@@ -12,9 +12,7 @@ env: | |||
- AWS_REGION=us-east-1 | |||
- SLS_DEBUG=true | |||
|
|||
before_install: | |||
- npm install -g serverless |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
dataLayer/mongo/user.js
Outdated
return updated; | ||
} catch (err) { | ||
log('crashing hard'); | ||
// TODO(Bouncey): Communicate the problem with the client |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
dataLayer/mongo/user.js
Outdated
|
||
export async function getUser(email) { | ||
const user = await findUserBy({ email }); | ||
return applyMigrations(user); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
graphql/typeDefs/User/query.js
Outdated
name: String | ||
email: String | ||
): [User] | ||
getSessionUser(email: String!): User |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
package.json
Outdated
"start": "serverless offline start --skipCacheInvalidation", | ||
"test": "snyk test" | ||
"start": "DEBUG=fcc:* serverless offline start --skipCacheInvalidation", | ||
"test": "jest", |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
graphql/resolvers/user.js
Outdated
|
||
export const userResolvers = { | ||
Query: { | ||
users: (_, args) => dbUsers.getUsers(args) | ||
// TODO(Bouncey): requires auth protection |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
@ojongerius Looking back at this, I think I could make the queries and mutations slicker by using context and not hitting the db on every request to find a user. I am going to re-write some parts of this PR. It may be that we need auth in place before this PR can/should progress. |
Waiting on #58 |
#58 went in (nice work!), what's the status of this one at the moment? |
Almost a rewrite, but it is nearly there. One issue I am having that ibmeant to ping you for is, if I use mongo in a different test suit in the same way that the users integration test does, I get a race condition between the the I have tried managing a connection in the global setup/teardown, but the tests would timeout. Any ideas? |
@Bouncey interesting! Does this happen when you run jest with |
@ojongerius yes it does, I think it is due to the async nature of the setup and teardown, where at times, they overlap. I will push what I have so far so you can see. I think I'm in a place where I shouldn't be adding any further commits to this PR, else the scope will slip too far. |
8dc081d
to
fff41fb
Compare
@ojongerius I might have fixed the race condition be returning the promise in |
src/dataLayer/mongo/user.js
Outdated
newUser.accountLinkId = accountLinkId; | ||
} else { | ||
newUser.accountLinkId = uuid(); | ||
// TODO: appy accountLinkId to app_metadata (auth0) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
I worte all of those test before rebasing, so glad that I did because I made a unholy mess and lost two days with of work with a clumsy Yay for tests! 🎉 |
Sounds good! Sounds like it's review time? Are you keeping the WiP label while finish writing the code to talk to auth0? |
Please review. None of this code should change, all I need to add is an API call to auth0 |
👍 will have a look today. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Started, but have not yet finished reviewing, will give this some more attention in a bit.
@@ -27,7 +27,7 @@ | |||
"snyk-test": "snyk test", | |||
"start": | |||
"cross-env DEBUG=fcc:* nodemon node_modules/serverless/bin/serverless offline start --skipCacheInvalidation", | |||
"test": "cross-env JWT_CERT=test jest --verbose", | |||
"test": "cross-env JWT_CERT=test jest --runInBand --verbose --silent", |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/dataLayer/model/user.js
Outdated
|
||
const userSchema = new Schema({ | ||
accountLinkId: { | ||
type: 'string', | ||
description: 'A uuid used to link SSO and freeCodeCamp accounts together', |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/dataLayer/model/user.js
Outdated
} | ||
}); | ||
|
||
module.exports = mongoose.model('User', userSchema, 'user'); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/dataLayer/model/user.js
Outdated
default: false | ||
}, | ||
isGithubCool: { |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
return new Promise(async function getUserPromise(resolve, reject) { | ||
if (!isString(email) || !validator.isEmail(email)) { | ||
reject( | ||
new TypeError(`Expected a valid email, got ${JSON.stringify(email)}`) |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/dataLayer/model/user.js
Outdated
|
||
const userSchema = new Schema({ | ||
accountLinkId: { | ||
type: 'string', | ||
description: 'A uuid used to link SSO and freeCodeCamp accounts together', |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/graphql/typeDefs/User/type.js
Outdated
} | ||
|
||
type CompletedChallenge { | ||
id: String |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
src/graphql/typeDefs/User/type.js
Outdated
type User { | ||
_id: ID @isAuthenticatedOnField |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
exports[`createUser should not create a second user for the same context: no duplicate users 1`] = ` | ||
Array [ | ||
Object { | ||
"accountLinkId": "[email protected]", |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
test/integration/userFlow.test.js
Outdated
.catch(done); | ||
}); | ||
|
||
it('should not create a second user for the same context', done => { |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
|
||
graphql(graphqlSchema, expectedUserQuery, rootValue, validContextCharlie) | ||
.then(({ data, errors }) => { | ||
expect(data).toMatchSnapshot('user found'); |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
test/utils/test-environment.js
Outdated
const token = jwt.sign({ id: 123, name: 'Charlie' }, JWT_CERT); | ||
const token = jwt.sign( | ||
{ | ||
id: 123, |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
test/utils/test-environment.js
Outdated
name: 'Charlie', | ||
email: '[email protected]', | ||
[namespace + | ||
'accountLinkId']: '[email protected]' |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
@@ -0,0 +1,5 @@ | |||
export default ` | |||
type Mutation { | |||
deleteGDPRUser(accountLinkId: String!): HTTPStatus! @isAuthenticatedOnQuery |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
Finished another pass 😅 This is turned into quite an epic. Awesome work but please don't add more complexity! 😄 FWIW tests are passing but are very noisy for me: ▶ JWT_CERT=test jest --runInBand --verbose
PASS ../test/integration/userFlow.test.js
createUser
✓ should return null and an auth error without a token (72ms)
✓ should return null and an auth error with an invalid token (3ms)
✓ should create a user by query (73ms)
✓ should not create a second user for the same context (36ms)
getUser
✓ should return null and an auth error without a token (3ms)
✓ should return null and an auth error with an invalid token (1ms)
✓ should return a user after one has been created (7ms)
✓ should return null if no user has been found (8ms)
✓ should return errors for a malformed query (4ms)
console.error dataLayer/mongo/user.js:60
Cannot create account, the unique id associated with this user is already in use [email protected]
console.log ../node_modules/graphql-tools/dist/schemaGenerator.js:514
{ Error: No user found for [email protected]
at getUserPromise (/Users/ojongerius/repos/fcc-open-api/src/dataLayer/mongo/user.js:28:14)
at <anonymous>
originalMessage: 'No user found for [email protected]',
message: 'Error in resolver Query.getUser\nNo user found for [email protected]' }
console.error utils/asyncErrorHandler.js:6
Error: No user found for [email protected]
at getUserPromise (/Users/ojongerius/repos/fcc-open-api/src/dataLayer/mongo/user.js:28:14)
at <anonymous>
console.log ../node_modules/graphql-tools/dist/schemaGenerator.js:514
{ TypeError: Expected a valid email, got "Ooops!"
at getUserPromise (/Users/ojongerius/repos/fcc-open-api/src/dataLayer/mongo/user.js:20:9)
at new Promise (<anonymous>)
at getUser (/Users/ojongerius/repos/fcc-open-api/src/dataLayer/mongo/user.js:17:10)
at Object.<anonymous> (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:683:22)
at class_1.<anonymous> (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:781:42)
at step (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:51:23)
at Object.next (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:32:53)
at /Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:26:71
at new Promise (<anonymous>)
at Object.<anonymous>.__awaiter (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:22:12)
at /Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:781:13
at isAuthenticatedOnQuery (/Users/ojongerius/repos/fcc-open-api/src/graphql/resolvers/directives.js:24:32)
at field.resolve (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:780:18)
at resolveFieldValueOrError (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql/execution/execute.js:531:18)
at resolveField (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql/execution/execute.js:495:16)
at /Users/ojongerius/repos/fcc-open-api/node_modules/graphql/execution/execute.js:364:18
originalMessage: 'Expected a valid email, got "Ooops!"',
message: 'Error in resolver Query.getUser\nExpected a valid email, got "Ooops!"' }
console.error utils/asyncErrorHandler.js:6
TypeError: Expected a valid email, got "Ooops!"
at getUserPromise (/Users/ojongerius/repos/fcc-open-api/src/dataLayer/mongo/user.js:20:9)
at new Promise (<anonymous>)
at getUser (/Users/ojongerius/repos/fcc-open-api/src/dataLayer/mongo/user.js:17:10)
at Object.<anonymous> (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:683:22)
at class_1.<anonymous> (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:781:42)
at step (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:51:23)
at Object.next (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:32:53)
at /Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:26:71
at new Promise (<anonymous>)
at Object.<anonymous>.__awaiter (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/dist/schemaGenerator.js:22:12)
at /Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:781:13
at isAuthenticatedOnQuery (/Users/ojongerius/repos/fcc-open-api/src/graphql/resolvers/directives.js:24:32)
at field.resolve (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql-tools/src/schemaGenerator.ts:780:18)
at resolveFieldValueOrError (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql/execution/execute.js:531:18)
at resolveField (/Users/ojongerius/repos/fcc-open-api/node_modules/graphql/execution/execute.js:495:16)
at /Users/ojongerius/repos/fcc-open-api/node_modules/graphql/execution/execute.js:364:18
PASS graphql/resolvers/directive.test.js
isAuthenticatedOnField
✓ should return null if authenication fails (3ms)
✓ should return the secretValue if authentication succeeds (1ms)
isAuthenticatedOnQuery
✓ should throw an error is auth fails (1ms)
✓ should call next if auth succeeds
PASS dataLayer/mongo/user-dataLayer.test.js
createUser
✓ should return a User object (24ms)
✓ should return user for accountLinkId if found in db (6ms)
getUser
✓ should return a User object fo a valid request (3ms)
✓ should throw for a user not found (1ms)
✓ should throw if the supplied email is not valid (3ms)
Test Suites: 3 passed, 3 total
Tests: 18 passed, 18 total
Snapshots: 18 passed, 18 total
Time: 4.39s
Ran all test suites.
console.error dataLayer/mongo/user.js:60
Cannot create account, the unique id associated with this user is already in use [email protected]
console.error dataLayer/mongo/user.js:60
Cannot create account, the unique id associated with this user is already in use [email protected] |
This is the reason for the |
😆 Would it not be neater to expect and handle those errors? Could we use tothrowerror and or tothrowerrormatchingsnapshot? |
src/graphql/typeDefs/User/type.js
Outdated
progressTimestamps: [ProgressTimestamp]!, | ||
isBanned: Boolean | ||
isCheater: Boolean | ||
githubURL: String |
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
This comment was marked as off-topic.
This comment was marked as off-topic.
Sorry, something went wrong.
fff41fb
to
13fa46f
Compare
I have no other concerns than that it looks messy to have uncaught errors in tests. Suppressing with a silent flag feels a little like a cover up. |
Outstanding tasks AFAICS
After that we should be good to merge, let's get this today or latest, tomorrow. |
Yes, I agree.. I am going ahead and giving this a merge, to keep things moving! Thanks a lot @Bouncey this is some incredible work! /cc @freeCodeCamp/open-api |
This PR contains commits from #48, by mistake.
This PR expands the
User
type, adjusts the user query's to return a single user and adds a challengeMap Mutation type.