function show_pset_table($pset) { global $Conf, $Me, $Now, $Profile, $LastPsetFix; echo '<div id="', $pset->urlkey, '">'; echo "<h3>", htmlspecialchars($pset->title), "</h3>"; if ($Me->privChair) { show_pset_actions($pset); } if ($pset->disabled) { echo "</div>\n"; return; } $t0 = $Profile ? microtime(true) : 0; // load students if ($Conf->opt("restrictRepoView")) { $view = "l2.link repoviewable"; $viewjoin = "left join ContactLink l2 on (l2.cid=c.contactId and l2.type=" . LINK_REPOVIEW . " and l2.link=l.link)\n"; } else { $view = "4 repoviewable"; $viewjoin = ""; } $result = Dbl::qe("select c.contactId, c.firstName, c.lastName, c.email,\n\tc.huid, c.github_username, c.seascode_username, c.anon_username, c.extension, c.disabled, c.dropped, c.roles, c.contactTags,\n\tgroup_concat(pl.link) pcid, group_concat(rpl.link) rpcid,\n\tr.repoid, r.cacheid, r.heads, r.url, r.open, r.working, r.lastpset, r.snapcheckat, {$view},\n\trg.gradehash, rg.gradercid, rg.placeholder, rg.placeholder_at\n\tfrom ContactInfo c\n\tleft join ContactLink l on (l.cid=c.contactId and l.type=" . LINK_REPO . " and l.pset={$pset->id})\n\t{$viewjoin}\n\tleft join Repository r on (r.repoid=l.link)\n\tleft join ContactLink pl on (pl.cid=c.contactId and pl.type=" . LINK_PARTNER . " and pl.pset={$pset->id})\n\tleft join ContactLink rpl on (rpl.cid=c.contactId and rpl.type=" . LINK_BACKPARTNER . " and rpl.pset={$pset->id})\n\tleft join RepositoryGrade rg on (rg.repoid=r.repoid and rg.pset={$pset->id})\n\twhere (c.roles&" . Contact::ROLE_PCLIKE . ")=0\n\tand (rg.repoid is not null or not c.dropped)\n\tgroup by c.contactId, r.repoid"); $t1 = $Profile ? microtime(true) : 0; $anonymous = $pset->anonymous; if (req("anonymous") !== null && $Me->privChair) { $anonymous = !!req("anonymous"); } $students = array(); while ($result && ($s = Contact::fetch($result))) { $s->set_anonymous($anonymous); Contact::set_sorter($s, req("sort")); $students[$s->contactId] = $s; // maybe lastpset links are out of order if ($s->lastpset < $pset) { $LastPsetFix = true; } } uasort($students, "Contact::compare"); $checkbox = $Me->privChair || !$pset->gitless && $pset->runners; $rows = array(); $max_ncol = 0; $incomplete = array(); $pcmembers = pcMembers(); $jx = []; foreach ($students as $s) { if (!$s->visited) { $row = (object) ["student" => $s, "text" => "", "ptext" => []]; $j = render_pset_row($pset, $students, $s, $row, $pcmembers, $anonymous); if ($s->pcid) { foreach (array_unique(explode(",", $s->pcid)) as $pcid) { if (isset($students[$pcid])) { $jj = render_pset_row($pset, $students, $students[$pcid], $row, $pcmembers, $anonymous); $j["partners"][] = $jj; } } } if ($row->sortprefix) { $j["boring"] = true; } $jx[$row->sortprefix . $s->sorter] = $j; $max_ncol = max($max_ncol, $row->ncol); if ($s->incomplete) { $u = $Me->user_linkpart($s); $incomplete[] = '<a href="' . hoturl("pset", array("pset" => $pset->urlkey, "u" => $u, "sort" => req("sort"))) . '">' . htmlspecialchars($u) . '</a>'; } } } if (count($incomplete)) { echo '<div id="incomplete_pset', $pset->id, '" style="display:none" class="merror">', '<strong>', htmlspecialchars($pset->title), '</strong>: ', 'Your grading is incomplete. Missing grades: ', join(", ", $incomplete), '</div>', '<script>jQuery("#incomplete_pset', $pset->id, '").remove().show().appendTo("#incomplete_notices")</script>'; } if ($checkbox) { echo Ht::form_div(hoturl_post("index", array("pset" => $pset->urlkey, "save" => 1))); } $sort_key = $anonymous ? "anon_username" : "username"; usort($jx, function ($a, $b) use($sort_key) { if (get($a, "boring") != get($b, "boring")) { return get($a, "boring") ? 1 : -1; } return strcmp($a[$sort_key], $b[$sort_key]); }); echo '<table class="s61', $anonymous ? " s61anonymous" : "", '" id="pa-pset' . $pset->id . '"></table>'; $jd = ["checkbox" => $checkbox, "anonymous" => $anonymous, "grade_keys" => array_keys($pset->grades), "gitless" => $pset->gitless, "gitless_grades" => $pset->gitless_grades, "urlpattern" => hoturl("pset", ["pset" => $pset->urlkey, "u" => "@", "sort" => req("sort")])]; $i = $nintotal = $last_in_total = 0; foreach ($pset->grades as $ge) { if (!$ge->no_total) { ++$nintotal; $last_in_total = $ge->name; } ++$i; } if ($nintotal > 1) { $jd["need_total"] = true; } else { if ($nintotal == 1) { $jd["total_key"] = $last_in_total; } } echo Ht::unstash(), '<script>pa_render_pset_table(', $pset->id, ',', json_encode($jd), ',', json_encode(array_values($jx)), ')</script>'; if ($Me->privChair && !$pset->gitless_grades) { echo "<div class='g'></div>"; $sel = array("none" => "N/A"); foreach (pcMembers() as $pcm) { $sel[$pcm->email] = Text::name_html($pcm); } $sel["__random__"] = "Random"; echo '<span class="nb" style="padding-right:2em">', Ht::select("grader", $sel, "none"), Ht::submit("setgrader", "Set grader"), '</span>'; } if (!$pset->gitless) { $sel = array(); foreach ($pset->runners as $r) { if ($Me->can_run($pset, $r)) { $sel[$r->name] = htmlspecialchars($r->title); } } if (count($sel)) { echo '<span class="nb" style="padding-right:2em">', Ht::select("runner", $sel), Ht::submit("runmany", "Run all"), '</span>'; } } if ($checkbox) { echo "</div></form>\n"; } if ($Profile) { $t2 = microtime(true); echo sprintf("<div>Δt %.06f DB, %.06f total</div>", $t1 - $t0, $t2 - $t0); } echo "</div>\n"; }
function show_pset_table($pset) { global $Conf, $Me, $Now, $Opt, $Profile, $LastPsetFix; echo '<div id="', $pset->urlkey, '">'; echo "<h3>", htmlspecialchars($pset->title), "</h3>"; if ($Me->privChair) { show_pset_actions($pset); } if ($pset->disabled) { return; } $t0 = $Profile ? microtime(true) : 0; // load students if (@$Opt["restrictRepoView"]) { $view = "l2.link repoviewable"; $viewjoin = "left join ContactLink l2 on (l2.cid=c.contactId and l2.type=" . LINK_REPOVIEW . " and l2.link=l.link)\n"; } else { $view = "4 repoviewable"; $viewjoin = ""; } $result = Dbl::qe("select c.contactId, c.firstName, c.lastName, c.email,\n\tc.huid, c.seascode_username, c.anon_username, c.extension, c.disabled, c.dropped, c.roles, c.contactTags,\n\tpl.link pcid, group_concat(rpl.link) rpcid,\n\tr.repoid, r.cacheid, r.heads, r.url, r.open, r.working, r.lastpset, r.snapcheckat, {$view},\n\trg.gradehash, rg.gradercid, rg.placeholder, rg.placeholder_at\n\tfrom ContactInfo c\n\tleft join ContactLink l on (l.cid=c.contactId and l.type=" . LINK_REPO . " and l.pset={$pset->id})\n\t{$viewjoin}\n\tleft join Repository r on (r.repoid=l.link)\n\tleft join ContactLink pl on (pl.cid=c.contactId and pl.type=" . LINK_PARTNER . " and pl.pset={$pset->id})\n\tleft join ContactLink rpl on (rpl.cid=c.contactId and rpl.type=" . LINK_BACKPARTNER . " and rpl.pset={$pset->id})\n\tleft join RepositoryGrade rg on (rg.repoid=r.repoid and rg.pset={$pset->id})\n\twhere (c.roles&" . Contact::ROLE_PCLIKE . ")=0\n\tand (rg.repoid is not null or not c.dropped)\n\tgroup by c.contactId"); $t1 = $Profile ? microtime(true) : 0; $students = array(); while ($result && ($s = $result->fetch_object("Contact"))) { $s->is_anonymous = $pset->anonymous; Contact::set_sorter($s, @$_REQUEST["sort"]); $students[$s->contactId] = $s; // maybe lastpset links are out of order if ($s->lastpset < $pset) { $LastPsetFix = true; } } uasort($students, "Contact::compare"); $checkbox = $Me->privChair || !$pset->gitless && $pset->runners; $rows = array(); $max_ncol = 0; $incomplete = array(); $pcmembers = pcMembers(); foreach ($students as $s) { if (!isset($s->printed)) { $row = (object) array("student" => $s); $row->text = render_pset_row($pset, $students, $s, $row, $pcmembers); if ($s->pcid && isset($students[$s->pcid])) { $row->ptext = render_pset_row($pset, $students, $students[$s->pcid], $row, $pcmembers); } $rows[$row->sortprefix . $s->sorter] = $row; $max_ncol = max($max_ncol, $row->ncol); if (@$s->incomplete) { $u = $Me->user_linkpart($s); $incomplete[] = '<a href="' . hoturl("pset", array("pset" => $pset->urlkey, "u" => $u, "sort" => @$_REQUEST["sort"])) . '">' . htmlspecialchars($u) . '</a>'; } } } ksort($rows, SORT_NATURAL | SORT_FLAG_CASE); if (count($incomplete)) { echo '<div id="incomplete_pset', $pset->id, '" style="display:none" class="merror">', '<strong>', htmlspecialchars($pset->title), '</strong>: ', 'Your grading is incomplete. Missing grades: ', join(", ", $incomplete), '</div>', '<script>jQuery("#incomplete_pset', $pset->id, '").remove().show().appendTo("#incomplete_notices")</script>'; } if ($checkbox) { echo Ht::form_div(hoturl_post("index", array("pset" => $pset->urlkey, "save" => 1))); } echo '<table class="s61"><tbody>'; $trn = 0; $sprefix = ""; foreach ($rows as $row) { ++$trn; if ($row->sortprefix !== $sprefix && $row->sortprefix[0] == "~") { echo "\n", '<tr><td colspan="' . ($max_ncol + ($checkbox ? 2 : 1)) . '"><hr></td></tr>', "\n"; } $sprefix = $row->sortprefix; echo '<tr class="k', $trn % 2, '">'; if ($checkbox) { echo '<td class="s61rownumber">', Ht::checkbox("s61_" . $Me->user_idpart($row->student), 1, array("class" => "s61check")), '</td>'; } echo '<td class="s61rownumber">', $trn, '.</td>', $row->text, "</tr>\n"; if (@$row->ptext) { echo '<tr class="k', $trn % 2, ' s61partner">'; if ($checkbox) { echo '<td></td>'; } echo '<td></td>', $row->ptext, "</tr>\n"; } } echo "</tbody></table>\n"; if ($Me->privChair && !$pset->gitless_grades) { echo "<div class='g'></div>"; $sel = array("none" => "N/A"); foreach (pcMembers() as $pcm) { $sel[$pcm->email] = Text::name_html($pcm); } $sel["__random__"] = "Random"; echo '<span class="nowrap" style="padding-right:2em">', Ht::select("grader", $sel, "none"), Ht::submit("setgrader", "Set grader"), '</span>'; } if (!$pset->gitless) { $sel = array(); foreach ($pset->runners as $r) { if ($Me->can_run($pset, $r)) { $sel[$r->name] = htmlspecialchars($r->title); } } if (count($sel)) { echo '<span class="nowrap" style="padding-right:2em">', Ht::select("runner", $sel), Ht::submit("runmany", "Run all"), '</span>'; } } if ($checkbox) { echo "</div></form>\n"; } if ($Profile) { $t2 = microtime(true); echo sprintf("<div>Δt %.06f DB, %.06f total</div>", $t1 - $t0, $t2 - $t0); } echo "</div>\n"; }