diff --git a/graphql/resolvers.test.js b/graphql/resolvers.test.js index 03d001832..c4cf0c3f0 100644 --- a/graphql/resolvers.test.js +++ b/graphql/resolvers.test.js @@ -1,10 +1,49 @@ import resolvers from '../graphql/resolvers' import db from '../helpers/dbload' -describe('resolvers', () => { +describe('GraphQL resolvers', () => { const { Lesson } = db test('lessons should return an empty array', async () => { Lesson.findAll = jest.fn().mockReturnValue([]) expect(resolvers.Query.lessons()).toEqual([]) }) }) + +describe('Session resolver', () => { + test('should return null if no userId', async () => { + const req = { session: null } + + return expect(await resolvers.Query.session({}, {}, { req })).toEqual(null) + }) + + test('should return user null if no user found', async () => { + const { User, Submission, UserLesson } = db + const req = { session: { userId: 2 } } + User.findOne = jest.fn().mockReturnValue(null) + Submission.findAll = jest.fn().mockReturnValue(null) + UserLesson.findAll = jest.fn().mockReturnValue(null) + + return expect(await resolvers.Query.session({}, {}, { req })).toEqual(null) + }) + + test('should return user including submissions and lessonStatus', async () => { + const { User, Submission, UserLesson } = db + const req = { session: { userId: 2 } } + + const result = { + user: { username: 'test' }, + submissions: [{ id: '1' }], + lessonStatus: [{ id: '1' }] + } + + User.findOne = jest.fn().mockReturnValue(result.user) + Submission.findAll = jest.fn().mockReturnValue(result.submissions) + UserLesson.findAll = jest.fn().mockReturnValue(result.lessonStatus) + + const returnValue = await resolvers.Query.session({}, {}, { req }) + + expect(returnValue.user).toEqual(result.user) + expect(returnValue.submissions).toEqual(result.submissions) + expect(returnValue.lessonStatus).toEqual(result.lessonStatus) + }) +}) diff --git a/graphql/resolvers.ts b/graphql/resolvers.ts index a294fcbc2..9a05aad59 100644 --- a/graphql/resolvers.ts +++ b/graphql/resolvers.ts @@ -1,23 +1,42 @@ -import { login, logout, signup } from '../helpers/controllers/authController' +import { Request } from 'express' import db from '../helpers/dbload' +import { login, logout, signup } from '../helpers/controllers/authController' +import _ from 'lodash' -const { Lesson, User } = db +const { User, Submission, Lesson, UserLesson } = db export default { Query: { lessons() { return Lesson.findAll({ - include: [ - 'challenges', - { - model: User, - through: { - attributes: ['isPassed', 'isTeaching', 'isEnrolled'] - } - } - ], + include: ['challenges'], order: [['order', 'ASC']] }) + }, + async session(_parent: void, _args: void, context: { req: Request }) { + const userId = _.get(context, 'req.session.userId', false) + + if (!userId) { + return null + } + + // FYI: The reason we are querying with parallelized promises: + // https://github.com/garageScript/c0d3-app/wiki/Sequelize-Query-Performance + const [user, submissions, lessonStatus] = await Promise.all([ + User.findOne({ where: { id: userId } }), + Submission.findAll({ where: { userId } }), + UserLesson.findAll({ where: { userId } }) + ]) + + if (!user) { + return null + } + + return { + user, + submissions, + lessonStatus + } } }, diff --git a/graphql/typeDefs.ts b/graphql/typeDefs.ts index 7f92fa9db..926ed489a 100644 --- a/graphql/typeDefs.ts +++ b/graphql/typeDefs.ts @@ -3,6 +3,7 @@ import { gql } from 'apollo-boost' export default gql` type Query { lessons: [Lesson] + session: Session } type Mutation { @@ -51,6 +52,12 @@ export default gql` isAdmin: Boolean } + type Session { + user: User + submissions: [Submission] + lessonStatus: [UserLesson] + } + type UserLesson { id: String userId: String diff --git a/helpers/dbload.ts b/helpers/dbload.ts index fab66a6a9..fac2521f8 100644 --- a/helpers/dbload.ts +++ b/helpers/dbload.ts @@ -66,6 +66,14 @@ User.belongsToMany(Lesson, { through: { model: UserLesson } }) +User.hasMany(Submission, { + foreignKey: 'userId' +}) + +User.hasMany(UserLesson, { + foreignKey: 'userId' +}) + sequelize.sync({ alter: false }) // We do not want this affect to production at the moment. export default { diff --git a/pages/api/graphql.ts b/pages/api/graphql.ts index b96577715..cfe2425b1 100644 --- a/pages/api/graphql.ts +++ b/pages/api/graphql.ts @@ -31,7 +31,6 @@ handler resave: false, saveUninitialized: false, cookie: { - domain: process.env.DB_HOST, maxAge: ONE_WEEK } }) diff --git a/yarn.lock b/yarn.lock index d8f2aefbd..fd036af19 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2585,6 +2585,11 @@ resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" integrity sha512-5qOlnZscTn4xxM5MeGXAMOsIOIKIbh9e85zJWfBRVPlRMEVawzoPhINYbRGkBZCI8LxvBe7tJCdWiarA99OZfQ== +"@types/prismjs@^1.16.0": + version "1.16.0" + resolved "https://registry.yarnpkg.com/@types/prismjs/-/prismjs-1.16.0.tgz#4328c9f65698e59f4feade8f4e5d928c748fd643" + integrity sha512-mEyuziLrfDCQ4juQP1k706BUU/c8OGn/ZFl69AXXY6dStHClKX4P+N8+rhqpul1vRDA2VOygzMRSJJZHyDEOfw== + "@types/prop-types@*": version "15.7.3" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" @@ -7022,6 +7027,11 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" +gitdiff-parser@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/gitdiff-parser/-/gitdiff-parser-0.2.2.tgz#c393ce9caf385860d005ce758a5e03221a7fc6be" + integrity sha512-iUE5gWohbUm+hogg9c1Gg/pDoDyGlC15hTdsnW7AqZw9+F9mYAxfnMNDstFxuF+qjiZot2s+3L+K9CLdw1ttvA== + glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -11140,7 +11150,7 @@ pretty-hrtime@^1.0.3: resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" integrity sha1-t+PqQkNaTJsnWdmeDyAesZWALuE= -prismjs@^1.8.4: +prismjs@^1.20.0, prismjs@^1.8.4: version "1.20.0" resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.20.0.tgz#9b685fc480a3514ee7198eac6a3bf5024319ff03" integrity sha512-AEDjSrVNkynnw6A+B1DsFkd6AVdTnp+/WoUixFRULlCLZVRZlVQMVWio/16jv7G1FscUxQxOQhWwApgbnxr6kQ==