Skip to content
This repository has been archived by the owner on Oct 21, 2020. It is now read-only.

Feat: Expand User type #55

Merged
merged 8 commits into from
May 3, 2018

Conversation

Bouncey
Copy link
Member

@Bouncey Bouncey commented Apr 20, 2018

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.

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.

This comment was marked as off-topic.

This comment was marked as off-topic.

@Bouncey Bouncey changed the title Feat/expand user types Feat: Expand User type Apr 20, 2018
@ojongerius
Copy link
Contributor

I'll need a little more time to review this, I can do that on my Monday, your Sunday.

@Bouncey Bouncey force-pushed the feat/expandUserTypes branch from 90befaa to 8dc081d Compare April 21, 2018 13:29
.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.

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.

This comment was marked as off-topic.


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.

name: String
email: String
): [User]
getSessionUser(email: String!): User

This comment was marked as off-topic.

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.


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.

@Bouncey
Copy link
Member Author

Bouncey commented Apr 23, 2018

@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.

@Bouncey Bouncey added the WiP Work in Progress, not ready for QA/merge label Apr 23, 2018
@Bouncey
Copy link
Member Author

Bouncey commented Apr 24, 2018

Waiting on #58

@ojongerius
Copy link
Contributor

#58 went in (nice work!), what's the status of this one at the moment?

@Bouncey
Copy link
Member Author

Bouncey commented Apr 30, 2018

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 afterAll disconnects. If onebsuit is still running then the tests fail because MongoError: Topology was destroyed or something to that effect.

I have tried managing a connection in the global setup/teardown, but the tests would timeout. Any ideas?

@ojongerius
Copy link
Contributor

@Bouncey interesting! Does this happen when you run jest with --runInBand too?

@Bouncey
Copy link
Member Author

Bouncey commented May 1, 2018

@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.

@Bouncey Bouncey force-pushed the feat/expandUserTypes branch from 8dc081d to fff41fb Compare May 1, 2018 14:04
@Bouncey
Copy link
Member Author

Bouncey commented May 1, 2018

@ojongerius I might have fixed the race condition be returning the promise in teardown?

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.

@Bouncey
Copy link
Member Author

Bouncey commented May 1, 2018

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 git stash pop.

Yay for tests! 🎉

@ojongerius
Copy link
Contributor

Sounds good! Sounds like it's review time? Are you keeping the WiP label while finish writing the code to talk to auth0?

@Bouncey
Copy link
Member Author

Bouncey commented May 1, 2018

Please review. None of this code should change, all I need to add is an API call to auth0

@ojongerius
Copy link
Contributor

👍 will have a look today.

Copy link
Contributor

@ojongerius ojongerius left a 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.

This comment was marked as off-topic.


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.

This comment was marked as off-topic.

This comment was marked as off-topic.

}
});

module.exports = mongoose.model('User', userSchema, 'user');

This comment was marked as off-topic.

This comment was marked as off-topic.

default: false
},
isGithubCool: {

This comment was marked as off-topic.

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.


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.

}

type CompletedChallenge {
id: String

This comment was marked as off-topic.

type User {
_id: ID @isAuthenticatedOnField

This comment was marked as off-topic.

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.

.catch(done);
});

it('should not create a second user for the same context', done => {

This comment was marked as off-topic.


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.

This comment was marked as off-topic.

const token = jwt.sign({ id: 123, name: 'Charlie' }, JWT_CERT);
const token = jwt.sign(
{
id: 123,

This comment was marked as off-topic.

name: 'Charlie',
email: '[email protected]',
[namespace +
'accountLinkId']: '[email protected]'

This comment was marked as off-topic.

@@ -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.

This comment was marked as off-topic.

@ojongerius
Copy link
Contributor

ojongerius commented May 2, 2018

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]

@Bouncey
Copy link
Member Author

Bouncey commented May 2, 2018

This is the reason for the --silent flag. 😁

@ojongerius
Copy link
Contributor

ojongerius commented May 2, 2018

😆

Would it not be neater to expect and handle those errors? Could we use tothrowerror and or tothrowerrormatchingsnapshot?

progressTimestamps: [ProgressTimestamp]!,
isBanned: Boolean
isCheater: Boolean
githubURL: String

This comment was marked as off-topic.

This comment was marked as off-topic.

@Bouncey Bouncey force-pushed the feat/expandUserTypes branch from fff41fb to 13fa46f Compare May 2, 2018 23:31
@Bouncey Bouncey removed the WiP Work in Progress, not ready for QA/merge label May 2, 2018
@ojongerius
Copy link
Contributor

ojongerius commented May 3, 2018

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.

@ojongerius
Copy link
Contributor

Outstanding tasks AFAICS

  • remove or improve deleteGDPRUser
  • agree if tests should have uncaught errors

After that we should be good to merge, let's get this today or latest, tomorrow.

@raisedadead raisedadead mentioned this pull request May 3, 2018
2 tasks
@raisedadead
Copy link
Member

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

@raisedadead raisedadead merged commit a339616 into freeCodeCamp:staging May 3, 2018
@Bouncey Bouncey deleted the feat/expandUserTypes branch May 3, 2018 09:22
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants