protected function run_table_test($columns, $headers, $sortable, $collapsible, $suppress, $nosorting, $data, $pagesize) { $table = new flexible_table('tablelib_test'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl('/invalid.php'); $table->sortable($sortable); $table->collapsible($collapsible); foreach ($suppress as $column) { $table->column_suppress($column); } foreach ($nosorting as $column) { $table->no_sorting($column); } $table->setup(); $table->pagesize($pagesize, count($data)); foreach ($data as $row) { $table->add_data_keyed($row); } $table->finish_output(); }
public function list_transactions($transactions) { global $CFG; $table = new flexible_table('local-magentoconnector-transaction-list'); $table->define_columns(array('user', 'course', 'transactionid', 'timestamp')); $table->define_headers(array(get_string('user'), get_string('course'), get_string('transactionid', 'local_magentoconnector'), get_string('timestamp', 'local_magentoconnector'))); $table->define_baseurl(new moodle_url('/local/magentoconnector/viewtransactions.php')); $table->sortable(false); $table->collapsible(false); $table->column_class('user', 'user'); $table->column_class('course', 'course'); $table->column_class('transactionid', 'transactionid'); $table->column_class('timestamp', 'timestamp'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'local-magentoconnector-transaction-list'); $table->set_attribute('class', 'local-magentoconnector-transaction-list generaltable'); $table->set_attribute('width', '100%'); $table->setup(); if ($transactions) { $user = new stdClass(); foreach ($transactions as $transaction) { $user->id = $transaction->userid; $user->firstname = $transaction->firstname; $user->lastname = $transaction->lastname; $user->firstnamephonetic = $transaction->firstnamephonetic; $user->lastnamephonetic = $transaction->lastnamephonetic; $user->middlename = $transaction->middlename; $user->alternatename = $transaction->alternatename; $row = array(); $userurl = new moodle_url($CFG->wwwroot . '/user/profile.php', array('id' => $user->id)); $row[] = html_writer::link($userurl, fullname($user), array('title' => get_string('viewprofile'))); $courseurl = new moodle_url($CFG->wwwroot . '/course/view.php', array('id' => $transaction->courseid)); $row[] = html_writer::link($courseurl, $transaction->course, array('title' => $transaction->course)); $row[] = $transaction->ordernum; $row[] = userdate($transaction->timestamp, get_string('strftimedatetime')); $table->add_data($row); } } $table->print_html(); }
/** * displays the full report * @param \stdClass $scorm full SCORM object * @param \stdClass $cm - full course_module object * @param \stdClass $course - full course object * @param string $download - type of download being requested */ public function display($scorm, $cm, $course, $download) { global $CFG, $DB, $OUTPUT, $PAGE; $contextmodule = \context_module::instance($cm->id); $action = optional_param('action', '', PARAM_ALPHA); $attemptids = optional_param_array('attemptid', array(), PARAM_RAW); $attemptsmode = optional_param('attemptsmode', SCORM_REPORT_ATTEMPTS_ALL_STUDENTS, PARAM_INT); $PAGE->set_url(new \moodle_url($PAGE->url, array('attemptsmode' => $attemptsmode))); if ($action == 'delete' && has_capability('mod/scorm:deleteresponses', $contextmodule) && confirm_sesskey()) { if (scorm_delete_responses($attemptids, $scorm)) { // Delete responses. echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess'); } } // Find out current groups mode. $currentgroup = groups_get_activity_group($cm, true); // Detailed report. $mform = new \mod_scorm_report_objectives_settings($PAGE->url, compact('currentgroup')); if ($fromform = $mform->get_data()) { $pagesize = $fromform->pagesize; $showobjectivescore = $fromform->objectivescore; set_user_preference('scorm_report_pagesize', $pagesize); set_user_preference('scorm_report_objectives_score', $showobjectivescore); } else { $pagesize = get_user_preferences('scorm_report_pagesize', 0); $showobjectivescore = get_user_preferences('scorm_report_objectives_score', 0); } if ($pagesize < 1) { $pagesize = SCORM_REPORT_DEFAULT_PAGE_SIZE; } // Select group menu. $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['objectivescore'] = $showobjectivescore; $mform->set_data($displayoptions + array('pagesize' => $pagesize)); if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used. if (!$download) { groups_print_activity_menu($cm, new \moodle_url($PAGE->url, $displayoptions)); } } $formattextoptions = array('context' => \context_course::instance($course->id)); // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/scorm:deleteresponses', $contextmodule) && $attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO; // Select the students. $nostudents = false; if (empty($currentgroup)) { // All users who can attempt scoes. if (!($students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', '', '', false))) { echo $OUTPUT->notification(get_string('nostudentsyet')); $nostudents = true; $allowedlist = ''; } else { $allowedlist = array_keys($students); } unset($students); } else { // All users who can attempt scoes and who are in the currently selected group. $groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', 'u.id', '', '', '', $currentgroup, '', false); if (!$groupstudents) { echo $OUTPUT->notification(get_string('nostudentsingroup')); $nostudents = true; $groupstudents = array(); } $allowedlist = array_keys($groupstudents); unset($groupstudents); } if (!$nostudents) { // Now check if asked download of data. $coursecontext = \context_course::instance($course->id); if ($download) { $filename = clean_filename("{$course->shortname} " . format_string($scorm->name, true, $formattextoptions)); } // Define table columns. $columns = array(); $headers = array(); if (!$download && $candelete) { $columns[] = 'checkbox'; $headers[] = null; } if (!$download && $CFG->grade_report_showuserimage) { $columns[] = 'picture'; $headers[] = ''; } $columns[] = 'fullname'; $headers[] = get_string('name'); $extrafields = get_extra_user_fields($coursecontext); foreach ($extrafields as $field) { $columns[] = $field; $headers[] = get_user_field_name($field); } $columns[] = 'attempt'; $headers[] = get_string('attempt', 'scorm'); $columns[] = 'start'; $headers[] = get_string('started', 'scorm'); $columns[] = 'finish'; $headers[] = get_string('last', 'scorm'); $columns[] = 'score'; $headers[] = get_string('score', 'scorm'); $scoes = $DB->get_records('scorm_scoes', array("scorm" => $scorm->id), 'sortorder, id'); foreach ($scoes as $sco) { if ($sco->launch != '') { $columns[] = 'scograde' . $sco->id; $headers[] = format_string($sco->title, '', $formattextoptions); } } $params = array(); list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED); // Construct the SQL. $select = 'SELECT DISTINCT ' . $DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)') . ' AS uniqueid, '; $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' . \user_picture::fields('u', array('idnumber'), 'userid') . get_extra_user_fields_sql($coursecontext, 'u', '', array('email', 'idnumber')) . ' '; // This part is the same for all cases - join users and scorm_scoes_track tables. $from = 'FROM {user} u '; $from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = ' . $scorm->id; switch ($attemptsmode) { case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts. $where = ' WHERE u.id ' . $usql . ' AND st.userid IS NOT NULL'; break; case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts. $where = ' WHERE u.id ' . $usql . ' AND st.userid IS NULL'; break; case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts. $where = ' WHERE u.id ' . $usql . ' AND (st.userid IS NOT NULL OR st.userid IS NULL)'; break; } $countsql = 'SELECT COUNT(DISTINCT(' . $DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)') . ')) AS nbresults, '; $countsql .= 'COUNT(DISTINCT(' . $DB->sql_concat('u.id', '\'#\'', 'st.attempt') . ')) AS nbattempts, '; $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers '; $countsql .= $from . $where; $nbmaincolumns = count($columns); // Get number of main columns used. $objectives = get_scorm_objectives($scorm->id); $nosort = array(); foreach ($objectives as $scoid => $sco) { foreach ($sco as $id => $objectivename) { $colid = $scoid . 'objectivestatus' . $id; $columns[] = $colid; $nosort[] = $colid; if (!$displayoptions['objectivescore']) { // Display the objective name only. $headers[] = $objectivename; } else { // Display the objective status header with a "status" suffix to avoid confusion. $headers[] = $objectivename . ' ' . get_string('status', 'scormreport_objectives'); // Now print objective score headers. $colid = $scoid . 'objectivescore' . $id; $columns[] = $colid; $nosort[] = $colid; $headers[] = $objectivename . ' ' . get_string('score', 'scormreport_objectives'); } } } $emptycell = ''; // Used when an empty cell is being printed - in html we add a space. if (!$download) { $emptycell = ' '; $table = new \flexible_table('mod-scorm-report'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl($PAGE->url); $table->sortable(true); $table->collapsible(true); // This is done to prevent redundant data, when a user has multiple attempts. $table->column_suppress('picture'); $table->column_suppress('fullname'); foreach ($extrafields as $field) { $table->column_suppress($field); } foreach ($nosort as $field) { $table->no_sorting($field); } $table->no_sorting('start'); $table->no_sorting('finish'); $table->no_sorting('score'); $table->no_sorting('checkbox'); $table->no_sorting('picture'); foreach ($scoes as $sco) { if ($sco->launch != '') { $table->no_sorting('scograde' . $sco->id); } } $table->column_class('picture', 'picture'); $table->column_class('fullname', 'bold'); $table->column_class('score', 'bold'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over. $table->setup(); } else { if ($download == 'ODS') { require_once "{$CFG->libdir}/odslib.class.php"; $filename .= ".ods"; // Creating a workbook. $workbook = new \MoodleODSWorkbook("-"); // Sending HTTP headers. $workbook->send($filename); // Creating the first worksheet. $sheettitle = get_string('report', 'scorm'); $myxls = $workbook->add_worksheet($sheettitle); // Format types. $format = $workbook->add_format(); $format->set_bold(0); $formatbc = $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb = $workbook->add_format(); $formatb->set_bold(1); $formaty = $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc = $workbook->add_format(); $formatc->set_align('center'); $formatr = $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg = $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers. $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'Excel') { require_once "{$CFG->libdir}/excellib.class.php"; $filename .= ".xls"; // Creating a workbook. $workbook = new \MoodleExcelWorkbook("-"); // Sending HTTP headers. $workbook->send($filename); // Creating the first worksheet. $sheettitle = get_string('report', 'scorm'); $myxls = $workbook->add_worksheet($sheettitle); // Format types. $format = $workbook->add_format(); $format->set_bold(0); $formatbc = $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb = $workbook->add_format(); $formatb->set_bold(1); $formaty = $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc = $workbook->add_format(); $formatc->set_align('center'); $formatr = $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg = $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'CSV') { $csvexport = new \csv_export_writer("tab"); $csvexport->set_filename($filename, ".txt"); $csvexport->add_data($headers); } } } } if (!$download) { $sort = $table->get_sql_sort(); } else { $sort = ''; } // Fix some wired sorting. if (empty($sort)) { $sort = ' ORDER BY uniqueid'; } else { $sort = ' ORDER BY ' . $sort; } if (!$download) { // Add extra limits due to initials bar. list($twhere, $tparams) = $table->get_sql_where(); if ($twhere) { $where .= ' AND ' . $twhere; // Initial bar. $params = array_merge($params, $tparams); } if (!empty($countsql)) { $count = $DB->get_record_sql($countsql, $params); $totalinitials = $count->nbresults; if ($twhere) { $countsql .= ' AND ' . $twhere; } $count = $DB->get_record_sql($countsql, $params); $total = $count->nbresults; } $table->pagesize($pagesize, $total); echo \html_writer::start_div('scormattemptcounts'); if ($count->nbresults == $count->nbattempts) { echo get_string('reportcountattempts', 'scorm', $count); } else { if ($count->nbattempts > 0) { echo get_string('reportcountallattempts', 'scorm', $count); } else { echo $count->nbusers . ' ' . get_string('users'); } } echo \html_writer::end_div(); } // Fetch the attempts. if (!$download) { $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params, $table->get_page_start(), $table->get_page_size()); echo \html_writer::start_div('', array('id' => 'scormtablecontainer')); if ($candelete) { // Start form. $strreallydel = addslashes_js(get_string('deleteattemptcheck', 'scorm')); echo \html_writer::start_tag('form', array('id' => 'attemptsform', 'method' => 'post', 'action' => $PAGE->url->out(false), 'onsubmit' => 'return confirm("' . $strreallydel . '");')); echo \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'delete')); echo \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); echo \html_writer::start_div('', array('style' => 'display: none;')); echo \html_writer::input_hidden_params($PAGE->url); echo \html_writer::end_div(); echo \html_writer::start_div(); } $table->initialbars($totalinitials > 20); // Build table rows. } else { $attempts = $DB->get_records_sql($select . $from . $where . $sort, $params); } if ($attempts) { foreach ($attempts as $scouser) { $row = array(); if (!empty($scouser->attempt)) { $timetracks = scorm_get_sco_runtime($scorm->id, false, $scouser->userid, $scouser->attempt); } else { $timetracks = ''; } if (in_array('checkbox', $columns)) { if ($candelete && !empty($timetracks->start)) { $row[] = \html_writer::checkbox('attemptid[]', $scouser->userid . ':' . $scouser->attempt, false); } else { if ($candelete) { $row[] = ''; } } } if (in_array('picture', $columns)) { $user = new \stdClass(); $additionalfields = explode(',', \user_picture::fields()); $user = username_load_fields_from_object($user, $scouser, null, $additionalfields); $user->id = $scouser->userid; $row[] = $OUTPUT->user_picture($user, array('courseid' => $course->id)); } if (!$download) { $url = new \moodle_url('/user/view.php', array('id' => $scouser->userid, 'course' => $course->id)); $row[] = \html_writer::link($url, fullname($scouser)); } else { $row[] = fullname($scouser); } foreach ($extrafields as $field) { $row[] = s($scouser->{$field}); } if (empty($timetracks->start)) { $row[] = '-'; $row[] = '-'; $row[] = '-'; $row[] = '-'; } else { if (!$download) { $url = new \moodle_url('/mod/scorm/report/userreport.php', array('id' => $cm->id, 'user' => $scouser->userid, 'attempt' => $scouser->attempt)); $row[] = \html_writer::link($url, $scouser->attempt); } else { $row[] = $scouser->attempt; } if ($download == 'ODS' || $download == 'Excel') { $row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig")); } else { $row[] = userdate($timetracks->start); } if ($download == 'ODS' || $download == 'Excel') { $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig')); } else { $row[] = userdate($timetracks->finish); } $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt); } // Print out all scores of attempt. foreach ($scoes as $sco) { if ($sco->launch != '') { if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) { if ($trackdata->status == '') { $trackdata->status = 'notattempted'; } $strstatus = get_string($trackdata->status, 'scorm'); if ($trackdata->score_raw != '') { // If raw score exists, print it. $score = $trackdata->score_raw; // Add max score if it exists. if (isset($trackdata->score_max)) { $score .= '/' . $trackdata->score_max; } } else { // ...else print out status. $score = $strstatus; } if (!$download) { $url = new \moodle_url('/mod/scorm/report/userreporttracks.php', array('id' => $cm->id, 'scoid' => $sco->id, 'user' => $scouser->userid, 'attempt' => $scouser->attempt)); $row[] = \html_writer::img($OUTPUT->pix_url($trackdata->status, 'scorm'), $strstatus, array('title' => $strstatus)) . \html_writer::empty_tag('br') . \html_writer::link($url, $score, array('title' => get_string('details', 'scorm'))); } else { $row[] = $score; } // Iterate over tracks and match objective id against values. $scorm2004 = false; if (scorm_version_check($scorm->version, SCORM_13)) { $scorm2004 = true; $objectiveprefix = "cmi.objectives."; } else { $objectiveprefix = "cmi.objectives_"; } $keywords = array(".id", $objectiveprefix); $objectivestatus = array(); $objectivescore = array(); foreach ($trackdata as $name => $value) { if (strpos($name, $objectiveprefix) === 0 && strrpos($name, '.id') !== false) { $num = trim(str_ireplace($keywords, '', $name)); if (is_numeric($num)) { if ($scorm2004) { $element = $objectiveprefix . $num . '.completion_status'; } else { $element = $objectiveprefix . $num . '.status'; } if (isset($trackdata->{$element})) { $objectivestatus[$value] = $trackdata->{$element}; } else { $objectivestatus[$value] = ''; } if ($displayoptions['objectivescore']) { $element = $objectiveprefix . $num . '.score.raw'; if (isset($trackdata->{$element})) { $objectivescore[$value] = $trackdata->{$element}; } else { $objectivescore[$value] = ''; } } } } } // Interaction data. if (!empty($objectives[$trackdata->scoid])) { foreach ($objectives[$trackdata->scoid] as $name) { if (isset($objectivestatus[$name])) { $row[] = s($objectivestatus[$name]); } else { $row[] = $emptycell; } if ($displayoptions['objectivescore']) { if (isset($objectivescore[$name])) { $row[] = s($objectivescore[$name]); } else { $row[] = $emptycell; } } } } // End of interaction data. } else { // If we don't have track data, we haven't attempted yet. $strstatus = get_string('notattempted', 'scorm'); if (!$download) { $row[] = \html_writer::img($OUTPUT->pix_url('notattempted', 'scorm'), $strstatus, array('title' => $strstatus)) . \html_writer::empty_tag('br') . $strstatus; } else { $row[] = $strstatus; } // Complete the empty cells. for ($i = 0; $i < count($columns) - $nbmaincolumns; $i++) { $row[] = $emptycell; } } } } if (!$download) { $table->add_data($row); } else { if ($download == 'Excel' or $download == 'ODS') { $colnum = 0; foreach ($row as $item) { $myxls->write($rownum, $colnum, $item, $format); $colnum++; } $rownum++; } else { if ($download == 'CSV') { $csvexport->add_data($row); } } } } if (!$download) { $table->finish_output(); if ($candelete) { echo \html_writer::start_tag('table', array('id' => 'commands')); echo \html_writer::start_tag('tr') . \html_writer::start_tag('td'); echo \html_writer::link('javascript:select_all_in(\'DIV\', null, \'scormtablecontainer\');', get_string('selectall', 'scorm')) . ' / '; echo \html_writer::link('javascript:deselect_all_in(\'DIV\', null, \'scormtablecontainer\');', get_string('selectnone', 'scorm')); echo ' '; echo \html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('deleteselected', 'scorm'), 'class' => 'btn btn-secondary')); echo \html_writer::end_tag('td') . \html_writer::end_tag('tr') . \html_writer::end_tag('table'); // Close form. echo \html_writer::end_tag('div'); echo \html_writer::end_tag('form'); } echo \html_writer::end_div(); if (!empty($attempts)) { echo \html_writer::start_tag('table', array('class' => 'boxaligncenter')) . \html_writer::start_tag('tr'); echo \html_writer::start_tag('td'); echo $OUTPUT->single_button(new \moodle_url($PAGE->url, array('download' => 'ODS') + $displayoptions), get_string('downloadods'), 'post', ['class' => 'm-t-1']); echo \html_writer::end_tag('td'); echo \html_writer::start_tag('td'); echo $OUTPUT->single_button(new \moodle_url($PAGE->url, array('download' => 'Excel') + $displayoptions), get_string('downloadexcel'), 'post', ['class' => 'm-t-1']); echo \html_writer::end_tag('td'); echo \html_writer::start_tag('td'); echo $OUTPUT->single_button(new \moodle_url($PAGE->url, array('download' => 'CSV') + $displayoptions), get_string('downloadtext'), 'post', ['class' => 'm-t-1']); echo \html_writer::end_tag('td'); echo \html_writer::start_tag('td'); echo \html_writer::end_tag('td'); echo \html_writer::end_tag('tr') . \html_writer::end_tag('table'); } } } else { if ($candelete && !$download) { echo \html_writer::end_div(); echo \html_writer::end_tag('form'); $table->finish_output(); } echo \html_writer::end_div(); } // Show preferences form irrespective of attempts are there to report or not. if (!$download) { $mform->set_data(compact('detailedrep', 'pagesize', 'attemptsmode')); $mform->display(); } if ($download == 'Excel' or $download == 'ODS') { $workbook->close(); exit; } else { if ($download == 'CSV') { $csvexport->download_file(); exit; } } } else { echo $OUTPUT->notification(get_string('noactivity', 'scorm')); } }
/** * Prints a table with users and their attempts * * @return void * @todo Add current grade to the table * Finnish documenting **/ function view_question($quiz, $question, $totalattempts, $ungraded) { global $CFG; $usercount = count($this->users); // set up table $tablecolumns = array('picture', 'fullname', 'timefinish', 'grade'); $tableheaders = array('', get_string('name'), get_string("completedon", "quiz"), ''); $table = new flexible_table('mod-quiz-report-grading'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($this->viewurl->out()); $table->sortable(true); $table->initialbars($usercount > 20); // will show initialbars if there are more than 20 users $table->pageable(true); $table->collapsible(true); $table->column_suppress('fullname'); $table->column_suppress('picture'); $table->column_suppress('grade'); $table->column_class('picture', 'picture'); // attributes in the table tag $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); $table->set_attribute('align', 'center'); //$table->set_attribute('width', '50%'); // get it ready! $table->setup(); list($select, $from, $where) = $this->attempts_sql($quiz->id, true, $question->id); if ($table->get_sql_where()) { // forgot what this does $where .= 'AND ' . $table->get_sql_where(); } // sorting of the table if ($sort = $table->get_sql_sort()) { $sort = 'ORDER BY ' . $sort; // seems like I would need to have u. or qa. infront of the ORDER BY attribues... but seems to work.. } else { // my default sort rule $sort = 'ORDER BY u.firstname, u.lastname, qa.timefinish ASC'; } // set up the pagesize $table->pagesize(QUIZ_REPORT_DEFAULT_PAGE_SIZE, $totalattempts); // get the attempts and process them if ($attempts = get_records_sql($select . $from . $where . $sort, $table->get_page_start(), $table->get_page_size())) { // grade all link $links = "<strong><a href=\"report.php?mode=grading&gradeall=1&q={$quiz->id}&questionid={$question->id}\">" . get_string('gradeall', 'quiz_grading', $totalattempts) . '</a></strong>'; if ($ungraded > 0) { $links .= "<br /><strong><a href=\"report.php?mode=grading&gradeungraded=1&q={$quiz->id}&questionid={$question->id}\">" . get_string('gradeungraded', 'quiz_grading', $ungraded) . '</a></strong>'; if ($ungraded > QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE) { $links .= "<br /><strong><a href=\"report.php?mode=grading&gradenextungraded=1&q={$quiz->id}&questionid={$question->id}\">" . get_string('gradenextungraded', 'quiz_grading', QUIZ_REPORT_DEFAULT_GRADING_PAGE_SIZE) . '</a></strong>'; } } $table->add_data_keyed(array('grade' => $links)); $table->add_separator(); foreach ($attempts as $attempt) { $picture = print_user_picture($attempt->userid, $quiz->course, $attempt->picture, false, true); // link to student profile $userlink = "<a href=\"{$CFG->wwwroot}/user/view.php?id={$attempt->userid}&course={$quiz->course}\">" . fullname($attempt, true) . '</a>'; $gradedclass = question_state_is_graded($attempt) ? ' class="highlightgraded" ' : ''; $gradedstring = question_state_is_graded($attempt) ? ' ' . get_string('graded', 'quiz_grading') : ''; // link for the attempt $attemptlink = "<a {$gradedclass}href=\"report.php?mode=grading&q={$quiz->id}&questionid={$question->id}&attemptid={$attempt->attemptid}\">" . userdate($attempt->timefinish, get_string('strftimedatetime')) . $gradedstring . '</a>'; // grade all attempts for this user $gradelink = "<a href=\"report.php?mode=grading&q={$quiz->id}&questionid={$question->id}&userid={$attempt->userid}\">" . get_string('grade') . '</a>'; $table->add_data(array($picture, $userlink, $attemptlink, $gradelink)); } $table->add_separator(); $table->add_data_keyed(array('grade' => $links)); // print everything here echo '<div id="tablecontainer">'; $table->print_html(); echo '</div>'; } else { notify(get_string('noattemptstoshow', 'quiz')); } }
/** * Display the report. */ function display($quiz, $cm, $course) { global $CFG, $db; // Define some strings $strreallydel = addslashes(get_string('deleteattemptcheck', 'quiz')); $strtimeformat = get_string('strftimedatetime'); $strreviewquestion = get_string('reviewresponse', 'quiz'); $context = get_context_instance(CONTEXT_MODULE, $cm->id); // Only print headers if not asked to download data if (!($download = optional_param('download', NULL))) { $this->print_header_and_tabs($cm, $course, $quiz, "overview"); } if ($attemptids = optional_param('attemptid', array(), PARAM_INT)) { //attempts need to be deleted require_capability('mod/quiz:deleteattempts', $context); $attemptids = optional_param('attemptid', array(), PARAM_INT); foreach ($attemptids as $attemptid) { add_to_log($course->id, 'quiz', 'delete attempt', 'report.php?id=' . $cm->id, $attemptid, $cm->id); quiz_delete_attempt($attemptid, $quiz); } //No need for a redirect, any attemptids that do not exist are ignored. //So no problem if the user refreshes and tries to delete the same attempts //twice. } // Work out some display options - whether there is feedback, and whether scores should be shown. $hasfeedback = quiz_has_feedback($quiz->id) && $quiz->grade > 1.0E-7 && $quiz->sumgrades > 1.0E-7; $fakeattempt = new stdClass(); $fakeattempt->preview = false; $fakeattempt->timefinish = $quiz->timeopen; $reviewoptions = quiz_get_reviewoptions($quiz, $fakeattempt, $context); $showgrades = $quiz->grade && $quiz->sumgrades && $reviewoptions->scores; $pageoptions = array(); $pageoptions['id'] = $cm->id; $pageoptions['q'] = $quiz->id; $pageoptions['mode'] = 'overview'; /// find out current groups mode $currentgroup = groups_get_activity_group($cm, true); $reporturl = new moodle_url($CFG->wwwroot . '/mod/quiz/report.php', $pageoptions); $qmsubselect = quiz_report_qm_filter_select($quiz); $mform = new mod_quiz_report_overview_settings($reporturl, compact('qmsubselect', 'quiz', 'currentgroup')); if ($fromform = $mform->get_data()) { $attemptsmode = $fromform->attemptsmode; if ($qmsubselect) { //control is not on the form if //the grading method is not set //to grade one attempt per user eg. for average attempt grade. $qmfilter = $fromform->qmfilter; } else { $qmfilter = 0; } set_user_preference('quiz_report_overview_detailedmarks', $fromform->detailedmarks); set_user_preference('quiz_report_pagesize', $fromform->pagesize); $detailedmarks = $fromform->detailedmarks; $pagesize = $fromform->pagesize; } else { $qmfilter = optional_param('qmfilter', 0, PARAM_INT); $attemptsmode = optional_param('attemptsmode', QUIZ_REPORT_ATTEMPTS_ALL, PARAM_INT); $detailedmarks = get_user_preferences('quiz_report_overview_detailedmarks', 1); $pagesize = get_user_preferences('quiz_report_pagesize', 0); } if ($attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL && $currentgroup) { $attemptsmode = QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH; } if (!$reviewoptions->scores) { $detailedmarks = 0; } if ($pagesize < 1) { $pagesize = QUIZ_REPORT_DEFAULT_PAGE_SIZE; } // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/quiz:deleteattempts', $context) && $attemptsmode != QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO; $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['qmfilter'] = $qmfilter; $reporturlwithdisplayoptions = new moodle_url($CFG->wwwroot . '/mod/quiz/report.php', $pageoptions + $displayoptions); if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used if (!$download) { groups_print_activity_menu($cm, $reporturlwithdisplayoptions->out()); } } // Print information on the number of existing attempts if (!$download) { //do not print notices when downloading if ($strattemptnum = quiz_num_attempt_summary($quiz, $cm, true, $currentgroup)) { echo '<div class="quizattemptcounts">' . $strattemptnum . '</div>'; } } $nostudents = false; if (!($students = get_users_by_capability($context, array('mod/quiz:reviewmyattempts', 'mod/quiz:attempt'), '', '', '', '', '', '', false))) { notify(get_string('nostudentsyet')); $nostudents = true; $studentslist = ''; } else { $studentslist = join(',', array_keys($students)); } if (empty($currentgroup)) { // all users who can attempt quizzes $groupstudentslist = ''; $allowedlist = $studentslist; } else { // all users who can attempt quizzes and who are in the currently selected group if (!($groupstudents = get_users_by_capability($context, 'mod/quiz:attempt', '', '', '', '', $currentgroup, '', false))) { notify(get_string('nostudentsingroup')); $nostudents = true; $groupstudents = array(); } $groupstudentslist = join(',', array_keys($groupstudents)); $allowedlist = $groupstudentslist; } if (!$nostudents || $attemptsmode == QUIZ_REPORT_ATTEMPTS_ALL) { // Print information on the grading method and whether we are displaying // if (!$download) { //do not print notices when downloading if ($strattempthighlight = quiz_report_highlighting_grading_method($quiz, $qmsubselect, $qmfilter)) { echo '<div class="quizattemptcounts">' . $strattempthighlight . '</div>'; } } // Now check if asked download of data if ($download) { $filename = clean_filename("{$course->shortname} " . format_string($quiz->name, true)); } // Define table columns $columns = array(); $headers = array(); if (!$download && $candelete) { $columns[] = 'checkbox'; $headers[] = NULL; } if (!$download && $CFG->grade_report_showuserimage) { $columns[] = 'picture'; $headers[] = ''; } $columns[] = 'fullname'; $headers[] = get_string('name'); if ($CFG->grade_report_showuseridnumber) { $columns[] = 'idnumber'; $headers[] = get_string('idnumber'); } $columns[] = 'timestart'; $headers[] = get_string('startedon', 'quiz'); $columns[] = 'timefinish'; $headers[] = get_string('timecompleted', 'quiz'); $columns[] = 'duration'; $headers[] = get_string('attemptduration', 'quiz'); if ($showgrades) { $columns[] = 'sumgrades'; $headers[] = get_string('grade', 'quiz') . '/' . $quiz->grade; } if ($detailedmarks) { // we want to display marks for all questions $questions = quiz_report_load_questions($quiz); foreach ($questions as $id => $question) { // Ignore questions of zero length $columns[] = 'qsgrade' . $id; $headers[] = '#' . $question->number; } } if ($hasfeedback) { $columns[] = 'feedbacktext'; $headers[] = get_string('feedback', 'quiz'); } if (!$download) { // Set up the table $table = new flexible_table('mod-quiz-report-overview-report'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl($reporturlwithdisplayoptions->out()); $table->sortable(true); $table->collapsible(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_suppress('idnumber'); $table->no_sorting('feedbacktext'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'bold'); $table->column_class('sumgrades', 'bold'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); } else { if ($download == 'ODS') { require_once "{$CFG->libdir}/odslib.class.php"; $filename .= ".ods"; // Creating a workbook $workbook = new MoodleODSWorkbook("-"); // Sending HTTP headers $workbook->send($filename); // Creating the first worksheet $sheettitle = get_string('reportoverview', 'quiz'); $myxls =& $workbook->add_worksheet($sheettitle); // format types $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'Excel') { require_once "{$CFG->libdir}/excellib.class.php"; $filename .= ".xls"; // Creating a workbook $workbook = new MoodleExcelWorkbook("-"); // Sending HTTP headers $workbook->send($filename); // Creating the first worksheet $sheettitle = get_string('reportoverview', 'quiz'); $myxls =& $workbook->add_worksheet($sheettitle); // format types $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'CSV') { $filename .= ".txt"; header("Content-Type: application/download\n"); header("Content-Disposition: attachment; filename=\"{$filename}\""); header("Expires: 0"); header("Cache-Control: must-revalidate,post-check=0,pre-check=0"); header("Pragma: public"); echo implode("\t", $headers) . " \n"; } } } } // Construct the SQL $select = 'SELECT ' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ' AS uniqueid, '; if ($qmsubselect) { $select .= "(CASE " . " WHEN {$qmsubselect} THEN 1" . " ELSE 0 " . "END) AS gradedattempt, "; } $select .= 'qa.uniqueid AS attemptuniqueid, qa.id AS attempt, ' . 'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, ' . 'qa.sumgrades, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration '; // This part is the same for all cases - join users and quiz_attempts tables $from = 'FROM ' . $CFG->prefix . 'user u '; $from .= 'LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON qa.userid = u.id AND qa.quiz = ' . $quiz->id; if ($qmsubselect && $qmfilter) { $from .= ' AND ' . $qmsubselect; } switch ($attemptsmode) { case QUIZ_REPORT_ATTEMPTS_ALL: // Show all attempts, including students who are no longer in the course $where = ' WHERE qa.id IS NOT NULL AND qa.preview = 0'; break; case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts $where = ' WHERE u.id IN (' . $allowedlist . ') AND qa.preview = 0 AND qa.id IS NOT NULL'; break; case QUIZ_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts $where = ' WHERE u.id IN (' . $allowedlist . ') AND qa.id IS NULL'; break; case QUIZ_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts $where = ' WHERE u.id IN (' . $allowedlist . ') AND (qa.preview = 0 OR qa.preview IS NULL)'; break; } $countsql = 'SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', 'COALESCE(qa.attempt, 0)') . ')) ' . $from . $where; // Add table joins so we can sort by question grade // unfortunately can't join all tables necessary to fetch all grades // to get the state for one question per attempt row we must join two tables // and there is a limit to how many joins you can have in one query. In MySQL it // is 61. This means that when having more than 29 questions the query will fail. // So we join just the tables needed to sort the attempts. if (!$download && ($sort = $table->get_sql_sort())) { if (!$download && $detailedmarks) { $from .= ' '; $sortparts = explode(',', $sort); $matches = array(); foreach ($sortparts as $sortpart) { $sortpart = trim($sortpart); if (preg_match('/^qsgrade([0-9]+)/', $sortpart, $matches)) { $qid = intval($matches[1]); $select .= ", qs{$qid}.grade AS qsgrade{$qid}, qs{$qid}.event AS qsevent{$qid}, qs{$qid}.id AS qsid{$qid}"; $from .= "LEFT JOIN {$CFG->prefix}question_sessions qns{$qid} ON qns{$qid}.attemptid = qa.uniqueid AND qns{$qid}.questionid = {$qid} "; $from .= "LEFT JOIN {$CFG->prefix}question_states qs{$qid} ON qs{$qid}.id = qns{$qid}.newgraded "; } else { $newsort[] = $sortpart; } } $select .= ' '; } } if ($download) { $sort = ''; } // Fix some wired sorting if (empty($sort)) { $sort = ' ORDER BY uniqueid'; } else { $sort = ' ORDER BY ' . $sort; } if (!$download) { // Add extra limits due to initials bar if ($table->get_sql_where()) { $where .= ' AND ' . $table->get_sql_where(); } if (!empty($countsql)) { $totalinitials = count_records_sql($countsql); if ($table->get_sql_where()) { $countsql .= ' AND ' . $table->get_sql_where(); } $total = count_records_sql($countsql); } $table->pagesize($pagesize, $total); } // Fetch the attempts if (!$download) { $attempts = get_records_sql($select . $from . $where . $sort, $table->get_page_start(), $table->get_page_size()); } else { $attempts = get_records_sql($select . $from . $where . $sort); } // Build table rows if (!$download) { $table->initialbars($totalinitials > 20); } if ($attempts) { if ($detailedmarks) { //get all the attempt ids we want to display on this page //or to export for download. $attemptids = array(); foreach ($attempts as $attempt) { if ($attempt->attemptuniqueid > 0) { $attemptids[] = $attempt->attemptuniqueid; } } $gradedstatesbyattempt = quiz_get_newgraded_states($attemptids, true, 'qs.id, qs.grade, qs.event, qs.question, qs.attempt'); } foreach ($attempts as $attempt) { // Username columns. $row = array(); if (in_array('checkbox', $columns)) { if ($attempt->attempt) { $row[] = '<input type="checkbox" name="attemptid[]" value="' . $attempt->attempt . '" />'; } else { $row[] = ''; } } if (in_array('picture', $columns)) { $attempt->id = $attempt->userid; $picture = print_user_picture($attempt, $course->id, NULL, false, true); $row[] = $picture; } if (!$download) { $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $attempt->userid . '&course=' . $course->id . '">' . fullname($attempt) . '</a>'; $row[] = $userlink; } else { $row[] = fullname($attempt); } if (in_array('idnumber', $columns)) { $row[] = $attempt->idnumber; } // Timing columns. if ($attempt->attempt) { $startdate = userdate($attempt->timestart, $strtimeformat); if (!$download) { $row[] = '<a href="review.php?q=' . $quiz->id . '&attempt=' . $attempt->attempt . '">' . $startdate . '</a>'; } else { $row[] = $startdate; } if ($attempt->timefinish) { $timefinish = userdate($attempt->timefinish, $strtimeformat); $duration = format_time($attempt->duration); if (!$download) { $row[] = '<a href="review.php?q=' . $quiz->id . '&attempt=' . $attempt->attempt . '">' . $timefinish . '</a>'; } else { $row[] = $timefinish; } $row[] = $duration; } else { $row[] = '-'; $row[] = get_string('unfinished', 'quiz'); } } else { $row[] = '-'; $row[] = '-'; $row[] = '-'; } // Grades columns. if ($showgrades) { if ($attempt->timefinish) { $grade = quiz_rescale_grade($attempt->sumgrades, $quiz); if (!$download) { $gradehtml = '<a href="review.php?q=' . $quiz->id . '&attempt=' . $attempt->attempt . '">' . $grade . '</a>'; if ($qmsubselect && $attempt->gradedattempt) { $gradehtml = '<div class="highlight">' . $gradehtml . '</div>'; } $row[] = $gradehtml; } else { $row[] = $grade; } } else { $row[] = '-'; } } if ($detailedmarks) { if (empty($attempt->attempt)) { foreach ($questions as $question) { $row[] = '-'; } } else { foreach ($questions as $questionid => $question) { $stateforqinattempt = $gradedstatesbyattempt[$attempt->attemptuniqueid][$questionid]; if (question_state_is_graded($stateforqinattempt)) { $grade = quiz_rescale_grade($stateforqinattempt->grade, $quiz); } else { $grade = '--'; } if (!$download) { $grade = $grade . '/' . quiz_rescale_grade($question->grade, $quiz); $row[] = link_to_popup_window('/mod/quiz/reviewquestion.php?state=' . $stateforqinattempt->id . '&number=' . $question->number, 'reviewquestion', $grade, 450, 650, $strreviewquestion, 'none', true); } else { $row[] = $grade; } } } } // Feedback column. if ($hasfeedback) { if ($attempt->timefinish) { $row[] = quiz_report_feedback_for_grade(quiz_rescale_grade($attempt->sumgrades, $quiz), $quiz->id); } else { $row[] = '-'; } } if (!$download) { $table->add_data($row); } else { if ($download == 'Excel' or $download == 'ODS') { $colnum = 0; foreach ($row as $item) { $myxls->write($rownum, $colnum, $item, $format); $colnum++; } $rownum++; } else { if ($download == 'CSV') { $text = implode("\t", $row); echo $text . " \n"; } } } } //end of adding data from attempts data to table / download //now add averages : if (!$download && $attempts) { $averagesql = "SELECT AVG(qg.grade) AS grade " . "FROM {$CFG->prefix}quiz_grades qg " . "WHERE quiz=" . $quiz->id; $table->add_separator(); if ($groupstudentslist) { $groupaveragesql = $averagesql . " AND qg.userid IN ({$groupstudentslist})"; $groupaverage = get_record_sql($groupaveragesql); $groupaveragerow = array('fullname' => get_string('groupavg', 'grades'), 'sumgrades' => round($groupaverage->grade, $quiz->decimalpoints), 'feedbacktext' => quiz_report_feedback_for_grade($groupaverage->grade, $quiz->id)); if ($detailedmarks && $qmsubselect) { $avggradebyq = quiz_get_average_grade_for_questions($quiz, $groupstudentslist); $groupaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download); } $table->add_data_keyed($groupaveragerow); } $overallaverage = get_record_sql($averagesql . " AND qg.userid IN ({$studentslist})"); $overallaveragerow = array('fullname' => get_string('overallaverage', 'grades'), 'sumgrades' => round($overallaverage->grade, $quiz->decimalpoints), 'feedbacktext' => quiz_report_feedback_for_grade($overallaverage->grade, $quiz->id)); if ($detailedmarks && $qmsubselect) { $avggradebyq = quiz_get_average_grade_for_questions($quiz, $studentslist); $overallaveragerow += quiz_format_average_grade_for_questions($avggradebyq, $questions, $quiz, $download); } $table->add_data_keyed($overallaveragerow); } if (!$download) { // Start form echo '<div id="tablecontainer">'; echo '<form id="attemptsform" method="post" action="' . $reporturlwithdisplayoptions->out(true) . '" onsubmit="return confirm(\'' . $strreallydel . '\');">'; echo '<div style="display: none;">'; echo $reporturlwithdisplayoptions->hidden_params_out(); echo '</div>'; echo '<div>'; // Print table $table->print_html(); // Print "Select all" etc. if (!empty($attempts) && $candelete) { echo '<table id="commands">'; echo '<tr><td>'; echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectall', 'quiz') . '</a> / '; echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectnone', 'quiz') . '</a> '; echo ' '; echo '<input type="submit" value="' . get_string('deleteselected', 'quiz_overview') . '"/>'; echo '</td></tr></table>'; } // Close form echo '</div>'; echo '</form></div>'; if (!empty($attempts)) { echo '<table class="boxaligncenter"><tr>'; echo '<td>'; print_single_button($reporturl->out(true), $pageoptions + $displayoptions + array('download' => 'ODS'), get_string('downloadods')); echo "</td>\n"; echo '<td>'; print_single_button($reporturl->out(true), $pageoptions + $displayoptions + array('download' => 'Excel'), get_string('downloadexcel')); echo "</td>\n"; echo '<td>'; print_single_button($reporturl->out(true), $pageoptions + $displayoptions + array('download' => 'CSV'), get_string('downloadtext')); echo "</td>\n"; echo "<td>"; helpbutton('overviewdownload', get_string('overviewdownload', 'quiz_overview'), 'quiz'); echo "</td>\n"; echo '</tr></table>'; } } } else { if (!$download) { $table->print_html(); } } if ($download == 'Excel' or $download == 'ODS') { $workbook->close(); exit; } else { if ($download == 'CSV') { exit; } } } if (!$download) { // Print display options $mform->set_data($displayoptions + compact('detailedmarks', 'pagesize')); $mform->display(); //should be quicker than a COUNT to test if there is at least one record : if ($showgrades && record_exists('quiz_grades', 'quiz', $quiz->id)) { $imageurl = $CFG->wwwroot . '/mod/quiz/report/overview/overviewgraph.php?id=' . $quiz->id; print_heading(get_string('overviewreportgraph', 'quiz_overview')); echo '<div class="mdl-align"><img src="' . $imageurl . '" alt="' . get_string('overviewreportgraph', 'quiz_overview') . '" /></div>'; } } return true; }
/** * Display all the submissions ready for grading */ function display_submissions() { global $CFG, $db, $USER; /* first we check to see if the form has just been submitted * to request user_preference updates */ if (isset($_POST['updatepref'])) { $perpage = optional_param('perpage', 10, PARAM_INT); $perpage = $perpage <= 0 ? 10 : $perpage; set_user_preference('webquestscorm_perpage', $perpage); set_user_preference('webquestscorm_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); } /* next we get perpage and quickgrade (allow quick grade) params * from database */ $perpage = get_user_preferences('webquestscorm_perpage', 10); $quickgrade = get_user_preferences('webquestscorm_quickgrade', 0); $teacherattempts = true; /// Temporary measure $page = optional_param('page', 0, PARAM_INT); $strsaveallfeedback = get_string('saveallfeedback', 'webquestscorm'); /// Some shortcuts to make the code read better $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet add_to_log($this->course->id, 'webquestscorm', 'view submission', 'editsubmissions.php?cmid=' . $this->cm->id . '&element=uploadedTasks&subelement=all', $this->wqid, $this->cm->id); $strwebquestscorms = get_string('modulenameplural', 'webquestscorm'); $strwebquestscorm = get_string('modulename', 'webquestscorm'); ///Position swapped if ($groupmode = groupmode($this->course, $this->cm)) { // Groups are being used $currentgroup = setup_and_print_groups($this->course, $groupmode, 'editsubmissions.php?cmid=' . $this->cm->id . '&element=uploadedTasks&subelement=all'); } else { $currentgroup = false; } /// Get all teachers and students if ($currentgroup) { $users = get_group_users($currentgroup); } else { //$users = get_users_by_capability($this->context, 'mod/webquestscorm:submit'); // everyone with this capability set to non-prohibit $users = get_course_students($this->course->id); } $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status'); $tableheaders = array('', get_string('fullname'), get_string('grade'), get_string('comment', 'webquestscorm'), get_string('lastmodified') . ' (' . $this->course->student . ')', get_string('lastmodified') . ' (' . $this->course->teacher . ')', get_string('status')); require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-webquestscorm-submissions'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/webquestscorm/editsubmissions.php?cmid=' . $this->cm->id . '&element=uploadedTasks&subelement=all&currentgroup=' . $currentgroup); $table->define_baseurl($CFG->wwwroot . '/mod/webquestscorm/editsubmissions.php?cmid=' . $this->cm->id . '&currentgroup=' . $currentgroup . '&element=uploadedTasks&subelement=all'); $table->sortable(true, 'lastname'); //sorted by lastname by default $table->collapsible(true); $table->initialbars(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('grade', 'grade'); $table->column_class('submissioncomment', 'comment'); $table->column_class('timemodified', 'timemodified'); $table->column_class('timemarked', 'timemarked'); $table->column_class('status', 'status'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'submissions'); $table->set_attribute('width', '90%'); $table->set_attribute('align', 'center'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); /// Check to see if groups are being used in this webquestscorm if (!$teacherattempts) { $teachers = get_course_teachers($this->course->id); if (!empty($teachers)) { $keys = array_keys($teachers); } foreach ($keys as $key) { unset($users[$key]); } } if (empty($users)) { print_heading(get_string('noattempts', 'webquestscorm')); print_footer($this->course); return true; } /// Construct the SQL if ($where = $table->get_sql_where()) { $where .= ' AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY ' . $sort; } $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, s.id AS submissionid, s.grade, s.submissioncomment, s.timemodified, s.timemarked '; $sql = 'FROM ' . $CFG->prefix . 'user u ' . 'LEFT JOIN ' . $CFG->prefix . 'webquestscorm_submissions s ON u.id = s.userid AND s.webquestscorm = ' . $this->wqid . ' ' . 'WHERE ' . $where . 'u.id IN (' . implode(',', array_keys($users)) . ') '; $table->pagesize($perpage, count($users)); ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next $offset = $page * $perpage; $strupdate = get_string('update'); $strgrade = get_string('grade'); $grademenu = make_grades_menu($this->wqgrade); if (($ausers = get_records_sql($select . $sql . $sort, $table->get_page_start(), $table->get_page_size())) !== false) { foreach ($ausers as $auser) { /// Calculate user status $auser->status = $auser->timemarked > 0 && $auser->timemarked >= $auser->timemodified; $picture = print_user_picture($auser->id, $this->course->id, $auser->picture, false, true); if (empty($auser->submissionid)) { $auser->grade = -1; //no submission yet } if (!empty($auser->submissionid)) { ///Prints student answer and student modified date ///attach file or print link to student answer, depending on the type of the webquestscorm. ///Refer to print_student_answer in inherited classes. if ($auser->timemodified > 0) { $studentmodified = '<div id="ts' . $auser->id . '">' . $this->print_student_answer($auser->id) . userdate($auser->timemodified) . '</div>'; } else { $studentmodified = '<div id="ts' . $auser->id . '"> </div>'; } ///Print grade, dropdown or text if ($auser->timemarked > 0) { $teachermodified = '<div id="tt' . $auser->id . '">' . userdate($auser->timemarked) . '</div>'; if ($quickgrade) { $grade = '<div id="g' . $auser->id . '">' . choose_from_menu(make_grades_menu($this->wqgrade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde'), '', -1, true, false, $tabindex++) . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; } } else { $teachermodified = '<div id="tt' . $auser->id . '"> </div>'; if ($quickgrade) { $grade = '<div id="g' . $auser->id . '">' . choose_from_menu(make_grades_menu($this->wqgrade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde'), '', -1, true, false, $tabindex++) . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; } } ///Print Comment if ($quickgrade) { $comment = '<div id="com' . $auser->id . '"><textarea tabindex="' . $tabindex++ . '" name="submissioncomment[' . $auser->id . ']" id="submissioncomment[' . $auser->id . ']">' . $auser->submissioncomment . '</textarea></div>'; } else { $comment = '<div id="com' . $auser->id . '">' . shorten_text(strip_tags($auser->submissioncomment), 15) . '</div>'; } } else { $studentmodified = '<div id="ts' . $auser->id . '"> </div>'; $teachermodified = '<div id="tt' . $auser->id . '"> </div>'; $status = '<div id="st' . $auser->id . '"> </div>'; if ($quickgrade) { // allow editing $grade = '<div id="g' . $auser->id . '">' . choose_from_menu(make_grades_menu($this->wqgrade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde'), '', -1, true, false, $tabindex++) . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">-</div>'; } if ($quickgrade) { $comment = '<div id="com' . $auser->id . '"><textarea tabindex="' . $tabindex++ . '" name="submissioncomment[' . $auser->id . ']" id="submissioncomment[' . $auser->id . ']">' . $auser->submissioncomment . '</textarea></div>'; } else { $comment = '<div id="com' . $auser->id . '"> </div>'; } } if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 $auser->status = 0; } else { $auser->status = 1; } $buttontext = $auser->status == 1 ? $strupdate : $strgrade; ///No more buttons, we use popups ;-). $button = link_to_popup_window('/mod/webquestscorm/submissions.php?cmid=' . $this->cm->id . '&element=uploadedTasks&userid=' . $auser->id . '&subelement=single' . '&offset=' . $offset++, 'grade' . $auser->id, $buttontext, 500, 780, $buttontext, 'none', true, 'button' . $auser->id); $status = '<div id="up' . $auser->id . '" class="s' . $auser->status . '">' . $button . '</div>'; $row = array($picture, fullname($auser), $grade, $comment, $studentmodified, $teachermodified, $status); $table->add_data($row); } } /// Print quickgrade form around the table if ($quickgrade) { echo '<form action="submissions.php?cmid=' . $this->cm->id . '" name="fastg" method="post">'; echo '<input type="hidden" name="id" value="' . $this->cm->id . '">'; echo '<input type="hidden" name="mode" value="fastgrade">'; echo '<input type="hidden" name="page" value="' . $page . '">'; echo '<input type="hidden" name="tabs" value="required" />'; echo '<p align="center"><input type="submit" name="fastg" value="' . get_string('saveallfeedback', 'webquestscorm') . '" /></p>'; } $table->print_html(); /// Print the whole table if ($quickgrade) { echo '<p align="center"><input type="submit" name="fastg" value="' . get_string('saveallfeedback', 'webquestscorm') . '" /></p>'; echo '</form>'; } /// End of fast grading form /// Mini form for setting user preference echo '<br />'; echo '<form name="options" action="submissions.php?cmid=' . $this->cm->id . '" method="post">'; echo '<input type="hidden" id="updatepref" name="updatepref" value="1" />'; echo '<input type="hidden" name="tabs" value="required" />'; echo '<table id="optiontable" align="center">'; echo '<tr align="right"><td>'; echo '<label for="perpage">' . get_string('pagesize', 'webquestscorm') . '</label>'; echo ':</td>'; echo '<td align="left">'; echo '<input type="text" id="perpage" name="perpage" size="1" value="' . $perpage . '" />'; helpbutton('pagesize', get_string('pagesize', 'webquestscorm'), 'webquestscorm'); echo '</td></tr>'; echo '<tr align="right">'; echo '<td>'; print_string('quickgrade', 'webquestscorm'); echo ':</td>'; echo '<td align="left">'; if ($quickgrade) { echo '<input type="checkbox" name="quickgrade" value="1" checked="checked" />'; } else { echo '<input type="checkbox" name="quickgrade" value="1" />'; } helpbutton('quickgrade', get_string('quickgrade', 'webquestscorm'), 'webquestscorm') . '</p></div>'; echo '</td></tr>'; echo '<tr>'; echo '<td colspan="2" align="right">'; echo '<input type="submit" value="' . get_string('savepreferences') . '" />'; echo '</td></tr></table>'; echo '</form>'; ///End of mini form print_footer($this->course); }
/** * Display all the submissions ready for grading * * @global object * @global object * @global object * @global object * @param string $message * @return bool|void */ function display_submissions($message='') { global $CFG, $DB, $USER, $DB, $OUTPUT, $PAGE; require_once($CFG->libdir.'/gradelib.php'); /* first we check to see if the form has just been submitted * to request user_preference updates */ $filters = array(self::FILTER_ALL => get_string('all'), self::FILTER_SUBMITTED => get_string('submitted', 'assignment'), self::FILTER_REQUIRE_GRADING => get_string('requiregrading', 'assignment')); $updatepref = optional_param('updatepref', 0, PARAM_INT); if (isset($_POST['updatepref'])){ $perpage = optional_param('perpage', 10, PARAM_INT); $perpage = ($perpage <= 0) ? 10 : $perpage ; $filter = optional_param('filter', 0, PARAM_INT); set_user_preference('assignment_perpage', $perpage); set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); set_user_preference('assignment_filter', $filter); } /* next we get perpage and quickgrade (allow quick grade) params * from database */ $perpage = get_user_preferences('assignment_perpage', 10); $quickgrade = get_user_preferences('assignment_quickgrade', 0); $filter = get_user_preferences('assignment_filter', 0); $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id); if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) { $uses_outcomes = true; } else { $uses_outcomes = false; } $page = optional_param('page', 0, PARAM_INT); $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); /// Some shortcuts to make the code read better $course = $this->course; $assignment = $this->assignment; $cm = $this->cm; $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id='.$this->cm->id, $this->assignment->id, $this->cm->id); $PAGE->set_title(format_string($this->assignment->name,true)); $PAGE->set_heading($this->course->fullname); echo $OUTPUT->header(); echo '<div class="usersubmissions">'; //hook to allow plagiarism plugins to update status/print links. plagiarism_update_status($this->course, $this->cm); /// Print quickgrade form around the table if ($quickgrade) { $formattrs = array(); $formattrs['action'] = new moodle_url('/mod/assignment/submissions.php'); $formattrs['id'] = 'fastg'; $formattrs['method'] = 'post'; echo html_writer::start_tag('form', $formattrs); echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=> $this->cm->id)); echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'mode', 'value'=> 'fastgrade')); echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'page', 'value'=> $page)); echo html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'sesskey', 'value'=> sesskey())); } $course_context = get_context_instance(CONTEXT_COURSE, $course->id); if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { echo '<div class="allcoursegrades"><a href="' . $CFG->wwwroot . '/grade/report/grader/index.php?id=' . $course->id . '">' . get_string('seeallcoursegrades', 'grades') . '</a></div>'; } if (!empty($message)) { echo $message; // display messages here if any } $context = get_context_instance(CONTEXT_MODULE, $cm->id); /// Check to see if groups are being used in this assignment /// find out current groups mode $groupmode = groups_get_activity_groupmode($cm); $currentgroup = groups_get_activity_group($cm, true); groups_print_activity_menu($cm, $CFG->wwwroot . '/mod/assignment/submissions.php?id=' . $this->cm->id); /// Get all ppl that are allowed to submit assignments list($esql, $params) = get_enrolled_sql($context, 'mod/assignment:view', $currentgroup); if ($filter == self::FILTER_ALL) { $sql = "SELECT u.id FROM {user} u ". "LEFT JOIN ($esql) eu ON eu.id=u.id ". "WHERE u.deleted = 0 AND eu.id=u.id "; } else { $wherefilter = ''; if($filter == self::FILTER_SUBMITTED) { $wherefilter = ' AND s.timemodified > 0'; } else if($filter == self::FILTER_REQUIRE_GRADING) { $wherefilter = ' AND s.timemarked < s.timemodified '; } $sql = "SELECT u.id FROM {user} u ". "LEFT JOIN ($esql) eu ON eu.id=u.id ". "LEFT JOIN {assignment_submissions} s ON (u.id = s.userid) " . "WHERE u.deleted = 0 AND eu.id=u.id ". 'AND s.assignment = '. $this->assignment->id . $wherefilter; } $users = $DB->get_records_sql($sql, $params); if (!empty($users)) { $users = array_keys($users); } // if groupmembersonly used, remove users who are not in any group if ($users and !empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) { if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { $users = array_intersect($users, array_keys($groupingusers)); } } $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status', 'finalgrade'); if ($uses_outcomes) { $tablecolumns[] = 'outcome'; // no sorting based on outcomes column } $tableheaders = array('', get_string('fullname'), get_string('grade'), get_string('comment', 'assignment'), get_string('lastmodified').' ('.get_string('submission', 'assignment').')', get_string('lastmodified').' ('.get_string('grade').')', get_string('status'), get_string('finalgrade', 'grades')); if ($uses_outcomes) { $tableheaders[] = get_string('outcome', 'grades'); } require_once($CFG->libdir.'/tablelib.php'); $table = new flexible_table('mod-assignment-submissions'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); $table->sortable(true, 'lastname');//sorted by lastname by default $table->collapsible(true); $table->initialbars(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('grade', 'grade'); $table->column_class('submissioncomment', 'comment'); $table->column_class('timemodified', 'timemodified'); $table->column_class('timemarked', 'timemarked'); $table->column_class('status', 'status'); $table->column_class('finalgrade', 'finalgrade'); if ($uses_outcomes) { $table->column_class('outcome', 'outcome'); } $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'submissions'); $table->set_attribute('width', '100%'); //$table->set_attribute('align', 'center'); $table->no_sorting('finalgrade'); $table->no_sorting('outcome'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); if (empty($users)) { echo $OUTPUT->heading(get_string('nosubmitusers','assignment')); echo '</div>'; return true; } if ($this->assignment->assignmenttype=='upload' || $this->assignment->assignmenttype=='online' || $this->assignment->assignmenttype=='uploadsingle') { //TODO: this is an ugly hack, where is the plugin spirit? (skodak) echo '<div style="text-align:right"><a href="submissions.php?id='.$this->cm->id.'&download=zip">'.get_string('downloadall', 'assignment').'</a></div>'; } /// Construct the SQL list($where, $params) = $table->get_sql_where(); if ($where) { $where .= ' AND '; } if ($filter == self::FILTER_SUBMITTED) { $where .= 's.timemodified > 0 AND '; } else if($filter == self::FILTER_REQUIRE_GRADING) { $where .= 's.timemarked < s.timemodified AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY '.$sort; } $ufields = user_picture::fields('u'); $select = "SELECT $ufields, s.id AS submissionid, s.grade, s.submissioncomment, s.timemodified, s.timemarked, COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status "; $sql = 'FROM {user} u '. 'LEFT JOIN {assignment_submissions} s ON u.id = s.userid AND s.assignment = '.$this->assignment->id.' '. 'WHERE '.$where.'u.id IN ('.implode(',',$users).') '; $ausers = $DB->get_records_sql($select.$sql.$sort, $params, $table->get_page_start(), $table->get_page_size()); $table->pagesize($perpage, count($users)); ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next $offset = $page * $perpage; $strupdate = get_string('update'); $strgrade = get_string('grade'); $grademenu = make_grades_menu($this->assignment->grade); if ($ausers !== false) { $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); $endposition = $offset + $perpage; $currentposition = 0; foreach ($ausers as $auser) { if ($currentposition == $offset && $offset < $endposition) { $final_grade = $grading_info->items[0]->grades[$auser->id]; $grademax = $grading_info->items[0]->grademax; $final_grade->formatted_grade = round($final_grade->grade,2) .' / ' . round($grademax,2); $locked_overridden = 'locked'; if ($final_grade->overridden) { $locked_overridden = 'overridden'; } /// Calculate user status $auser->status = ($auser->timemarked > 0) && ($auser->timemarked >= $auser->timemodified); $picture = $OUTPUT->user_picture($auser); if (empty($auser->submissionid)) { $auser->grade = -1; //no submission yet } if (!empty($auser->submissionid)) { ///Prints student answer and student modified date ///attach file or print link to student answer, depending on the type of the assignment. ///Refer to print_student_answer in inherited classes. if ($auser->timemodified > 0) { $studentmodified = '<div id="ts'.$auser->id.'">'.$this->print_student_answer($auser->id) . userdate($auser->timemodified).'</div>'; } else { $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; } ///Print grade, dropdown or text if ($auser->timemarked > 0) { $teachermodified = '<div id="tt'.$auser->id.'">'.userdate($auser->timemarked).'</div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g'.$auser->id.'" class="'. $locked_overridden .'">'.$final_grade->formatted_grade.'</div>'; } else if ($quickgrade) { $attributes = array(); $attributes['tabindex'] = $tabindex++; $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); $grade = '<div id="g'.$auser->id.'">'. $menu .'</div>'; } else { $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; } } else { $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g'.$auser->id.'" class="'. $locked_overridden .'">'.$final_grade->formatted_grade.'</div>'; } else if ($quickgrade) { $attributes = array(); $attributes['tabindex'] = $tabindex++; $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>'; } else { $grade = '<div id="g'.$auser->id.'">'.$this->display_grade($auser->grade).'</div>'; } } ///Print Comment if ($final_grade->locked or $final_grade->overridden) { $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($final_grade->str_feedback),15).'</div>'; } else if ($quickgrade) { $comment = '<div id="com'.$auser->id.'">' . '<textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment' . $auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>'; } else { $comment = '<div id="com'.$auser->id.'">'.shorten_text(strip_tags($auser->submissioncomment),15).'</div>'; } } else { $studentmodified = '<div id="ts'.$auser->id.'"> </div>'; $teachermodified = '<div id="tt'.$auser->id.'"> </div>'; $status = '<div id="st'.$auser->id.'"> </div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g'.$auser->id.'">'.$final_grade->formatted_grade . '</div>'; } else if ($quickgrade) { // allow editing $attributes = array(); $attributes['tabindex'] = $tabindex++; $menu = html_writer::select(make_grades_menu($this->assignment->grade), 'menu['.$auser->id.']', $auser->grade, array(-1=>get_string('nograde')), $attributes); $grade = '<div id="g'.$auser->id.'">'.$menu.'</div>'; } else { $grade = '<div id="g'.$auser->id.'">-</div>'; } if ($final_grade->locked or $final_grade->overridden) { $comment = '<div id="com'.$auser->id.'">'.$final_grade->str_feedback.'</div>'; } else if ($quickgrade) { $comment = '<div id="com'.$auser->id.'">' . '<textarea tabindex="'.$tabindex++.'" name="submissioncomment['.$auser->id.']" id="submissioncomment' . $auser->id.'" rows="2" cols="20">'.($auser->submissioncomment).'</textarea></div>'; } else { $comment = '<div id="com'.$auser->id.'"> </div>'; } } if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 $auser->status = 0; } else { $auser->status = 1; } $buttontext = ($auser->status == 1) ? $strupdate : $strgrade; ///No more buttons, we use popups ;-). $popup_url = '/mod/assignment/submissions.php?id='.$this->cm->id . '&userid='.$auser->id.'&mode=single'.'&filter='.$filter.'&offset='.$offset++; $button = $OUTPUT->action_link($popup_url, $buttontext); $status = '<div id="up'.$auser->id.'" class="s'.$auser->status.'">'.$button.'</div>'; $finalgrade = '<span id="finalgrade_'.$auser->id.'">'.$final_grade->str_grade.'</span>'; $outcomes = ''; if ($uses_outcomes) { foreach($grading_info->outcomes as $n=>$outcome) { $outcomes .= '<div class="outcome"><label>'.$outcome->name.'</label>'; $options = make_grades_menu(-$outcome->scaleid); if ($outcome->grades[$auser->id]->locked or !$quickgrade) { $options[0] = get_string('nooutcome', 'grades'); $outcomes .= ': <span id="outcome_'.$n.'_'.$auser->id.'">'.$options[$outcome->grades[$auser->id]->grade].'</span>'; } else { $attributes = array(); $attributes['tabindex'] = $tabindex++; $attributes['id'] = 'outcome_'.$n.'_'.$auser->id; $outcomes .= ' '.html_writer::select($options, 'outcome_'.$n.'['.$auser->id.']', $outcome->grades[$auser->id]->grade, array(0=>get_string('nooutcome', 'grades')), $attributes); } $outcomes .= '</div>'; } } $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&course=' . $course->id . '">' . fullname($auser, has_capability('moodle/site:viewfullnames', $this->context)) . '</a>'; $row = array($picture, $userlink, $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); if ($uses_outcomes) { $row[] = $outcomes; } $table->add_data($row); } $currentposition++; } } $table->print_html(); /// Print the whole table /// Print quickgrade form around the table if ($quickgrade && $table->started_output){ $mailinfopref = false; if (get_user_preferences('assignment_mailinfo', 1)) { $mailinfopref = true; } $emailnotification = html_writer::checkbox('mailinfo', 1, $mailinfopref, get_string('enableemailnotification','assignment')); $emailnotification .= $OUTPUT->help_icon('enableemailnotification', 'assignment'); echo html_writer::tag('div', $emailnotification, array('class'=>'emailnotification')); $savefeedback = html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'fastg', 'value'=>get_string('saveallfeedback', 'assignment'))); echo html_writer::tag('div', $savefeedback, array('class'=>'fastgbutton')); echo html_writer::end_tag('form'); } else if ($quickgrade) { echo html_writer::end_tag('form'); } echo '</div>'; /// End of fast grading form /// Mini form for setting user preference $formaction = new moodle_url('/mod/assignment/submissions.php', array('id'=>$this->cm->id)); $mform = new MoodleQuickForm('optionspref', 'post', $formaction, '', array('class'=>'optionspref')); $mform->addElement('hidden', 'updatepref'); $mform->setDefault('updatepref', 1); $mform->addElement('header', 'qgprefs', get_string('optionalsettings', 'assignment')); $mform->addElement('select', 'filter', get_string('show'), $filters); $mform->setDefault('filter', $filter); $mform->addElement('text', 'perpage', get_string('pagesize', 'assignment'), array('size'=>1)); $mform->setDefault('perpage', $perpage); $mform->addElement('checkbox', 'quickgrade', get_string('quickgrade','assignment')); $mform->setDefault('quickgrade', $quickgrade); $mform->addHelpButton('quickgrade', 'quickgrade', 'assignment'); $mform->addElement('submit', 'savepreferences', get_string('savepreferences')); $mform->display(); echo $OUTPUT->footer(); }
/** * List conversations of either open or closed type for the current user * * Called when a user clicks the "Current Dialogues" or "Closed Dialogues" tabs * rendering those out directly as HTML inside a print_table() showing who the * conversation is with, what the subject is, how many entries there are, * how many are un-read and what the most recent post date is * * @param object $dialogue * @param int $groupid of the group to filter conversations by (default: 0) * @param string $type 'open' (default) or 'closed' * @todo remove the embedded style for 'th', make it a class driven thing in the theme */ function dialogue_list_conversations($dialogue, $groupid = 0, $type = 'open') { global $USER, $CFG; $condition = $type == 'closed' ? " closed='1' " : " closed='0' "; $tabid = $type == 'closed' ? 3 : 1; if (!($course = get_record('course', 'id', $dialogue->course))) { error('Course is misconfigured'); } if (!($cm = get_coursemodule_from_instance('dialogue', $dialogue->id, $course->id))) { error('Course Module ID was incorrect'); } $context = get_context_instance(CONTEXT_MODULE, $cm->id); $dialoguemanagers = array_keys(get_users_by_capability($context, 'mod/dialogue:manage')); echo '<style>th.header { text-align: left; }</style>'; require_once $CFG->libdir . '/tablelib.php'; $tablecolumns = array('picture', 'subject', 'fullname', 'total', 'unread', 'lastentry'); $tableheaders = array('', get_string('subject', 'dialogue'), get_string('fullname', ''), get_string('numberofentries', 'dialogue'), get_string('unread', 'dialogue'), get_string('lastentry', 'dialogue')); $table = new flexible_table('mod-dialogue-submissions'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/dialogue/view.php?id=' . $cm->id . '&pane=' . $tabid); $table->sortable(true, 'subject'); $table->collapsible(false); //$table->column_suppress('picture'); // supress multiple subsequent row entries //$table->column_suppress('fullname'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'dialogue'); $table->set_attribute('class', 'conversations'); $table->set_attribute('width', '100%'); $table->setup(); $order = ''; // so we can filter the get_conversations() call later $namesort = ''; // if we want to sort by other calculated fields, e.g. first/last name if ($sort = $table->get_sql_sort('mod-dialogue-submissions')) { $sortparts = explode(',', $sort); $sqlsort = $sortparts[0]; if (strpos($sqlsort, 'subject') !== false) { $order = $sqlsort; } if (strpos($sqlsort, 'total') !== false) { $order = $sqlsort; } if (strpos($sqlsort, 'lastentry') !== false) { $order = $sqlsort; $order = str_replace('lastentry', 'c.timemodified', $order); } if (strpos($sqlsort, 'firstname') !== false) { $namesort = $sqlsort; } if (strpos($sqlsort, 'lastname') !== false) { $namesort = $sqlsort; } if (strpos($sqlsort, 'unread') !== false) { $namesort = $sqlsort; } } // list the conversations requiring a resonse from this user in full if ($conversations = dialogue_get_conversations($dialogue, $USER, $condition, $order, $groupid)) { foreach ($conversations as $conversation) { if (in_array($USER->id, $dialoguemanagers)) { if (!in_array($conversation->userid, $dialoguemanagers)) { if (!($with = get_record('user', 'id', $conversation->userid))) { error("User's record not found"); } } else { if (!($with = get_record('user', 'id', $conversation->recipientid))) { error("User's record not found"); } } } else { if ($USER->id != $conversation->userid) { if (!($with = get_record('user', 'id', $conversation->userid))) { error("User's record not found"); } } else { if (!($with = get_record('user', 'id', $conversation->recipientid))) { error("User's record not found"); } } } // save sortable field values for each conversation so can sort by them later $names[$conversation->id] = fullname($with); $unread[$conversation->id] = $conversation->total - $conversation->readings; $names_firstlast[$conversation->id] = $with->firstname . ' ' . $with->lastname; $names_lastfirst[$conversation->id] = $with->lastname . ' ' . $with->firstname; $photos[$conversation->id] = print_user_picture($with, $course->id, true, 0, true); $ids[$conversation->id] = $with->id; } // sort an array of conversations based on which field user clicked to sort in the UI $sortedvalues = $names; // default is sort by fullname from above switch ($namesort) { case 'firstname ASC': $sortedvalues = $names_firstlast; natcasesort($sortedvalues); break; case 'firstname DESC': $sortedvalues = $names_firstlast; natcasesort($sortedvalues); $sortedvalues = array_reverse($sortedvalues, true); break; case 'lastname ASC': $sortedvalues = $names_lastfirst; natcasesort($sortedvalues); break; case 'lastname DESC': $sortedvalues = $names_lastfirst; natcasesort($sortedvalues); $sortedvalues = array_reverse($sortedvalues, true); break; case 'unread ASC': $sortedvalues = $unread; asort($sortedvalues); break; case 'unread DESC': $sortedvalues = $unread; arsort($sortedvalues); break; } foreach ($sortedvalues as $cid => $val) { $conversation = $conversations[$cid]; if ($unread[$cid] > 0) { $unreadcount = '<span class="unread">' . $unread[$cid] . '</span>'; } else { $unreadcount = 0; } $profileurl = "{$CFG->wwwroot}/user/view.php?id=" . $ids[$conversation->id] . "&course={$dialogue->course}"; $entryurl = "{$CFG->wwwroot}/mod/dialogue/dialogues.php?id=" . $cm->id . "&action=printdialogue&cid=" . $cid; $row = array($photos[$conversation->id], "<a href='{$entryurl}'>" . $conversation->subject . '</a>', "<a href='{$profileurl}'>" . $names[$conversation->id] . '</a>', $conversation->total, $unreadcount, userdate($conversation->timemodified)); $table->add_data($row); } $table->print_html(); /// Print the whole table } }
if ($sco->launch != '') { $columns[] = 'scograde' . $sco->id; $headers[] = format_string($sco->title); $table->head[] = format_string($sco->title); } } } else { $scoes = NULL; } if (!$download) { $table = new flexible_table('mod-scorm-report'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl($reporturlwithdisplayoptions->out()); $table->sortable(true); $table->collapsible(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_suppress('idnumber'); $table->no_sorting('start'); $table->no_sorting('finish'); $table->no_sorting('score'); if ($scoes) { foreach ($scoes as $sco) { if ($sco->launch != '') { $table->no_sorting('scograde' . $sco->id); } } } $table->column_class('picture', 'picture'); $table->column_class('fullname', 'bold');
public function display_allfilesform() { global $CFG, $OUTPUT, $DB, $USER; $cm = $this->coursemodule; $context = $this->context; $course = $this->course; $updatepref = optional_param('updatepref', 0, PARAM_BOOL); if ($updatepref) { $perpage = optional_param('perpage', 10, PARAM_INT); $perpage = $perpage <= 0 ? 10 : $perpage; $filter = optional_param('filter', 0, PARAM_INT); set_user_preference('publication_perpage', $perpage); } /* next we get perpage and quickgrade (allow quick grade) params * from database */ $perpage = get_user_preferences('publication_perpage', 10); $quickgrade = get_user_preferences('publication_quickgrade', 0); $filter = get_user_preferences('publicationfilter', 0); $page = optional_param('page', 0, PARAM_INT); $formattrs = array(); $formattrs['action'] = new moodle_url('/mod/publication/view.php'); $formattrs['id'] = 'fastg'; $formattrs['method'] = 'post'; $formattrs['class'] = 'mform'; $html = ''; $html .= html_writer::start_tag('form', $formattrs); $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'id', 'value' => $this->get_coursemodule()->id)); $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'page', 'value' => $page)); $html .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); echo $html; echo html_writer::start_tag('div', array('id' => 'id_allfiles', 'class' => 'clearfix', 'aria-live' => 'polite')); $title = has_capability('mod/publication:approve', $context) ? get_string('allfiles', 'publication') : get_string('publicfiles', 'publication'); echo html_writer::tag('div', $title, array('class' => 'legend')); echo html_writer::start_div('fcontainer clearfix'); // Check to see if groups are being used in this assignment. // Find out current groups mode. $groupmode = groups_get_activity_groupmode($cm); $currentgroup = groups_get_activity_group($cm, true); echo groups_print_activity_menu($cm, $CFG->wwwroot . '/mod/publication/view.php?id=' . $cm->id, true); $html = ''; // Get all ppl that are allowed to submit assignments. list($esql, $params) = get_enrolled_sql($context, 'mod/publication:view', $currentgroup); $showall = false; if (has_capability('mod/publication:approve', $context) || has_capability('mod/publication:grantextension', $context)) { $showall = true; } if ($showall) { $sql = 'SELECT u.id FROM {user} u ' . 'LEFT JOIN (' . $esql . ') eu ON eu.id=u.id ' . 'WHERE u.deleted = 0 AND eu.id=u.id '; } else { $sql = 'SELECT u.id FROM {user} u ' . 'LEFT JOIN (' . $esql . ') eu ON eu.id=u.id ' . 'LEFT JOIN {publication_file} files ON (u.id = files.userid) ' . 'WHERE u.deleted = 0 AND eu.id=u.id ' . 'AND files.publication = ' . $this->get_instance()->id . ' '; if ($this->get_instance()->mode == PUBLICATION_MODE_UPLOAD) { // Node upload. if ($this->get_instance()->obtainteacherapproval) { // Need teacher approval. $where = 'files.teacherapproval = 1'; } else { // No need for teacher approval. // Teacher only hasnt rejected. $where = '(files.teacherapproval = 1 OR files.teacherapproval IS NULL)'; } } else { // Mode import. if (!$this->get_instance()->obtainstudentapproval) { // No need to ask student and teacher has approved. $where = 'files.teacherapproval = 1'; } else { // Student and teacher have approved. $where = 'files.teacherapproval = 1 AND files.studentapproval = 1'; } } $sql .= 'AND ' . $where . ' '; $sql .= 'GROUP BY u.id'; } $users = $DB->get_records_sql($sql, $params); if (!empty($users)) { $users = array_keys($users); } // If groupmembersonly used, remove users who are not in any group. if ($users and !empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) { if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { $users = array_intersect($users, array_keys($groupingusers)); } } $selectallnone = html_writer::checkbox('selectallnone', false, false, '', array('id' => 'selectallnone', 'onClick' => 'toggle_userselection()')); $tablecolumns = array('selection', 'fullname'); $tableheaders = array($selectallnone, get_string('fullnameuser')); $useridentity = $CFG->showuseridentity != '' ? explode(',', $CFG->showuseridentity) : array(); foreach ($useridentity as $cur) { if (!(get_config('publication', 'hideidnumberfromstudents') && $cur == "idnumber" && !has_capability('mod/publication:approve', $context)) && !($cur != "idnumber" && !has_capability('mod/publication:approve', $context))) { $tablecolumns[] = $cur; $tableheaders[] = $cur == 'phone1' ? get_string('phone') : get_string($cur); } } $tableheaders[] = get_string('lastmodified'); $tablecolumns[] = 'timemodified'; if (has_capability('mod/publication:approve', $context)) { // Not necessary in upload mode without studentapproval. if ($this->get_instance()->mode == PUBLICATION_MODE_IMPORT && $this->get_instance()->obtainstudentapproval) { $tablecolumns[] = 'studentapproval'; $tableheaders[] = get_string('studentapproval', 'publication') . ' ' . $OUTPUT->help_icon('studentapproval', 'publication'); } $tablecolumns[] = 'teacherapproval'; if ($this->get_instance()->mode == PUBLICATION_MODE_IMPORT && $this->get_instance()->obtainstudentapproval) { $tableheaders[] = get_string('obtainstudentapproval', 'publication'); } else { $tableheaders[] = get_string('teacherapproval', 'publication'); } $tablecolumns[] = 'visibleforstudents'; $tableheaders[] = get_string('visibleforstudents', 'publication'); } require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-publication-allfiles'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/publication/view.php?id=' . $cm->id . '&currentgroup=' . $currentgroup); $table->sortable(true, 'lastname'); // Sorted by lastname by default. $table->collapsible(false); $table->initialbars(true); $table->column_class('fullname', 'fullname'); $table->column_class('timemodified', 'timemodified'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'publications'); $table->set_attribute('width', '100%'); $table->no_sorting('studentapproval'); $table->no_sorting('selection'); $table->no_sorting('teacherapproval'); $table->no_sorting('visibleforstudents'); // Start working -- this is necessary as soon as the niceties are over. $table->setup(); // Construct the SQL. list($where, $params) = $table->get_sql_where(); if ($where) { $where .= ' AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY ' . $sort; } $ufields = user_picture::fields('u'); $useridentityfields = $CFG->showuseridentity != '' ? 'u.' . str_replace(', ', ', u.', $CFG->showuseridentity) . ', ' : ''; $totalfiles = 0; if (!empty($users)) { $select = 'SELECT ' . $ufields . ', ' . $useridentityfields . ' username, COUNT(*) filecount, SUM(files.studentapproval) as status, MAX(files.timecreated) timemodified '; $sql = 'FROM {user} u ' . 'LEFT JOIN {publication_file} files ON u.id = files.userid AND files.publication = ' . $this->get_instance()->id . ' ' . 'WHERE ' . $where . 'u.id IN (' . implode(', ', $users) . ') ' . 'GROUP BY ' . $ufields . ', ' . $useridentityfields . ' username '; $ausers = $DB->get_records_sql($select . $sql . $sort, $params, $table->get_page_start(), $table->get_page_size()); $table->pagesize($perpage, count($users)); // Offset used to calculate index of student in that particular query, needed for the pop up to know who's next. $offset = $page * $perpage; $strupdate = get_string('update'); if ($ausers !== false) { $endposition = $offset + $perpage; $currentposition = 0; $valid = $OUTPUT->pix_icon('i/valid', get_string('student_approved', 'publication')); $questionmark = $OUTPUT->pix_icon('questionmark', get_string('student_pending', 'publication'), 'mod_publication'); $invalid = $OUTPUT->pix_icon('i/invalid', get_string('student_rejected', 'publication')); $visibleforstundetsyes = $OUTPUT->pix_icon('i/valid', get_string('visibleforstudents_yes', 'publication')); $visibleforstundetsno = $OUTPUT->pix_icon('i/invalid', get_string('visibleforstudents_no', 'publication')); $viewfullnames = has_capability('moodle/site:viewfullnames', $this->context); foreach ($ausers as $auser) { if ($currentposition >= $offset && $currentposition < $endposition) { // Calculate user status. $selecteduser = html_writer::checkbox('selectedeuser[' . $auser->id . ']', 'selected', false, null, array('class' => 'userselection')); $useridentity = $CFG->showuseridentity != '' ? explode(',', $CFG->showuseridentity) : array(); foreach ($useridentity as $cur) { if (!(get_config('publication', 'hideidnumberfromstudents') && $cur == "idnumber" && !has_capability('mod/publication:approve', $context)) && !($cur != "idnumber" && !has_capability('mod/publication:approve', $context))) { if (!empty($auser->{$cur})) { ${$cur} = html_writer::tag('div', $auser->{$cur}, array('id' => 'u' . $cur . $auser->id)); } else { ${$cur} = html_writer::tag('div', '-', array('id' => 'u' . $cur . $auser->id)); } } } $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&course=' . $course->id . '">' . fullname($auser, $viewfullnames) . '</a>'; $extension = $this->user_extensionduedate($auser->id); if ($extension) { if (has_capability('mod/publication:grantextension', $context) || has_capability('mod/publication:approve', $context)) { $userlink .= '<br/>' . get_string('extensionto', 'publication') . ': ' . userdate($extension); } } $row = array($selecteduser, $userlink); $useridentity = $CFG->showuseridentity != '' ? explode(',', $CFG->showuseridentity) : array(); foreach ($useridentity as $cur) { if (!(get_config('publication', 'hideidnumberfromstudents') && $cur == "idnumber" && !has_capability('mod/publication:approve', $context)) && !($cur != "idnumber" && !has_capability('mod/publication:approve', $context))) { if (true) { $row[] = ${$cur}; } else { $row[] = ""; } } } $filearea = 'attachment'; $sid = $auser->id; $fs = get_file_storage(); $files = $fs->get_area_files($this->get_context()->id, 'mod_publication', $filearea, $sid, 'timemodified', false); $filetable = new html_table(); $filetable->attributes = array('class' => 'filetable'); $statustable = new html_table(); $statustable->attributes = array('class' => 'statustable'); $permissiontable = new html_table(); $permissiontable->attributes = array('class' => 'permissionstable'); $visibleforuserstable = new html_table(); $visibleforuserstable->attributes = array('class' => 'statustable'); $conditions = array(); $conditions['publication'] = $this->get_instance()->id; $conditions['userid'] = $auser->id; foreach ($files as $file) { $conditions['fileid'] = $file->get_id(); $filepermissions = $DB->get_record('publication_file', $conditions); $showfile = false; if (has_capability('mod/publication:approve', $context)) { $showfile = true; } else { if ($this->has_filepermission($file->get_id())) { $showfile = true; } } if ($this->has_filepermission($file->get_id())) { $visibleforuserstable->data[] = array($visibleforstundetsyes); } else { $visibleforuserstable->data[] = array($visibleforstundetsno); } if ($showfile) { $filerow = array(); $filerow[] = $OUTPUT->pix_icon(file_file_icon($file), get_mimetype_description($file)); $url = new moodle_url('/mod/publication/view.php', array('id' => $cm->id, 'download' => $file->get_id())); $filerow[] = html_writer::link($url, $file->get_filename()); if (has_capability('mod/publication:approve', $context)) { $checked = $filepermissions->teacherapproval; if (is_null($checked)) { $checked = ""; } else { $checked = $checked + 1; } $permissionrow = array(); $options = array(); $options['2'] = get_string('yes'); $options['1'] = get_string('no'); $permissionrow[] = html_writer::select($options, 'files[' . $file->get_id() . ']', $checked); $statusrow = array(); if (is_null($filepermissions->studentapproval)) { $statusrow[] = $questionmark; } else { if ($filepermissions->studentapproval) { $statusrow[] = $valid; } else { $statusrow[] = $invalid; } } $statustable->data[] = $statusrow; $permissiontable->data[] = $permissionrow; } $filetable->data[] = $filerow; $totalfiles++; } } $lastmodified = ""; if (count($filetable->data) > 0) { $lastmodified = html_writer::table($filetable); $lastmodified .= html_writer::span(userdate($auser->timemodified), "timemodified"); } else { $lastmodified = get_string('nofiles', 'publication'); } $row[] = $lastmodified; if (has_capability('mod/publication:approve', $context)) { // Not necessary in upload mode without studentapproval. if ($this->get_instance()->mode == PUBLICATION_MODE_IMPORT && $this->get_instance()->obtainstudentapproval) { if (count($statustable->data) > 0) { $status = html_writer::table($statustable); } else { $status = ''; } $row[] = $status; } if (count($permissiontable->data) > 0) { $permissions = html_writer::table($permissiontable); } else { $permissions = ''; } $row[] = $permissions; $row[] = html_writer::table($visibleforuserstable); } $table->add_data($row); } $currentposition++; } if (true) { // Always display download option. $html .= html_writer::start_tag('div', array('class' => 'mod-publication-download-link')); $html .= html_writer::link(new moodle_url('/mod/publication/view.php', array('id' => $this->coursemodule->id, 'action' => 'zip')), get_string('downloadall', 'publication')); $html .= html_writer::end_tag('div'); } echo $html; $html = ""; $table->print_html(); // Print the whole table. $options = array(); if (true) { // Always display download option. $options['zipusers'] = get_string('zipusers', 'publication'); } if ($totalfiles > 0) { if (has_capability('mod/publication:approve', $context)) { $options['approveusers'] = get_string('approveusers', 'publication'); $options['rejectusers'] = get_string('rejectusers', 'publication'); if ($this->get_instance()->mode == PUBLICATION_MODE_IMPORT && $this->get_instance()->obtainstudentapproval) { $options['resetstudentapproval'] = get_string('resetstudentapproval', 'publication'); } } } if (has_capability('mod/publication:grantextension', $this->get_context())) { $options['grantextension'] = get_string('grantextension', 'publication'); } if (count($options) > 0) { if (has_capability('mod/publication:approve', $context)) { $html .= html_writer::empty_tag('input', array('type' => 'reset', 'name' => 'resetvisibility', 'value' => get_string('reset', 'publication'), 'class' => 'visibilitysaver')); if ($this->get_instance()->mode == PUBLICATION_MODE_IMPORT && $this->get_instance()->obtainstudentapproval) { $html .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'savevisibility', 'value' => get_string('saveapproval', 'publication'), 'class' => 'visibilitysaver')); } else { $html .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'savevisibility', 'value' => get_string('saveteacherapproval', 'publication'), 'class' => 'visibilitysaver')); } } $html .= html_writer::start_div('withselection'); $html .= html_writer::span(get_string('withselected', 'publication')); $html .= html_writer::select($options, 'action'); $html .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'submitgo', 'value' => get_string('go', 'publication'))); $html .= html_writer::end_div(); } } else { $html .= html_writer::tag('div', get_string('nothingtodisplay', 'publication'), array('class' => 'nosubmisson')); } } else { $html .= html_writer::tag('div', get_string('nothingtodisplay', 'publication'), array('class' => 'nosubmisson')); } // Select all/none. $html .= html_writer::start_tag('div', array('class' => 'checkboxcontroller')); $html .= "<script type=\"text/javascript\">\n function toggle_userselection() {\n var checkboxes = document.getElementsByClassName('userselection');\n var sel = document.getElementById('selectallnone');\n\n if (checkboxes.length > 0) {\n checkboxes[0].checked = sel.checked;\n\n for(var i = 1; i < checkboxes.length;i++) {\n checkboxes[i].checked = checkboxes[0].checked;\n }\n }\n }\n </script>"; $html .= html_writer::end_div(); $html .= html_writer::end_div(); $html .= html_writer::end_div(); echo $html; echo html_writer::end_tag('form'); // Mini form for setting user preference. $html = ''; $formaction = new moodle_url('/mod/publication/view.php', array('id' => $this->coursemodule->id)); $mform = new MoodleQuickForm('optionspref', 'post', $formaction, '', array('class' => 'optionspref')); $mform->addElement('hidden', 'updatepref'); $mform->setDefault('updatepref', 1); $mform->addElement('header', 'qgprefs', get_string('optionalsettings', 'publication')); $mform->addElement('text', 'perpage', get_string('entiresperpage', 'publication'), array('size' => 1)); $mform->setDefault('perpage', $perpage); $mform->addElement('submit', 'savepreferences', get_string('savepreferences')); $mform->display(); return $html; }
function geogebra_view_results($geogebra, $context, $cm, $course, $action) { global $CFG, $DB, $OUTPUT, $PAGE, $USER; if ($action == 'submitgrade') { // Upgrade submitted grade $grade = optional_param('grade', '', PARAM_INT); $gradecomment = optional_param_array('comment_editor', '', PARAM_RAW); $attemptid = optional_param('attemptid', '', PARAM_INT); $attempt = geogebra_get_attempt($attemptid); parse_str($attempt->vars, $parsedvars); $parsedvars['grade'] = $grade; $attempt->vars = http_build_query($parsedvars, '', '&'); geogebra_update_attempt($attemptid, $attempt->vars, GEOGEBRA_UPDATE_TEACHER, $gradecomment['text']); } // Show students list with their results require_once $CFG->libdir . '/gradelib.php'; $perpage = optional_param('perpage', 10, PARAM_INT); $perpage = $perpage <= 0 ? 10 : $perpage; $page = optional_param('page', 0, PARAM_INT); // Find out current groups mode $groupmode = groups_get_activity_groupmode($cm); $currentgroup = groups_get_activity_group($cm, true); // Get all ppl that are allowed to submit geogebra list($esql, $params) = get_enrolled_sql($context, 'mod/geogebra:submit', $currentgroup); $sql = "SELECT u.id FROM {user} u " . "LEFT JOIN ({$esql}) eu ON eu.id=u.id " . "WHERE u.deleted = 0 AND eu.id=u.id "; $users = $DB->get_records_sql($sql, $params); if (!empty($users)) { $users = array_keys($users); } // If groupmembersonly used, remove users who are not in any group if ($users and !empty($CFG->enablegroupmembersonly) and $cm->groupmembersonly) { if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { $users = array_intersect($users, array_keys($groupingusers)); } } // TODO: Review to show all users information if (!empty($users)) { // Create results table $extrafields = get_extra_user_fields($context); $tablecolumns = array_merge(array('picture', 'fullname'), $extrafields, array('attempts', 'duration', 'grade', 'comment', 'datestudent', 'dateteacher', 'status')); $extrafieldnames = array(); foreach ($extrafields as $field) { $extrafieldnames[] = get_user_field_name($field); } $tableheaders = array_merge(array('', get_string('fullnameuser')), $extrafieldnames, array(get_string('attempts', 'geogebra'), get_string('duration', 'geogebra'), get_string('grade'), get_string('comment', 'geogebra'), get_string('lastmodifiedsubmission', 'geogebra'), get_string('lastmodifiedgrade', 'geogebra'), get_string('status', 'geogebra'))); require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-geogebra-results'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/geogebra/report.php?id=' . $cm->id . '&currentgroup=' . $currentgroup); $table->sortable(true, 'lastname'); // Sorted by lastname by default $table->collapsible(true); $table->initialbars(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); foreach ($extrafields as $field) { $table->column_class($field, $field); } $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'results generaltable generalbox'); $table->set_attribute('width', '100%'); $table->no_sorting('attempts'); $table->no_sorting('duration'); $table->no_sorting('grade'); $table->no_sorting('comment'); $table->no_sorting('datestudent'); $table->no_sorting('dateteacher'); $table->no_sorting('status'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); // Construct the SQL list($where, $params) = $table->get_sql_where(); if ($where) { $where .= ' AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY ' . $sort; } $ufields = user_picture::fields('u', $extrafields); $select = "SELECT {$ufields} "; $sql = 'FROM {user} u WHERE ' . $where . 'u.id IN (' . implode(',', $users) . ') '; $ausers = $DB->get_records_sql($select . $sql . $sort, $params, $table->get_page_start(), $table->get_page_size()); $table->pagesize($perpage, count($users)); $offset = $page * $perpage; // Offset used to calculate index of student in that particular query, needed for the pop up to know who's next if ($ausers !== false) { // $grading_info = grade_get_grades($course->id, 'mod', 'geogebra', $geogebra->id, array_keys($ausers)); foreach ($ausers as $auser) { $picture = $OUTPUT->user_picture($auser); $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&course=' . $course->id . '">' . fullname($auser, has_capability('moodle/site:viewfullnames', $context)) . '</a>'; $row = array($picture, $userlink); $extradata = array(); foreach ($extrafields as $field) { $extradata[] = $auser->{$field}; } $row += $extradata; // Attempts summary $attempts = geogebra_get_user_attempts($geogebra->id, $auser->id); $attemptssummary = geogebra_get_user_grades($geogebra, $auser->id); if ($attemptssummary) { $row[] = $attemptssummary->attempts; $row[] = geogebra_time2str($attemptssummary->duration); $row[] = $attemptssummary->grade; $rowclass = $attemptssummary->attempts > 0 ? 'summary-row' : ""; } else { $row[] = ""; $row[] = ""; $row[] = ""; $rowclass = ""; } $row[] = ""; $row[] = ""; $row[] = ""; $row[] = ""; $table->add_data($row, $rowclass); // Show attempts information foreach ($attempts as $attempt) { $row = array(); // In the attempts row, show only the summary of the attempt (it's not necessary to repeat user information) for ($i = 0; $i < count($extradata) + 2; $i++) { array_push($row, ''); } // Attempt information $row = geogebra_get_attempt_row($geogebra, $attempt, $auser, $cm, $context, $row); /*array_push($row, $attempt->duration); array_push($row, $attempt->grade); array_push($row, $attempt->comment);*/ $table->add_data($row); } } } $table->print_html(); // Print the whole table } else { echo $OUTPUT->notification(get_string('msg_nosessions', 'geogebra'), 'notifymessage'); } }
/** * Create a table with properties as passed in params. * * @param string[] $columns * @param string[] $headers * @param bool $sortable * @param bool $collapsible * @param string[] $suppress * @param string[] $nosorting * @return flexible_table */ protected function create_and_setup_table($columns, $headers, $sortable, $collapsible, $suppress, $nosorting) { $table = new flexible_table('tablelib_test'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl('/invalid.php'); $table->sortable($sortable); $table->collapsible($collapsible); foreach ($suppress as $column) { $table->column_suppress($column); } foreach ($nosorting as $column) { $table->no_sorting($column); } $table->setup(); return $table; }
public function test_persistent_table() { global $SESSION; $data = $this->generate_data(5, 5); $columns = $this->generate_columns(5); $headers = $this->generate_headers(5); // Testing without persistence first to verify that the results are different. $table1 = new flexible_table('tablelib_test'); $table1->define_columns($columns); $table1->define_headers($headers); $table1->define_baseurl('/invalid.php'); $table1->sortable(true); $table1->collapsible(true); $table1->is_persistent(false); $_GET['thide'] = 'column0'; $_GET['tsort'] = 'column1'; $_GET['tifirst'] = 'A'; $_GET['tilast'] = 'Z'; foreach ($data as $row) { $table1->add_data_keyed($row); } $table1->setup(); // Clear session data between each new table. unset($SESSION->flextable); $table2 = new flexible_table('tablelib_test'); $table2->define_columns($columns); $table2->define_headers($headers); $table2->define_baseurl('/invalid.php'); $table2->sortable(true); $table2->collapsible(true); $table2->is_persistent(false); unset($_GET); foreach ($data as $row) { $table2->add_data_keyed($row); } $table2->setup(); $this->assertNotEquals($table1, $table2); unset($SESSION->flextable); // Now testing with persistence to check that the tables are the same. $table3 = new flexible_table('tablelib_test'); $table3->define_columns($columns); $table3->define_headers($headers); $table3->define_baseurl('/invalid.php'); $table3->sortable(true); $table3->collapsible(true); $table3->is_persistent(true); $_GET['thide'] = 'column0'; $_GET['tsort'] = 'column1'; $_GET['tifirst'] = 'A'; $_GET['tilast'] = 'Z'; foreach ($data as $row) { $table3->add_data_keyed($row); } $table3->setup(); unset($SESSION->flextable); $table4 = new flexible_table('tablelib_test'); $table4->define_columns($columns); $table4->define_headers($headers); $table4->define_baseurl('/invalid.php'); $table4->sortable(true); $table4->collapsible(true); $table4->is_persistent(true); unset($_GET); foreach ($data as $row) { $table4->add_data_keyed($row); } $table4->setup(); $this->assertEquals($table3, $table4); unset($SESSION->flextable); // Finally, another test with no persistence, but without clearing the session data. $table5 = new flexible_table('tablelib_test'); $table5->define_columns($columns); $table5->define_headers($headers); $table5->define_baseurl('/invalid.php'); $table5->sortable(true); $table5->collapsible(true); $table5->is_persistent(true); $_GET['thide'] = 'column0'; $_GET['tsort'] = 'column1'; $_GET['tifirst'] = 'A'; $_GET['tilast'] = 'Z'; foreach ($data as $row) { $table5->add_data_keyed($row); } $table5->setup(); $table6 = new flexible_table('tablelib_test'); $table6->define_columns($columns); $table6->define_headers($headers); $table6->define_baseurl('/invalid.php'); $table6->sortable(true); $table6->collapsible(true); $table6->is_persistent(true); unset($_GET); foreach ($data as $row) { $table6->add_data_keyed($row); } $table6->setup(); $this->assertEquals($table5, $table6); }
/** * Display the report. */ public function display($game, $cm, $course) { global $CFG, $SESSION, $DB; // Define some strings. $strreallydel = addslashes(get_string('deleteattemptcheck', 'game')); $strtimeformat = get_string('strftimedatetime'); $strreviewquestion = get_string('reviewresponse', 'quiz'); // Only print headers if not asked to download data. if (!($download = optional_param('download', null))) { $this->print_header_and_tabs($cm, $course, $game, $reportmode = "overview"); } // Deal with actions. $action = optional_param('action', '', PARAM_ACTION); switch ($action) { case 'delete': // Some attempts need to be deleted. $attemptids = optional_param('attemptid', array(), PARAM_INT); foreach ($attemptids as $attemptid) { if ($attemptid && ($todelete = get_record('game_attempts', 'id', $attemptid))) { delete_records('game_attempts', 'id', $attemptid); delete_records('game_queries', 'attemptid', $attemptid); // Search game_attempts for other instances by this user. // If none, then delete record for this game, this user from game_grades. // else recalculate best grade. $userid = $todelete->userid; if (!record_exists('game_attempts', 'userid', $userid, 'gameid', $game->id)) { delete_records('game_grades', 'userid', $userid, 'gameid', $game->id); } else { game_save_best_score($game, $userid); } } } break; } // Print information on the number of existing attempts. if (!$download) { // Do not print notices when downloading. if ($attemptnum = count_records('game_attempts', 'gameid', $game->id)) { $a = new stdClass(); $a->attemptnum = $attemptnum; $a->studentnum = count_records_select('game_attempts', "gameid = '{$game->id}' AND preview = '0'", 'COUNT(DISTINCT userid)'); $a->studentstring = $course->students; notify(get_string('numattempts', 'game', $a)); } } $context = get_context_instance(CONTEXT_MODULE, $cm->id); // Find out current groups mode. if ($groupmode = groupmode($course, $cm)) { // Groups are being used. if (!$download) { $currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id={$cm->id}&mode=overview"); } else { $currentgroup = get_and_set_current_group($course, $groupmode); } } else { $currentgroup = get_and_set_current_group($course, $groupmode); } // Set table options. $noattempts = optional_param('noattempts', 0, PARAM_INT); $detailedmarks = optional_param('detailedmarks', 0, PARAM_INT); $pagesize = optional_param('pagesize', 10, PARAM_INT); $hasfeedback = game_has_feedback($game->id) && $game->grade > 1.0E-7; if ($pagesize < 1) { $pagesize = 10; } // Now check if asked download of data. if ($download) { $filename = clean_filename("{$course->shortname} " . format_string($game->name, true)); $sort = ''; } // Define table columns. $tablecolumns = array('checkbox', 'picture', 'fullname', 'timestart', 'timefinish', 'duration'); $tableheaders = array(null, '', get_string('fullname'), get_string('startedon', 'game'), get_string('timecompleted', 'game'), get_string('attemptduration', 'game')); if ($game->grade) { $tablecolumns[] = 'grade'; $tableheaders[] = get_string('grade', 'game') . '/' . $game->grade; } if ($detailedmarks) { // We want to display marks for all questions. // Start by getting all questions. $questionlist = game_questions_in_game($game->questions); $questionids = explode(',', $questionlist); $sql = "SELECT q.*, i.score AS maxgrade, i.id AS instance" . " FROM {question} q," . " {game_queries} i" . " WHERE i.gameid = '{$game->id}' AND q.id = i.questionid" . " AND q.id IN ({$questionlist})"; if (!($questions = get_records_sql($sql))) { print_error('No questions found'); } $number = 1; foreach ($questionids as $key => $id) { if ($questions[$id]->length) { // Only print questions of non-zero length. $tablecolumns[] = '$' . $id; $tableheaders[] = '#' . $number; $questions[$id]->number = $number; $number += $questions[$id]->length; } else { // Get rid of zero length questions. unset($questions[$id]); unset($questionids[$key]); } } } if ($hasfeedback) { $tablecolumns[] = 'feedbacktext'; $tableheaders[] = get_string('feedback', 'game'); } if (!$download) { // Set up the table. $table = new flexible_table('mod-game-report-overview-report'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/game/report.php?mode=overview&id=' . $cm->id . '&noattempts=' . $noattempts . '&detailedmarks=' . $detailedmarks . '&pagesize=' . $pagesize); $table->sortable(true); $table->collapsible(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over. $table->setup(); } else { if ($download == 'ODS') { require_once "{$CFG->libdir}/odslib.class.php"; $filename .= ".ods"; // Creating a workbook. $workbook = new MoodleODSWorkbook("-"); // Sending HTTP headers. $workbook->send($filename); // Creating the first worksheet. $sheettitle = get_string('reportoverview', 'game'); $myxls =& $workbook->add_worksheet($sheettitle); // Format types. $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers. $headers = array(get_string('fullname'), get_string('startedon', 'game'), get_string('timecompleted', 'game'), get_string('attemptduration', 'game')); if ($game->grade) { $headers[] = get_string('grade', 'game') . '/' . $game->grade; } if ($detailedmarks) { foreach ($questionids as $id) { $headers[] = '#' . $questions[$id]->number; } } if ($hasfeedback) { $headers[] = get_string('feedback', 'game'); } $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'Excel') { require_once "{$CFG->libdir}/excellib.class.php"; $filename .= ".xls"; // Creating a workbook. $workbook = new MoodleExcelWorkbook("-"); // Sending HTTP headers. $workbook->send($filename); // Creating the first worksheet. $sheettitle = get_string('reportoverview', 'game'); $myxls =& $workbook->add_worksheet($sheettitle); // Format types. $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers. $headers = array(get_string('fullname'), get_string('startedon', 'game'), get_string('timecompleted', 'game'), get_string('attemptduration', 'game')); if ($game->grade) { $headers[] = get_string('grade', 'game') . '/' . $game->grade; } if ($detailedmarks) { foreach ($questionids as $id) { $headers[] = '#' . $questions[$id]->number; } } if ($hasfeedback) { $headers[] = get_string('feedback', 'game'); } $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else { if ($download == 'CSV') { $filename .= ".txt"; header("Content-Type: application/download\n"); header("Content-Disposition: attachment; filename=\"{$filename}\""); header("Expires: 0"); header("Cache-Control: must-revalidate,post-check=0,pre-check=0"); header("Pragma: public"); $headers = get_string('fullname') . "\t" . get_string('startedon', 'game') . "\t" . get_string('timecompleted', 'game') . "\t" . get_string('attemptduration', 'game'); if ($game->grade) { $headers .= "\t" . get_string('grade', 'game') . "/" . $game->grade; } if ($detailedmarks) { foreach ($questionids as $id) { $headers .= "\t#" . $questions[$id]->number; } } if ($hasfeedback) { $headers .= "\t" . get_string('feedback', 'game'); } echo $headers . " \n"; } } } } $contextlists = get_related_contexts_string(get_context_instance(CONTEXT_COURSE, $course->id)); // Construct the SQL. $select = 'SELECT qa.id,' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ' AS uniqueid, ' . 'qa.id as attemptuniqueid, qa.id AS attempt, u.id AS userid, u.firstname, u.lastname, u.picture, ' . 'qa.score, qa.timefinish, qa.timestart, qa.timefinish - qa.timestart AS duration '; if ($course->id != SITEID) { // This is too complicated, so just do it for each of the four cases. if (!empty($currentgroup) && empty($noattempts)) { // We want a particular group and we only want to see students WITH attempts. // So join on groups_members and do an inner join on attempts. $from = 'FROM {user} u JOIN {role_assignments} ra ON ra.userid = u.id ' . groups_members_join_sql() . 'JOIN {game_attempts} qa ON u.id = qa.userid AND qa.gameid = ' . $game->id; $where = ' WHERE ra.contextid ' . $contextlists . ' AND ' . groups_members_where_sql($currentgroup) . ' AND qa.preview = 0'; } else { if (!empty($currentgroup) && !empty($noattempts)) { // We want a particular group and we want to do something funky with attempts. // So join on groups_members and left join on attempts... $from = 'FROM {user} u JOIN {role_assignments} ra ON ra.userid = u.id ' . groups_members_join_sql() . 'LEFT JOIN {game_attempts} qa ON u.id = qa.userid AND qa.gameid = ' . $game->id; $where = ' WHERE ra.contextid ' . $contextlists . ' AND ' . groups_members_where_sql($currentgroup); if ($noattempts == 1) { // Noattempts = 1 means only no attempts, so make the left join ask. // For only records where the right is null (no attempts). $where .= ' AND qa.userid IS NULL'; // Show ONLY no attempts. } else { // We are including attempts, so exclude previews. $where .= ' AND qa.preview = 0'; } } else { if (empty($currentgroup)) { // We don't care about group, and we to do something funky with attempts. // So do a left join on attempts. $from = 'FROM {user} u JOIN {role_assignments} ra ON ra.userid = u.id ' . ' LEFT JOIN {game_attempts} qa ON u.id = qa.userid AND qa.gameid = ' . $game->id; $where = " WHERE ra.contextid {$contextlists}"; if (empty($noattempts)) { // Show ONLY students with attempts. $where .= ' AND qa.userid IS NOT NULL AND qa.preview = 0'; } else { if ($noattempts == 1) { // The noattempts = 1 means only no attempts,. // So make the left join ask for only records where the right is null (no attempts). // Show ONLY students without attempts. $where .= ' AND qa.userid IS NULL'; } else { if ($noattempts == 3) { // We want all attempts. $from = 'FROM {user} u JOIN {game_attempts} qa ON u.id = qa.userid '; $where = ' WHERE qa.gameid = ' . $game->id . ' AND qa.preview = 0'; } } } // The noattempts = 2 means we want all students, with or without attempts. } } } $countsql = 'SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ')) ' . $from . $where; } else { if (empty($noattempts)) { $from = 'FROM {user} u JOIN {game_attempts} qa ON u.id = qa.userid '; $where = ' WHERE qa.gameid = ' . $game->id . ' AND qa.preview = 0'; $countsql = 'SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ')) ' . $from . $where; } } if (!$download) { // Add extra limits due to initials bar. if ($table->get_sql_where()) { $where .= ' AND ' . $table->get_sql_where(); } // Count the records NOW, before funky question grade sorting messes up $from. if (!empty($countsql)) { $totalinitials = count_records_sql($countsql); if ($table->get_sql_where()) { $countsql .= ' AND ' . $table->get_sql_where(); } $total = count_records_sql($countsql); } // Add extra limits due to sorting by question grade. if ($sort = $table->get_sql_sort()) { $sortparts = explode(',', $sort); $newsort = array(); $questionsort = false; foreach ($sortparts as $sortpart) { $sortpart = trim($sortpart); if (substr($sortpart, 0, 1) == '$') { if (!$questionsort) { $qid = intval(substr($sortpart, 1)); $select .= ', grade '; $from .= ' LEFT JOIN {question_sessions} qns ON qns.attemptid = qa.id ' . 'LEFT JOIN {question_states} qs ON qs.id = qns.newgraded '; $where .= ' AND (' . sql_isnull('qns.questionid') . ' OR qns.questionid = ' . $qid . ')'; $newsort[] = 'grade ' . (strpos($sortpart, 'ASC') ? 'ASC' : 'DESC'); $questionsort = true; } } else { $newsort[] = $sortpart; } } // Reconstruct the sort string. $sort = ' ORDER BY ' . implode(', ', $newsort); } // Fix some wired sorting. if (empty($sort)) { $sort = ' ORDER BY qa.id'; } $table->pagesize($pagesize, $total); } // If there is feedback, include it in the query. if ($hasfeedback) { $select .= ', qf.feedbacktext '; $from .= " JOIN {game_feedback} qf ON " . "qf.gameid = {$game->id} AND qf.mingrade <= qa.score * {$game->grade} AND qa.score * {$game->grade} < qf.maxgrade"; } // Fetch the attempts. if (!empty($from)) { // If we're in the site course and displaying no attempts, it makes no sense to do the query. if (!$download) { $attempts = get_records_sql($select . $from . $where . $sort, $table->get_page_start(), $table->get_page_size()); } else { $attempts = get_records_sql($select . $from . $where . $sort); } } else { $attempts = array(); } // Build table rows. if (!$download) { $table->initialbars($totalinitials > 20); } if (!empty($attempts) || !empty($noattempts)) { if ($attempts) { foreach ($attempts as $attempt) { $picture = print_user_picture($attempt->userid, $course->id, $attempt->picture, false, true); /* Uncomment the commented lines below if you are choosing to show unenrolled users and * have uncommented the corresponding lines earlier in this script * if (in_array($attempt->userid, $unenrolledusers)) { * $userlink = '<a class="dimmed" href="'.$CFG->wwwroot. * '/user/view.php?id='.$attempt->userid.'&course='.$course->id.'">'.fullname($attempt).'</a>'; *} *else { * $userlink = '<a href="'.$CFG->wwwroot.'/user/view.php?id='. * $attempt->userid.'&course='.$course->id.'">'.fullname($attempt).'</a>'; *} */ if (!$download) { $row = array('<input type="checkbox" name="attemptid[]" value="' . $attempt->attempt . '" />', $picture, $userlink, empty($attempt->attempt) ? '-' : '<a href="review.php?q=' . $game->id . '&attempt=' . $attempt->attempt . '">' . userdate($attempt->timestart, $strtimeformat) . '</a>', empty($attempt->timefinish) ? '-' : '<a href="review.php?q=' . $game->id . '&attempt=' . $attempt->attempt . '">' . userdate($attempt->timefinish, $strtimeformat) . '</a>', empty($attempt->attempt) ? '-' : (empty($attempt->timefinish) ? get_string('unfinished', 'game') : format_time($attempt->duration))); } else { $row = array(fullname($attempt), empty($attempt->attempt) ? '-' : userdate($attempt->timestart, $strtimeformat), empty($attempt->timefinish) ? '-' : userdate($attempt->timefinish, $strtimeformat), empty($attempt->attempt) ? '-' : (empty($attempt->timefinish) ? get_string('unfinished', 'game') : format_time($attempt->duration))); } if ($game->grade) { if (!$download) { $row[] = $attempt->score === null ? '-' : '<a href="review.php?q=' . $game->id . '&attempt=' . $attempt->attempt . '">' . round($attempt->score * $game->grade, $game->decimalpoints) . '</a>'; } else { $row[] = $attempt->score === null ? '-' : round($attempt->score * $game->grade, $game->decimalpoints); } } if ($detailedmarks) { if (empty($attempt->attempt)) { foreach ($questionids as $questionid) { $row[] = '-'; } } else { foreach ($questionids as $questionid) { if ($gradedstateid = get_field('question_sessions', 'newgraded', 'attemptid', $attempt->attemptuniqueid, 'questionid', $questionid)) { $grade = round(get_field('question_states', 'grade', 'id', $gradedstateid), $game->decimalpoints); } else { $grade = '--'; } if (!$download) { $row[] = link_to_popup_window('/mod/game/reviewquestion.php?state=' . $gradedstateid . '&number=' . $questions[$questionid]->number, 'reviewquestion', $grade, 450, 650, $strreviewquestion, 'none', true); } else { $row[] = $grade; } } } } if ($hasfeedback) { if ($attempt->timefinish) { $row[] = $attempt->feedbacktext; } else { $row[] = '-'; } } if (!$download) { $table->add_data($row); } else { if ($download == 'Excel' or $download == 'ODS') { $colnum = 0; foreach ($row as $item) { $myxls->write($rownum, $colnum, $item, $format); $colnum++; } $rownum++; } else { if ($download == 'CSV') { $text = implode("\t", $row); echo $text . " \n"; } } } } } if (!$download) { // Start form. echo '<div id="tablecontainer">'; echo '<form id="attemptsform" method="post" action="report.php" ' . 'onsubmit="var menu = document.getElementById(\'menuaction\'); ' . 'return (menu.options[menu.selectedIndex].value == \'delete\' ? confirm(\'' . $strreallydel . '\') : true);">'; echo '<div>'; echo '<input type="hidden" name="id" value="' . $cm->id . '" />'; echo '<input type="hidden" name="mode" value="overview" />'; // Print table. $table->print_html(); // Print "Select all" etc.. if (!empty($attempts)) { echo '<table id="commands">'; echo '<tr><td>'; echo '<a href="javascript:select_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectall', 'game') . '</a> / '; echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'tablecontainer\');">' . get_string('selectnone', 'game') . '</a> '; echo ' '; $options = array('delete' => get_string('delete')); echo choose_from_menu($options, 'action', '', get_string('withselected', 'game'), 'if(this.selectedIndex > 0) submitFormById(\'attemptsform\');', '', true); echo '<noscript id="noscriptmenuaction" style="display: inline;"><div>'; echo '<input type="submit" value="' . get_string('go') . '" /></div></noscript>'; echo '<script type="text/javascript">' . "\n<!--\n" . 'document.getElementById("noscriptmenuaction").style.display = "none";' . "\n-->\n" . '</script>'; echo '</td></tr></table>'; } // Close form. echo '</div>'; echo '</form></div>'; if (!empty($attempts)) { echo '<table class="boxaligncenter"><tr>'; $options = array(); $options["id"] = "{$cm->id}"; $options["q"] = "{$game->id}"; $options["mode"] = "overview"; $options['sesskey'] = sesskey(); $options["noheader"] = "yes"; $options['noattempts'] = $noattempts; $options['detailedmarks'] = $detailedmarks; echo '<td>'; $options["download"] = "ODS"; print_single_button("report.php", $options, get_string("downloadods", 'game')); echo "</td>\n"; echo '<td>'; $options["download"] = "Excel"; print_single_button("report.php", $options, get_string("downloadexcel")); echo "</td>\n"; echo '<td>'; $options["download"] = "CSV"; print_single_button('report.php', $options, get_string("downloadtext")); echo "</td>\n"; echo "<td>"; helpbutton('overviewdownload', get_string('overviewdownload', 'quiz'), 'game'); echo "</td>\n"; echo '</tr></table>'; } } else { if ($download == 'Excel' or $download == 'ODS') { $workbook->close(); exit; } else { if ($download == 'CSV') { exit; } } } } else { if (!$download) { $table->print_html(); } } // Print display options. echo '<div class="controls">'; echo '<form id="options" action="report.php" method="get">'; echo '<div>'; echo '<p>' . get_string('displayoptions', 'game') . ': </p>'; echo '<input type="hidden" name="id" value="' . $cm->id . '" />'; echo '<input type="hidden" name="q" value="' . $game->id . '" />'; echo '<input type="hidden" name="mode" value="overview" />'; echo '<input type="hidden" name="noattempts" value="0" />'; echo '<input type="hidden" name="detailedmarks" value="0" />'; echo '<table id="overview-options" class="boxaligncenter">'; echo '<tr align="left">'; echo '<td><label for="pagesize">' . get_string('pagesize', 'game') . '</label></td>'; echo '<td><input type="text" id="pagesize" name="pagesize" size="3" value="' . $pagesize . '" /></td>'; echo '</tr>'; echo '<tr align="left">'; echo '<td colspan="2">'; $options = array(0 => get_string('attemptsonly', 'game', $course->students)); if ($course->id != SITEID) { $options[1] = get_string('noattemptsonly', 'game', $course->students); $options[2] = get_string('allstudents', 'game', $course->students); $options[3] = get_string('allattempts', 'game'); } choose_from_menu($options, 'noattempts', $noattempts, ''); echo '</td></tr>'; echo '<tr align="left">'; echo '<td colspan="2"><input type="checkbox" id="checkdetailedmarks" name="detailedmarks" ' . ($detailedmarks ? 'checked="checked" ' : '') . 'value="1" /> <label for="checkdetailedmarks">' . get_string('showdetailedmarks', 'game') . '</label> '; echo '</td></tr>'; echo '<tr><td colspan="2" align="center">'; echo '<input type="submit" value="' . get_string('go') . '" />'; echo '</td></tr></table>'; echo '</div>'; echo '</form>'; echo '</div>'; echo "\n"; return true; }
if (isset($_POST['updatepref'])) { $perpage = optional_param('perpage', STAMPCOLL_USERS_PER_PAGE, PARAM_INT); $perpage = $perpage <= 0 ? STAMPCOLL_USERS_PER_PAGE : $perpage; set_user_preference('stampcoll_perpage', $perpage); } /// Next we get perpage param from database $perpage = get_user_preferences('stampcoll_perpage', STAMPCOLL_USERS_PER_PAGE); $tablecolumns = array('picture', 'fullname', 'count', 'stamps'); $tableheaders = array('', get_string('fullname'), get_string('numberofstamps', 'stampcoll'), ''); require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-stampcoll-stamps'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/stampcoll/view.php?id=' . $cm->id . '&currentgroup=' . $currentgroup); $table->sortable(true); $table->collapsible(false); $table->initialbars(true); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('count', 'count'); $table->column_class('stamps', 'stamps'); $table->column_style('stamps', 'width', '50%'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'stamps'); $table->set_attribute('class', 'stamps'); $table->set_attribute('width', '90%'); $table->set_attribute('align', 'center'); $table->setup(); if (empty($users)) { print_heading(get_string('nousers', 'stampcoll')); return true;
/** * displays the full report * @param stdClass $scorm full SCORM object * @param stdClass $cm - full course_module object * @param stdClass $course - full course object * @param string $download - type of download being requested */ function display($scorm, $cm, $course, $download) { global $CFG, $DB, $OUTPUT, $PAGE; $contextmodule = get_context_instance(CONTEXT_MODULE, $cm->id); $action = optional_param('action', '', PARAM_ALPHA); $attemptids = optional_param_array('attemptid', array(), PARAM_RAW); $attemptsmode = optional_param('attemptsmode', SCORM_REPORT_ATTEMPTS_ALL_STUDENTS, PARAM_INT); $PAGE->set_url(new moodle_url($PAGE->url, array('attemptsmode' => $attemptsmode))); if ($action == 'delete' && has_capability('mod/scorm:deleteresponses', $contextmodule) && confirm_sesskey()) { if (scorm_delete_responses($attemptids, $scorm)) { //delete responses. add_to_log($course->id, 'scorm', 'delete attempts', 'report.php?id=' . $cm->id, implode(",", $attemptids), $cm->id); echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess'); } } // find out current groups mode $currentgroup = groups_get_activity_group($cm, true); // detailed report $mform = new mod_scorm_report_interactions_settings($PAGE->url, compact('currentgroup')); if ($fromform = $mform->get_data()) { $pagesize = $fromform->pagesize; $includeqtext = $fromform->qtext; $includeresp = $fromform->resp; $includeright = $fromform->right; set_user_preference('scorm_report_pagesize', $pagesize); set_user_preference('scorm_report_interactions_qtext', $includeqtext); set_user_preference('scorm_report_interactions_resp', $includeresp); set_user_preference('scorm_report_interactions_right', $includeright); } else { $pagesize = get_user_preferences('scorm_report_pagesize', 0); $includeqtext = get_user_preferences('scorm_report_interactions_qtext', 0); $includeresp = get_user_preferences('scorm_report_interactions_resp', 1); $includeright = get_user_preferences('scorm_report_interactions_right', 0); } if ($pagesize < 1) { $pagesize = SCORM_REPORT_DEFAULT_PAGE_SIZE; } // select group menu $displayoptions = array(); $displayoptions['attemptsmode'] = $attemptsmode; $displayoptions['qtext'] = $includeqtext; $displayoptions['resp'] = $includeresp; $displayoptions['right'] = $includeright; $mform->set_data($displayoptions + array('pagesize' => $pagesize)); if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used if (!$download) { groups_print_activity_menu($cm, new moodle_url($PAGE->url, $displayoptions)); } } $formattextoptions = array('context' => get_context_instance(CONTEXT_COURSE, $course->id)); // We only want to show the checkbox to delete attempts // if the user has permissions and if the report mode is showing attempts. $candelete = has_capability('mod/scorm:deleteresponses', $contextmodule) && ($attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO); // select the students $nostudents = false; if (empty($currentgroup)) { // all users who can attempt scoes if (!$students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', '', '', '', '', '', '', false)) { echo $OUTPUT->notification(get_string('nostudentsyet')); $nostudents = true; $allowedlist = ''; } else { $allowedlist = array_keys($students); } } else { // all users who can attempt scoes and who are in the currently selected group if (!$groupstudents = get_users_by_capability($contextmodule, 'mod/scorm:savetrack', '', '', '', '', $currentgroup, '', false)) { echo $OUTPUT->notification(get_string('nostudentsingroup')); $nostudents = true; $groupstudents = array(); } $allowedlist = array_keys($groupstudents); } if ( !$nostudents ) { // Now check if asked download of data $coursecontext = context_course::instance($course->id); if ($download) { $filename = clean_filename("$course->shortname ".format_string($scorm->name, true,$formattextoptions)); } // Define table columns $columns = array(); $headers = array(); if (!$download && $candelete) { $columns[] = 'checkbox'; $headers[] = null; } if (!$download && $CFG->grade_report_showuserimage) { $columns[] = 'picture'; $headers[] = ''; } $columns[] = 'fullname'; $headers[] = get_string('name'); $extrafields = get_extra_user_fields($coursecontext); foreach ($extrafields as $field) { $columns[] = $field; $headers[] = get_user_field_name($field); } $columns[] = 'attempt'; $headers[] = get_string('attempt', 'scorm'); $columns[] = 'start'; $headers[] = get_string('started', 'scorm'); $columns[] = 'finish'; $headers[] = get_string('last', 'scorm'); $columns[] = 'score'; $headers[] = get_string('score', 'scorm'); $scoes = $DB->get_records('scorm_scoes', array("scorm"=>$scorm->id), 'id'); foreach ($scoes as $sco) { if ($sco->launch != '') { $columns[] = 'scograde'.$sco->id; $headers[] = format_string($sco->title,'',$formattextoptions); } } $params = array(); list($usql, $params) = $DB->get_in_or_equal($allowedlist, SQL_PARAMS_NAMED); // Construct the SQL $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, '; $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' . 'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt, u.email'. get_extra_user_fields_sql($coursecontext, 'u', '', array('idnumber')) . ' '; // This part is the same for all cases - join users and scorm_scoes_track tables $from = 'FROM {user} u '; $from .= 'LEFT JOIN {scorm_scoes_track} st ON st.userid = u.id AND st.scormid = '.$scorm->id; switch ($attemptsmode) { case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH: // Show only students with attempts $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NOT NULL'; break; case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO: // Show only students without attempts $where = ' WHERE u.id ' .$usql. ' AND st.userid IS NULL'; break; case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS: // Show all students with or without attempts $where = ' WHERE u.id ' .$usql. ' AND (st.userid IS NOT NULL OR st.userid IS NULL)'; break; } $countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').')) AS nbresults, '; $countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'st.attempt').')) AS nbattempts, '; $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers '; $countsql .= $from.$where; $attempts = $DB->get_records_sql($select.$from.$where, $params); $questioncount = get_scorm_question_count($scorm->id); for($id = 0; $id < $questioncount; $id++) { if ($displayoptions['qtext']) { $columns[] = 'question' . $id; $headers[] = get_string('questionx', 'scormreport_interactions', $id); } if ($displayoptions['resp']) { $columns[] = 'response' . $id; $headers[] = get_string('responsex', 'scormreport_interactions', $id); } if ($displayoptions['right']) { $columns[] = 'right' . $id; $headers[] = get_string('rightanswerx', 'scormreport_interactions', $id); } } if (!$download) { $table = new flexible_table('mod-scorm-report'); $table->define_columns($columns); $table->define_headers($headers); $table->define_baseurl($PAGE->url); $table->sortable(true); $table->collapsible(true); // This is done to prevent redundant data, when a user has multiple attempts $table->column_suppress('picture'); $table->column_suppress('fullname'); foreach ($extrafields as $field) { $table->column_suppress($field); } $table->no_sorting('start'); $table->no_sorting('finish'); $table->no_sorting('score'); foreach ($scoes as $sco) { if ($sco->launch != '') { $table->no_sorting('scograde'.$sco->id); } } $table->column_class('picture', 'picture'); $table->column_class('fullname', 'bold'); $table->column_class('score', 'bold'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); } else if ($download == 'ODS') { require_once("$CFG->libdir/odslib.class.php"); $filename .= ".ods"; // Creating a workbook $workbook = new MoodleODSWorkbook("-"); // Sending HTTP headers $workbook->send($filename); // Creating the first worksheet $sheettitle = get_string('report', 'scorm'); $myxls =& $workbook->add_worksheet($sheettitle); // format types $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); // Here starts workshhet headers $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else if ($download =='Excel') { require_once("$CFG->libdir/excellib.class.php"); $filename .= ".xls"; // Creating a workbook $workbook = new MoodleExcelWorkbook("-"); // Sending HTTP headers $workbook->send($filename); // Creating the first worksheet $sheettitle = get_string('report', 'scorm'); $myxls =& $workbook->add_worksheet($sheettitle); // format types $format =& $workbook->add_format(); $format->set_bold(0); $formatbc =& $workbook->add_format(); $formatbc->set_bold(1); $formatbc->set_align('center'); $formatb =& $workbook->add_format(); $formatb->set_bold(1); $formaty =& $workbook->add_format(); $formaty->set_bg_color('yellow'); $formatc =& $workbook->add_format(); $formatc->set_align('center'); $formatr =& $workbook->add_format(); $formatr->set_bold(1); $formatr->set_color('red'); $formatr->set_align('center'); $formatg =& $workbook->add_format(); $formatg->set_bold(1); $formatg->set_color('green'); $formatg->set_align('center'); $colnum = 0; foreach ($headers as $item) { $myxls->write(0, $colnum, $item, $formatbc); $colnum++; } $rownum = 1; } else if ($download == 'CSV') { $filename .= ".txt"; header("Content-Type: application/download\n"); header("Content-Disposition: attachment; filename=\"$filename\""); header("Expires: 0"); header("Cache-Control: must-revalidate,post-check=0,pre-check=0"); header("Pragma: public"); echo implode("\t", $headers)." \n"; } if (!$download) { $sort = $table->get_sql_sort(); } else { $sort = ''; } // Fix some wired sorting if (empty($sort)) { $sort = ' ORDER BY uniqueid'; } else { $sort = ' ORDER BY '.$sort; } if (!$download) { // Add extra limits due to initials bar list($twhere, $tparams) = $table->get_sql_where(); if ($twhere) { $where .= ' AND '.$twhere; //initial bar $params = array_merge($params, $tparams); } if (!empty($countsql)) { $count = $DB->get_record_sql($countsql,$params); $totalinitials = $count->nbresults; if ($twhere) { $countsql .= ' AND '.$twhere; } $count = $DB->get_record_sql($countsql, $params); $total = $count->nbresults; } $table->pagesize($pagesize, $total); echo '<div class="quizattemptcounts">'; if ( $count->nbresults == $count->nbattempts ) { echo get_string('reportcountattempts', 'scorm', $count); } else if ( $count->nbattempts>0 ) { echo get_string('reportcountallattempts', 'scorm', $count); } else { echo $count->nbusers.' '.get_string('users'); } echo '</div>'; } // Fetch the attempts if (!$download) { $attempts = $DB->get_records_sql($select.$from.$where.$sort, $params, $table->get_page_start(), $table->get_page_size()); echo '<div id="scormtablecontainer">'; if ($candelete) { // Start form $strreallydel = addslashes_js(get_string('deleteattemptcheck', 'scorm')); echo '<form id="attemptsform" method="post" action="' . $PAGE->url->out(false) . '" onsubmit="return confirm(\''.$strreallydel.'\');">'; echo '<input type="hidden" name="action" value="delete"/>'; echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />'; echo '<div style="display: none;">'; echo html_writer::input_hidden_params($PAGE->url); echo '</div>'; echo '<div>'; } $table->initialbars($totalinitials>20); // Build table rows } else { $attempts = $DB->get_records_sql($select.$from.$where.$sort, $params); } if ($attempts) { foreach ($attempts as $scouser) { $row = array(); if (!empty($scouser->attempt)) { $timetracks = scorm_get_sco_runtime($scorm->id, false, $scouser->userid, $scouser->attempt); } else { $timetracks = ''; } if (in_array('checkbox', $columns)) { if ($candelete && !empty($timetracks->start)) { $row[] = '<input type="checkbox" name="attemptid[]" value="'. $scouser->userid . ':' . $scouser->attempt . '" />'; } else if ($candelete) { $row[] = ''; } } if (in_array('picture', $columns)) { $user = (object)array( 'id'=>$scouser->userid, 'picture'=>$scouser->picture, 'imagealt'=>$scouser->imagealt, 'email'=>$scouser->email, 'firstname'=>$scouser->firstname, 'lastname'=>$scouser->lastname); $row[] = $OUTPUT->user_picture($user, array('courseid'=>$course->id)); } if (!$download) { $row[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$scouser->userid.'&course='.$course->id.'">'.fullname($scouser).'</a>'; } else { $row[] = fullname($scouser); } foreach ($extrafields as $field) { $row[] = s($scouser->{$field}); } if (empty($timetracks->start)) { $row[] = '-'; $row[] = '-'; $row[] = '-'; $row[] = '-'; } else { if (!$download) { $row[] = '<a href="userreport.php?a='.$scorm->id.'&user='******'&attempt='.$scouser->attempt.'">'.$scouser->attempt.'</a>'; } else { $row[] = $scouser->attempt; } if ($download =='ODS' || $download =='Excel' ) { $row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig")); } else { $row[] = userdate($timetracks->start); } if ($download =='ODS' || $download =='Excel' ) { $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig')); } else { $row[] = userdate($timetracks->finish); } $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt); } // print out all scores of attempt foreach ($scoes as $sco) { if ($sco->launch != '') { if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) { if ($trackdata->status == '') { $trackdata->status = 'notattempted'; } $strstatus = get_string($trackdata->status, 'scorm'); // if raw score exists, print it if ($trackdata->score_raw != '') { $score = $trackdata->score_raw; // add max score if it exists if ($scorm->version == 'SCORM_1.3') { $maxkey = 'cmi.score.max'; } else { $maxkey = 'cmi.core.score.max'; } if (isset($trackdata->$maxkey)) { $score .= '/'.$trackdata->$maxkey; } // else print out status } else { $score = $strstatus; } if (!$download) { $row[] = '<img src="'.$OUTPUT->pix_url($trackdata->status, 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" /><br/> <a href="userreport.php?b='.$sco->id.'&user='******'&attempt='.$scouser->attempt. '" title="'.get_string('details', 'scorm').'">'.$score.'</a>'; } else { $row[] = $score; } // interaction data $i=0; $element='cmi.interactions_'.$i.'.id'; while(isset($trackdata->$element)) { if ($displayoptions['qtext']) { $element='cmi.interactions_'.$i.'.id'; if (isset($trackdata->$element)) { $row[] = s($trackdata->$element); } else { $row[] = ' '; } } if ($displayoptions['resp']) { $element='cmi.interactions_'.$i.'.student_response'; if (isset($trackdata->$element)) { $row[] = s($trackdata->$element); } else { $row[] = ' '; } } if ($displayoptions['right']) { $j=0; $element = 'cmi.interactions_'.$i.'.correct_responses_'.$j.'.pattern'; $rightans = ''; if (isset($trackdata->$element)) { while(isset($trackdata->$element)) { if($j>0) { $rightans .= ','; } $rightans .= s($trackdata->$element); $j++; $element = 'cmi.interactions_'.$i.'.correct_responses_'.$j.'.pattern'; } $row[] = $rightans; } else { $row[] = ' '; } } $i++; $element = 'cmi.interactions_'.$i.'.id'; } //---end of interaction data*/ } else { // if we don't have track data, we haven't attempted yet $strstatus = get_string('notattempted', 'scorm'); if (!$download) { $row[] = '<img src="'.$OUTPUT->pix_url('notattempted', 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" /><br/>'.$strstatus; } else { $row[] = $strstatus; } } } } if (!$download) { $table->add_data($row); } else if ($download == 'Excel' or $download == 'ODS') { $colnum = 0; foreach ($row as $item) { $myxls->write($rownum, $colnum, $item, $format); $colnum++; } $rownum++; } else if ($download == 'CSV') { $text = implode("\t", $row); echo $text." \n"; } } if (!$download) { $table->finish_output(); if ($candelete) { echo '<table id="commands">'; echo '<tr><td>'; echo '<a href="javascript:select_all_in(\'DIV\', null, \'scormtablecontainer\');">'. get_string('selectall', 'scorm').'</a> / '; echo '<a href="javascript:deselect_all_in(\'DIV\', null, \'scormtablecontainer\');">'. get_string('selectnone', 'scorm').'</a> '; echo ' '; echo '<input type="submit" value="'.get_string('deleteselected', 'quiz_overview').'"/>'; echo '</td></tr></table>'; // Close form echo '</div>'; echo '</form>'; } echo '</div>'; if (!empty($attempts)) { echo '<table class="boxaligncenter"><tr>'; echo '<td>'; echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('download'=>'ODS') + $displayoptions), get_string('downloadods')); echo "</td>\n"; echo '<td>'; echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('download'=>'Excel') + $displayoptions), get_string('downloadexcel')); echo "</td>\n"; echo '<td>'; echo $OUTPUT->single_button(new moodle_url($PAGE->url, array('download'=>'CSV') + $displayoptions), get_string('downloadtext')); echo "</td>\n"; echo "<td>"; echo "</td>\n"; echo '</tr></table>'; } } } else { if ($candelete && !$download) { echo '</div>'; echo '</form>'; $table->finish_output(); } echo '</div>'; } // Show preferences form irrespective of attempts are there to report or not if (!$download) { $mform->set_data(compact('detailedrep', 'pagesize', 'attemptsmode')); $mform->display(); } if ($download == 'Excel' or $download == 'ODS') { $workbook->close(); exit; } else if ($download == 'CSV') { exit; } } else { echo $OUTPUT->notification(get_string('noactivity', 'scorm')); } }// function ends
/** * Real raster that prints graphs and data * */ function print_dashboard() { global $CFG, $EXTRADBCONNECT, $COURSE, $DB, $OUTPUT; /* $text = '<link type="text/css" rel="stylesheet" href="'.$CFG->wwwroot.'/blocks/dashboard/js/dhtmlxCalendar/codebase/dhtmlxcalendar.css" />'; $text .= '<link type="text/css" rel="stylesheet" href="'.$CFG->wwwroot.'/blocks/dashboard/js/dhtmlxCalendar/codebase/skins/dhtmlxcalendar_dhx_web.css" />'; */ $text = ''; if (!isset($this->config)) { $this->config = new StdClass(); } $this->config->limit = 20; $coursepage = ''; if ($COURSE->format == 'page') { include_once $CFG->dirroot . '/course/format/page/lib.php'; $pageid = optional_param('page', 0, PARAM_INT); // flexipage page number if (!$pageid) { $flexpage = course_page::get_current_page($COURSE->id); } else { $flexpage = new StdClass(); $flexpage->id = $pageid; } $coursepage = "&page=" . $flexpage->id; } $rpage = optional_param('rpage' . $this->instance->id, 0, PARAM_INT); // result page if ($rpage < 0) { $rpage = 0; } // unlogged people cannot see their status if ((!isloggedin() || isguestuser()) && @$this->config->guestsallowed) { $text = get_string('guestsnotallowed', 'block_dashboard'); $loginstr = get_string('login'); $text .= "<a href=\"{$wwwroot}/login/index.php\">{$loginstr}</a>"; return $text; } if (!isset($this->config) || empty($this->config->query)) { $noquerystr = get_string('noquerystored', 'block_dashboard'); $text = $noquerystr; return $text; } if (!isset($CFG->block_dashboard_big_result_threshold)) { $CFG->block_dashboard_big_result_threshold = 500; } // connecting if ($this->config->target == 'moodle') { // already connected } else { $error = ''; if (!isset($EXTRADBCONNECT)) { $EXTRADBCONNECT = extra_db_connect(true, $error); } if ($error) { $text = $error; return $text; } } // prepare all params from config $this->prepare_config(); $graphdata = array(); $ticks = array(); $filterquerystring = ''; if (!empty($this->config->filters)) { try { $filterquerystring = $this->prepare_filters(); } catch (Exception $e) { if (debugging()) { echo $e->error; } return get_string('invalidorobsoletefilterquery', 'block_dashboard'); } } else { $this->filteredsql = str_replace('<%%FILTERS%%>', '', $this->sql); } $this->sql = str_replace('<%%FILTERS%%>', '', $this->sql); // needed to prepare for filter range prefetch if (!empty($this->params)) { $filterquerystring = $filterquerystring ? $filterquerystring . '&' . $this->prepare_params() : $this->prepare_params(); } else { $this->sql = str_replace('<%%PARAMS%%>', '', $this->sql); // needed to prepare for filter range prefetch $this->filteredsql = str_replace('<%%PARAMS%%>', '', $this->filteredsql); // needed to prepare for filter range prefetch } $sort = optional_param('tsort' . $this->instance->id, @$this->config->defaultsort, PARAM_TEXT); if (!empty($sort)) { // do not sort if already sorted in explained query if (!preg_match('/ORDER\\s+BY/si', $this->sql)) { $this->filteredsql .= " ORDER BY {$sort}"; } } $this->filteredsql = $this->protect($this->filteredsql); // ######### GETTING RESULTS $countres = $this->count_records($error); // if too many results, we force paging mode if (empty($this->config->pagesize) && $countres > $CFG->block_dashboard_big_result_threshold && !empty($this->config->bigresult)) { $text .= '<span class="error">' . get_string('toomanyrecordsusepaging', 'block_dashboard') . '</span><br/>'; $this->config->pagesize = $CFG->block_dashboard_big_result_threshold; $rpage = 0; } // getting real results including page and offset if (!empty($this->config->pagesize)) { $offset = $rpage * $this->config->pagesize; } else { $offset = ''; } try { $results = $this->fetch_dashboard_data($this->filteredsql, @$this->config->pagesize, $offset); } catch (Exception $e) { return get_string('invalidorobsoletequery', 'block_dashboard', $this->config->query); } if ($results) { $table = new flexible_table('mod-dashboard' . $this->instance->id); $instancecontrolvars = array(TABLE_VAR_PAGE => 'rpage' . $this->instance->id, TABLE_VAR_SORT => 'tsort' . $this->instance->id, TABLE_VAR_HIDE => 'thide' . $this->instance->id, TABLE_VAR_SHOW => 'tshow' . $this->instance->id); $table->set_control_variables($instancecontrolvars); // use full not to collide with flexipage paging $tablecolumns = array(); $tableheaders = array(); foreach ($this->output as $field => $label) { $tablecolumns[] = $field; $tableheaders[] = $label; } $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $filterquerystringadd = isset($filterquerystring) ? "&{$filterquerystring}" : ''; if (@$this->config->inblocklayout) { $table->define_baseurl($CFG->wwwroot . '/course/view.php?id=' . $COURSE->id . $coursepage . $filterquerystringadd); } else { $table->define_baseurl($CFG->wwwroot . '/blocks/dashboard/view.php?id=' . $COURSE->id . '&blockid=' . $this->instance->id . $coursepage . $filterquerystringadd); } if (!empty($this->config->sortable)) { $table->sortable(true, $this->config->xaxisfield, SORT_DESC); } //sorted by xaxisfield by default $table->collapsible(true); $table->initialbars(true); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'dashboard' . $this->instance->id); $table->set_attribute('class', 'dashboard'); $table->set_attribute('width', '100%'); foreach ($this->output as $field => $label) { $table->column_class($field, $field); } $table->setup(); /* $where = $table->get_sql_where(); $sortsql = $table->get_sql_sort(); */ if (!empty($this->config->pagesize)) { $table->pagesize($this->config->pagesize, $countres); // no paginating at start } $graphseries = array(); $treedata = array(); $treekeys = array(); $lastvalue = array(); $hcols = array(); $splitnumsonsort = @$this->config->splitsumsonsort; foreach ($results as $result) { // prepare for subsums if (!empty($splitnumsonsort)) { $orderkeyed = strtoupper($result->{$splitnumsonsort}); if (!isset($oldorderkeyed)) { $oldorderkeyed = $orderkeyed; } // first time } // pre-aggregates sums if (!empty($this->config->shownumsums)) { foreach (array_keys($this->numsumsf) as $numsum) { if (empty($numsum)) { continue; } if (!isset($result->{$numsum})) { continue; } // make subaggregates (only for linear tables and when sorting criteria is the split column) // post aggregate after table output if (!isset($aggr)) { $aggr = new StdClass(); } $aggr->{$numsum} = 0 + (double) @$aggr->{$numsum} + (double) $result->{$numsum}; if (!empty($splitnumsonsort) && @$this->config->tabletype == 'linear' && preg_match("/\\b{$splitnumsonsort}\\b/", $sort)) { $this->subaggr[$orderkeyed]->{$numsum} = 0 + (double) @$this->subaggr[$orderkeyed]->{$numsum} + (double) $result->{$numsum}; } } } if (!empty($splitnumsonsort) && @$this->config->tabletype == 'linear' && preg_match("/\\b{$splitnumsonsort}\\b/", $sort)) { if ($orderkeyed != $oldorderkeyed) { // when range changes $k = 0; $tabledata = null; foreach (array_keys($this->output) as $field) { if (in_array($field, array_keys($this->numsumsf))) { if (is_null($tabledata)) { $tabledata = array(); for ($j = 0; $j < $k; $j++) { $tabledata[$j] = ''; } } $tabledata[$k] = '<b>Tot: ' . @$this->subaggr[$oldorderkeyed]->{$field} . '</b>'; } $k++; } if (!is_null($tabledata)) { $table->add_data($tabledata); } $oldorderkeyed = $orderkeyed; } } // Print data in results if (!empty($this->config->showdata)) { if (empty($this->config->tabletype) || $this->config->tabletype == 'linear') { $tabledata = array(); foreach (array_keys($this->output) as $field) { if (empty($field)) { continue; } // did we ask for cumulative results ? $cumulativeix = null; if (preg_match('/S\\((.+?)\\)/', $field, $matches)) { $field = $matches[1]; $cumulativeix = $this->instance->id . '_' . $field; } if (!empty($this->outputf[$field])) { $datum = dashboard_format_data($this->outputf[$field], $result->{$field}, $cumulativeix); } else { $datum = dashboard_format_data(null, @$result->{$field}, $cumulativeix); } // process coloring if required if (!empty($this->config->colorfield) && $this->config->colorfield == $field) { $datum = dashboard_colour_code($this, $datum, $this->colourcoding); } if (!empty($this->config->cleandisplay)) { if (!array_key_exists($field, $lastvalue) || $lastvalue[$field] != $datum) { $lastvalue[$field] = $datum; $tabledata[] = $datum; } else { $tabledata[] = ''; // if same as above, add blanck } } else { $tabledata[] = $datum; } } $table->add_data($tabledata); } else { if ($this->config->tabletype == 'tabular') { // this is a tabular table /* in a tabular table, data can be placed : * - in first columns in order of vertical keys * the results are grabbed sequentially and spread into the matrix */ $keystack = array(); $matrix = array(); foreach (array_keys($this->vertkeys->formats) as $vkey) { if (empty($vkey)) { continue; } $vkeyvalue = $result->{$vkey}; $matrix[] = "['" . addslashes($vkeyvalue) . "']"; } $hkey = $this->config->horizkey; $hkeyvalue = !empty($hkey) ? $result->{$hkey} : ''; $matrix[] = "['" . addslashes($hkeyvalue) . "']"; $matrixst = "\$m" . implode($matrix); if (!in_array($hkeyvalue, $hcols)) { $hcols[] = $hkeyvalue; } // now put the cell value in it $outvalues = array(); foreach (array_keys($this->output) as $field) { // did we ask for cumulative results ? $cumulativeix = null; if (preg_match('/S\\((.+?)\\)/', $field, $matches)) { $field = $matches[1]; $cumulativeix = $this->instance->id . '_' . $field; } if (!empty($this->outputf[$field])) { $datum = dashboard_format_data($this->outputf[$field], $result->{$field}, $cumulativeix); } else { $datum = dashboard_format_data(null, @$result->{$field}, $cumulativeix); } if (!empty($this->config->colorfield) && $this->config->colorfield == $field) { $datum = dashboard_colour_code($this, $datum, $this->colourcoding); } $outvalues[] = str_replace("\"", "\\\"", $datum); } $matrixst .= ' = "' . implode(' ', $outvalues) . '"'; // make the matrix in memory eval($matrixst . ";"); } else { $debug = optional_param('debug', false, PARAM_BOOL); // treeview $resultarr = array_values((array) $result); $resultid = $resultarr[0]; if (!empty($parentserie)) { if (!empty($result->{$parentserie})) { // non root node, attache to his parent if we found it if (array_key_exists($result->{$parentserie}, $treekeys)) { if (!empty($debug)) { echo 'binding to ' . $result->{$parentserie} . '. '; } $treekeys[$result->{$parentserie}]->childs[$resultid] = $result; if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } } else { // in case nodes do not come in correct order, do not connect but register only if (!empty($debug)) { echo 'waiting for ' . $result->{$parentserie} . '. '; } $waitingnodes[$resultid] = $result; if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } } } else { // root node if (!empty($debug)) { echo 'root as ' . $resultid . '. '; } if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } $treedata[$resultid] =& $treekeys[$resultid]; } } else { if (!array_key_exists($resultid, $treekeys)) { $treekeys[$resultid] = $result; } } } } } // Prepare data for graphs if (!empty($this->config->showgraph)) { if (!empty($this->config->xaxisfield) && $this->config->graphtype != 'googlemap' && $this->config->graphtype != 'timeline') { $xaxisfield = $this->config->xaxisfield; if ($this->config->graphtype != 'pie') { // TODO : check if $this->config->xaxisfield exists really (misconfiguration) $ticks[] = addslashes($result->{$xaxisfield}); $ys = 0; foreach (array_keys($this->yseriesf) as $yserie) { if (!isset($result->{$yserie})) { continue; } // did we ask for cumulative results ? $cumulativeix = null; if (preg_match('/S\\((.+?)\\)/', $yserie, $matches)) { $yserie = $matches[1]; $cumulativeix = $this->instance->id . '_' . $yserie; } if ($this->config->graphtype != 'timegraph') { if (!empty($this->yseriesf[$yserie])) { $graphseries[$yserie][] = dashboard_format_data($this->yseriesf[$yserie], $result->{$yserie}, $cumulativeix); } else { $graphseries[$yserie][] = dashboard_format_data(null, $result->{$yserie}, $cumulativeix); } } else { if (!empty($this->yseriesf[$yserie])) { $timeelm = array($result->{$xaxisfield}, dashboard_format_data($this->yseriesf[$yserie], $result->{$yserie}, $cumulativeix)); $graphseries[$ys][] = $timeelm; } else { $timeelm = array($result->{$xaxisfield}, dashboard_format_data(null, $result->{$yserie}, $cumulativeix)); $graphseries[$ys][] = $timeelm; } } $ys++; } } elseif ($this->config->graphtype == 'pie') { foreach ($yseries as $yserie) { if (empty($result->{$xaxisfield})) { $result->{$xaxisfield} = 'N.C.'; } if (!empty($this->yseriesf[$field])) { $graphseries[$yserie][] = array($result->{$xaxisfield}, dashboard_format_data($this->yseriesf[$field], $result->{$yserie}, false)); } else { $graphseries[$yserie][] = array($result->{$xaxisfield}, $result->{$yserie}); } } } } else { $data[] = $result; } } $graphdata = array_values($graphseries); } //************ post aggregating last subtotal *************// if (!empty($this->config->shownumsums) && $results) { if (!empty($splitnumsonsort) && @$this->config->tabletype == 'linear' && preg_match("/\\b{$splitnumsonsort}\\b/", $sort)) { $k = 0; $tabledata = null; foreach (array_keys($this->output) as $field) { if (in_array($field, array_keys($this->numsumsf))) { if (is_null($tabledata)) { $tabledata = array(); for ($j = 0; $j < $k; $j++) { $tabledata[$j] = ''; } } $tabledata[$k] = '<b>Tot: ' . @$this->subaggr[$orderkeyed]->{$field} . '</b>'; } $k++; } $oldorderkeyed = $orderkeyed; if (!is_null($tabledata)) { $table->add_data($tabledata); } } } //************ Starting outputing data ************************// // if treeview, need to post process waiting nodes if (@$this->config->tabletype == 'treeview') { if (!empty($waitingnodes)) { foreach ($waitingnodes as $wnid => $wn) { if (array_key_exists($wn->{$parentserie}, $treekeys)) { if (!empty($debug)) { echo ' postbinding to ' . $wn->{$parentserie} . '. '; } $treekeys[$wn->{$parentserie}]->childs[$wnid] = $wn; unset($waitingnodes[$wnid]); // free some stuff } } } } if (@$this->config->inblocklayout) { $url = $CFG->wwwroot . '/course/view.php?id=' . $COURSE->id . $coursepage . '&tsort' . $this->instance->id . '=' . $sort; } else { $url = $CFG->wwwroot . '/blocks/dashboard/view.php?id=' . $COURSE->id . '&blocksid=' . $this->instance->id . $coursepage . '&tsort' . $this->instance->id . '=' . $sort; } $text .= dashboard_render_filters_and_params_form($this, $sort); if ($this->config->showdata) { $allexportstr = get_string('exportall', 'block_dashboard'); $tableexportstr = get_string('exportdataastable', 'block_dashboard'); $filteredexportstr = get_string('exportfiltered', 'block_dashboard'); $filterquerystring = !empty($filterquerystring) ? '&' . $filterquerystring : ''; if (empty($this->config->tabletype) || @$this->config->tabletype == 'linear') { ob_start(); $table->print_html(); $text .= ob_get_clean(); $text .= "<div style=\"text-align:right\">"; $text .= "<a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}&alldata=1\">{$allexportstr}</a>"; if ($filterquerystring) { $text .= " - <a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}{$filterquerystring}\">{$filteredexportstr}</a>"; } $text .= "</div>"; } elseif (@$this->config->tabletype == 'tabular') { // forget table and use $m matrix for making display $text .= print_cross_table($this, $m, $hcols, $this->config->horizkey, $this->vertkeys, $this->config->horizlabel, true); $text .= "<div style=\"text-align:right\"><a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}&alldata=1\">{$allexportstr}</a></div>"; $text .= "<div style=\"text-align:right\"><a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv_tabular.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}{$filterquerystring}\">{$tableexportstr}</a></div>"; } else { $text .= dashboard_print_tree_view($this, $treedata, $this->treeoutput, $this->output, $this->outputf, $this->colourcoding, true); $text .= "<div style=\"text-align:right\"><a href=\"{$CFG->wwwroot}/blocks/dashboard/export/export_csv.php?id={$COURSE->id}&instance={$this->instance->id}&tsort{$this->instance->id}={$sort}&alldata=1\">{$allexportstr}</a></div>"; } } else { $text .= ''; } } else { // no data, but render filters anyway $text .= dashboard_render_filters_and_params_form($this, $sort); } // showing graph if ($this->config->showgraph && !empty($this->config->graphtype)) { $text .= $OUTPUT->box_start('dashboard-graph-box'); $graphdesc = $this->dashboard_graph_properties(); if ($this->config->graphtype != 'googlemap' && $this->config->graphtype != 'timeline') { $data = $graphdata; $text .= jqplot_print_graph('dashboard' . $this->instance->id, $graphdesc, $data, $this->config->graphwidth, $this->config->graphheight, '', true, $ticks); } elseif ($this->config->graphtype == 'googlemap') { $text .= dashboard_render_googlemaps_data($this, $data, $graphdesc); } else { // timeline graph if (empty($this->config->timelineeventstart) || empty($this->config->timelineeventend)) { $text .= $OUTPUT->notification("Missing mappings (start or titles)", 'notifyproblem'); } else { $text .= timeline_print_graph($this, 'dashboard' . $this->instance->id, $this->config->graphwidth, $this->config->graphheight, $data, true); } } $text .= $OUTPUT->box_end(); } // showing bottom summators if ($this->config->numsums) { $text .= dashboard_render_numsums($this, $aggr); } // showing query if (@$this->config->showquery) { $text .= '<div class="dashboard-query-box" style="padding:1px;border:1px solid #808080;margin:2px;font-size:0.75em;font-family:monospace">'; $text .= '<pre>' . $this->filteredsql . '</pre>'; $text .= '</div>'; } // showing SQL benches if (@$this->config->showbenches) { $text .= '<div class="dashboard-benches-box" style="padding:1px;border:1px solid #808080;margin:2px;font-size:0.75em;font-family:monospace">'; $text .= '<table width="100%">'; foreach ($this->benches as $bench) { $value = $bench->end - $bench->start; $text .= "<tr><td>{$bench->name}</td><td>{$value} sec.</td></tr>"; } $text .= '</table>'; $text .= '</div>'; } return $text; }
/** * Display all the submissions ready for grading * * @global object * @global object * @global object * @global object * @param string $message * @return bool|void */ function display_submissions($message = '') { global $CFG, $DB, $USER, $DB, $OUTPUT; require_once $CFG->libdir . '/gradelib.php'; /* first we check to see if the form has just been submitted * to request user_preference updates */ if (isset($_POST['updatepref'])) { $perpage = optional_param('perpage', 10, PARAM_INT); $perpage = $perpage <= 0 ? 10 : $perpage; set_user_preference('assignment_perpage', $perpage); set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); } /* next we get perpage and quickgrade (allow quick grade) params * from database */ $perpage = get_user_preferences('assignment_perpage', 10); $quickgrade = get_user_preferences('assignment_quickgrade', 0); $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id); if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) { $uses_outcomes = true; } else { $uses_outcomes = false; } $page = optional_param('page', 0, PARAM_INT); $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); /// Some shortcuts to make the code read better $course = $this->course; $assignment = $this->assignment; $cm = $this->cm; $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id=' . $this->cm->id, $this->assignment->id, $this->cm->id); $navigation = build_navigation($this->strsubmissions, $this->cm); print_header_simple(format_string($this->assignment->name, true), "", $navigation, '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); $course_context = get_context_instance(CONTEXT_COURSE, $course->id); if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) { echo '<div class="allcoursegrades"><a href="' . $CFG->wwwroot . '/grade/report/grader/index.php?id=' . $course->id . '">' . get_string('seeallcoursegrades', 'grades') . '</a></div>'; } if (!empty($message)) { echo $message; // display messages here if any } $context = get_context_instance(CONTEXT_MODULE, $cm->id); /// Check to see if groups are being used in this assignment /// find out current groups mode $groupmode = groups_get_activity_groupmode($cm); $currentgroup = groups_get_activity_group($cm, true); groups_print_activity_menu($cm, 'submissions.php?id=' . $this->cm->id); /// Get all ppl that are allowed to submit assignments if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $currentgroup, '', false)) { $users = array_keys($users); } // if groupmembersonly used, remove users who are not in any group if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { $users = array_intersect($users, array_keys($groupingusers)); } } $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status', 'finalgrade'); if ($uses_outcomes) { $tablecolumns[] = 'outcome'; // no sorting based on outcomes column } $tableheaders = array('', get_string('fullname'), get_string('grade'), get_string('comment', 'assignment'), get_string('lastmodified') . ' (' . get_string('submission', 'assignment') . ')', get_string('lastmodified') . ' (' . get_string('grade') . ')', get_string('status'), get_string('finalgrade', 'grades')); if ($uses_outcomes) { $tableheaders[] = get_string('outcome', 'grades'); } require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-assignment-submissions'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/assignment/submissions.php?id=' . $this->cm->id . '&currentgroup=' . $currentgroup); $table->sortable(true, 'lastname'); //sorted by lastname by default $table->collapsible(true); $table->initialbars(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('grade', 'grade'); $table->column_class('submissioncomment', 'comment'); $table->column_class('timemodified', 'timemodified'); $table->column_class('timemarked', 'timemarked'); $table->column_class('status', 'status'); $table->column_class('finalgrade', 'finalgrade'); if ($uses_outcomes) { $table->column_class('outcome', 'outcome'); } $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'submissions'); $table->set_attribute('width', '100%'); //$table->set_attribute('align', 'center'); $table->no_sorting('finalgrade'); $table->no_sorting('outcome'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); if (empty($users)) { echo $OUTPUT->heading(get_string('nosubmitusers', 'assignment')); return true; } /// Construct the SQL if ($where = $table->get_sql_where()) { $where .= ' AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY ' . $sort; } $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, s.id AS submissionid, s.grade, s.submissioncomment, s.timemodified, s.timemarked, COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; $sql = 'FROM {user} u ' . 'LEFT JOIN {assignment_submissions} s ON u.id = s.userid AND s.assignment = ' . $this->assignment->id . ' ' . 'WHERE ' . $where . 'u.id IN (' . implode(',', $users) . ') '; $table->pagesize($perpage, count($users)); ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next $offset = $page * $perpage; $strupdate = get_string('update'); $strgrade = get_string('grade'); $grademenu = make_grades_menu($this->assignment->grade); if (($ausers = $DB->get_records_sql($select . $sql . $sort, null, $table->get_page_start(), $table->get_page_size())) !== false) { $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); foreach ($ausers as $auser) { $final_grade = $grading_info->items[0]->grades[$auser->id]; $grademax = $grading_info->items[0]->grademax; $final_grade->formatted_grade = round($final_grade->grade, 2) . ' / ' . round($grademax, 2); $locked_overridden = 'locked'; if ($final_grade->overridden) { $locked_overridden = 'overridden'; } /// Calculate user status $auser->status = $auser->timemarked > 0 && $auser->timemarked >= $auser->timemodified; $picture = $OUTPUT->user_picture(moodle_user_picture::make($auser, $course->id)); if (empty($auser->submissionid)) { $auser->grade = -1; //no submission yet } if (!empty($auser->submissionid)) { ///Prints student answer and student modified date ///attach file or print link to student answer, depending on the type of the assignment. ///Refer to print_student_answer in inherited classes. if ($auser->timemodified > 0) { $studentmodified = '<div id="ts' . $auser->id . '">' . $this->print_student_answer($auser->id) . userdate($auser->timemodified) . '</div>'; } else { $studentmodified = '<div id="ts' . $auser->id . '"> </div>'; } ///Print grade, dropdown or text if ($auser->timemarked > 0) { $teachermodified = '<div id="tt' . $auser->id . '">' . userdate($auser->timemarked) . '</div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g' . $auser->id . '" class="' . $locked_overridden . '">' . $final_grade->formatted_grade . '</div>'; } else { if ($quickgrade) { $select = html_select::make(make_grades_menu($this->assignment->grade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde')); $select->nothingvalue = '-1'; $select->tabindex = $tabindex++; $menu = $OUTPUT->select($select); $grade = '<div id="g' . $auser->id . '">' . $menu . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; } } } else { $teachermodified = '<div id="tt' . $auser->id . '"> </div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g' . $auser->id . '" class="' . $locked_overridden . '">' . $final_grade->formatted_grade . '</div>'; } else { if ($quickgrade) { $select = html_select::make(make_grades_menu($this->assignment->grade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde')); $select->nothingvalue = '-1'; $select->tabindex = $tabindex++; $menu = $OUTPUT->select($select); $grade = '<div id="g' . $auser->id . '">' . $menu . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; } } } ///Print Comment if ($final_grade->locked or $final_grade->overridden) { $comment = '<div id="com' . $auser->id . '">' . shorten_text(strip_tags($final_grade->str_feedback), 15) . '</div>'; } else { if ($quickgrade) { $comment = '<div id="com' . $auser->id . '">' . '<textarea tabindex="' . $tabindex++ . '" name="submissioncomment[' . $auser->id . ']" id="submissioncomment' . $auser->id . '" rows="2" cols="20">' . $auser->submissioncomment . '</textarea></div>'; } else { $comment = '<div id="com' . $auser->id . '">' . shorten_text(strip_tags($auser->submissioncomment), 15) . '</div>'; } } } else { $studentmodified = '<div id="ts' . $auser->id . '"> </div>'; $teachermodified = '<div id="tt' . $auser->id . '"> </div>'; $status = '<div id="st' . $auser->id . '"> </div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g' . $auser->id . '">' . $final_grade->formatted_grade . '</div>'; } else { if ($quickgrade) { // allow editing $select = html_select::make(make_grades_menu($this->assignment->grade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde')); $select->nothingvalue = '-1'; $select->tabindex = $tabindex++; $menu = $OUTPUT->select($select); $grade = '<div id="g' . $auser->id . '">' . $menu . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">-</div>'; } } if ($final_grade->locked or $final_grade->overridden) { $comment = '<div id="com' . $auser->id . '">' . $final_grade->str_feedback . '</div>'; } else { if ($quickgrade) { $comment = '<div id="com' . $auser->id . '">' . '<textarea tabindex="' . $tabindex++ . '" name="submissioncomment[' . $auser->id . ']" id="submissioncomment' . $auser->id . '" rows="2" cols="20">' . $auser->submissioncomment . '</textarea></div>'; } else { $comment = '<div id="com' . $auser->id . '"> </div>'; } } } if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 $auser->status = 0; } else { $auser->status = 1; } $buttontext = $auser->status == 1 ? $strupdate : $strgrade; ///No more buttons, we use popups ;-). $popup_url = '/mod/assignment/submissions.php?id=' . $this->cm->id . '&userid=' . $auser->id . '&mode=single' . '&offset=' . $offset++; $link = html_link::make($popup_url, $buttontext); $link->add_action(new popup_action('click', $link->url, 'grade' . $auser->id, array('height' => 600, 'width' => 700))); $link->title = $buttontext; $button = $OUTPUT->link($link); $status = '<div id="up' . $auser->id . '" class="s' . $auser->status . '">' . $button . '</div>'; $finalgrade = '<span id="finalgrade_' . $auser->id . '">' . $final_grade->str_grade . '</span>'; $outcomes = ''; if ($uses_outcomes) { foreach ($grading_info->outcomes as $n => $outcome) { $outcomes .= '<div class="outcome"><label>' . $outcome->name . '</label>'; $options = make_grades_menu(-$outcome->scaleid); if ($outcome->grades[$auser->id]->locked or !$quickgrade) { $options[0] = get_string('nooutcome', 'grades'); $outcomes .= ': <span id="outcome_' . $n . '_' . $auser->id . '">' . $options[$outcome->grades[$auser->id]->grade] . '</span>'; } else { $outcomes .= ' '; $select = html_select::make($options, 'outcome_' . $n . '[' . $auser->id . ']', $outcome->grades[$auser->id]->grade, get_string('nooutcome', 'grades')); $select->nothingvalue = '0'; $select->tabindex = $tabindex++; $select->id = 'outcome_' . $n . '_' . $auser->id; $outcomes .= $OUTPUT->select($select); } $outcomes .= '</div>'; } } $userlink = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&course=' . $course->id . '">' . fullname($auser) . '</a>'; $row = array($picture, $userlink, $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); if ($uses_outcomes) { $row[] = $outcomes; } $table->add_data($row); } } /// Print quickgrade form around the table if ($quickgrade) { echo '<form action="submissions.php" id="fastg" method="post">'; echo '<div>'; echo '<input type="hidden" name="id" value="' . $this->cm->id . '" />'; echo '<input type="hidden" name="mode" value="fastgrade" />'; echo '<input type="hidden" name="page" value="' . $page . '" />'; echo '</div>'; } $table->print_html(); /// Print the whole table if ($quickgrade) { $lastmailinfo = get_user_preferences('assignment_mailinfo', 1) ? 'checked="checked"' : ''; echo '<div class="fgcontrols">'; echo '<div class="emailnotification">'; echo '<label for="mailinfo">' . get_string('enableemailnotification', 'assignment') . '</label>'; echo '<input type="hidden" name="mailinfo" value="0" />'; echo '<input type="checkbox" id="mailinfo" name="mailinfo" value="1" ' . $lastmailinfo . ' />'; echo $OUTPUT->help_icon(moodle_help_icon::make('emailnotification', get_string('enableemailnotification', 'assignment'), 'assignment')) . '</p></div>'; echo '</div>'; echo '<div class="fastgbutton"><input type="submit" name="fastg" value="' . get_string('saveallfeedback', 'assignment') . '" /></div>'; echo '</div>'; echo '</form>'; } /// End of fast grading form /// Mini form for setting user preference echo '<div class="qgprefs">'; echo '<form id="options" action="submissions.php?id=' . $this->cm->id . '" method="post"><div>'; echo '<input type="hidden" name="updatepref" value="1" />'; echo '<table id="optiontable">'; echo '<tr><td>'; echo '<label for="perpage">' . get_string('pagesize', 'assignment') . '</label>'; echo '</td>'; echo '<td>'; echo '<input type="text" id="perpage" name="perpage" size="1" value="' . $perpage . '" />'; echo $OUTPUT->help_icon(moodle_help_icon::make('pagesize', get_string('pagesize', 'assignment'), 'assignment')); echo '</td></tr>'; echo '<tr><td>'; echo '<label for="quickgrade">' . get_string('quickgrade', 'assignment') . '</label>'; echo '</td>'; echo '<td>'; $checked = $quickgrade ? 'checked="checked"' : ''; echo '<input type="checkbox" id="quickgrade" name="quickgrade" value="1" ' . $checked . ' />'; echo $OUTPUT->help_icon(moodle_help_icon::make('quickgrade', get_string('quickgrade', 'assignment'), 'assignment')) . '</p></div>'; echo '</td></tr>'; echo '<tr><td colspan="2">'; echo '<input type="submit" value="' . get_string('savepreferences') . '" />'; echo '</td></tr></table>'; echo '</div></form></div>'; ///End of mini form echo $OUTPUT->footer(); }
function display_submissions($message = '') { global $CFG, $db, $USER; require_once $CFG->libdir . '/gradelib.php'; // Update preferences if (isset($_POST['updatepref'])) { $perpage = optional_param('perpage', 20, PARAM_INT); $perpage = $perpage <= 0 ? 20 : $perpage; set_user_preference('assignment_perpage', $perpage); $moderationtarget = optional_param('moderationtarget', 0, PARAM_INT); $moderationtarget = $moderationtarget <= 0 ? 0 : $moderationtarget; set_user_preference('assignment_moderationtarget', $moderationtarget); } // Get preferences $perpage = get_user_preferences('assignment_perpage', 10); $moderationtarget = get_user_preferences('assignment_moderationtarget', 0); // Some shortcuts to make the code read better $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id); $course = $this->course; $assignment = $this->assignment; $cm = $this->cm; $context = get_context_instance(CONTEXT_MODULE, $cm->id); $page = optional_param('page', 0, PARAM_INT); // Log this view add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id=' . $this->assignment->id, $this->assignment->id, $this->cm->id); // Print header and navigation breadcrumbs $navigation = build_navigation($this->strsubmissions, $this->cm); print_header_simple(format_string($this->assignment->name, true), "", $navigation, '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); // Print tabs at top of page $tabs = array(); $row = array(); $inactive = array(); $activated = array(); $row[] = new tabobject('criteria', "type/peerreview/" . self::CRITERIA_FILE . "?id=" . $this->cm->id . "&a=" . $this->assignment->id, get_string('criteria', 'assignment_peerreview')); $row[] = new tabobject('submissions', '', get_string('submissions', 'assignment_peerreview')); $tabs[] = $row; $currenttab = 'submissions'; $inactive[] = 'submissions'; $activated[] = 'submissions'; print_tabs($tabs, $currenttab, $inactive, $activated); // Print optional message if (!empty($message)) { echo $message; // display messages here if any } // Check to see if groups are being used in this assignment // find out current groups mode // $groupmode = groups_get_activity_groupmode($cm); // $currentgroup = groups_get_activity_group($cm, true); // groups_print_activity_menu($cm, $CFG->wwwroot.'/mod/assignment/submissions.php?id=' . $cm->id); // Get all ppl that are allowed to submit assignments // if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id', '', '', '', $currentgroup, '', false)) { if ($users = get_users_by_capability($context, 'mod/assignment:submit', 'u.id')) { $users = array_keys($users); } // Filter out teachers if ($users && ($teachers = get_users_by_capability($context, 'mod/assignment:grade', 'u.id'))) { $users = array_diff($users, array_keys($teachers)); } // Warn if class is too small if (count($users) < 5) { notify(get_string('numberofstudentswarning', 'assignment_peerreview')); } // if groupmembersonly used, remove users who are not in any group // if ($users and !empty($CFG->enablegroupings) and $cm->groupmembersonly) { // if ($groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id')) { // $users = array_intersect($users, array_keys($groupingusers)); // } // } // Create the table to be shown require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-assignment-submissions'); $tablecolumns = array('picture', 'fullname', 'submitted', 'reviews', 'moderations', 'status', 'seedoreviews', 'suggestedmark', 'finalgrade'); $table->define_columns($tablecolumns); $tableheaders = array('', get_string('fullname'), get_string('submission', 'assignment_peerreview'), get_string('reviewsbystudent', 'assignment_peerreview') . helpbutton('reviewsbystudent', get_string('reviewsbystudent', 'assignment_peerreview'), 'assignment/type/peerreview/', true, false, '', true), get_string('moderationstitle', 'assignment_peerreview') . helpbutton('moderationtarget', get_string('moderationtarget', 'assignment_peerreview'), 'assignment/type/peerreview/', true, false, '', true), get_string('status') . helpbutton('status', get_string('status', 'assignment_peerreview'), 'assignment/type/peerreview/', true, false, '', true), get_string('seedoreviews', 'assignment_peerreview') . helpbutton('seedoreviews', get_string('seedoreviews', 'assignment_peerreview'), 'assignment/type/peerreview/', true, false, '', true), get_string('suggestedgrade', 'assignment_peerreview') . helpbutton('suggestedgrade', get_string('suggestedgrade', 'assignment_peerreview'), 'assignment/type/peerreview/', true, false, '', true), get_string('finalgrade', 'assignment_peerreview') . helpbutton('finalgrade', get_string('finalgrade', 'assignment_peerreview'), 'assignment/type/peerreview/', true, false, '', true)); $table->define_headers($tableheaders); // $table->define_baseurl($CFG->wwwroot.'/mod/assignment/submissions.php?id='.$this->cm->id.'&currentgroup='.$currentgroup); $table->define_baseurl($CFG->wwwroot . '/mod/assignment/submissions.php?id=' . $this->cm->id); // $table->sortable(true, 'submitted'); $table->sortable(false); $table->collapsible(true); // $table->initialbars(true); $table->initialbars(false); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('submitted', 'submitted'); $table->column_class('reviews', 'reviews'); $table->column_class('moderations', 'moderations'); $table->column_class('status', 'status'); $table->column_class('seedoreviews', 'seedoreviews'); $table->column_class('suggestedmark', 'suggestedmark'); $table->column_class('finalgrade', 'finalgrade'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'submissions'); $table->set_attribute('width', '99%'); $table->set_attribute('align', 'center'); $table->column_style('submitted', 'text-align', $alignment); $table->column_style('finalgrade', 'text-align', 'center'); /* $table->no_sorting('picture'); $table->no_sorting('fullname'); $table->no_sorting('submitted'); $table->no_sorting('reviews'); $table->no_sorting('moderations'); $table->no_sorting('status'); $table->no_sorting('seedoreviews'); $table->no_sorting('suggestedmark'); $table->no_sorting('finalgrade'); */ $table->setup(); if (empty($users)) { print_heading(get_string('nosubmitusers', 'assignment')); return true; } // Construct the SQL if ($where = $table->get_sql_where()) { $where .= ' AND '; } $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, u.imagealt, s.id AS submissionid, s.grade, s.timecreated as submitted, s.timemarked '; $sql = 'FROM ' . $CFG->prefix . 'user u ' . 'LEFT JOIN ' . $CFG->prefix . 'assignment_submissions s ON u.id=s.userid AND s.assignment=' . $this->assignment->id . ' ' . 'WHERE ' . $where . 'u.id IN (' . implode(',', $users) . ') '; $sort = 'ORDER BY COALESCE(submitted,2147483647) ASC, submissionid ASC, u.lastname ASC'; // if ($sort = $table->get_sql_sort()) { // $sort = ' ORDER BY '.$sort; // } $table->pagesize($perpage, count($users)); ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next $offset = $page * $perpage; $strupdate = get_string('update'); $strgrade = get_string('grade'); $grademenu = make_grades_menu($this->assignment->grade); // Get the criteria $criteriaList = get_records_list('assignment_criteria', 'assignment', $this->assignment->id, 'ordernumber'); $numberOfCriteria = 0; if (is_array($criteriaList)) { $criteriaList = array_values($criteriaList); $numberOfCriteria = count($criteriaList); } if (($ausers = get_records_sql($select . $sql . $sort, $table->get_page_start(), $table->get_page_size())) !== false) { // $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); foreach ($ausers as $auser) { // $final_grade = $grading_info->items[0]->grades[$auser->id]; // Calculate user status $auser->status = $auser->timemarked > 0; $picture = print_user_picture($auser, $course->id, $auser->picture, false, true); $studentName = '<a href="' . $CFG->wwwroot . '/user/view.php?id=' . $auser->id . '&course=' . $this->course->id . '">' . fullname($auser) . '</a>'; // If submission has been made if (!empty($auser->submissionid)) { $filearea = $this->file_area_name($auser->id); $fileLink = ''; if (isset($this->assignment->var3) && $this->assignment->var3 == self::ONLINE_TEXT) { $url = '/mod/assignment/type/peerreview/' . self::VIEW_ONLINE_TEXT . '?id=' . $this->cm->id . '&a=' . $this->assignment->id . '&userid=' . $auser->id . '&view=moderation'; $fileLink .= '<a href="' . $CFG->wwwroot . $url . '" target="_blank" onclick="return openpopup(\'' . $url . '\',\'\',\'menubar=0,location=0,scrollbars,resizable,width=500,height=400\');"><img src="' . $CFG->pixpath . '/f/html.gif" /></a>'; } else { $basedir = $this->file_area($auser->id); if ($files = get_directory_list($basedir)) { require_once $CFG->libdir . '/filelib.php'; foreach ($files as $key => $file) { $icon = mimeinfo('icon', $file); $ffurl = get_file_url("{$filearea}/{$file}", array('forcedownload' => 1)); $fileLink .= '<a href="' . $ffurl . '" ><img src="' . $CFG->pixpath . '/f/' . $icon . '" class="icon" alt="' . $icon . '" /></a>'; } } } $submitted = '<div class="files" style="display:inline;">' . $fileLink . '</div><div style="display:inline;" id="tt' . $auser->id . '">' . userdate($auser->submitted, get_string('strftimeintable', 'assignment_peerreview')) . '</div>'; $submitted .= ' <a href="' . $CFG->wwwroot . '/mod/assignment/type/peerreview/' . self::RESUBMIT_FILE . '?id=' . $this->cm->id . '&a=' . $this->assignment->id . '&userid=' . $auser->id . '">(' . get_string('resubmitlabel', 'assignment_peerreview') . ')</a>'; // Reviews by student $numberOfReviewsByThisStudent = 0; if ($reviewsByThisStudent = get_records_select('assignment_review', 'assignment=\'' . $this->assignment->id . '\' AND reviewer=\'' . $auser->id . '\' AND complete=\'1\'')) { $numberOfReviewsByThisStudent = count($reviewsByThisStudent); $reviewsByThisStudent = array_values($reviewsByThisStudent); $reviews = '<div style="text-align:center;" id="re' . $auser->id . '">'; for ($i = 0; $i < $numberOfReviewsByThisStudent; $i++) { $reviews .= '<span id="rev' . $reviewsByThisStudent[$i]->id . '" style="padding:5px 2px;">'; $popup_url = '/mod/assignment/submissions.php?id=' . $this->cm->id . '&userid=' . $reviewsByThisStudent[$i]->reviewee . '&mode=single&offset=1'; $reviews .= element_to_popup_window('button', $popup_url, 'grade' . $auser->id, $i + 1, 600, 780, $i + 1, 'none', true, 'user' . $auser->id . 'rev' . $i); $reviews .= '</span>'; // $reviews .= $i<$numberOfReviewsByThisStudent-1?', ':''; } $reviews .= '</div>'; $reviews .= '<script>'; for ($i = 0; $i < $numberOfReviewsByThisStudent; $i++) { $reviews .= 'document.getElementById(\'user' . $auser->id . 'rev' . $i . '\').setAttribute(\'onmouseover\',\'document.getElementById("se' . $reviewsByThisStudent[$i]->reviewee . '").style.background="#ff9999";\');'; $reviews .= 'document.getElementById(\'user' . $auser->id . 'rev' . $i . '\').setAttribute(\'onmouseout\',\'document.getElementById("se' . $reviewsByThisStudent[$i]->reviewee . '").style.background="transparent";\');'; } $reviews .= '</script>'; } else { $reviews = '<div id="re' . $auser->id . '"> </div>'; } // Reviews of student $reviewsOfThisStudent = $this->get_reviews_of_student($auser->id); $numberOfReviewsOfThisStudent = 0; if (is_array($reviewsOfThisStudent)) { $numberOfReviewsOfThisStudent = count($reviewsOfThisStudent); } $statusCode = $this->get_status($reviewsOfThisStudent, $numberOfCriteria); $status = '<div id="st' . $auser->id . '">' . $this->print_status($statusCode, true) . '</div>'; $buttontext = get_string('review', 'assignment_peerreview'); $popup_url = '/mod/assignment/submissions.php?id=' . $this->cm->id . '&userid=' . $auser->id . '&mode=single' . '&offset=' . $offset++; $button = element_to_popup_window('button', $popup_url, 'grade' . $auser->id, $buttontext, 600, 780, $buttontext, 'none', true, 'reviewbutton' . $auser->id); $seedoreviews = '<div id="se' . $auser->id . '" style="text-align:center;padding:5px 0;"><span id="seOutline' . $auser->id . '" class="s' . ($statusCode <= 3 ? '0' : '1') . '" style="padding:4px 1px;">' . $button . '</span></div>'; $seedoreviews .= '<script>'; $seedoreviews .= 'document.getElementById(\'reviewbutton' . $auser->id . '\').setAttribute(\'onmouseover\',\''; for ($i = 0; $i < $numberOfReviewsOfThisStudent; $i++) { $seedoreviews .= 'buttonHighlight=document.getElementById("rev' . $reviewsOfThisStudent[$i]->review . '"); if(buttonHighlight) buttonHighlight.style.background="#ff9999";'; } $seedoreviews .= '\');'; $seedoreviews .= 'document.getElementById(\'reviewbutton' . $auser->id . '\').setAttribute(\'onmouseout\',\''; for ($i = 0; $i < $numberOfReviewsOfThisStudent; $i++) { $seedoreviews .= 'buttonHighlight=document.getElementById("rev' . $reviewsOfThisStudent[$i]->review . '"); if(buttonHighlight) buttonHighlight.style.background="transparent";'; } $seedoreviews .= '\');'; $seedoreviews .= '</script>'; // Suggest mark $suggestedmark = '<div style="text-align:center;" id="su' . $auser->id . '">'; $suggestedMarkToDisplay = $this->get_marks($reviewsOfThisStudent, $criteriaList, $numberOfReviewsByThisStudent, $this->assignment->var1); $suggestedmark .= '<input type="text" size="4" id="gvalue' . $auser->id . '" value="' . $suggestedMarkToDisplay . '" />'; $suggestedmark .= '<input type="button" value="' . get_string('set', 'assignment_peerreview') . '" onclick="mark=parseInt(document.getElementById(\'gvalue' . $auser->id . '\').value); if(isNaN(mark)) {alert(\'' . get_string('gradenotanumber', 'assignment_peerreview') . '\'); return false;} else {popup_url=\'/mod/assignment/type/peerreview/' . self::SET_MARK_FILE . '?id=' . $this->cm->id . '&a=' . $this->assignment->id . '&userid=' . $auser->id . '&mark=\'+mark; return openpopup(popup_url, \'grade5\', \'menubar=0,location=0,scrollbars,resizable,width=400,height=300\', 0);}" />'; $suggestedmark .= '</div>'; // Final grade if ($auser->timemarked > 0) { // if ($final_grade->locked or $final_grade->overridden) { // $grade = '<div id="g'.$auser->id.'">'.$final_grade->str_grade.'</div>'; // } // else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; // } } else { $grade = '<div id="g' . $auser->id . '">' . get_string('notset', 'assignment_peerreview') . '</div>'; } } else { $submitted = '<div id="tt' . $auser->id . '"> </div>'; $reviews = '<div id="re' . $auser->id . '"> </div>'; $status = '<div id="st' . $auser->id . '"> </div>'; $seedoreviews = '<div id="se' . $auser->id . '"> </div>'; $suggestedmark = '<div id="su' . $auser->id . '"> </div>'; $grade = '<div id="g' . $auser->id . '">-</div>'; } $moderationCountSQL = 'SELECT count(r.id) FROM ' . $CFG->prefix . 'assignment a, ' . $CFG->prefix . 'assignment_review r WHERE a.course=' . $course->id . ' AND a.id=r.assignment AND r.teacherreview=1 AND r.reviewee=\'' . $auser->id . '\''; $moderationCount = count_records_sql($moderationCountSQL); $moderations = '<div id="mo' . $auser->id . '" style="text-align:center;">' . ($moderationCount < $moderationtarget ? '<span class="errorStatus">' . $moderationCount . '</span>' : $moderationCount) . '</div>'; // $finalgrade = '<span id="finalgrade_'.$auser->id.'">'.$final_grade->str_grade.'</span>'; // Add the row to the table $row = array($picture, $studentName, $submitted, $reviews, $moderations, $status, $seedoreviews, $suggestedmark, $grade); $table->add_data($row); } } /// Print quickgrade form around the table require_once $CFG->dirroot . '/mod/assignment/type/peerreview/' . self::STYLES_FILE; $table->print_html(); /// Print the whole table /// Mini form for setting user preference echo '<div style="margin:5px 10px;">'; echo '<table id="optiontable" align="right">'; echo '<tr><td colspan="2" align="right">'; echo '<form id="options" action="type/peerreview/' . self::MASS_MARK_FILE . '?id=' . $this->cm->id . '&a=' . $this->assignment->id . '" method="post">'; echo '<input type="submit" value="' . get_string('massmark', 'assignment_peerreview') . '" />'; helpbutton('massmark', get_string('massmark', 'assignment_peerreview'), 'assignment/type/peerreview/'); echo '</form>'; echo '<br />'; echo '</td></tr>'; echo '<form id="options" action="submissions.php?id=' . $this->cm->id . '" method="post">'; echo '<input type="hidden" id="updatepref" name="updatepref" value="1" />'; echo '<tr align="right"><td>'; echo '<label for="perpage">' . get_string('pagesize', 'assignment') . '</label>'; echo ':</td>'; echo '<td>'; echo '<input type="text" id="perpage" name="perpage" size="1" value="' . $perpage . '" />'; helpbutton('pagesize', get_string('pagesize', 'assignment'), 'assignment'); echo '</td></tr>'; echo '<tr align="right"><td>'; echo '<label for="moderationtarget">' . get_string('moderationtarget', 'assignment_peerreview') . '</label>'; echo ':</td>'; echo '<td>'; echo '<input type="text" id="moderationtarget" name="moderationtarget" size="1" value="' . $moderationtarget . '" />'; helpbutton('moderationtarget', get_string('moderationtargetwhy', 'assignment_peerreview'), 'assignment/type/peerreview'); echo '</td></tr>'; echo '<tr>'; echo '<td colspan="2" align="right">'; echo '<input type="submit" value="' . get_string('savepreferences') . '" />'; echo '</form>'; echo '</td></tr></table>'; echo '</div>'; ///End of mini form print_footer($this->course); }
/** * Display all the submissions ready for grading */ function display_submissions($message = '') { global $CFG, $db, $USER; require_once $CFG->libdir . '/gradelib.php'; /* first we check to see if the form has just been submitted * to request user_preference updates */ if (isset($_POST['updatepref'])) { $perpage = optional_param('perpage', 10, PARAM_INT); $perpage = $perpage <= 0 ? 10 : $perpage; set_user_preference('assignment_perpage', $perpage); set_user_preference('assignment_quickgrade', optional_param('quickgrade', 0, PARAM_BOOL)); } /* next we get perpage and quickgrade (allow quick grade) params * from database */ $perpage = get_user_preferences('assignment_perpage', 10); $quickgrade = get_user_preferences('assignment_quickgrade', 0); $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id); if (!empty($CFG->enableoutcomes) and !empty($grading_info->outcomes)) { $uses_outcomes = true; } else { $uses_outcomes = false; } $teacherattempts = true; /// Temporary measure $page = optional_param('page', 0, PARAM_INT); $strsaveallfeedback = get_string('saveallfeedback', 'assignment'); /// Some shortcuts to make the code read better $course = $this->course; $assignment = $this->assignment; $cm = $this->cm; $tabindex = 1; //tabindex for quick grading tabbing; Not working for dropdowns yet add_to_log($course->id, 'assignment', 'view submission', 'submissions.php?id=' . $this->assignment->id, $this->assignment->id, $this->cm->id); $navlinks = array(); $navlinks[] = array('name' => $this->strassignments, 'link' => "index.php?id={$course->id}", 'type' => 'activity'); $navlinks[] = array('name' => format_string($this->assignment->name, true), 'link' => "view.php?a={$this->assignment->id}", 'type' => 'activityinstance'); $navlinks[] = array('name' => $this->strsubmissions, 'link' => '', 'type' => 'title'); $navigation = build_navigation($navlinks); print_header_simple(format_string($this->assignment->name, true), "", $navigation, '', '', true, update_module_button($cm->id, $course->id, $this->strassignment), navmenu($course, $cm)); if (!empty($message)) { echo $message; // display messages here if any } $context = get_context_instance(CONTEXT_MODULE, $cm->id); /// find out current groups mode $groupmode = groups_get_activity_groupmode($cm); $currentgroup = groups_get_activity_group($cm, true); groups_print_activity_menu($cm, 'submissions.php?id=' . $this->cm->id); /// Get all ppl that are allowed to submit assignments $users = get_users_by_capability($context, 'mod/assignment:submit', '', '', '', '', $currentgroup, '', false); $users = array_keys($users); if (!empty($CFG->enablegroupings) && !empty($cm->groupingid)) { $groupingusers = groups_get_grouping_members($cm->groupingid, 'u.id', 'u.id'); $users = array_intersect($users, array_keys($groupingusers)); } $tablecolumns = array('picture', 'fullname', 'grade', 'submissioncomment', 'timemodified', 'timemarked', 'status', 'finalgrade'); if ($uses_outcomes) { $tablecolumns[] = 'outcome'; // no sorting based on outcomes column } $tableheaders = array('', get_string('fullname'), get_string('grade'), get_string('comment', 'assignment'), get_string('lastmodified') . ' (' . $course->student . ')', get_string('lastmodified') . ' (' . $course->teacher . ')', get_string('status'), get_string('finalgrade', 'grades')); if ($uses_outcomes) { $tableheaders[] = get_string('outcome', 'grades'); } require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mod-assignment-submissions'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/assignment/submissions.php?id=' . $this->cm->id . '&currentgroup=' . $currentgroup); $table->sortable(true, 'lastname'); //sorted by lastname by default $table->collapsible(true); $table->initialbars(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('grade', 'grade'); $table->column_class('submissioncomment', 'comment'); $table->column_class('timemodified', 'timemodified'); $table->column_class('timemarked', 'timemarked'); $table->column_class('status', 'status'); $table->column_class('finalgrade', 'finalgrade'); if ($uses_outcomes) { $table->column_class('outcome', 'outcome'); } $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'submissions'); $table->set_attribute('width', '90%'); //$table->set_attribute('align', 'center'); $table->no_sorting('finalgrade'); $table->no_sorting('outcome'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); /// Check to see if groups are being used in this assignment if (!$teacherattempts) { $teachers = get_course_teachers($course->id); if (!empty($teachers)) { $keys = array_keys($teachers); } foreach ($keys as $key) { unset($users[$key]); } } if (empty($users)) { print_heading(get_string('noattempts', 'assignment')); return true; } /// Construct the SQL if ($where = $table->get_sql_where()) { $where .= ' AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY ' . $sort; } $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, s.id AS submissionid, s.grade, s.submissioncomment, s.timemodified, s.timemarked, COALESCE(SIGN(SIGN(s.timemarked) + SIGN(s.timemarked - s.timemodified)), 0) AS status '; $sql = 'FROM ' . $CFG->prefix . 'user u ' . 'LEFT JOIN ' . $CFG->prefix . 'assignment_submissions s ON u.id = s.userid AND s.assignment = ' . $this->assignment->id . ' ' . 'WHERE ' . $where . 'u.id IN (' . implode(',', $users) . ') '; $table->pagesize($perpage, count($users)); ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next $offset = $page * $perpage; $strupdate = get_string('update'); $strgrade = get_string('grade'); $grademenu = make_grades_menu($this->assignment->grade); if (($ausers = get_records_sql($select . $sql . $sort, $table->get_page_start(), $table->get_page_size())) !== false) { $grading_info = grade_get_grades($this->course->id, 'mod', 'assignment', $this->assignment->id, array_keys($ausers)); foreach ($ausers as $auser) { $final_grade = $grading_info->items[0]->grades[$auser->id]; /// Calculate user status $auser->status = $auser->timemarked > 0 && $auser->timemarked >= $auser->timemodified; $picture = print_user_picture($auser->id, $course->id, $auser->picture, false, true); if (empty($auser->submissionid)) { $auser->grade = -1; //no submission yet } if (!empty($auser->submissionid)) { ///Prints student answer and student modified date ///attach file or print link to student answer, depending on the type of the assignment. ///Refer to print_student_answer in inherited classes. if ($auser->timemodified > 0) { $studentmodified = '<div id="ts' . $auser->id . '">' . $this->print_student_answer($auser->id) . userdate($auser->timemodified) . '</div>'; } else { $studentmodified = '<div id="ts' . $auser->id . '"> </div>'; } ///Print grade, dropdown or text if ($auser->timemarked > 0) { $teachermodified = '<div id="tt' . $auser->id . '">' . userdate($auser->timemarked) . '</div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g' . $auser->id . '">' . $final_grade->str_grade . '</div>'; } else { if ($quickgrade) { $menu = choose_from_menu(make_grades_menu($this->assignment->grade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde'), '', -1, true, false, $tabindex++); $grade = '<div id="g' . $auser->id . '">' . $menu . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; } } } else { $teachermodified = '<div id="tt' . $auser->id . '"> </div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g' . $auser->id . '">' . $final_grade->str_grade . '</div>'; } else { if ($quickgrade) { $menu = choose_from_menu(make_grades_menu($this->assignment->grade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde'), '', -1, true, false, $tabindex++); $grade = '<div id="g' . $auser->id . '">' . $menu . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">' . $this->display_grade($auser->grade) . '</div>'; } } } ///Print Comment if ($final_grade->locked or $final_grade->overridden) { $comment = '<div id="com' . $auser->id . '">' . shorten_text(strip_tags($final_grade->str_feedback), 15) . '</div>'; } else { if ($quickgrade) { $comment = '<div id="com' . $auser->id . '">' . '<textarea tabindex="' . $tabindex++ . '" name="submissioncomment[' . $auser->id . ']" id="submissioncomment' . $auser->id . '" rows="2" cols="20">' . $auser->submissioncomment . '</textarea></div>'; } else { $comment = '<div id="com' . $auser->id . '">' . shorten_text(strip_tags($auser->submissioncomment), 15) . '</div>'; } } } else { $studentmodified = '<div id="ts' . $auser->id . '"> </div>'; $teachermodified = '<div id="tt' . $auser->id . '"> </div>'; $status = '<div id="st' . $auser->id . '"> </div>'; if ($final_grade->locked or $final_grade->overridden) { $grade = '<div id="g' . $auser->id . '">' . $final_grade->str_grade . '</div>'; } else { if ($quickgrade) { // allow editing $menu = choose_from_menu(make_grades_menu($this->assignment->grade), 'menu[' . $auser->id . ']', $auser->grade, get_string('nograde'), '', -1, true, false, $tabindex++); $grade = '<div id="g' . $auser->id . '">' . $menu . '</div>'; } else { $grade = '<div id="g' . $auser->id . '">-</div>'; } } if ($final_grade->locked or $final_grade->overridden) { $comment = '<div id="com' . $auser->id . '">' . $final_grade->str_feedback . '</div>'; } else { if ($quickgrade) { $comment = '<div id="com' . $auser->id . '">' . '<textarea tabindex="' . $tabindex++ . '" name="submissioncomment[' . $auser->id . ']" id="submissioncomment' . $auser->id . '" rows="2" cols="20">' . $auser->submissioncomment . '</textarea></div>'; } else { $comment = '<div id="com' . $auser->id . '"> </div>'; } } } if (empty($auser->status)) { /// Confirm we have exclusively 0 or 1 $auser->status = 0; } else { $auser->status = 1; } $buttontext = $auser->status == 1 ? $strupdate : $strgrade; ///No more buttons, we use popups ;-). $popup_url = '/mod/assignment/submissions.php?id=' . $this->cm->id . '&userid=' . $auser->id . '&mode=single' . '&offset=' . $offset++; $button = link_to_popup_window($popup_url, 'grade' . $auser->id, $buttontext, 600, 780, $buttontext, 'none', true, 'button' . $auser->id); $status = '<div id="up' . $auser->id . '" class="s' . $auser->status . '">' . $button . '</div>'; $finalgrade = '<span id="finalgrade_' . $auser->id . '">' . $final_grade->str_grade . '</span>'; $outcomes = ''; if ($uses_outcomes) { foreach ($grading_info->outcomes as $n => $outcome) { $outcomes .= '<div class="outcome"><label>' . $outcome->name . '</label>'; $options = make_grades_menu(-$outcome->scaleid); if ($outcome->grades[$auser->id]->locked or !$quickgrade) { $options[0] = get_string('nooutcome', 'grades'); $outcomes .= ': <span id="outcome_' . $n . '_' . $auser->id . '">' . $options[$outcome->grades[$auser->id]->grade] . '</span>'; } else { $outcomes .= ' '; $outcomes .= choose_from_menu($options, 'outcome_' . $n . '[' . $auser->id . ']', $outcome->grades[$auser->id]->grade, get_string('nooutcome', 'grades'), '', 0, true, false, 0, 'outcome_' . $n . '_' . $auser->id); } $outcomes .= '</div>'; } } $row = array($picture, fullname($auser), $grade, $comment, $studentmodified, $teachermodified, $status, $finalgrade); if ($uses_outcomes) { $row[] = $outcomes; } $table->add_data($row); } } /// Print quickgrade form around the table if ($quickgrade) { echo '<form action="submissions.php" id="fastg" method="post">'; echo '<div>'; echo '<input type="hidden" name="id" value="' . $this->cm->id . '" />'; echo '<input type="hidden" name="mode" value="fastgrade" />'; echo '<input type="hidden" name="page" value="' . $page . '" />'; echo '</div>'; //echo '<div style="text-align:center"><input type="submit" name="fastg" value="'.get_string('saveallfeedback', 'assignment').'" /></div>'; } $table->print_html(); /// Print the whole table if ($quickgrade) { echo '<div style="text-align:center"><input type="submit" name="fastg" value="' . get_string('saveallfeedback', 'assignment') . '" /></div>'; echo '</form>'; } /// End of fast grading form /// Mini form for setting user preference echo '<br />'; echo '<form id="options" action="submissions.php?id=' . $this->cm->id . '" method="post">'; echo '<div>'; echo '<input type="hidden" id="updatepref" name="updatepref" value="1" />'; echo '<table id="optiontable" align="right">'; echo '<tr align="right"><td>'; echo '<label for="perpage">' . get_string('pagesize', 'assignment') . '</label>'; echo ':</td>'; echo '<td>'; echo '<input type="text" id="perpage" name="perpage" size="1" value="' . $perpage . '" />'; helpbutton('pagesize', get_string('pagesize', 'assignment'), 'assignment'); echo '</td></tr>'; echo '<tr align="right">'; echo '<td>'; print_string('quickgrade', 'assignment'); echo ':</td>'; echo '<td>'; if ($quickgrade) { echo '<input type="checkbox" name="quickgrade" value="1" checked="checked" />'; } else { echo '<input type="checkbox" name="quickgrade" value="1" />'; } helpbutton('quickgrade', get_string('quickgrade', 'assignment'), 'assignment') . '</p></div>'; echo '</td></tr>'; echo '<tr>'; echo '<td colspan="2" align="right">'; echo '<input type="submit" value="' . get_string('savepreferences') . '" />'; echo '</td></tr></table>'; echo '</div>'; echo '</form>'; ///End of mini form print_footer($this->course); }
/** * Prints a table with users and their attempts * * @return void * @todo Add current grade to the table * Finnish documenting **/ function view_question($quiz, $question) { global $CFG, $db; $users = get_course_students($quiz->course); $userids = implode(',', array_keys($users)); $usercount = count($users); // set up table $tablecolumns = array('picture', 'fullname', 'timefinish', 'grade'); $tableheaders = array('', get_string('name'), get_string("completedon", "quiz"), ''); $table = new flexible_table('mod-quiz-report-grading'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/quiz/report.php?mode=grading&q=' . $quiz->id . '&action=viewquestion&questionid=' . $question->id); $table->sortable(true); $table->initialbars($usercount > 20); // will show initialbars if there are more than 20 users $table->pageable(true); $table->collapsible(true); $table->column_suppress('fullname'); $table->column_suppress('picture'); $table->column_suppress('grade'); $table->column_class('picture', 'picture'); // attributes in the table tag $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'generaltable generalbox'); $table->set_attribute('align', 'center'); //$table->set_attribute('width', '50%'); // get it ready! $table->setup(); // this sql is a join of the attempts table and the user table. I do this so I can sort by user name and attempt number (not id) $select = 'SELECT ' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ' AS userattemptid, qa.id AS attemptid, qa.uniqueid, qa.attempt, qa.timefinish, u.id AS userid, u.firstname, u.lastname, u.picture '; $from = 'FROM ' . $CFG->prefix . 'user u LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON (u.id = qa.userid AND qa.quiz = ' . $quiz->id . ') '; $where = 'WHERE u.id IN (' . $userids . ') '; $where .= 'AND ' . $db->IfNull('qa.attempt', '0') . ' != 0 '; $where .= 'AND ' . $db->IfNull('qa.timefinish', '0') . ' != 0 '; $where .= 'AND preview = 0 '; // ignore previews if ($table->get_sql_where()) { // forgot what this does $where .= 'AND ' . $table->get_sql_where(); } // sorting of the table if ($sort = $table->get_sql_sort()) { $sort = 'ORDER BY ' . $sort; // seems like I would need to have u. or qa. infront of the ORDER BY attribues... but seems to work.. } else { // my default sort rule $sort = 'ORDER BY u.firstname, u.lastname, qa.timefinish ASC'; } // set up the pagesize $total = count_records_sql('SELECT COUNT(DISTINCT(' . sql_concat('u.id', '\'#\'', $db->IfNull('qa.attempt', '0')) . ')) ' . $from . $where); $table->pagesize(10, $total); // get the attempts and process them if ($attempts = get_records_sql($select . $from . $where . $sort, $table->get_page_start(), $table->get_page_size())) { foreach ($attempts as $attempt) { $picture = print_user_picture($attempt->userid, $quiz->course, $attempt->picture, false, true); // link to student profile $userlink = "<a href=\"{$CFG->wwwroot}/user/view.php?id={$attempt->userid}&course={$quiz->course}\">" . fullname($attempt, true) . '</a>'; if (!$this->is_graded($question, $attempt)) { $style = 'class="manual-ungraded"'; } else { $style = 'class="manual-graded"'; } // link for the attempt $attemptlink = "<a {$style} href=\"report.php?mode=grading&action=grade&q={$quiz->id}&questionid={$question->id}&attemptid={$attempt->attemptid}\">" . userdate($attempt->timefinish, get_string('strftimedatetime')) . '</a>'; // grade all attempts for this user $gradelink = "<a href=\"report.php?mode=grading&action=grade&q={$quiz->id}&questionid={$question->id}&userid={$attempt->userid}\">" . get_string('grade') . '</a>'; $table->add_data(array($picture, $userlink, $attemptlink, $gradelink)); } } // grade all and "back" links $links = "<div class=\"boxaligncenter\"><a href=\"report.php?mode=grading&action=grade&q={$quiz->id}&questionid={$question->id}&gradeall=1\">" . get_string('gradeall', 'quiz') . '</a> | ' . "<a href=\"report.php?mode=grading&q={$quiz->id}&action=viewquestions\">" . get_string('backtoquestionlist', 'quiz') . '</a></div>' . print_heading($question->name); echo $links; echo '<div id="tablecontainer">'; $table->print_html(); echo '</div>'; echo $links; }
function display($quiz, $cm, $course) { /// This function just displays the report global $CFG, $SESSION, $db, $QTYPES; $strnoquiz = get_string('noquiz', 'quiz'); $strnoattempts = get_string('noattempts', 'quiz'); /// Only print headers if not asked to download data $download = optional_param('download', NULL); if (!$download) { $this->print_header_and_tabs($cm, $course, $quiz, $reportmode = "analysis"); } /// Construct the table for this particular report if (!$quiz->questions) { print_heading($strnoattempts); return true; } /// Check to see if groups are being used in this quiz if ($groupmode = groupmode($course, $cm)) { // Groups are being used if (!$download) { $currentgroup = setup_and_print_groups($course, $groupmode, "report.php?id={$cm->id}&mode=analysis"); } else { $currentgroup = get_and_set_current_group($course, $groupmode); } } else { $currentgroup = get_and_set_current_group($course, $groupmode); } // set Table and Analysis stats options if (!isset($SESSION->quiz_analysis_table)) { $SESSION->quiz_analysis_table = array('attemptselection' => 0, 'lowmarklimit' => 0, 'pagesize' => 10); } foreach ($SESSION->quiz_analysis_table as $option => $value) { $urlparam = optional_param($option, NULL); if ($urlparam === NULL) { ${$option} = $value; } else { ${$option} = $SESSION->quiz_analysis_table[$option] = $urlparam; } } $scorelimit = $quiz->sumgrades * $lowmarklimit / 100; // ULPGC ecastro DEBUG this is here to allow for different SQL to select attempts switch ($attemptselection) { case QUIZ_ALLATTEMPTS: $limit = ''; $group = ''; break; case QUIZ_HIGHESTATTEMPT: $limit = ', max(qa.sumgrades) '; $group = ' GROUP BY qa.userid '; break; case QUIZ_FIRSTATTEMPT: $limit = ', min(qa.timemodified) '; $group = ' GROUP BY qa.userid '; break; case QUIZ_LASTATTEMPT: $limit = ', max(qa.timemodified) '; $group = ' GROUP BY qa.userid '; break; } if ($attemptselection != QUIZ_ALLATTEMPTS) { $sql = 'SELECT qa.userid ' . $limit . 'FROM ' . $CFG->prefix . 'user u LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid ' . 'WHERE qa.quiz = ' . $quiz->id . ' AND qa.preview = 0 ' . $group; $usermax = get_records_sql_menu($sql); } $groupmembers = ''; $groupwhere = ''; //Add this to the SQL to show only group users if ($currentgroup) { $groupmembers = ', ' . groups_members_from_sql(); $groupwhere = ' AND ' . groups_members_where_sql($currentgroup, 'u.id'); } $sql = 'SELECT qa.* FROM ' . $CFG->prefix . 'quiz_attempts qa, ' . $CFG->prefix . 'user u ' . $groupmembers . 'WHERE u.id = qa.userid AND qa.quiz = ' . $quiz->id . ' AND qa.preview = 0 AND ( qa.sumgrades >= ' . $scorelimit . ' ) ' . $groupwhere; // ^^^^^^ es posible seleccionar aqu TODOS los quizzes, como quiere Jussi, // pero habra que llevar la cuenta ed cada quiz para restaura las preguntas (quizquestions, states) /// Fetch the attempts $attempts = get_records_sql($sql); if (empty($attempts)) { print_heading(get_string('nothingtodisplay')); $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize); return true; } /// Here we rewiew all attempts and record data to construct the table $questions = array(); $statstable = array(); $questionarray = array(); foreach ($attempts as $attempt) { $questionarray[] = quiz_questions_in_quiz($attempt->layout); } $questionlist = quiz_questions_in_quiz(implode(",", $questionarray)); $questionarray = array_unique(explode(",", $questionlist)); $questionlist = implode(",", $questionarray); unset($questionarray); foreach ($attempts as $attempt) { switch ($attemptselection) { case QUIZ_ALLATTEMPTS: $userscore = 0; // can be anything, not used break; case QUIZ_HIGHESTATTEMPT: $userscore = $attempt->sumgrades; break; case QUIZ_FIRSTATTEMPT: $userscore = $attempt->timemodified; break; case QUIZ_LASTATTEMPT: $userscore = $attempt->timemodified; break; } if ($attemptselection == QUIZ_ALLATTEMPTS || $userscore == $usermax[$attempt->userid]) { $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . " FROM {$CFG->prefix}question q," . " {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . " AND q.id IN ({$questionlist})"; if (!($quizquestions = get_records_sql($sql))) { error('No questions found'); } // Load the question type specific information if (!get_question_options($quizquestions)) { error('Could not load question options'); } // Restore the question sessions to their most recent states // creating new sessions where required if (!($states = get_question_states($quizquestions, $quiz, $attempt))) { error('Could not restore question sessions'); } $numbers = explode(',', $questionlist); $statsrow = array(); foreach ($numbers as $i) { if (!isset($quizquestions[$i]) or !isset($states[$i])) { continue; } $qtype = $quizquestions[$i]->qtype == 'random' ? $states[$i]->options->question->qtype : $quizquestions[$i]->qtype; $q = get_question_responses($quizquestions[$i], $states[$i]); if (empty($q)) { continue; } $qid = $q->id; if (!isset($questions[$qid])) { $questions[$qid]['id'] = $qid; $questions[$qid]['qname'] = $quizquestions[$i]->name; foreach ($q->responses as $answer => $r) { $r->count = 0; $questions[$qid]['responses'][$answer] = $r->answer; $questions[$qid]['rcounts'][$answer] = 0; $questions[$qid]['credits'][$answer] = $r->credit; $statsrow[$qid] = 0; } } $responses = get_question_actual_response($quizquestions[$i], $states[$i]); foreach ($responses as $resp) { if ($resp) { if ($key = array_search($resp, $questions[$qid]['responses'])) { $questions[$qid]['rcounts'][$key]++; } else { $test = new stdClass(); $test->responses = $QTYPES[$quizquestions[$i]->qtype]->get_correct_responses($quizquestions[$i], $states[$i]); if ($key = $QTYPES[$quizquestions[$i]->qtype]->check_response($quizquestions[$i], $states[$i], $test)) { $questions[$qid]['rcounts'][$key]++; } else { $questions[$qid]['responses'][] = $resp; $questions[$qid]['rcounts'][] = 1; $questions[$qid]['credits'][] = 0; } } } } $statsrow[$qid] = get_question_fraction_grade($quizquestions[$i], $states[$i]); } $attemptscores[$attempt->id] = $attempt->sumgrades; $statstable[$attempt->id] = $statsrow; } } // Statistics Data table built unset($attempts); unset($quizquestions); unset($states); // now calculate statistics and set the values in the $questions array $top = max($attemptscores); $bottom = min($attemptscores); $gap = ($top - $bottom) / 3; $top -= $gap; $bottom += $gap; foreach ($questions as $qid => $q) { $questions[$qid] = $this->report_question_stats($q, $attemptscores, $statstable, $top, $bottom); } unset($attemptscores); unset($statstable); /// Now check if asked download of data if ($download = optional_param('download', NULL)) { $filename = clean_filename("{$course->shortname} " . format_string($quiz->name, true)); switch ($download) { case "Excel": $this->Export_Excel($questions, $filename); break; case "ODS": $this->Export_ODS($questions, $filename); break; case "CSV": $this->Export_CSV($questions, $filename); break; } } /// Construct the table for this particular report $tablecolumns = array('id', 'qname', 'responses', 'credits', 'rcounts', 'rpercent', 'facility', 'qsd', 'disc_index', 'disc_coeff'); $tableheaders = array(get_string('qidtitle', 'quiz_analysis'), get_string('qtexttitle', 'quiz_analysis'), get_string('responsestitle', 'quiz_analysis'), get_string('rfractiontitle', 'quiz_analysis'), get_string('rcounttitle', 'quiz_analysis'), get_string('rpercenttitle', 'quiz_analysis'), get_string('facilitytitle', 'quiz_analysis'), get_string('stddevtitle', 'quiz_analysis'), get_string('dicsindextitle', 'quiz_analysis'), get_string('disccoefftitle', 'quiz_analysis')); $table = new flexible_table('mod-quiz-report-itemanalysis'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/quiz/report.php?q=' . $quiz->id . '&mode=analysis'); $table->sortable(true); $table->no_sorting('rpercent'); $table->collapsible(true); $table->initialbars(false); $table->column_class('id', 'numcol'); $table->column_class('credits', 'numcol'); $table->column_class('rcounts', 'numcol'); $table->column_class('rpercent', 'numcol'); $table->column_class('facility', 'numcol'); $table->column_class('qsd', 'numcol'); $table->column_class('disc_index', 'numcol'); $table->column_class('disc_coeff', 'numcol'); $table->column_suppress('id'); $table->column_suppress('qname'); $table->column_suppress('facility'); $table->column_suppress('qsd'); $table->column_suppress('disc_index'); $table->column_suppress('disc_coeff'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'itemanalysis'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); $tablesort = $table->get_sql_sort(); $sorts = explode(",", trim($tablesort)); if ($tablesort and is_array($sorts)) { $sortindex = array(); $sortorder = array(); foreach ($sorts as $sort) { $data = explode(" ", trim($sort)); $sortindex[] = trim($data[0]); $s = trim($data[1]); if ($s == "ASC") { $sortorder[] = SORT_ASC; } else { $sortorder[] = SORT_DESC; } } if (count($sortindex) > 0) { $sortindex[] = "id"; $sortorder[] = SORT_ASC; foreach ($questions as $qid => $row) { $index1[$qid] = $row[$sortindex[0]]; $index2[$qid] = $row[$sortindex[1]]; } array_multisort($index1, $sortorder[0], $index2, $sortorder[1], $questions); } } $format_options = new stdClass(); $format_options->para = false; $format_options->noclean = true; $format_options->newlines = false; // Now it is time to page the data, simply slice the keys in the array if (!isset($pagesize) || (int) $pagesize < 1) { $pagesize = 10; } $table->pagesize($pagesize, count($questions)); $start = $table->get_page_start(); $pagequestions = array_slice(array_keys($questions), $start, $pagesize); foreach ($pagequestions as $qnum) { $q = $questions[$qnum]; $qid = $q['id']; $question = get_record('question', 'id', $qid); if (has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $course->id))) { $qnumber = " (" . link_to_popup_window('/question/question.php?id=' . $qid, '&cmid=' . $cm->id . 'editquestion', $qid, 450, 550, get_string('edit'), 'none', true) . ") "; } else { $qnumber = $qid; } $qname = '<div class="qname">' . format_text($question->name . " : ", $question->questiontextformat, $format_options, $quiz->course) . '</div>'; $qicon = print_question_icon($question, true); $qreview = quiz_question_preview_button($quiz, $question); $qtext = format_text($question->questiontext, $question->questiontextformat, $format_options, $quiz->course); $qquestion = $qname . "\n" . $qtext . "\n"; $responses = array(); foreach ($q['responses'] as $aid => $resp) { $response = new stdClass(); if ($q['credits'][$aid] <= 0) { $qclass = 'uncorrect'; } elseif ($q['credits'][$aid] == 1) { $qclass = 'correct'; } else { $qclass = 'partialcorrect'; } $response->credit = '<span class="' . $qclass . '">(' . format_float($q['credits'][$aid], 2) . ') </span>'; $response->text = '<span class="' . $qclass . '">' . format_text($resp, FORMAT_MOODLE, $format_options, $quiz->course) . ' </span>'; $count = $q['rcounts'][$aid] . '/' . $q['count']; $response->rcount = $count; $response->rpercent = '(' . format_float($q['rcounts'][$aid] / $q['count'] * 100, 0) . '%)'; $responses[] = $response; } $facility = format_float($q['facility'] * 100, 0) . "%"; $qsd = format_float($q['qsd'], 3); $di = format_float($q['disc_index'], 2); $dc = format_float($q['disc_coeff'], 2); $response = array_shift($responses); $table->add_data(array($qnumber . "\n<br />" . $qicon . "\n " . $qreview, $qquestion, $response->text, $response->credit, $response->rcount, $response->rpercent, $facility, $qsd, $di, $dc)); foreach ($responses as $response) { $table->add_data(array('', '', $response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', '')); } } print_heading_with_help(get_string("analysistitle", "quiz_analysis"), "itemanalysis", "quiz"); echo '<div id="tablecontainer">'; $table->print_html(); echo '</div>'; $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize); return true; }
/** * Function for showing the students points to a creator, teacher or trainer */ function show_grades($currentgroup, $cm, $course, $mumiemodule) { global $CFG, $USER, $db; //needed? I am not sure $page = optional_param('page', 0, PARAM_INT); $context = get_context_instance(CONTEXT_COURSE, $course->id); /// Get all teachers and students if ($currentgroup) { $users = get_records('mumiemodule_students', 'groupid', $currentgroup, '', 'userid'); //$users = get_group_users($currentgroup); } else { //$context = get_context_instance(CONTEXT_MODULE, $cm->id); $course_groups = groups_get_all_groups($course->id, 0, 0, 'g.id'); $groups = array(); foreach ($course_groups as $group) { $groups[] = $group->id; } $users = get_users_by_capability($context, 'mod/mumiemodule:participate', '', '', '', '', $groups); // everyone with this capability set to non-prohibit //TODO we need a user-list with just students that are in groups } $tablecolumns = array('picture', 'fullname', 'grade', 'timemodified'); $tableheaders = array('', get_string('fullname'), get_string('grade', 'mumiemodule'), get_string('lastmodified', 'mumiemodule') . ' (' . $course->student . ')'); require_once $CFG->libdir . '/tablelib.php'; $table = new flexible_table('mumiemodule-current-grades'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/mumiemodule/view.php?id=' . $cm->id . '&currentgroup=' . $currentgroup); $table->sortable(true, 'lastname'); //sorted by lastname by default $table->collapsible(true); $table->initialbars(true); $table->column_suppress('picture'); $table->column_suppress('fullname'); $table->column_class('picture', 'picture'); $table->column_class('fullname', 'fullname'); $table->column_class('grade', 'grade'); $table->column_class('timemodified', 'timemodified'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'attempts'); $table->set_attribute('class', 'grades'); $table->set_attribute('width', '90%'); $table->set_attribute('align', 'center'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); /// Check to see if groups are being used in this assignment /*if (!$teacherattempts) { //@toDo: check variable!!! $teachers = get_course_teachers($course->id); if (!empty($teachers)) { $keys = array_keys($teachers); } foreach ($keys as $key) { unset($users[$key]); } }*/ /// Construct the SQL if ($where = $table->get_sql_where()) { $where .= ' AND '; } if ($sort = $table->get_sql_sort()) { $sort = ' ORDER BY ' . $sort; } $select = 'SELECT u.id, u.firstname, u.lastname, u.picture, s.id AS mumiepartsid, s.grade, s.timemodified '; $sql = 'FROM ' . $CFG->prefix . 'user u ' . 'LEFT JOIN ' . $CFG->prefix . 'mumiemodule_students s ON u.id = s.userid AND s.mumiemodule = ' . $mumiemodule->id . ' ' . 'WHERE ' . $where . 'u.id IN (' . implode(',', array_keys($users)) . ') '; $table->pagesize(10, count($users)); ///offset used to calculate index of student in that particular query, needed for the pop up to know who's next $offset = $page * 10; $strupdate = get_string('update'); $strgrade = get_string('grade'); $grademenu = make_grades_menu($mumiemodule->grade); if (($ausers = get_records_sql($select . $sql . $sort, $table->get_page_start(), $table->get_page_size())) !== false) { //if (($ausers = get_records($select.$sql.$sort, $table->get_page_start(), $table->get_page_size())) !== false) { foreach ($ausers as $auser) { /// Calculate user status $auser->status = 1; $picture = print_user_picture($auser->id, $course->id, $auser->picture, false, true); $studentmodified = '<div id="ts' . $auser->id . '">' . userdate($auser->timemodified) . '</div>'; $grade = '<div id="g' . $auser->id . '">' . $auser->grade . '/' . $mumiemodule->grade . '</div>'; $buttontext = $auser->status == 1 ? $strupdate : $strgrade; ///No more buttons, we use popups ;-). $button = link_to_popup_window('/mod/mumiemodule/view.php?id=' . $cm->id . '&userid=' . $auser->id . '&mode=single' . '&offset=' . $offset++, 'grade' . $auser->id, $buttontext, 500, 780, $buttontext, 'none', true, 'button' . $auser->id); $status = '<div id="up' . $auser->id . '" class="s' . $auser->status . '">' . $button . '</div>'; $row = array($picture, fullname($auser), $grade, $studentmodified); $table->add_data($row); } } /** * Return a grade in user-friendly form, whether it's a scale or not * * @param $grade * @return string User-friendly representation of grade */ function display_grade($grade, $mumiemodule) { $scalegrades = array(); if ($mumiemodule->grade >= 0) { // Normal number if ($grade == -1) { return '-'; } else { return $grade . ' / ' . $mumiemodule->grade; } } else { // Scale if (empty($scalegrades[$mumiemodule->id])) { if ($scale = get_record('scale', 'id', -$mumiemodule->grade)) { $scalegrades[$mumiemodule->id] = make_menu_from_list($scale->scale); } else { return '-'; } } if (isset($scalegrades[$mumiemodule->id][$grade])) { return $scalegrades[$mumiemodule->id][$grade]; } return '-'; } } $table->print_html(); /// Print the whole table }