Untitled
unknown
plain_text
9 months ago
12 kB
19
Indexable
<?php
namespace App\Http\Controllers\Student;
use App\Models\CodingAnswer;
use App\Models\Exam;
use App\Models\ExamRecord;
use App\Models\Reviewer;
use App\Models\StudentAnswer;
use App\Models\StudentPaper;
use App\Services\ExamTakingService;
use App\Services\QuestionService;
use Carbon\Carbon;
use DB;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Redis;
use Storage;
use Str;
class ExamRecordController extends Controller
{
public function index(Exam $exam)
{
$user = auth()->user();
$exam_records = ExamRecord::whereHas('studentPaper', function ($query) use ($exam, $user) {
$query->where('exam_id', $exam->id)
->where('user_id', $user->id);
})->with('subjects')->get();
return view( 'students/records/index', ['exam' => $exam, 'exam_records' => $exam_records]);
}
public function store(StudentPaper $student_paper)
{
$user = auth()->user();
// validate that the student_paper's author is the authenticated user
$student_paper->update(['submitted_at' => now()]);
$exam_id = $student_paper->exam->id;
$exam = Exam::find($exam_id);
$attempt_count = session()->pull('current_attempt', 1);
// AGGREGATE student points by subjects, get subject id, subject name, sum of student points for that subject, sum of obtainable points for subject
$subject_table = DB::table('student_answers')
->join('questions', 'student_answers.question_id', '=', 'questions.id')
->join('topics', 'questions.topic_id', '=', 'topics.id')
->join('subjects', 'topics.subject_id', '=', 'subjects.id')
->where('student_answers.student_paper_id', $student_paper->id)
->groupBy('subjects.id', 'subjects.name')
->select(
'subjects.id as id',
'subjects.name as subject_name',
DB::raw('SUM(student_answers.points) as subject_score_obtained'),
DB::raw('SUM(questions.total_points) as subject_score'))
->get()
->keyBy('id');
$total_score = $subject_table->sum('subject_score_obtained');
$date_taken = $student_paper->created_at;
$time_taken = round($student_paper->created_at->diffInMinutes($student_paper->submitted_at));
$exam_record = $student_paper->examRecord()->updateOrCreate(
['student_paper_id' => $student_paper->id],
[
'attempt' => $attempt_count,
'total_score' => $total_score,
'date_taken' => $date_taken,
'time_taken' => $time_taken,
]);
$transformed_subject_table = $subject_table->map(function ($item) use ($exam_record) {
return [
'exam_record_id' => $exam_record->id,
'subject_id' => $item->id,
'subject_name' => $item->subject_name,
'score_obtained' => (int) $item->subject_score_obtained,
'score' => (int) $item->subject_score,
'created_at' => now(),
'updated_at' => now(),
];
})->values()->toArray();
DB::table('exam_records_subjects')->upsert(
$transformed_subject_table,
['exam_record_id', 'subject_id'],
['score_obtained', 'score', 'updated_at']
);
$coding_question_answers_pattern = "user:{$user->id}:paper:{$student_paper->id}:language:*:answer:*:code";
$keys = Redis::keys($coding_question_answers_pattern);
if (!empty($keys)) {
Self::storeCodeToJSON($user->id, $student_paper->id);
} else {
$score = $exam_record->total_score;
if ($score == $exam->max_score) {
$status = 'perfect_score';
} elseif ($score >= $exam->max_score/2) {
$status = 'pass';
} else {
$status = 'more_review';
}
$exam_record->update(['status' => $status]);
}
$student_paper->update(['status' => 'completed']);
return response('', 204)->header('HX-Redirect', route('exam_records.show', ['exam' => $exam, 'exam_record' => $exam_record]));
}
public function show(Exam $exam, ExamRecord $examRecord)
{
$examRecord->load('subjects');
$student_paper = StudentPaper::with('studentAnswers.question')
->find($examRecord->student_paper_id);
$rows = [];
foreach ($student_paper->studentAnswers as $i => $answer) {
$question = $answer->question;
$question->load('multipleChoiceQuestions');
$neededRelations = $student_paper->studentAnswers
->map(fn($a) => $a->question->question_type->value)
->unique()
->map(fn($type) => 'studentAnswers.' . Str::camel($type) . (in_array($type, ['ranking', 'matching']) ? 'Answers' : 'Answer'))
->values()
->all();
$student_paper->load(array_merge(['studentAnswers.question'], $neededRelations));
// Load and get the specific answer
$question_service = new QuestionService();
$exam_taking_service = new ExamTakingService($question_service);
if ($answer->is_answered){
$question_type_answer = $exam_taking_service->getAnswerType($answer, $question);
if ($question_type_answer != null){
switch ($question->question_type->value) {
case 'multiple_choice':
$matched = $question->multipleChoiceQuestions->firstWhere('choice_key', $question_type_answer?->answer);
$yourAnswer = $matched->item ?? 'N/A';
break;
case 'identification':
$yourAnswer = $question_type_answer?->answer ?? 'N/A';
break;
case 'true_or_false':
$yourAnswer = ($question_type_answer?->answer) ? 'True' : 'False';
break;
case 'ranking':
$yourAnswer = $question_type_answer ?? 'N/A';
break;
case 'matching':
$yourAnswer = $question_type_answer
? $question_type_answer->map(fn($a) => "{$a->first_item_answer} → {$a->secondd_item_answer}")->implode(', ')
: 'N/A';
break;
case 'coding':
$yourAnswer = $answer->codingAnswer;
break;
default:
$yourAnswer = 'Unsupported';
}
}
}
$rows[] = [
'number' => $i + 1,
'question' => $question->name,
'question_type' => $question->question_type->getName(),
'your_answer' => $yourAnswer ?? $answer->is_answered ?? 'Not answered',
'is_answered'=> $answer->is_answered,
'score' => $answer->points ?? 0,
'max_score' => $question->total_points,
'status' => ($answer->gained_points >= $question->points) ? 'Correct' : 'Incorrect',
'question_type_answer' => $question_type_answer ?? null,
];
}
// Get topics from exam questions
$topicNames = $exam->questions()
->with('topic')
->get()
->pluck('topic.name')
->unique();
// Get reviewers matching the exam question topics
$reviewers = Reviewer::whereIn('topic', $topicNames)->get();
$data = [
'exam_record' => $examRecord,
'student_paper' => $student_paper,
'exam' => $exam,
'rows' => $rows,
'reviewers' => $reviewers
];
return view('students/records/show', $data);
}
public function showCodingResult(CodingAnswer $codingAnswer){
$coding_answer_status = Redis::hget('checked_code', $codingAnswer->id);
$data['status'] = $coding_answer_status;
if ($coding_answer_status == 'checked'){
$data['code_answer'] = $codingAnswer;
$data['success'] = $codingAnswer->is_code_success;
$data['test_results'] = json_decode($codingAnswer->test_results);
$data['failures'] = json_decode($codingAnswer->failures);
$data['syntax_points'] = $codingAnswer->answer_syntax_points;
$data['runtime_points'] = $codingAnswer->answer_runtime_points;
$data['test_case_points'] = $codingAnswer->answer_test_case_points;
$data['number'] = request()->input('number');
$data['question'] = request()->input('question');
$data['score'] = $codingAnswer->answer_syntax_points + $codingAnswer->answer_runtime_points + $codingAnswer->answer_test_case_points;
$data['max_score'] = request()->input('max_score');
return view('students/records/get-coding-result', ['data' => $data]);
} else {
return response('', 212);
}
}
public function showUpdatedScore(ExamRecord $examRecord){
if ($examRecord->status != 'in_progress'){
$examRecord->load('subjects');
$examRecord['max_score'] = request()->input('max_score');
return view('students/records/get-updated-score', ['exam_record' => $examRecord]);
} else {
return response('', 212);
}
}
private static function storeCodeToJSON($user_id, $student_paper_id){
$pattern = "user:$user_id:paper:$student_paper_id:language:*:answer:*:code";
$student_paper_date = StudentPaper::find($student_paper_id)->submitted_at;
$student_paper_submitted_at_unix = (String) Carbon::parse($student_paper_date)->timestamp;
$key = $student_paper_submitted_at_unix . '-' . $user_id;
$keys = Redis::keys($pattern);
$values = Redis::mget($keys);
$data = [];
foreach ($keys as $index => $key) {
preg_match('/paper:([^:]+)/', $key, $student_paper_matches);
$student_paper_id = (int)$student_paper_matches[1] ?? null;
preg_match('/language:([^:]+)/', $key, $language_matches);
$language = $language_matches[1] ?? null;
preg_match('/answer:(\d+)/', $key, $answer_matches);
$answer_id = isset($answer_matches[1]) ? (int)$answer_matches[1] : null;
preg_match('/coding_answer:(\d+)/', $key, $coding_answer_matches);
$coding_answer_id = isset($coding_answer_matches[1]) ? (int)$coding_answer_matches[1] : null;
$hashData = Redis::hgetall($key);
$data[] = [
'student_paper_id' => $student_paper_id,
'answer_id' => $answer_id,
'coding_answer_id' => $coding_answer_id,
'language' => $language,
'data' => $hashData,
];
}
$json_pretty_print = json_encode($data, JSON_PRETTY_PRINT);
$json = json_encode($data);
$folder = "codeInJSON/";
$answer_file_path = "{$folder}user_{$user_id}:paper_{$student_paper_id}.json";
Storage::makeDirectory($folder);
Storage::put($answer_file_path, $json_pretty_print);
Redis::XADD("code_checker", '*', ["data" => $json]);
}
}Editor is loading...
Leave a Comment