Skip to content

Commit

Permalink
Add basic backend logic for solving quiz
Browse files Browse the repository at this point in the history
  • Loading branch information
maxidragon committed Sep 23, 2023
1 parent 4ecf16a commit 8747fc8
Show file tree
Hide file tree
Showing 13 changed files with 152 additions and 46 deletions.
39 changes: 39 additions & 0 deletions backend/app/controllers/solving_quiz_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class SolvingQuizController < ApplicationController
before_action :authenticate_user!

def start_quiz
quiz = Quiz.find(params[:quiz_id])
quiz_attempt = quiz.quiz_attempts.build(quiz_attempt_params)
if quiz_attempt.save
render json: quiz_attempt
else
render json: {error: quiz_attempt.errors.full_messages}, status: :unprocessable_entity
end
end

def get_info_with_questions
#quiz with questions and answers but without info about correct answers
quiz = Quiz.find(params[:quiz_id])
render json: quiz, include: [:questions, :answers.except(:is_correct)]
end

def submit_answer
quiz_attempt = QuizAttempt.find(params[:quiz_attempt_id])
answer = Answer.find(params[:answer_id])
user_answer_params = {quiz_attempt_id: quiz_attempt.id, answer_id: answer.id}
user_answer = quiz_attempt.user_answers.build(user_answer_params)
if user_answer.save
render json: user_answer
else
render json: {error: user_answer.errors.full_messages}, status: :unprocessable_entity
end
end

def finish_quiz
quiz_attempt = QuizAttempt.find(params[:quiz_attempt_id])
quiz_attempt_params = {finished: true}
quiz_attempt.update(quiz_attempt_params)
render json: quiz_attempt
end

end
2 changes: 2 additions & 0 deletions backend/app/models/quiz.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class Quiz < ApplicationRecord
belongs_to :user
has_many :questions, dependent: :destroy
has_many :quiz_attempts, dependent: :destroy
validates :name, presence: true
validates :description, presence: true

end
5 changes: 5 additions & 0 deletions backend/app/models/quiz_attempt.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class QuizAttempt < ApplicationRecord
belongs_to :user
belongs_to :quiz
has_many :user_answers, dependent: :destroy
end
1 change: 1 addition & 0 deletions backend/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ class User < ApplicationRecord
devise :database_authenticatable, :registerable, :recoverable, :validatable, :jwt_authenticatable, jwt_revocation_strategy: self

has_many :quizzes, dependent: :destroy
has_many :quiz_attempts, dependent: :destroy
end
2 changes: 1 addition & 1 deletion backend/app/models/user_answer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class UserAnswer < ApplicationRecord
belongs_to :user
belongs_to :quiz_attempt
belongs_to :answer
end
16 changes: 16 additions & 0 deletions backend/db/migrate/20230923163539_create_quiz_attempts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
class CreateQuizAttempts < ActiveRecord::Migration[7.0]
def change
create_table :quiz_attempts do |t|
t.integer :user_id, null: false
t.integer :quiz_id, null: false
t.datetime :started_at
t.datetime :finished_at
t.boolean :is_active, default: true, null: false

t.timestamps
end

add_foreign_key :quiz_attempts, :users
add_foreign_key :quiz_attempts, :quizzes
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class ChangeUserAnswersUserIdToQuizAttemptId < ActiveRecord::Migration[7.0]
def change
rename_column :user_answers, :user_id, :quiz_attempt_id
add_foreign_key :user_answers, :quiz_attempts
end
end
21 changes: 17 additions & 4 deletions backend/db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

56 changes: 31 additions & 25 deletions frontend/src/Components/Forms/EditQuizInfoForm.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
Box,
Button,
Checkbox,
FormControlLabel,
TextField,
Typography,
} from "@mui/material";
import { Box, Button, TextField, Typography } from "@mui/material";
import { Answer, Question, Quiz } from "../../logic/interfaces";
import EditIcon from "@mui/icons-material/Edit";
import DeleteIcon from "@mui/icons-material/Delete";
Expand Down Expand Up @@ -58,7 +51,27 @@ const EditQuizInfoForm = (props: {
}
})
.catch(() => {
enqueueSnackbar("Quiz not deleted!", { variant: "error" });
enqueueSnackbar("Quiz not deleted!", { variant: "info" });
});
};

const handlePublish = async () => {
confirm({
description:
"Are you sure you want to publish this quiz? Once published, it cannot be edited.",
})
.then(async () => {
props.updateQuiz({ ...props.quiz, is_public: true });
const response = await updateQuiz({ ...props.quiz, is_public: true });
if (response.status === "updated") {
enqueueSnackbar("Quiz published!", { variant: "success" });
}
if (response.error) {
enqueueSnackbar("Something went wrong!", { variant: "error" });
}
})
.catch(() => {
enqueueSnackbar("Quiz not published!", { variant: "info" });
});
};

Expand Down Expand Up @@ -117,28 +130,21 @@ const EditQuizInfoForm = (props: {
})
}
/>
<FormControlLabel
control={
<Checkbox
checked={props.quiz.is_public}
onChange={(event: React.ChangeEvent<HTMLInputElement>) =>
props.updateQuiz({
...props.quiz,
is_public: event.target.checked,
})
}
disabled={!canBePublished}
/>
}
label="Public"
/>
<Box sx={{ display: "flex", justifyContent: "end", mt: 2 }}>
<Button
variant="contained"
color="success"
disabled={!canBePublished || props.quiz.is_public}
onClick={handlePublish}
>
Publish
</Button>
<Button
variant="contained"
endIcon={<EditIcon />}
onClick={handleEdit}
>
Edit
Save
</Button>
<Button
variant="contained"
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/Components/Questions/AnswerRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const AnswerRow = (props: {
quizId: number;
updateQuestion: (question: Question) => void;
question: Question;
isPublic: boolean;
}) => {
const confirm = useConfirm();
const { answerRow } = props;
Expand Down Expand Up @@ -79,10 +80,11 @@ const AnswerRow = (props: {
onClick={() => {
setOpenEditAnswerModal(true);
}}
disabled={props.isPublic}
>
<EditIcon />
</IconButton>
<IconButton onClick={handleDelete}>
<IconButton onClick={handleDelete} disabled={props.isPublic}>
<DeleteIcon />
</IconButton>
</TableCell>
Expand Down
14 changes: 10 additions & 4 deletions frontend/src/Components/Questions/QuestionRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ import AnswerRow from "./AnswerRow";

const QuestionRow = (props: {
row: Question;
handleCloseCreateModal: () => void;
handleCreateAnswer: () => void;
questionNumber: number;
isPublic: boolean;
}) => {
const confirm = useConfirm();
const { row } = props;
Expand All @@ -40,7 +41,7 @@ const QuestionRow = (props: {

const handleCloseCreateModal = async () => {
setOpenCreateModal(false);
props.handleCloseCreateModal();
props.handleCreateAnswer();
};

const handleDelete = async () => {
Expand Down Expand Up @@ -96,10 +97,13 @@ const QuestionRow = (props: {
{editedQuestion.text}
</TableCell>
<TableCell>
<IconButton onClick={() => setOpenEditQuestionModal(true)}>
<IconButton
onClick={() => setOpenEditQuestionModal(true)}
disabled={props.isPublic}
>
<EditIcon />
</IconButton>
<IconButton onClick={handleDelete}>
<IconButton onClick={handleDelete} disabled={props.isPublic}>
<DeleteIcon />
</IconButton>
</TableCell>
Expand All @@ -122,6 +126,7 @@ const QuestionRow = (props: {
aria-label="add question"
size="small"
onClick={() => setOpenCreateModal(true)}
disabled={props.isPublic}
>
<AddIcon />
</IconButton>
Expand Down Expand Up @@ -153,6 +158,7 @@ const QuestionRow = (props: {
answerNumber={answerNumber}
updateQuestion={updateQuestion}
question={editedQuestion}
isPublic={props.isPublic}
/>
),
)}
Expand Down
25 changes: 15 additions & 10 deletions frontend/src/Components/Questions/Questions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {
import AddIcon from "@mui/icons-material/Add";
import CreateQuestionModal from "../ModalComponents/Create/CreateQuestionModal";

const Questions = (props: { quizId: number }) => {
const Questions = (props: { quizId: number; isPublic: boolean }) => {
const [questions, setQuestions] = useState<Question[]>([]);
const [openCreateModal, setOpenCreateModal] = useState<boolean>(false);

Expand All @@ -35,6 +35,10 @@ const Questions = (props: { quizId: number }) => {
await fetchQuestions();
};

const handleCreateAnswer = async () => {
await fetchQuestions();
};

return (
<>
<Grid
Expand All @@ -51,6 +55,7 @@ const Questions = (props: { quizId: number }) => {
aria-label="add question"
size="small"
onClick={() => setOpenCreateModal(true)}
disabled={props.isPublic}
>
<AddIcon />
</IconButton>
Expand All @@ -74,15 +79,15 @@ const Questions = (props: { quizId: number }) => {
</TableRow>
</TableHead>
<TableBody>
{questions &&
questions.map((question: Question, i: number) => (
<QuestionRow
key={question.id}
row={question}
handleCloseCreateModal={handleCloseCreateModal}
questionNumber={i + 1}
/>
))}
{questions.map((question: Question, i: number) => (
<QuestionRow
key={question.id}
row={question}
handleCreateAnswer={handleCreateAnswer}
questionNumber={i + 1}
isPublic={props.isPublic}
/>
))}
</TableBody>
</Table>
</TableContainer>
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/Pages/ManageQuiz/ManageQuiz.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,12 +46,17 @@ const ManageQuiz = () => {
>
<Grid item>
<Typography variant="h5">Manage quiz</Typography>
<Typography variant="body1" color="gray">
{quiz.is_public
? "After publishing quiz you can't edit questions and answers anymore. You can only edit quiz info."
: "Here you can edit quiz info and questions."}
</Typography>
</Grid>
<Grid item>
<EditQuizInfoForm quiz={quiz} updateQuiz={updateQuiz} />
</Grid>
<Grid item>
<Questions quizId={quiz.id} />
<Questions quizId={quiz.id} isPublic={quiz.is_public} />
</Grid>
</Grid>
) : (
Expand Down

0 comments on commit 8747fc8

Please sign in to comment.