Skip to content

Commit

Permalink
Merge pull request #1553 from flacial/fixCreateSubmission
Browse files Browse the repository at this point in the history
Mitigate the issue of creating a submission based on the cliToken ID
  • Loading branch information
flacial authored Mar 9, 2022
2 parents 3d0be49 + 04deba5 commit be707fe
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 10 deletions.
5 changes: 5 additions & 0 deletions @types/user.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,8 @@ export type UserInfo = {
discordUsername: string
discordAvatarUrl: string
}

export type CliToken = {
id: number
cliToken: string
}
25 changes: 22 additions & 3 deletions helpers/controllers/submissionController.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
jest.mock('../discordBot.ts')
jest.mock('../hasPassedLesson')
jest.mock('../updateSubmission')
jest.mock('@sentry/node')
import { SubmissionStatus } from '../../graphql'
import prismaMock from '../../__tests__/utils/prismaMock'
import { hasPassedLesson } from '../hasPassedLesson'
Expand All @@ -16,6 +17,7 @@ import {
rejectSubmission,
submissions
} from './submissionController'
import * as Sentry from '@sentry/node'

describe('Submissions Mutations', () => {
hasPassedLesson.mockResolvedValue(true)
Expand Down Expand Up @@ -43,6 +45,7 @@ describe('Submissions Mutations', () => {
diff: 'fakeDiff',
lessonId: 1
}
const ctx = { req: { user: { id: 2 } } }

beforeEach(() => {
prismaMock.submission.create.mockResolvedValue({
Expand All @@ -53,7 +56,7 @@ describe('Submissions Mutations', () => {
})

test('should save and return submission', async () => {
await expect(createSubmission(null, args)).resolves.toEqual({
await expect(createSubmission(null, args, ctx)).resolves.toEqual({
id: 1,
diff: 'fakeDiff',
lesson: {
Expand All @@ -68,15 +71,31 @@ describe('Submissions Mutations', () => {

test('should overwrite previous submission status if it exists', async () => {
prismaMock.submission.findFirst.mockResolvedValue({ id: 1 })
await createSubmission(null, args)
await createSubmission(null, args, ctx)
expect(prismaMock.submission.update).toBeCalled()
})

test('should throw error Invalid args', () => {
return expect(createSubmission(null, null)).rejects.toThrow(
return expect(createSubmission(null, null, ctx)).rejects.toThrow(
'Invalid args'
)
})

test('should set id to the decoded clientToken id when req.user is undefined', async () => {
await createSubmission(null, args, { ...ctx, req: { user: null } })
expect(prismaMock.user.findFirst).toBeCalled()
})

test('should send message to Sentry if req.user does not exist and cliToken does', async () => {
prismaMock.user.findFirst.mockResolvedValue({
id: 1210,
username: 'noob'
})
await createSubmission(null, args, { ...ctx, req: { user: null } })
expect(Sentry.captureException).toHaveBeenCalledWith({
message: `${1210}/${'noob'} is using the wrong CLI version. Must be 2.2.5`
})
})
})

describe('acceptSubmission', () => {
Expand Down
26 changes: 23 additions & 3 deletions helpers/controllers/submissionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,38 @@ import {
SubmissionStatus
} from '../../graphql'
import prisma from '../../prisma'
import { decode } from '../encoding'
import { hasPassedLesson } from '../hasPassedLesson'
import { updateSubmission } from '../updateSubmission'
import { sendSubmissionNotification, IdType } from '../discordBot'
import { decode } from '../encoding'
import * as Sentry from '@sentry/node'
import { CliToken } from '../../@types/user'

export const createSubmission = async (
_parent: void,
args: MutationCreateSubmissionArgs
args: MutationCreateSubmissionArgs,
ctx: Context
): Promise<CreateSubmissionMutation['createSubmission']> => {
const { req } = ctx

if (!args) throw new Error('Invalid args')
const { challengeId, cliToken, diff, lessonId } = args
const { id } = decode(cliToken)

let id = req.user!?.id

if (!id && cliToken) {
const decodedCliToken: CliToken = cliToken && decode(cliToken)
const user = await prisma.user.findFirst({
where: { cliToken: decodedCliToken.cliToken }
})

id = user!?.id

Sentry.captureException({
message: `${user?.id}/${user?.username} is using the wrong CLI version. Must be 2.2.5`
})
}

const previousSubmission = await prisma.submission.findFirst({
where: {
challengeId,
Expand Down
30 changes: 27 additions & 3 deletions helpers/middleware/user.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const mockUserInfo = {
password: '$2b$10$W9KwQ6Sbi0RJjD2GZYX9BugAtgSm/W999gNW1f/XiRcI6NiC9pTdK',
email: '[email protected]',
isAdmin: false,
cliToken: 'KfizzIlWp111fizzDbuzzr'
cliToken: 'W29iamVjdCBPYmplY3Rd'
}

const res = {}
Expand All @@ -26,15 +26,39 @@ const next = () => {}
describe('User Middleware', () => {
beforeEach(() => {
prismaMock.user.findUnique.mockResolvedValue(mockUserInfo)
prismaMock.user.findFirst.mockResolvedValue(mockUserInfo)
})
test('Should return null when userId property of req.session is not there', async () => {
const req = { session: '' }
const req = {
session: '',
headers: {
authorization: null
}
}
await userMiddleware(req, res, next)
expect(req.user).toBeNull
})

test('Should return correct info from database if session.userId exists', async () => {
const req = { session: { userId: 'noob' } }
const req = {
session: {
userId: 'noob'
},
headers: {
authorization: null
}
}
await userMiddleware(req, res, next)
expect(req.user).toEqual(mockUserInfo)
})
test('Should return correct info from database if authorization header exists', async () => {
const req = {
session: { userId: 'noob' },
headers: {
authorization:
'Bearer eyJpZCI6MSwiY2xpVG9rZW4iOiJXMjlpYW1WamRDQlBZbXBsWTNSZCJ9'
}
}
await userMiddleware(req, res, next)
expect(req.user).toEqual(mockUserInfo)
})
Expand Down
20 changes: 19 additions & 1 deletion helpers/middleware/user.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,29 @@
import { LoggedRequest } from '../../@types/helpers'
import { NextApiResponse } from 'next'
import prisma from '../../prisma'
import { decode } from '../encoding'
import { CliToken } from '../../@types/user'

export default async (
const userMiddleware = async (
req: LoggedRequest,
_: NextApiResponse,
next: () => void
) => {
req.user = null

const auth = req.headers.authorization
const cliToken = auth && auth.split(' ')[1]
if (cliToken) {
const decodedCliToken: CliToken = decode(cliToken)

const user = await prisma.user.findFirst({
where: { cliToken: decodedCliToken.cliToken }
})

req.user = user
return next()
}

const { session } = req
if (session?.userId) {
const { userId: id } = session
Expand All @@ -16,3 +32,5 @@ export default async (
}
next()
}

export default userMiddleware

1 comment on commit be707fe

@vercel
Copy link

@vercel vercel bot commented on be707fe Mar 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.