1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once 'Modules/Test/classes/inc.AssessmentConstants.php';
5include_once 'Modules/Test/classes/class.ilTestScoringGUI.php';
6
7/**
8 * ilTestScoringByQuestionsGUI
9 * @author     Michael Jansen <mjansen@databay.de>
10 * @author     Björn Heyser <bheyser@databay.de>
11 * @version    $Id$
12 * @ingroup    ModulesTest
13 * @extends    ilTestServiceGUI
14 */
15class ilTestScoringByQuestionsGUI extends ilTestScoringGUI
16{
17    const ONLY_FINALIZED = 1;
18    const EXCEPT_FINALIZED = 2;
19
20    /**
21     * @param ilObjTest $a_object
22     */
23    public function __construct(ilObjTest $a_object)
24    {
25        parent::__construct($a_object);
26    }
27
28    /**
29     * @return string
30     */
31    protected function getDefaultCommand()
32    {
33        return 'showManScoringByQuestionParticipantsTable';
34    }
35
36    /**
37     * @return string
38     */
39    protected function getActiveSubTabId()
40    {
41        return 'man_scoring_by_qst';
42    }
43
44    /**
45     * @param array $manPointsPost
46     */
47    protected function showManScoringByQuestionParticipantsTable($manPointsPost = array())
48    {
49        global $DIC;
50
51        $tpl = $DIC->ui()->mainTemplate();
52        $ilAccess = $DIC->access();
53
54        $DIC->tabs()->activateTab(ilTestTabsManager::TAB_ID_MANUAL_SCORING);
55
56        if (
57            false == $ilAccess->checkAccess("write", "", $this->ref_id) &&
58            false == $ilAccess->checkAccess("man_scoring_access", "", $this->ref_id)
59        ) {
60            ilUtil::sendInfo($this->lng->txt('cannot_edit_test'), true);
61            $this->ctrl->redirectByClass('ilobjtestgui', 'infoScreen');
62        }
63
64        iljQueryUtil::initjQuery();
65        ilYuiUtil::initPanel();
66        ilYuiUtil::initOverlay();
67
68        $mathJaxSetting = new ilSetting('MathJax');
69
70        if ($mathJaxSetting->get("enable")) {
71            $tpl->addJavaScript($mathJaxSetting->get("path_to_mathjax"));
72        }
73
74        $tpl->addJavaScript("./Services/JavaScript/js/Basic.js");
75        $tpl->addJavaScript("./Services/Form/js/Form.js");
76        $tpl->addJavascript('./Services/UIComponent/Modal/js/Modal.js');
77        $tpl->addCss($this->object->getTestStyleLocation("output"), "screen");
78        $this->lng->toJSMap(['answer' => $this->lng->txt('answer')]);
79
80        $table = new ilTestManScoringParticipantsBySelectedQuestionAndPassTableGUI($this);
81        $table->setManualScoringPointsPostData($manPointsPost);
82
83        $qst_id = $table->getFilterItemByPostVar('question')->getValue();
84        $passNr = $table->getFilterItemByPostVar('pass')->getValue();
85        $finalized_filter = $table->getFilterItemByPostVar('finalize_evaluation')->getValue();
86        $table_data = [];
87        $selected_questionData = null;
88        $complete_feedback = $this->object->getCompleteManualFeedback($qst_id);
89
90        if (is_numeric($qst_id)) {
91            $info = assQuestion::_getQuestionInfo($qst_id);
92            $selected_questionData = $info;
93        }
94
95        if ($selected_questionData && is_numeric($passNr)) {
96            $data = $this->object->getCompleteEvaluationData(false);
97            $participants = $data->getParticipants();
98            $participantData = new ilTestParticipantData($DIC->database(), $DIC->language());
99            $participantData->setActiveIdsFilter(array_keys($data->getParticipants()));
100            $participantData->setParticipantAccessFilter(
101                ilTestParticipantAccessFilter::getScoreParticipantsUserFilter($this->ref_id)
102            );
103            $participantData->load($this->object->getTestId());
104
105            foreach ($participantData->getActiveIds() as $active_id) {
106                $participant = $participants[$active_id];
107                $testResultData = $this->object->getTestResult($active_id, $passNr - 1);
108
109                foreach ($testResultData as $questionData) {
110                    $feedback = [];
111
112                    if (isset($complete_feedback[$active_id][$passNr - 1][$qst_id])) {
113                        $feedback = $complete_feedback[$active_id][$passNr - 1][$qst_id];
114                    }
115
116                    if (false == isset($feedback['finalized_evaluation'])) {
117                        $feedback['finalized_evaluation'] = "";
118                    }
119
120                    $check_filter =
121                        ($finalized_filter != self::ONLY_FINALIZED || $feedback['finalized_evaluation'] == 1) &&
122                        ($finalized_filter != self::EXCEPT_FINALIZED || $feedback['finalized_evaluation'] != 1);
123
124                    if (
125                        isset($questionData['qid']) &&
126                        $questionData['qid'] == $selected_questionData['question_id'] &&
127                        $check_filter
128                    ) {
129                        $table_data[] = [
130                            'pass_id' => $passNr - 1,
131                            'active_id' => $active_id,
132                            'qst_id' => $questionData['qid'],
133                            'reached_points' => assQuestion::_getReachedPoints($active_id, $questionData['qid'], $passNr - 1),
134                            'maximum_points' => assQuestion::_getMaximumPoints($questionData['qid']),
135                            'participant' => $participant,
136                            'feedback' => $feedback,
137                        ];
138                    }
139                }
140            }
141        } else {
142            $table->disable('header');
143        }
144
145        $table->setTitle($this->lng->txt('tst_man_scoring_by_qst'));
146
147        if ($selected_questionData) {
148            $maxpoints = assQuestion::_getMaximumPoints($selected_questionData['question_id']);
149            $table->setCurQuestionMaxPoints($maxpoints);
150            $maxpoints = ' (' . $maxpoints . ' ' . $this->lng->txt('points') . ')';
151            if ($maxpoints == 1) {
152                $maxpoints = ' (' . $maxpoints . ' ' . $this->lng->txt('point') . ')';
153            }
154
155            $table->setTitle(
156                $this->lng->txt('tst_man_scoring_by_qst') . ': ' . $selected_questionData['title'] . $maxpoints .
157                ' [' . $this->lng->txt('question_id_short') . ': ' . $selected_questionData['question_id'] . ']'
158            );
159        }
160
161        $table->setData($table_data);
162        $tpl->setContent($table->getHTML());
163    }
164
165    /**
166     * @param bool $ajax
167     */
168    protected function saveManScoringByQuestion($ajax = false)
169    {
170        global $DIC;
171        $ilAccess = $DIC->access();
172
173        if (
174            false == $ilAccess->checkAccess("write", "", $this->ref_id) &&
175            false == $ilAccess->checkAccess("man_scoring_access", "", $this->ref_id)
176        ) {
177            if ($ajax) {
178                echo $this->lng->txt('cannot_edit_test');
179                exit();
180            }
181
182            ilUtil::sendInfo($this->lng->txt('cannot_edit_test'), true);
183            $this->ctrl->redirectByClass('ilobjtestgui', 'infoScreen');
184        }
185
186        if (false == isset($_POST['scoring']) || false == is_array($_POST['scoring'])) {
187            ilUtil::sendFailure($this->lng->txt('tst_save_manscoring_failed_unknown'));
188            $this->showManScoringByQuestionParticipantsTable();
189            return;
190        }
191
192        $pass = key($_POST['scoring']);
193        $activeData = current($_POST['scoring']);
194        $participantData = new ilTestParticipantData($DIC->database(), $DIC->language());
195        $oneExceededMaxPoints = false;
196        $manPointsPost = [];
197        $skipParticipant = [];
198        $maxPointsByQuestionId = [];
199
200        $participantData->setActiveIdsFilter(array_keys($activeData));
201        $participantData->setParticipantAccessFilter(
202            ilTestParticipantAccessFilter::getScoreParticipantsUserFilter($this->ref_id)
203        );
204        $participantData->load($this->object->getTestId());
205
206        foreach ($participantData->getActiveIds() as $active_id) {
207            $questions = $activeData[$active_id];
208
209            // check for existing test result data
210            if (!$this->object->getTestResult($active_id, $pass)) {
211                if (false == isset($skipParticipant[$pass])) {
212                    $skipParticipant[$pass] = [];
213                }
214                $skipParticipant[$pass][$active_id] = true;
215
216                continue;
217            }
218
219            foreach ((array) $questions as $qst_id => $reached_points) {
220                $this->saveFeedback($active_id, $qst_id, $pass, $ajax);
221
222                if (false == isset($manPointsPost[$pass])) {
223                    $manPointsPost[$pass] = [];
224                }
225                if (false == isset($manPointsPost[$pass][$active_id])) {
226                    $manPointsPost[$pass][$active_id] = [];
227                }
228                $maxPointsByQuestionId[$qst_id] = assQuestion::_getMaximumPoints($qst_id);
229                $manPointsPost[$pass][$active_id][$qst_id] = $reached_points;
230                if ($reached_points > $maxPointsByQuestionId[$qst_id]) {
231                    $oneExceededMaxPoints = true;
232                }
233            }
234        }
235
236        if ($oneExceededMaxPoints) {
237            ilUtil::sendFailure(sprintf($this->lng->txt('tst_save_manscoring_failed'), $pass + 1));
238            $this->showManScoringByQuestionParticipantsTable($manPointsPost);
239            return;
240        }
241
242        $changed_one = false;
243        $lastAndHopefullyCurrentQuestionId = null;
244
245        foreach ($participantData->getActiveIds() as $active_id) {
246            $questions = $activeData[$active_id];
247            $update_participant = false;
248
249            if (false == $skipParticipant[$pass][$active_id]) {
250                foreach ((array) $questions as $qst_id => $reached_points) {
251                    $this->saveFeedback($active_id, $qst_id, $pass, $ajax);
252                    $update_participant = assQuestion::_setReachedPoints(
253                        $active_id,
254                        $qst_id,
255                        $reached_points,
256                        $maxPointsByQuestionId[$qst_id],
257                        $pass,
258                        1,
259                        $this->object->areObligationsEnabled()
260                    );
261                }
262
263                if ($update_participant) {
264                    $changed_one = true;
265                    $lastAndHopefullyCurrentQuestionId = $qst_id;
266
267                    ilLPStatusWrapper::_updateStatus(
268                        $this->object->getId(),
269                        ilObjTestAccess::_getParticipantId($active_id)
270                    );
271                }
272            }
273        }
274
275        $correction_feedback = [];
276        $correction_points = 0;
277
278        if ($changed_one) {
279            $qTitle = '';
280
281            if ($lastAndHopefullyCurrentQuestionId) {
282                $question = assQuestion::_instantiateQuestion($lastAndHopefullyCurrentQuestionId);
283                $qTitle = $question->getTitle();
284            }
285
286            $msg = sprintf(
287                $this->lng->txt('tst_saved_manscoring_by_question_successfully'),
288                $qTitle,
289                $pass + 1
290            );
291
292            ilUtil::sendSuccess($msg, true);
293
294            if (isset($active_id)) {
295                $correction_feedback = $this->object->getSingleManualFeedback($active_id, $qst_id, $pass);
296                $correction_points = assQuestion::_getReachedPoints($active_id, $qst_id, $pass);
297            }
298        }
299
300        if ($ajax && is_array($correction_feedback)) {
301            $correction_feedback['finalized_by'] = ilObjUser::_lookupFullname($correction_feedback['finalized_by_usr_id']);
302            $correction_feedback['finalized_on_date'] = '';
303
304            if (strlen($correction_feedback['finalized_tstamp']) > 0) {
305                $time = new ilDateTime($correction_feedback['finalized_tstamp'], IL_CAL_UNIX);
306                $correction_feedback['finalized_on_date'] = $time->get(IL_CAL_DATETIME);
307            }
308
309            if (!$correction_feedback['feedback']) {
310                $correction_feedback['feedback'] = [];
311            }
312
313            echo json_encode([ 'feedback' => $correction_feedback, 'points' => $correction_points, "translation" => ['yes' => $this->lng->txt('yes'), 'no' => $this->lng->txt('no')]]);
314            exit();
315        } else {
316            $this->showManScoringByQuestionParticipantsTable();
317        }
318    }
319
320    /**
321     *
322     */
323    protected function applyManScoringByQuestionFilter()
324    {
325        $table = new ilTestManScoringParticipantsBySelectedQuestionAndPassTableGUI($this);
326        $table->resetOffset();
327        $table->writeFilterToSession();
328        $this->showManScoringByQuestionParticipantsTable();
329    }
330
331    /**
332     *
333     */
334    protected function resetManScoringByQuestionFilter()
335    {
336        $table = new ilTestManScoringParticipantsBySelectedQuestionAndPassTableGUI($this);
337        $table->resetOffset();
338        $table->resetFilter();
339        $this->showManScoringByQuestionParticipantsTable();
340    }
341
342    protected function getAnswerDetail()
343    {
344        $active_id = (int) $_GET['active_id'];
345        $pass = (int) $_GET['pass_id'];
346        $question_id = (int) $_GET['qst_id'];
347
348        if (!$this->getTestAccess()->checkScoreParticipantsAccessForActiveId($active_id)) {
349            exit; // illegal ajax call
350        }
351
352        $data = $this->object->getCompleteEvaluationData(false);
353        $participant = $data->getParticipant($active_id);
354        $question_gui = $this->object->createQuestionGUI('', $question_id);
355        $tmp_tpl = new ilTemplate('tpl.il_as_tst_correct_solution_output.html', true, true, 'Modules/Test');
356        if ($question_gui->supportsIntermediateSolutionOutput() && $question_gui->hasIntermediateSolution($active_id, $pass)) {
357            $question_gui->setUseIntermediateSolution(true);
358            $aresult_output = $question_gui->getSolutionOutput($active_id, $pass, false, false, true, false, false, true);
359            $question_gui->setUseIntermediateSolution(false);
360            $tmp_tpl->setVariable('TEXT_ASOLUTION_OUTPUT', $this->lng->txt('autosavecontent'));
361            $tmp_tpl->setVariable('ASOLUTION_OUTPUT', $aresult_output);
362        }
363        $result_output = $question_gui->getSolutionOutput(
364            $active_id,
365            $pass,
366            false,
367            false,
368            false,
369            $this->object->getShowSolutionFeedback(),
370            false,
371            true
372        );
373        $max_points = $question_gui->object->getMaximumPoints();
374
375        $this->appendUserNameToModal($tmp_tpl, $participant);
376        $this->appendQuestionTitleToModal($tmp_tpl, $question_id, $max_points, $question_gui->object->getTitle());
377        $this->appendSolutionAndPointsToModal(
378            $tmp_tpl,
379            $result_output,
380            $question_gui->object->getReachedPoints($active_id, $pass),
381            $max_points
382        );
383        $this->appendFormToModal($tmp_tpl, $pass, $active_id, $question_id, $max_points);
384        $tmp_tpl->setVariable('TEXT_YOUR_SOLUTION', $this->lng->txt('answers_of') . ' ' . $participant->getName());
385        $suggested_solution = assQuestion::_getSuggestedSolutionOutput($question_id);
386        if ($this->object->getShowSolutionSuggested() && strlen($suggested_solution) > 0) {
387            $tmp_tpl->setVariable('TEXT_SOLUTION_HINT', $this->lng->txt("solution_hint"));
388            $tmp_tpl->setVariable("SOLUTION_HINT", assQuestion::_getSuggestedSolutionOutput($question_id));
389        }
390
391        $tmp_tpl->setVariable('TEXT_SOLUTION_OUTPUT', $this->lng->txt('question'));
392        $tmp_tpl->setVariable('TEXT_RECEIVED_POINTS', $this->lng->txt('scoring'));
393        $add_title = ' [' . $this->lng->txt('question_id_short') . ': ' . $question_id . ']';
394        $question_title = $this->object->getQuestionTitle($question_gui->object->getTitle());
395        $lng = $this->lng->txt('points');
396        if ($max_points == 1) {
397            $lng = $this->lng->txt('point');
398        }
399
400        $tmp_tpl->setVariable(
401            'QUESTION_TITLE',
402            $question_title . ' (' . $max_points . ' ' . $lng . ')' . $add_title
403        );
404        $tmp_tpl->setVariable('SOLUTION_OUTPUT', $result_output);
405
406        $tmp_tpl->setVariable(
407            'RECEIVED_POINTS',
408            sprintf(
409                $this->lng->txt('part_received_a_of_b_points'),
410                $question_gui->object->getReachedPoints($active_id, $pass),
411                $max_points
412            )
413        );
414
415        echo $tmp_tpl->get();
416        exit();
417    }
418
419    /**
420     *
421     */
422    public function checkConstraintsBeforeSaving()
423    {
424        $this->saveManScoringByQuestion(true);
425    }
426
427    /**
428     * @param ilTemplate $tmp_tpl
429     * @param $participant
430     */
431    private function appendUserNameToModal($tmp_tpl, $participant)
432    {
433        global $DIC;
434        $ilAccess = $DIC->access();
435
436        $tmp_tpl->setVariable(
437            'TEXT_YOUR_SOLUTION',
438            $this->lng->txt('answers_of') . ' ' . $participant->getName()
439        );
440
441        if (
442            $this->object->anonymity == 1 ||
443            ($this->object->getAnonymity() == 2 && !$ilAccess->checkAccess('write', '', $this->object->getRefId()))
444        ) {
445            $tmp_tpl->setVariable(
446                'TEXT_YOUR_SOLUTION',
447                $this->lng->txt('answers_of') . ' ' . $this->lng->txt('anonymous')
448            );
449        }
450    }
451
452    /**
453     * @param ilTemplate $tmp_tpl
454     * @param $question_id
455     * @param $max_points
456     * @param $title
457     */
458    private function appendQuestionTitleToModal($tmp_tpl, $question_id, $max_points, $title)
459    {
460        $add_title = ' [' . $this->lng->txt('question_id_short') . ': ' . $question_id . ']';
461        $question_title = $this->object->getQuestionTitle($title);
462        $lng = $this->lng->txt('points');
463        if ($max_points == 1) {
464            $lng = $this->lng->txt('point');
465        }
466
467        $tmp_tpl->setVariable(
468            'QUESTION_TITLE',
469            $question_title . ' (' . $max_points . ' ' . $lng . ')' . $add_title
470        );
471    }
472
473    /**
474     * @param ilTemplate $tmp_tpl
475     * @param $pass
476     * @param $active_id
477     * @param $question_id
478     * @param $max_points
479     */
480    private function appendFormToModal($tmp_tpl, $pass, $active_id, $question_id, $max_points)
481    {
482        global $DIC;
483
484        $ilCtrl = $DIC->ctrl();
485        $post_var = '[' . $pass . '][' . $active_id . '][' . $question_id . ']';
486        $scoring_post_var = 'scoring' . $post_var;
487        $reached_points = assQuestion::_getReachedPoints($active_id, $question_id, $pass);
488        $form = new ilPropertyFormGUI();
489        $feedback = $this->object->getSingleManualFeedback($active_id, $question_id, $pass);
490        $disable = false;
491        $form->setFormAction($ilCtrl->getFormAction($this, 'showManScoringByQuestionParticipantsTable'));
492        $form->setTitle($this->lng->txt('manscoring'));
493
494        if (isset($feedback['finalized_evaluation']) && $feedback['finalized_evaluation'] == 1) {
495            $disable = true;
496            $hidden_points = new ilHiddenInputGUI($scoring_post_var);
497            $scoring_post_var = $scoring_post_var . '_disabled';
498            $hidden_points->setValue($reached_points);
499            $form->addItem($hidden_points);
500        }
501
502        $tmp_tpl->setVariable('TINYMCE_ACTIVE', ilObjAdvancedEditing::_getRichTextEditor());
503        $text_area = new ilTextAreaInputGUI($this->lng->txt('set_manual_feedback'), 'm_feedback' . $post_var);
504        $feedback_text = '';
505        if (array_key_exists('feedback', $feedback)) {
506            $feedback_text = $feedback['feedback'];
507        }
508        $text_area->setDisabled($disable);
509        $text_area->setValue($feedback_text);
510        $form->addItem($text_area);
511
512        $reached_points_form = new ilNumberInputGUI($this->lng->txt('tst_change_points_for_question'), $scoring_post_var);
513        $reached_points_form->allowDecimals(true);
514        $reached_points_form->setSize(5);
515        $reached_points_form->setMaxValue($max_points, true);
516        $reached_points_form->setMinValue(0);
517        $reached_points_form->setDisabled($disable);
518        $reached_points_form->setValue($reached_points);
519        $form->addItem($reached_points_form);
520
521        $hidden_points = new ilHiddenInputGUI('qst_max_points');
522        $hidden_points->setValue($max_points);
523        $form->addItem($hidden_points);
524
525        $hidden_points_name = new ilHiddenInputGUI('qst_hidden_points_name');
526        $hidden_points_name->setValue('scoring' . $post_var);
527        $form->addItem($hidden_points_name);
528
529        $hidden_feedback_name = new ilHiddenInputGUI('qst_hidden_feedback_name');
530        $hidden_feedback_name->setValue('m_feedback' . $post_var);
531        $form->addItem($hidden_feedback_name);
532
533        $hidden_feedback_id = new ilHiddenInputGUI('qst_hidden_feedback_id');
534        $post_id = '__' . $pass . '____' . $active_id . '____' . $question_id . '__';
535        $hidden_feedback_id->setValue('m_feedback' . $post_id);
536        $form->addItem($hidden_feedback_id);
537
538        $evaluated = new ilCheckboxInputGUI($this->lng->txt('finalized_evaluation'), 'evaluated' . $post_var);
539        if (isset($feedback['finalized_evaluation']) && $feedback['finalized_evaluation'] == 1) {
540            $evaluated->setChecked(true);
541        }
542        $form->addItem($evaluated);
543
544        $form->addCommandButton('checkConstraintsBeforeSaving', $this->lng->txt('save'));
545
546        $tmp_tpl->setVariable(
547            'MANUAL_FEEDBACK',
548            $form->getHTML()
549        );
550        $tmp_tpl->setVariable(
551            'MODAL_AJAX_URL',
552            $this->ctrl->getLinkTarget($this, 'checkConstraintsBeforeSaving', '', true, false)
553        );
554        $tmp_tpl->setVariable(
555            'INFO_TEXT_MAX_POINTS_EXCEEDS',
556            sprintf($this->lng->txt('tst_manscoring_maxpoints_exceeded_input_alert'), $max_points)
557        );
558    }
559
560    /**
561     * @param ilTemplate $tmp_tpl
562     * @param $result_output
563     * @param $reached_points
564     * @param $max_points
565     */
566    private function appendSolutionAndPointsToModal($tmp_tpl, $result_output, $reached_points, $max_points)
567    {
568        $tmp_tpl->setVariable(
569            'SOLUTION_OUTPUT',
570            $result_output
571        );
572        $tmp_tpl->setVariable(
573            'RECEIVED_POINTS',
574            sprintf(
575                $this->lng->txt('part_received_a_of_b_points'),
576                $reached_points,
577                $max_points
578            )
579        );
580    }
581
582    /**
583     * @param $active_id
584     * @param $qst_id
585     * @param $pass
586     * @param $is_single_feedback
587     */
588    protected function saveFeedback($active_id, $qst_id, $pass, $is_single_feedback)
589    {
590        $feedback = null;
591        if ($this->doesValueExistsInPostArray('feedback', $active_id, $qst_id, $pass)) {
592            $feedback = ilUtil::stripSlashes($_POST['feedback'][$pass][$active_id][$qst_id]);
593        } elseif ($this->doesValueExistsInPostArray('m_feedback', $active_id, $qst_id, $pass)) {
594            $feedback = ilUtil::stripSlashes($_POST['m_feedback'][$pass][$active_id][$qst_id]);
595        }
596        $this->saveFinalization($active_id, $qst_id, $pass, $feedback, $is_single_feedback);
597    }
598
599    /**
600     * @param $active_id
601     * @param $qst_id
602     * @param $pass
603     * @param $feedback
604     */
605    protected function saveFinalization($active_id, $qst_id, $pass, $feedback, $is_single_feedback)
606    {
607        $evaluated = false;
608        if ($this->doesValueExistsInPostArray('evaluated', $active_id, $qst_id, $pass)) {
609            $evaluated = (int) $_POST['evaluated'][$pass][$active_id][$qst_id];
610            if ($evaluated === 1) {
611                $evaluated = true;
612            }
613        }
614        $this->object->saveManualFeedback($active_id, $qst_id, $pass, $feedback, $evaluated, $is_single_feedback);
615    }
616    /**
617     * @param $post_value
618     * @param $active_id
619     * @param $qst_id
620     * @param $pass
621     * @return bool
622     */
623    protected function doesValueExistsInPostArray($post_value, $active_id, $qst_id, $pass)
624    {
625        return (
626            isset($_POST[$post_value][$pass][$active_id][$qst_id]) &&
627            strlen($_POST[$post_value][$pass][$active_id][$qst_id]) > 0
628        );
629    }
630}
631