Skip to content

Commit

Permalink
Merge pull request #81 from CS3219-AY2425S1/shishir/fix-question-serv…
Browse files Browse the repository at this point in the history
…ice-bug

Fix Question Service Bug
  • Loading branch information
shishirbychapur authored Oct 1, 2024
2 parents ebd9424 + 26b8e27 commit cd35fb9
Show file tree
Hide file tree
Showing 7 changed files with 70 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { IPaginationRequest, ITypedBodyRequest } from '@repo/request-types'
import { ValidationError } from 'class-validator'
import { Request, Response } from 'express'
import {
createQuestion,
Expand All @@ -18,10 +17,12 @@ import {
isValidSort,
updateQuestion,
} from '../models/question.repository'

import { Category } from '../types/Category'
import { CreateQuestionDto } from '../types/CreateQuestionDto'
import { IQuestion } from '../types/IQuestion'
import { QuestionDto } from '../types/QuestionDto'
import { ValidationError } from 'class-validator'

export async function handleCreateQuestion(
request: ITypedBodyRequest<CreateQuestionDto>,
Expand Down Expand Up @@ -134,7 +135,7 @@ export async function handleUpdateQuestion(request: ITypedBodyRequest<QuestionDt
}

const duplicate = await findOneQuestionByTitle(updateDto.title)
if (duplicate) {
if (duplicate && duplicate.id !== id) {
response.status(409).json('DUPLICATE_TITLE').send()
return
}
Expand Down
17 changes: 7 additions & 10 deletions backend/question-service/src/routes/question.routes.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// import passport from 'passport'
import {
handleCreateQuestion,
handleDeleteQuestion,
Expand All @@ -10,22 +9,20 @@ import {
handleUpdateQuestion,
} from '../controllers/question.controller'

// import { Role } from '@repo/user-types'
import { Role } from '@repo/user-types'
import { Router } from 'express'
// import { handleRoleBasedAccessControl } from '../middlewares/accessControl.middleware'
import { handleRoleBasedAccessControl } from '../middlewares/accessControl.middleware'
import passport from 'passport'

const router = Router()

// router.use(passport.authenticate('jwt', { session: false }))
router.use(passport.authenticate('jwt', { session: false }))

router.get('/', handleGetPaginatedQuestions)
router.get('/:id', handleGetQuestionById)
// router.post('/', handleRoleBasedAccessControl([Role.ADMIN]), handleCreateQuestion)
// router.put('/:id', handleRoleBasedAccessControl([Role.ADMIN]), handleUpdateQuestion)
// router.delete('/:id', handleRoleBasedAccessControl([Role.ADMIN]), handleDeleteQuestion)
router.post('/', handleCreateQuestion)
router.put('/:id', handleUpdateQuestion)
router.delete('/:id', handleDeleteQuestion)
router.post('/', handleRoleBasedAccessControl([Role.ADMIN]), handleCreateQuestion)
router.put('/:id', handleRoleBasedAccessControl([Role.ADMIN]), handleUpdateQuestion)
router.delete('/:id', handleRoleBasedAccessControl([Role.ADMIN]), handleDeleteQuestion)
router.get('/filters', handleGetFilters)
router.get('/sorts', handleGetSorts)
router.get('/categories', handleGetCategories)
Expand Down
11 changes: 6 additions & 5 deletions frontend/components/auth/Login.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
'use client'

import { tokenState, userState } from '@/atoms/auth'
import validateInput, { initialFormValues } from '@/util/input-validation'

import { Button } from '../ui/button'
import { InputField } from '../customs/custom-input'
import { PasswordReset } from './PasswordReset'
import React from 'react'
import { loginRequest } from '@/services/user-service-api'
import { toast } from 'sonner'
import usePasswordToggle from '../../hooks/UsePasswordToggle'
import { useState } from 'react'
import { loginRequest } from '@/services/user-service-api'
import { useSetRecoilState } from 'recoil'
import { tokenState, userState } from '@/atoms/auth'
import { useRouter } from 'next/router'
import React from 'react'
import { useSetRecoilState } from 'recoil'
import { useState } from 'react'

export default function Login() {
const [formValues, setFormValues] = useState({ ...initialFormValues })
Expand Down Expand Up @@ -55,6 +55,7 @@ export default function Login() {
sessionStorage.setItem('email', res.email)
sessionStorage.setItem('TTL', new Date().toString())
sessionStorage.setItem('isAuth', 'true')
sessionStorage.setItem('role', res.role)
setIsAuth(true)
setIsValid(true)
router.push('/')
Expand Down
48 changes: 28 additions & 20 deletions frontend/pages/questions/index.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
'use client'

import { Button } from '@/components/ui/button'
import { useEffect, useState } from 'react'
import Datatable from '@/components/customs/datatable'
import {
Difficulty,
IGetQuestions,
Expand All @@ -14,20 +11,25 @@ import {
SortDirection,
} from '@/types'
import { columns, formFields } from './props'
import CustomModal from '@/components/customs/custom-modal'
import CustomForm from '@/components/customs/custom-form'
import ConfirmDialog from '@/components/customs/confirm-dialog'
import { capitalizeFirst } from '@/util/string-modification'
import {
createQuestionRequest,
deleteQuestionById,
getQuestionbyIDRequest,
getQuestionsRequest,
updateQuestionRequest,
} from '@/services/question-service-api'
import { useEffect, useState } from 'react'

import { Button } from '@/components/ui/button'
import ConfirmDialog from '@/components/customs/confirm-dialog'
import CustomForm from '@/components/customs/custom-form'
import CustomModal from '@/components/customs/custom-modal'
import Datatable from '@/components/customs/datatable'
import { capitalizeFirst } from '@/util/string-modification'
import { toast } from 'sonner'

export default function Questions() {
const [isAdmin, setIsAdmin] = useState(false)
const [data, setData] = useState<IQuestion[]>([])
const [isLoading, setLoading] = useState<boolean>(false)
const [pagination, setPagination] = useState<IPagination>({
Expand Down Expand Up @@ -102,6 +104,10 @@ export default function Questions() {
setIsInit(true)
}, [isInit])

useEffect(() => {
setIsAdmin(sessionStorage.getItem('role') === 'ADMIN')
}, [])

const sortHandler = (sortBy: ISortBy) => {
setSortBy(sortBy)
const body: IGetQuestions = {
Expand Down Expand Up @@ -235,19 +241,21 @@ export default function Questions() {
<div className="m-8">
<div className="flex items-center justify-between mb-4">
<h2 className="text-xl font-bold">Questions</h2>
<Button
variant={'primary'}
onClick={() => {
setModalData({
...modalData,
title: 'Create new question',
isOpen: true,
})
setModificationType(Modification.CREATE)
}}
>
Create
</Button>
{isAdmin && (
<Button
variant={'primary'}
onClick={() => {
setModalData({
...modalData,
title: 'Create new question',
isOpen: true,
})
setModificationType(Modification.CREATE)
}}
>
Create
</Button>
)}
</div>
<Datatable
data={data}
Expand Down
14 changes: 12 additions & 2 deletions frontend/pages/questions/props.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { TickIcon, ExclamationIcon } from '@/assets/icons'
import { DifficultyLabel } from '@/components/customs/difficulty-label'
import { Difficulty, FormType, IDatatableColumn, IFormFields, QuestionStatus } from '@/types'
import { ExclamationIcon, TickIcon } from '@/assets/icons'

import { Badge } from '@/components/ui/badge'
import { Category } from '@repo/user-types'
import { DifficultyLabel } from '@/components/customs/difficulty-label'

const columns: IDatatableColumn[] = [
{
Expand All @@ -15,6 +17,14 @@ const columns: IDatatableColumn[] = [
},
{
key: 'categories',
formatter: (values) => {
const c = values.map((v: string) => (
<Badge key={v} className="m-1 bg-violet-600">
{v}
</Badge>
))
return <div className="flex flex-wrap items-center justify-center">{c}</div>
},
},
{
key: 'description',
Expand Down
14 changes: 0 additions & 14 deletions frontend/services/axios-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,18 +43,4 @@ api.interceptors.response.use(
}
)

// Request interceptor for all axios calls
api.interceptors.request.use(
(config) => {
const token = sessionStorage.getItem('accessToken')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)

export default api
14 changes: 14 additions & 0 deletions frontend/services/axios-middleware2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,20 @@ const api = axios.create({
baseURL: 'http://localhost:3004',
})

// Request interceptor for all axios calls
api.interceptors.request.use(
(config) => {
const token = sessionStorage.getItem('accessToken')
if (token) {
config.headers['Authorization'] = `Bearer ${token}`
}
return config
},
(error) => {
return Promise.reject(error)
}
)

// Response interceptor for all axios calls
api.interceptors.response.use(
(response) => {
Expand Down

0 comments on commit cd35fb9

Please sign in to comment.