Skip to content

Commit

Permalink
Merge branch 'master' into 2215-fix-cant-dismiss-an-alert
Browse files Browse the repository at this point in the history
  • Loading branch information
flacial authored Aug 28, 2022
2 parents 874b3ec + a39a411 commit 5f31a3b
Show file tree
Hide file tree
Showing 11 changed files with 235 additions and 199 deletions.
26 changes: 26 additions & 0 deletions containers/withAdminContainer.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { withAdminContainer } from './withAdminContainer'

const adminMockReq = { req: { user: { isAdmin: true, id: 1 } } }
const noAdminMockReq = { req: { user: { isAdmin: false, id: 1 } } }

const mockAdminContainer = withAdminContainer(async _parent => {
return true
}, 'errorMessage')

describe('withAdminContainer test', () => {
test('if there is admin error and errorMessage is provided, it should throw errorMessage', () => {
expect.assertions(1)

expect(
mockAdminContainer({}, { name: 'John', title: 'Doe' }, noAdminMockReq)
).rejects.toThrow(new Error('errorMessage'))
})

test('if there is no admin error, it should execute the resolver function passed in', () => {
expect.assertions(1)

expect(
mockAdminContainer({}, { name: 'John', title: 'Doe' }, adminMockReq)
).resolves.toEqual(true)
})
})
27 changes: 27 additions & 0 deletions containers/withAdminContainer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Context } from '../@types/helpers'
import { isAdmin } from '../helpers/isAdmin'
import { withUserContainer } from './withUserContainer'
import _ from 'lodash'

//use when only checking if user is admin
export const withAdminContainer =
<Type, ArgsType>(
resolver: (_parent: void, args: ArgsType, ctx: Context) => Type,
errorMessage?: string
) =>
async (_parent: void, args: ArgsType, ctx: Context) => {
const { req } = ctx

if (!isAdmin(req)) {
throw new Error(errorMessage || 'User is not an admin')
}

return resolver(_parent, args, ctx)
}

export function withAdminUserContainer<Type, ArgsType>(
resolver: (_parent: void, args: ArgsType, ctx: Context) => Type,
errorMessage?: string
) {
return withUserContainer(withAdminContainer(resolver, errorMessage))
}
13 changes: 6 additions & 7 deletions content/lessons/js3/sublesson/objects.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1206,7 +1206,7 @@ environment.
2. **Shape**
```jsx
const. headers = () => {
const headers = () => {

}
```
Expand Down Expand Up @@ -1235,7 +1235,7 @@ environment.
`<h1>` tags.
```jsx
const ressult2 = headers(info)
const result2 = headers(info)
// result2 is '<h1>ironman: arrogant</h1><h1>spiderman: naive</h1><h1>hulk: strong</h1>'
```
Expand Down Expand Up @@ -1311,7 +1311,7 @@ environment.
```jsx
const result3 = headers(info)
// result3 is '<div><h1>ironman</h1><h2>arrogant</h2></div><div><h1>spiderman</h1><h2>arrogant</h2></div><div><h1>hulk</h1><h2>strong</h2></div>'
// result3 is '<div><h1>ironman</h1><h2>arrogant</h2></div><div><h1>spiderman</h1><h2>naive</h2></div><div><h1>hulk</h1><h2>strong</h2></div>'
```
<Spoiler>
Expand Down Expand Up @@ -1936,11 +1936,10 @@ object `{}`, to store the results.
common element.
```jsx
;[9, 8, 7, 8, 7, 7, 7].getMostCommon()[
;[9, 8, 7, 8, 7, 7, 7].getMostCommon()
// returns 7 because it is the most common element

('Batman', 8, 7, 'Batman', 'Robin')
].getMostCommon()
;['Batman', 8, 7, 'Batman', 'Robin'].getMostCommon()
// returns "Batman" because it is the most common element
```
Expand Down Expand Up @@ -1993,7 +1992,7 @@ frequency, then store these little objects in an array.
**Steps for Solution 1:**
- We need a local variable(let's call it `mapOfElments`) which stores the
- We need a local variable(let's call it `mapOfElements`) which stores the
`reduce` method attached to `this`.
- Inside the `reduce` method, build the object with the given array.
- We need another local variable(let's call it `mostCommon`) which stores:
Expand Down
8 changes: 3 additions & 5 deletions graphql/resolvers/allUsers.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Context } from '../../@types/helpers'
import { isAdminOrThrow } from '../../helpers/isAdmin'
import prisma from '../../prisma'
import { withAdminContainer } from '../../containers/withAdminContainer'

export const allUsers = (_parent: void, _args: void, { req }: Context) => {
isAdminOrThrow(req)
export const allUsers = withAdminContainer((_parent: void, _args: void) => {
return prisma.user.findMany()
}
})
49 changes: 19 additions & 30 deletions graphql/resolvers/challengesController.ts
Original file line number Diff line number Diff line change
@@ -1,39 +1,28 @@
import { Context } from '../../@types/helpers'
import type {
CreateChallengeMutationVariables,
UpdateChallengeMutationVariables
} from '../../graphql'
import { lessons } from './lessons'
import prisma from '../../prisma'
import { isAdminOrThrow } from '../../helpers/isAdmin'
import { validateLessonId } from '../../helpers/validation/validateLessonId'
import { withAdminContainer } from '../../containers/withAdminContainer'

export const createChallenge = async (
_parent: void,
arg: CreateChallengeMutationVariables,
ctx: Context
) => {
const { req } = ctx
export const createChallenge = withAdminContainer(
async (_parent: void, arg: CreateChallengeMutationVariables) => {
await validateLessonId(arg.lessonId)
await prisma.challenge.create({ data: arg })
return lessons()
}
)

isAdminOrThrow(req)
await validateLessonId(arg.lessonId)
await prisma.challenge.create({ data: arg })
return lessons()
}

export const updateChallenge = async (
_parent: void,
arg: UpdateChallengeMutationVariables,
ctx: Context
) => {
const { req } = ctx

isAdminOrThrow(req)
const { id, lessonId, ...data } = arg
await validateLessonId(lessonId)
await prisma.challenge.update({
where: { id },
data
})
return lessons()
}
export const updateChallenge = withAdminContainer(
async (_parent: void, arg: UpdateChallengeMutationVariables) => {
const { id, lessonId, ...data } = arg
await validateLessonId(lessonId)
await prisma.challenge.update({
where: { id },
data
})
return lessons()
}
)
11 changes: 4 additions & 7 deletions graphql/resolvers/exerciseCrud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { Exercise } from '@prisma/client'
import { isAdmin } from '../../helpers/isAdmin'
import { get } from 'lodash'
import { withUserContainer } from '../../containers/withUserContainer'
import { withAdminUserContainer } from '../../containers/withAdminContainer'

export const exercises = () => {
return prisma.exercise.findMany({
Expand Down Expand Up @@ -131,14 +132,10 @@ export const flagExercise = withUserContainer<
})
})

export const removeExerciseFlag = withUserContainer<
export const removeExerciseFlag = withAdminUserContainer<
Promise<Exercise>,
MutationRemoveExerciseFlagArgs
>(async (_parent: void, arg: MutationRemoveExerciseFlagArgs, ctx: Context) => {
const { req } = ctx

if (!isAdmin(req)) throw new Error('Not authorized to unflag')

>(async (_parent: void, arg) => {
const { id } = arg

const exercise = await prisma.exercise.findUnique({
Expand All @@ -162,4 +159,4 @@ export const removeExerciseFlag = withUserContainer<
module: true
}
})
})
}, 'Not authorized to unflag')
31 changes: 13 additions & 18 deletions graphql/resolvers/lessonsController.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { Context } from '../../@types/helpers'
import type {
CreateLessonMutation,
CreateLessonMutationVariables,
Expand All @@ -7,27 +6,23 @@ import type {
} from '../../graphql'
import { lessons } from './lessons'
import prisma from '../../prisma'
import { isAdminOrThrow } from '../../helpers/isAdmin'
import { validateLessonId } from '../../helpers/validation/validateLessonId'
import { withAdminContainer } from '../../containers/withAdminContainer'

export const createLesson = async (
_parent: void,
arg: CreateLessonMutationVariables,
{ req }: Context
): Promise<CreateLessonMutation['createLesson']> => {
isAdminOrThrow(req)
await prisma.lesson.create({ data: arg })
export const createLesson = withAdminContainer<
Promise<CreateLessonMutation['createLesson']>,
CreateLessonMutationVariables
>(async (_parent: void, args) => {
await prisma.lesson.create({ data: args })
return lessons()
}
})

export const updateLesson = async (
_parent: void,
arg: UpdateLessonMutationVariables,
{ req }: Context
): Promise<UpdateLessonMutation['updateLesson']> => {
isAdminOrThrow(req)
const { id, ...data } = arg
export const updateLesson = withAdminContainer<
Promise<UpdateLessonMutation['updateLesson']>,
UpdateLessonMutationVariables
>(async (_parent: void, args) => {
const { id, ...data } = args
await validateLessonId(id)
await prisma.lesson.update({ where: { id }, data })
return lessons()
}
})
14 changes: 5 additions & 9 deletions graphql/resolvers/moduleCrud.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import prisma from '../../prisma'
import { Context } from '../../@types/helpers'
import { isAdminOrThrow } from '../../helpers/isAdmin'
import type { Module } from '@prisma/client'
import { withUserContainer } from '../../containers/withUserContainer'
import { withAdminUserContainer } from '../../containers/withAdminContainer'

export const modules = (): Promise<Module[]> => {
return prisma.module.findMany({
Expand Down Expand Up @@ -37,12 +37,10 @@ export const addModule = async (
})
}

export const updateModule = withUserContainer<
export const updateModule = withAdminUserContainer<
Promise<Module>,
MutationUpdateModuleArgs
>(async (_parent: void, args: MutationUpdateModuleArgs, ctx: Context) => {
const { req } = ctx
isAdminOrThrow(req)
>(async (_parent: void, args) => {
const { id, lessonId, name, content, order } = args
return prisma.module.update({
where: { id },
Expand All @@ -54,12 +52,10 @@ export const updateModule = withUserContainer<
})
})

export const deleteModule = withUserContainer<
export const deleteModule = withAdminUserContainer<
Promise<Module>,
MutationDeleteModuleArgs
>(async (_parent: void, arg: MutationDeleteModuleArgs, ctx: Context) => {
const { req } = ctx
isAdminOrThrow(req)
>(async (_parent: void, arg) => {
const { id } = arg
return prisma.module.delete({
where: { id },
Expand Down
4 changes: 2 additions & 2 deletions helpers/discordAuth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ const getTokenFromRefreshToken = (
'content-type': 'application/x-www-form-urlencoded;charset=utf-8'
},
body: new URLSearchParams({
client_id,
client_secret,
client_id: client_id!,
client_secret: client_secret!,
grant_type: 'refresh_token',
refresh_token
})
Expand Down
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"next-connect": "^0.13.0",
"next-mdx-remote": "^3.0.8",
"nodemailer": "^6.7.7",
"posthog-js": "^1.29.1",
"posthog-js": "^1.29.2",
"prism-react-renderer": "^1.3.5",
"prismjs": "^1.29.0",
"react": "^17.0.2",
Expand All @@ -74,7 +74,7 @@
"yup": "^0.32.11"
},
"devDependencies": {
"@graphql-codegen/cli": "^2.11.6",
"@graphql-codegen/cli": "^2.11.8",
"@graphql-codegen/typescript": "^2.7.2",
"@graphql-codegen/typescript-apollo-client-helpers": "^2.2.3",
"@graphql-codegen/typescript-operations": "^2.5.3",
Expand All @@ -97,13 +97,13 @@
"@types/lodash": "^4.14.184",
"@types/mdx-js__react": "^1.5.5",
"@types/node": "^16.7.5",
"@types/nodemailer": "^6.4.4",
"@types/nodemailer": "^6.4.5",
"@types/prismjs": "^1.26.0",
"@types/react": "^17.0.43",
"@types/react-dom": "^18.0.3",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"babel-jest": "^28.1.3",
"babel-jest": "^29.0.0",
"babel-plugin-prismjs": "^2.1.0",
"copy-webpack-plugin": "^11.0.0",
"cross-env": "^7.0.3",
Expand All @@ -112,7 +112,7 @@
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-mdx": "^1.17.1",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react": "^7.31.1",
"fetch-mock": "^9.11.0",
"husky": "^8.0.1",
"identity-obj-proxy": "^3.0.0",
Expand Down
Loading

0 comments on commit 5f31a3b

Please sign in to comment.