| 22 | | select e.id into e_id |
| 23 | | from enrollment e |
| 24 | | where e.user_id = write_review.user_id |
| 25 | | and e.course_version_id = write_review.course_version_id |
| 26 | | limit 1; |
| | 32 | -- check all questions belong to the quiz |
| | 33 | if exists (select 1 |
| | 34 | from jsonb_array_elements(p_answers) a |
| | 35 | where not exists (select 1 |
| | 36 | from quiz_question |
| | 37 | where id = (a ->> 'question_id')::bigint |
| | 38 | and quiz_id = p_quiz_id)) then |
| | 39 | raise exception 'One or more questions do not belong to quiz %', p_quiz_id; |
| | 40 | end if; |
| 28 | | -- Validate enrollment exists |
| 29 | | if e_id is null then |
| 30 | | raise exception 'No enrollment found for user % on course version %', |
| 31 | | user_id, course_version_id |
| 32 | | using errcode = 'NO_DATA_FOUND'; |
| 33 | | end if; |
| | 42 | -- check all answer options belong to their respective questions |
| | 43 | if exists (select 1 |
| | 44 | from jsonb_array_elements(p_answers) a |
| | 45 | where not exists (select 1 |
| | 46 | from quiz_answer_option |
| | 47 | where id = (a ->> 'answer_option_id')::bigint |
| | 48 | and quiz_question_id = (a ->> 'question_id')::bigint)) then |
| | 49 | raise exception 'One or more answer options do not belong to their question'; |
| | 50 | end if; |
| 39 | | return r; |
| 40 | | end; |
| 41 | | $$ language plpgsql; |
| | 58 | select coalesce(sum(points), 0) |
| | 59 | into v_total_points |
| | 60 | from quiz_question |
| | 61 | where quiz_id = p_quiz_id; |
| | 62 | |
| | 63 | select coalesce(sum(qq.points), 0) |
| | 64 | into v_earned_points |
| | 65 | from jsonb_array_elements(p_answers) a |
| | 66 | join quiz_question qq on qq.id = (a ->> 'question_id')::bigint |
| | 67 | join quiz_answer_option qao on qao.id = (a ->> 'answer_option_id')::bigint |
| | 68 | where qao.correct = true; |
| | 69 | |
| | 70 | select passing_score |
| | 71 | into v_passing_score |
| | 72 | from quiz |
| | 73 | where id = p_quiz_id; |
| | 74 | |
| | 75 | v_score := case |
| | 76 | when v_total_points > 0 |
| | 77 | then ((v_earned_points::numeric / v_total_points) * 100)::int |
| | 78 | else 0 end; |
| | 79 | |
| | 80 | v_passed := v_score >= v_passing_score; |
| | 81 | |
| | 82 | insert into quiz_attempt (attempt_number, completed_at, status, score, total_points, earned_points, passed, quiz_id, |
| | 83 | enrollment_id) |
| | 84 | values (v_attempt_num, now(), |
| | 85 | case when v_passed then 'PASSED' else 'FAILED' end, |
| | 86 | v_score, v_total_points, v_earned_points, v_passed, |
| | 87 | p_quiz_id, p_enrollment_id) |
| | 88 | returning id into v_attempt_id; |
| | 89 | |
| | 90 | insert into quiz_attempt_answer (correct, quiz_question_id, quiz_attempt_id) |
| | 91 | select qao.correct, |
| | 92 | (a ->> 'question_id')::bigint, |
| | 93 | v_attempt_id |
| | 94 | from jsonb_array_elements(p_answers) a |
| | 95 | join quiz_answer_option qao on qao.id = (a ->> 'answer_option_id')::bigint; |
| | 96 | |
| | 97 | insert into quiz_attempt_answer_selected_options (quiz_attempt_answer_id, quiz_answer_option_id) |
| | 98 | select qaa.id, (a ->> 'answer_option_id')::bigint |
| | 99 | from jsonb_array_elements(p_answers) a |
| | 100 | join quiz_attempt_answer qaa |
| | 101 | on qaa.quiz_attempt_id = v_attempt_id |
| | 102 | and qaa.quiz_question_id = (a ->> 'question_id')::bigint; |
| | 103 | |
| | 104 | return v_attempt_id; |
| | 105 | end; |
| | 106 | $$; |