Skip to content

Commit 78116f8

Browse files
authored
Merge pull request #3 from Vignesh-30/temp
Enable cors, intergrate frontend and backend, change dto structure, change question service structure
2 parents 7a8b8f3 + ae5271b commit 78116f8

File tree

11 files changed

+230
-129
lines changed

11 files changed

+230
-129
lines changed

backend/question-service/src/dto/CreateQuestion.dto.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,10 @@ enum Difficulty {
2626
}
2727

2828
export class CreateQuestionDto {
29+
@IsNotEmpty()
30+
@IsString()
31+
id: string;
32+
2933
@IsNotEmpty()
3034
@IsString()
3135
title: string;
@@ -39,7 +43,10 @@ export class CreateQuestionDto {
3943
message:
4044
'Category must be Algorithm, DynamicProgramming, Array, SQL, Heap, Recursion, Graph, Sorting',
4145
})
42-
categories: Category[];
46+
47+
categories: Category;
48+
// categories: Category[];
49+
4350

4451
@IsNotEmpty()
4552
@IsEnum(Difficulty, {

backend/question-service/src/main.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,11 @@ import { AppModule } from './app.module';
33

44
async function bootstrap() {
55
const app = await NestFactory.create(AppModule);
6+
app.enableCors({
7+
origin: '*',
8+
});
9+
app.enableShutdownHooks();
610
await app.listen(3002);
11+
// console.log(app.getHttpAdapter().getInstance()._router.stack);
712
}
813
bootstrap();

backend/question-service/src/questions/questions.controller.ts

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,10 @@ export class QuestionsController {
4141
@Param('id') id: string,
4242
@Body() UpdateQuestionDto: UpdateQuestionDto,
4343
) {
44-
const isValid = mongoose.Types.ObjectId.isValid(id);
45-
if (!isValid) throw new HttpException('Invalid ID', 400);
44+
// NEED TO CHANGE THIS, PREVIOUSLY ID IS THE AUTOMATICALLY GENERATED ID BY MONGODB, NOW IT IS SPECIFIED BY USER
45+
//
46+
// const isValid = mongoose.Types.ObjectId.isValid(id);
47+
// if (!isValid) throw new HttpException('Invalid ID', 400);
4648
const updateQuestion = await this.questionsService.updateQuestion(
4749
id,
4850
UpdateQuestionDto,
@@ -53,8 +55,11 @@ export class QuestionsController {
5355

5456
@Delete(':id')
5557
async deleteQuestion(@Param('id') id: string) {
56-
const isValid = mongoose.Types.ObjectId.isValid(id);
57-
if (!isValid) throw new HttpException('Invalid ID', 400);
58+
// NEED TO CHANGE THIS, PREVIOUSLY ID IS THE AUTOMATICALLY GENERATED ID BY MONGODB, NOW IT IS SPECIFIED BY USER
59+
//
60+
// const isValid = mongoose.Types.ObjectId.isValid(id);
61+
// if (!isValid) throw new HttpException('Invalid ID', 400);
62+
5863
const deletedUser = await this.questionsService.deleteQuestion(id);
5964
if (!deletedUser) throw new HttpException('Question not Found', 404);
6065
return;

backend/question-service/src/questions/questions.service.ts

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,15 @@ export class QuestionsService {
2424
return this.questionModel.findById(id);
2525
}
2626

27-
updateQuestion(id: string, updateUserDto: UpdateQuestionDto) {
28-
return this.questionModel.findByIdAndUpdate(id, updateUserDto, {
29-
new: true,
30-
});
27+
updateQuestion(id: string, updateQuestionDto: UpdateQuestionDto) {
28+
return this.questionModel
29+
.findOneAndUpdate({ id: id }, updateQuestionDto, {
30+
new: true,
31+
})
32+
.exec();
3133
}
3234

3335
deleteQuestion(id: string) {
34-
return this.questionModel.findByIdAndDelete(id);
36+
return this.questionModel.deleteOne({ id: id }).exec();
3537
}
3638
}

backend/question-service/src/schemas/Question.schema.ts

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import mongoose from 'mongoose';
33

44
@Schema()
55
export class Question {
6-
@Prop({ unique: true })
7-
id: string;
6+
@Prop({ unique: true, required: true })
7+
id: number;
88

99
@Prop({ unique: true, required: true })
1010
title: string;
@@ -13,10 +13,13 @@ export class Question {
1313
description: string;
1414

1515
@Prop({ required: true })
16-
category: string;
16+
categories: string;
17+
18+
@Prop({ required: true })
19+
complexity: string;
1720

1821
@Prop({ required: true })
19-
difficulty: string;
22+
link: string;
2023
}
2124

22-
export const QuestionSchema = SchemaFactory.createForClass(Question)
25+
export const QuestionSchema = SchemaFactory.createForClass(Question);

backend/user-service/src/main.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ import { AppModule } from './app.module';
44
async function bootstrap() {
55
const app = await NestFactory.create(AppModule);
66
app.enableCors({
7-
origin: 'http://localhost:3000',
7+
origin: '*',
88
});
99
await app.listen(3001);
1010
}
11-
bootstrap();
11+
bootstrap();

frontend/package-lock.json

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
"react-dom": "^18.3.1",
2020
"react-router-dom": "^6.26.2",
2121
"react-scripts": "^5.0.1",
22+
"react-services": "^0.1.2",
2223
"typescript": "^4.9.5",
2324
"web-vitals": "^2.1.4"
2425
},
Lines changed: 137 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -1,105 +1,153 @@
1-
import React, { useState } from 'react';
2-
import EditQuestionForm from './editquestionform';
1+
import axios from "axios";
2+
import React, { useState } from "react";
3+
import EditQuestionForm from "./editquestionform";
34

45
export interface Question {
5-
id: number;
6-
title: string;
7-
description: string;
8-
categories: string;
9-
complexity: string;
10-
link: string;
6+
id: string;
7+
title: string;
8+
description: string;
9+
categories: string;
10+
complexity: string;
11+
link: string;
1112
}
1213

1314
interface QuestionTableProps {
14-
searchTerm: string;
15-
category: string;
16-
complexity: string;
17-
questions: Question[];
18-
setQuestions: React.Dispatch<React.SetStateAction<Question[]>>;
15+
searchTerm: string;
16+
category: string;
17+
complexity: string;
18+
questions: Question[];
19+
setQuestions: React.Dispatch<React.SetStateAction<Question[]>>;
1920
}
2021

21-
const QuestionTable: React.FC<QuestionTableProps> = ({ searchTerm, category, complexity, questions, setQuestions }) => {
22+
const QuestionTable: React.FC<QuestionTableProps> = ({
23+
searchTerm,
24+
category,
25+
complexity,
26+
questions,
27+
setQuestions,
28+
}) => {
29+
const [editingQuestion, setEditingQuestion] = useState<Question | null>(null);
2230

23-
const [editingQuestion, setEditingQuestion] = useState<Question | null>(null);
24-
25-
const filteredQuestions = questions.filter((question) => {
26-
const matchesSearchTerm = question.title.toLowerCase().includes(searchTerm.toLowerCase());
27-
const matchesCategory = category ? question.categories.includes(category) : true;
28-
const matchesComplexity = complexity ? question.complexity === complexity : true;
29-
return matchesSearchTerm && matchesCategory && matchesComplexity;
30-
});
31+
const filteredQuestions = questions.filter((question) => {
32+
const matchesSearchTerm = question.title
33+
.toLowerCase()
34+
.includes(searchTerm.toLowerCase());
35+
const matchesCategory = category
36+
? question.categories.includes(category)
37+
: true;
38+
const matchesComplexity = complexity
39+
? question.complexity === complexity
40+
: true;
41+
return matchesSearchTerm && matchesCategory && matchesComplexity;
42+
});
3143

32-
const handleDelete = (id: number) => {
33-
setQuestions((prevQuestions) => prevQuestions.filter(question => question.id !== id));
34-
};
44+
const handleDelete = async (id: string) => {
45+
try {
46+
console.log("id is ", id);
47+
await axios.delete(`http://localhost:3002/questions/${id}`);
48+
setQuestions((prevQuestions) =>
49+
prevQuestions.filter((question) => question.id !== id)
50+
);
51+
} catch (error) {
52+
alert("Error deleting question: " + error);
53+
}
54+
setQuestions((prevQuestions) =>
55+
prevQuestions.filter((question) => question.id !== id)
56+
);
57+
};
3558

36-
const handleUpdate = (updatedQuestion: Question) => {
37-
setQuestions((prevQuestions) =>
38-
prevQuestions.map(question => (question.id === updatedQuestion.id ? updatedQuestion : question))
39-
);
40-
};
59+
const handleUpdate = async (updatedQuestion: Question) => {
60+
try {
61+
console.log("updated question is ", updatedQuestion)
62+
const response = await axios.patch(
63+
`http://localhost:3002/questions/${updatedQuestion.id}`,
64+
updatedQuestion
65+
);
66+
setQuestions((prevQuestions) =>
67+
prevQuestions.map((question) =>
68+
question.id === updatedQuestion.id ? response.data : question
69+
)
70+
);
71+
} catch (error) {
72+
alert("Error updating question: " + error);
73+
}
74+
};
4175

42-
const closeEditForm = () => {
43-
setEditingQuestion(null);
44-
};
76+
const closeEditForm = () => {
77+
setEditingQuestion(null);
78+
};
4579

46-
return (
47-
<div>
48-
<table className="min-w-full table-auto">
49-
<thead>
50-
<tr>
51-
<th className="border px-4 py-2">ID</th>
52-
<th className="border px-4 py-2">Title</th>
53-
<th className="border px-4 py-2">Description</th>
54-
<th className="border px-4 py-2">Categories</th>
55-
<th className="border px-4 py-2">Complexity</th>
56-
<th className="border px-4 py-2">Link</th>
57-
<th className="border px-4 py-2">Actions</th>
58-
</tr>
59-
</thead>
60-
<tbody>
61-
{filteredQuestions.map((question) => (
62-
<tr key={question.id}>
63-
<td className="border px-4 py-2">{question.id}</td>
64-
<td className="border px-4 py-2">{question.title}</td>
65-
<td className="border px-4 py-2">{question.description}</td>
66-
<td className="border px-4 py-2">{question.categories}</td>
67-
<td className="border px-4 py-2">{question.complexity}</td>
68-
<td className="border px-4 py-2">
69-
<a href={question.link} target="_blank" rel="noopener noreferrer" className="text-blue-500">
70-
View
71-
</a>
72-
</td>
73-
<td className="border px-4 py-2">
74-
<div className="flex space-x-2">
75-
<button onClick={() => handleDelete(question.id)} className="bg-red-500 text-white rounded px-2 py-1">
76-
Delete
77-
</button>
78-
<button onClick={() => setEditingQuestion(question)} className="bg-red-500 text-white rounded px-2 py-1">
79-
Edit
80-
</button>
81-
</div>
82-
</td>
83-
</tr>
84-
))}
85-
{filteredQuestions.length === 0 && (
86-
<tr>
87-
<td colSpan={7} className="border border-gray-300 px-4 py-2 text-center">
88-
No questions found.
89-
</td>
90-
</tr>
91-
)}
92-
</tbody>
93-
</table>
94-
{editingQuestion && (
95-
<EditQuestionForm
96-
question={editingQuestion}
97-
onUpdate={handleUpdate}
98-
onClose={closeEditForm}
99-
/>
100-
)}
80+
return (
81+
<div className="bg-gray-800 text-white">
82+
<table className="min-w-full table-auto">
83+
<thead className="bg-gray-700">
84+
<tr>
85+
<th className="border px-4 py-2">ID</th>
86+
<th className="border px-4 py-2">Title</th>
87+
<th className="border px-4 py-2">Description</th>
88+
<th className="border px-4 py-2">Categories</th>
89+
<th className="border px-4 py-2">Complexity</th>
90+
<th className="border px-4 py-2">Link</th>
91+
<th className="border px-4 py-2">Actions</th>
92+
</tr>
93+
</thead>
94+
<tbody className="bg-gray-800">
95+
{filteredQuestions.map((question) => (
96+
<tr key={question.id}>
97+
<td className="border px-4 py-2">{question.id}</td>
98+
<td className="border px-4 py-2">{question.title}</td>
99+
<td className="border px-4 py-2">{question.description}</td>
100+
<td className="border px-4 py-2">{question.categories}</td>
101+
<td className="border px-4 py-2">{question.complexity}</td>
102+
<td className="border px-4 py-2">
103+
<a
104+
href={question.link}
105+
target="_blank"
106+
rel="noopener noreferrer"
107+
className="text-blue-500"
108+
>
109+
View
110+
</a>
111+
</td>
112+
<td className="border px-4 py-2">
113+
<div className="flex space-x-2">
114+
<button
115+
onClick={() => handleDelete(question.id)}
116+
className="bg-red-500 text-white rounded px-2 py-1"
117+
>
118+
Delete
119+
</button>
120+
<button
121+
onClick={() => setEditingQuestion(question)}
122+
className="bg-red-500 text-white rounded px-2 py-1"
123+
>
124+
Edit
125+
</button>
126+
</div>
127+
</td>
128+
</tr>
129+
))}
130+
{filteredQuestions.length === 0 && (
131+
<tr>
132+
<td
133+
colSpan={7}
134+
className="border border-gray-300 px-4 py-2 text-center"
135+
>
136+
No questions found.
137+
</td>
138+
</tr>
139+
)}
140+
</tbody>
141+
</table>
142+
{editingQuestion && (
143+
<EditQuestionForm
144+
question={editingQuestion}
145+
onUpdate={handleUpdate}
146+
onClose={closeEditForm}
147+
/>
148+
)}
101149
</div>
102-
);
150+
);
103151
};
104152

105153
export default QuestionTable;

0 commit comments

Comments
 (0)