public function document_to_json($dtype, $docid) { global $Conf; if (!is_object($docid)) { $dresult = $Conf->document_result($this->paperid, $dtype, $docid); $drow = $Conf->document_row($dresult, $dtype); Dbl::free($dresult); } else { $drow = $docid; $docid = $drow ? $drow->paperStorageId : null; } $d = (object) array(); if ($docid && !$this->hide_docids) { $d->docid = $docid; } if ($drow) { if ($drow->mimetype) { $d->mimetype = $drow->mimetype; } if ($drow->sha1 !== null && $drow->sha1 !== "") { $d->sha1 = bin2hex($drow->sha1); } if ($drow->timestamp) { $d->timestamp = (int) $drow->timestamp; } if (get($drow, "filename")) { $d->filename = $drow->filename; } $meta = null; if (isset($drow->infoJson) && is_object($drow->infoJson)) { $meta = $drow->infoJson; } else { if (isset($drow->infoJson) && is_string($drow->infoJson)) { $meta = json_decode($drow->infoJson); } } if ($meta) { $d->metadata = $meta; } if ($this->export_content && $drow->docclass->load($drow)) { $d->content_base64 = base64_encode(Filer::content($drow)); } } foreach ($this->document_callbacks as $cb) { call_user_func($cb, $d, $this->prow, $dtype, $drow); } if (!count(get_object_vars($d))) { $d = null; } return $d; }
function _update_schema_regrade_flags(Conf $conf) { $result = $conf->ql("select rgr.*, u.cid from RepositoryGradeRequest rgr\n left join (select link, pset, min(cid) cid\n from ContactLink where type=" . LINK_REPO . " group by link, pset) u on (u.link=rgr.repoid)"); while ($row = edb_orow($result)) { if ($row->cid && ($u = $conf->user_by_id($row->cid)) && ($pset = $conf->pset_by_id($row->pset))) { $info = new PsetView($pset, $u, $u); $info->force_set_commit($row->hash); $update = ["flags" => ["t" . $row->requested_at => ["uid" => $u->contactId]]]; $info->update_current_info($update); } } Dbl::free($result); return true; }
public function __construct($user, $rounds = null) { global $Conf; $this->contact = $user; $qp = "select PaperReview.contactId, timeRequested, reviewSubmitted, reviewRound"; if (!$this->contact->privChair) { $qp .= ", conflictType from PaperReview left join PaperConflict on (PaperConflict.paperId=PaperReview.paperId and PaperConflict.contactId=" . $this->contact->contactId . ")"; } else { $qp .= ", 0 conflictType from PaperReview"; } $qp .= " where reviewType>" . REVIEW_PC . " or (reviewType=" . REVIEW_PC . " and timeRequested>0 and reviewSubmitted>0)"; if (!$this->contact->privChair) { $qp .= " and coalesce(conflictType,0)=0"; } $qa = array(); if ($rounds) { $qp .= " and reviewRound ?a"; $qa[] = $rounds; } $result = Dbl::qe_apply($qp, $qa); while ($row = edb_row($result)) { $cid = (int) $row[4] ? "conflicts" : (int) $row[0]; $this->r[$cid][] = array((int) $row[1], (int) $row[2], (int) $row[3]); } Dbl::free($result); foreach ($Conf->round_list() as $rn => $r) { $dl = $Conf->review_deadline($rn, true, false); $this->dl[$rn] = +$Conf->setting($dl); } // maybe hide who's who if (!$this->contact->can_view_aggregated_review_identity()) { $who = $r = array(); foreach ($this->r as $cid => $data) { if ($cid === "conflicts" || $cid == $this->contact->contactId) { $r[$cid] = $data; } else { do { $ncid = mt_rand(1, 10 * count(pcMembers())); } while (isset($who[$ncid])); $who[$ncid] = true; $r["x" . $ncid] = $data; } } $this->r = $r; } }
function fix_one_delegation() { global $Conf; $row = Dbl::fetch_first_row("select r.paperId, r.contactId, u.email, q.ct, q.cs, r.reviewNeedsSubmit\n from PaperReview r\n left join (select paperId, requestedBy, count(reviewId) ct, count(reviewSubmitted) cs\n from PaperReview where reviewType<" . REVIEW_SECONDARY . "\n group by paperId, requestedBy) q\n on (q.paperId=r.paperId and q.requestedBy=r.contactId)\n left join ContactInfo u on (u.contactId=r.contactId)\n where r.reviewType=" . REVIEW_SECONDARY . " and r.reviewSubmitted is null\n and if(coalesce(q.ct,0)=0,1,if(q.cs=0,-1,0))!=r.reviewNeedsSubmit\n limit 1"); if (!$row) { return false; } $pid = (int) $row[0]; $req_cid = (int) $row[1]; $req_email = $row[2]; $prow = $Conf->paperRow(["paperId" => $pid], null); fwrite(STDERR, "Problem: #{$pid} review by {$req_email}\n"); fwrite(STDERR, " reviewNeedsSubmit {$row['5']}, " . plural($row[3] ?: 0, "delegate") . ", " . plural($row[4] ?: 0, "submitted delegate") . "\n"); $result = Dbl::qe("select l.* from ActionLog l where paperId=? order by logId asc", $pid); $proposals = $confirmations = []; while ($row = edb_orow($result)) { if ($row->contactId == $req_cid && preg_match('/\\ALogged proposal for (\\S+) to review/', $row->action, $m) && ($xid = Contact::id_by_email($m[1]))) { $proposals[$xid] = true; } else { if (preg_match('/\\AAdded External review by (\\S+)/', $row->action, $m) && ($pc = pcByEmail($m[1])) && $pc->can_administer($prow)) { $confirmations[$row->contactId] = $pc->contactId; } } } Dbl::free($result); foreach ($proposals as $xid => $x) { if (isset($confirmations[$xid])) { $result1 = Dbl::qe("update PaperReview set requestedBy=? where paperId=? and contactId=? and requestedBy=?", $req_cid, $pid, $xid, $confirmations[$xid]); $result2 = Dbl::qe("update PaperReview r, PaperReview q set r.reviewNeedsSubmit=0 where r.paperId=? and r.contactId=? and q.paperId=? and q.contactId=? and q.reviewSubmitted is not null", $pid, $req_cid, $pid, $xid); if ($result1->affected_rows || $result2->affected_rows) { return true; } } } error_log("Failed to resolve paper #{$pid} review by {$req_email}"); return false; }
function load_grade() { if ($this->pset->gitless_grades) { $this->grade = $this->pset->contact_grade_for($this->user); $this->grade_notes = get($this->grade, "notes"); } else { $this->repo_grade = null; if ($this->repo) { $result = $this->conf->qe("select rg.*, cn.hash, cn.notes, cn.notesversion\n from RepositoryGrade rg\n left join CommitNotes cn on (cn.hash=rg.gradehash and cn.pset=rg.pset)\n where rg.repoid=? and rg.pset=? and not rg.placeholder", $this->repo->repoid, $this->pset->psetid); $this->repo_grade = $result ? $result->fetch_object() : null; Dbl::free($result); if ($this->repo_grade && $this->repo_grade->notes) { $this->repo_grade->notes = json_decode($this->repo_grade->notes); } } $this->grade = $this->repo_grade; $this->grade_notes = get($this->grade, "notes"); if ($this->grade_notes && get($this->grade, "gradercid") && !get($this->grade_notes, "gradercid")) { $this->update_commit_info_at($this->grade->gradehash, ["gradercid" => $this->grade->gradercid]); } if (get($this->grade, "gradehash") && $this->commit === null) { // NB don't check recent_commits association here $this->commit = $this->grade->gradehash; } } $this->can_see_comments = $this->viewer->can_see_comments($this->pset, $this->user, $this); $this->can_see_grades = $this->viewer->can_see_grades($this->pset, $this->user, $this); $this->user_can_see_grades = $this->user->can_see_grades($this->pset, $this->user, $this); }
private static function status_papers($status, $tracker, $acct) { global $Conf; $pids = array_slice($tracker->ids, $tracker->position, 3); $pc_conflicts = $acct->privChair || $acct->tracker_kiosk_state; $col = $j = ""; if ($pc_conflicts) { $col = ", allconfs.conflictIds"; $j = "left join (select paperId, group_concat(contactId) conflictIds from PaperConflict where paperId in (" . join(",", $pids) . ") group by paperId) allconfs on (allconfs.paperId=p.paperId)\n\t\t"; $pcm = pcMembers(); } $result = $Conf->qe("select p.paperId, p.title, p.paperFormat, p.leadContactId, p.managerContactId, r.reviewType, conf.conflictType{$col}\n from Paper p\n left join PaperReview r on (r.paperId=p.paperId and " . ($acct->contactId ? "r.contactId={$acct->contactId}" : "false") . ")\n left join PaperConflict conf on (conf.paperId=p.paperId and " . ($acct->contactId ? "conf.contactId={$acct->contactId}" : "false") . ")\n {$j}where p.paperId in (" . join(",", $pids) . ")"); $papers = array(); while ($row = PaperInfo::fetch($result, $acct)) { $papers[$row->paperId] = $p = (object) array(); if (($acct->privChair || !$row->conflictType || !get($status, "hide_conflicts")) && $acct->tracker_kiosk_state != 1) { $p->pid = (int) $row->paperId; $p->title = $row->title; if ($format = $row->title_format()) { $p->format = $format; } } if ($acct->contactId > 0 && $row->managerContactId == $acct->contactId) { $p->is_manager = true; } if ($row->reviewType) { $p->is_reviewer = true; } if ($row->conflictType) { $p->is_conflict = true; } if ($acct->contactId > 0 && $row->leadContactId == $acct->contactId) { $p->is_lead = true; } if ($pc_conflicts) { $p->pc_conflicts = array(); foreach (explode(",", (string) $row->conflictIds) as $cid) { if ($pc = get($pcm, $cid)) { $p->pc_conflicts[$pc->sort_position] = (object) array("email" => $pc->email, "name" => Text::name_text($pc)); } } ksort($p->pc_conflicts); $p->pc_conflicts = array_values($p->pc_conflicts); } } Dbl::free($result); $status->papers = array(); foreach ($pids as $pid) { $status->papers[] = $papers[$pid]; } }
function find_snapshot($commit) { if (isset($this->_commitinfo[$commit])) { return $this->_commitinfo[$commit]; } $this->analyze_snapshots(); $bcommit = hex2bin(substr($commit, 0, strlen($commit) & ~1)); if (strlen($bcommit) == 20) { $result = $this->conf->qe("select * from RepositoryCommitSnapshot where repoid=? and hash=?", $this->repoid, $bcommit); } else { $result = $this->conf->qe("select * from RepositoryCommitSnapshot where repoid=? and hash like '?ls%'", $this->repoid, $bcommit); } $match = null; while ($row = $result->fetch_object()) { $h = bin2hex($row->hash); if (str_starts_with($h, $commit)) { if ($match) { $match = false; break; } $match = $row; } } Dbl::free($result); if ($match) { $list = $this->commits_from_head("repo{$this->repoid}.snap" . gmstrftime("%Y%m%d.%H%M%S", $match->snapshot)); $cinfo = $list[bin2hex($match->hash)]; $cinfo->fromhead = "snapshot of " . strftime("%Y-%m-%d %H:%M:%S", $match->snapshot); } else { $cinfo = false; } $this->_commitinfo[$commit] = $cinfo; return $cinfo; }
function show_regrades($result) { global $Conf, $Me, $Now, $LastPsetFix; $rows = $uids = []; while ($row = edb_orow($result)) { $row->notes = json_decode($row->notes); $latest = ""; $uid = 0; foreach (get($row->notes, "flags", []) as $t => $v) { if (!get($v, "resolved") && $t > $latest) { $latest = $t; $uid = get($v, "uid"); } } if ($latest) { $rows[] = [$latest, $uid, $row]; $uids[$uid] = true; } } Dbl::free($result); if (empty($rows)) { return; } usort($rows, function ($a, $b) { return strcmp($a[0], $b[0]); }); $contacts = []; $result = $Conf->qe("select * from ContactInfo where contactId?a", array_keys($uids)); while ($c = Contact::fetch($result, $Conf)) { $contacts[$c->contactId] = $c; } Dbl::free($result); echo '<div id="_regrades">'; echo "<h3>flagged commits</h3>"; echo '<table class="s61"><tbody>'; $trn = 0; $checkbox = false; $sprefix = ""; $reqsort = req("sort"); $reqanonymize = req("anonymize"); $pcmembers = pcMembers(); foreach ($rows as $rowx) { $uid = $rowx[1]; $row = $rowx[2]; $u = $contacts[$uid]; ++$trn; echo '<tr class="k', $trn % 2, '">'; if ($checkbox) { echo '<td class="s61checkbox">', Ht::checkbox("s61_" . urlencode($Me->user_idpart($u)), 1, array("class" => "s61check")), '</td>'; } echo '<td class="s61rownumber">', $trn, '.</td>'; $pset = $Conf->pset_by_id($row->pset); echo '<td class="s61pset">', htmlspecialchars($pset->title), '</td>'; echo '<td class="s61username">', '<a href="', hoturl("pset", ["pset" => $pset->urlkey, "u" => $Me->user_linkpart($u), "commit" => $row->hash, "sort" => $reqsort]), '">', htmlspecialchars($Me->user_linkpart($u)), '</a></td>', '<td class="s61hash"><a href="', hoturl("pset", array("pset" => $pset->urlkey, "u" => $Me->user_linkpart($u), "commit" => $row->hash, "sort" => $reqsort)), '">', substr($row->hash, 0, 7), '</a></td>'; if (get($row->notes, "gradercid") || $row->main_gradercid) { $gcid = get($row->notes, "gradercid") ?: $row->main_gradercid; if (isset($pcmembers[$gcid])) { echo "<td>" . htmlspecialchars($pcmembers[$gcid]->firstName) . "</td>"; } else { echo "<td>???</td>"; } } else { echo "<td></td>"; } echo "<td>"; if ($row->hash === $row->gradehash) { echo "✱"; } if ($row->haslinenotes) { echo "♪"; } echo "</td>"; $total = ""; if ($row->notes) { $garr = render_grades($pset, $row->notes, null); if ($garr->totalindex !== null) { $total = $garr->all[$garr->totalindex]; } } echo '<td class="r">' . $total . '</td>'; echo '</tr>'; } echo "</tbody></table></div>\n"; }
function edb_orows($result) { $x = array(); while ($result && ($row = $result->fetch_object())) { $x[] = $row; } Dbl::free($result); return $x; }
function commit_notes($hash) { assert(!$this->gitless); $result = $this->conf->qe("select * from CommitNotes where hash=? and pset=?", $hash, $this->psetid); $cn = edb_orow($result); if ($cn && $cn->notes) { $cn->notes = json_decode($cn->notes); } Dbl::free($result); return $cn; }
function save_logs($on) { if ($on && $this->_save_logs === false) { $this->_save_logs = array(); } else { if (!$on && $this->_save_logs !== false) { $qs = []; foreach ($this->_save_logs as $cid_text => $pids) { $pos = strpos($cid_text, "|"); $qs[] = self::format_log_query(substr($cid_text, $pos + 1), substr($cid_text, 0, $pos), array_keys($pids)); } $mresult = Dbl::multi_q_raw(join(";", $qs)); while ($result = $mresult->next()) { Dbl::free($result); } $this->_save_logs = false; } } }
function _search() { global $Conf; if ($this->_matches === false) { return false; } assert($this->_matches === null); if ($this->limitName === "x") { $this->_matches = array(); return true; } // parse and clean the query $qe = $this->_searchQueryType($this->q); //Conf::msg_info(Ht::pre_text(var_export($qe, true))); if (!$qe) { $qe = new SearchTerm("t"); } // apply complex limiters (only current example: "acc" for non-chairs) $limit = $this->limitName; if ($limit === "acc" && !$this->privChair) { $qe = SearchTerm::make_op("and", array($qe, $this->_searchQueryWord("dec:yes", false))); } // apply review rounds (top down, needs separate step) if ($this->reviewAdjust) { $qe = $this->_query_adjust_reviews($qe, null); if ($this->_reviewAdjustError) { $this->warn("Unexpected use of “round:” or “rate:” ignored. Stick to the basics, such as “re:reviewername round:roundname”."); } } //Conf::msg_info(Ht::pre_text(var_export($qe, true))); // collect clauses into tables, columns, and filters $sqi = new SearchQueryInfo(); $sqi->add_table("Paper"); $sqi->add_column("paperId", "Paper.paperId"); // always include columns needed by rights machinery $sqi->add_column("timeSubmitted", "Paper.timeSubmitted"); $sqi->add_column("timeWithdrawn", "Paper.timeWithdrawn"); $sqi->add_column("outcome", "Paper.outcome"); $filters = array(); $this->_clauseTermSet($qe, $sqi, $filters); //Conf::msg_info(Ht::pre_text(var_export($filters, true))); // status limitation parts if ($limit === "rable") { $limitcontact = $this->_reviewer_fixed ? $this->reviewer() : $this->contact; if ($limitcontact->can_accept_review_assignment_ignore_conflict(null)) { $limit = $Conf->can_pc_see_all_submissions() ? "act" : "s"; } else { if (!$limitcontact->isPC) { $limit = "r"; } } } if ($limit === "s" || $limit === "req" || $limit === "acc" || $limit === "und" || $limit === "unm" || $limit === "rable" && !$Conf->can_pc_see_all_submissions()) { $filters[] = "Paper.timeSubmitted>0"; } else { if ($limit === "act" || $limit === "r" || $limit === "rable") { $filters[] = "Paper.timeWithdrawn<=0"; } else { if ($limit === "unsub") { $filters[] = "(Paper.timeSubmitted<=0 and Paper.timeWithdrawn<=0)"; } else { if ($limit === "lead") { $filters[] = "Paper.leadContactId=" . $this->cid; } else { if ($limit === "manager") { if ($this->privChair) { $filters[] = "(Paper.managerContactId=" . $this->cid . " or Paper.managerContactId=0)"; } else { $filters[] = "Paper.managerContactId=" . $this->cid; } $filters[] = "Paper.timeSubmitted>0"; } } } } } // decision limitation parts if ($limit === "acc") { $filters[] = "Paper.outcome>0"; } else { if ($limit === "und") { $filters[] = "Paper.outcome=0"; } } // other search limiters if ($limit === "a") { $filters[] = $this->contact->actAuthorSql("PaperConflict"); $this->needflags |= self::F_AUTHOR; } else { if ($limit === "r") { $filters[] = "MyReview.reviewType is not null"; $this->needflags |= self::F_REVIEWER; } else { if ($limit === "ar") { $filters[] = "(" . $this->contact->actAuthorSql("PaperConflict") . " or (Paper.timeWithdrawn<=0 and MyReview.reviewType is not null))"; $this->needflags |= self::F_AUTHOR | self::F_REVIEWER; } else { if ($limit === "rout") { $filters[] = "MyReview.reviewNeedsSubmit!=0"; $this->needflags |= self::F_REVIEWER; } else { if ($limit === "revs") { $sqi->add_table("Limiter", array("join", "PaperReview")); } else { if ($limit === "req") { $sqi->add_table("Limiter", array("join", "PaperReview", "Limiter.requestedBy={$this->cid} and Limiter.reviewType=" . REVIEW_EXTERNAL)); } else { if ($limit === "unm") { $filters[] = "Paper.managerContactId=0"; } } } } } } } // add common tables: conflicts, my own review, paper blindness if ($this->needflags & (self::F_MANAGER | self::F_NONCONFLICT | self::F_AUTHOR)) { $sqi->add_table("PaperConflict", array("left join", "PaperConflict", "PaperConflict.contactId={$this->cid}")); $sqi->add_column("conflictType", "PaperConflict.conflictType"); } if ($this->needflags & self::F_REVIEWER) { if ($Conf->submission_blindness() == Conf::BLIND_OPTIONAL) { $sqi->add_column("paperBlind", "Paper.blind"); } $qb = ""; if ($tokens = $this->contact->review_tokens()) { $qb = " or MyReview.reviewToken in (" . join(",", $tokens) . ")"; } $sqi->add_table("MyReview", array("left join", "PaperReview", "(MyReview.contactId={$this->cid}{$qb})")); $sqi->add_column("myReviewType", "MyReview.reviewType"); $sqi->add_column("myReviewNeedsSubmit", "MyReview.reviewNeedsSubmit"); $sqi->add_column("myReviewSubmitted", "MyReview.reviewSubmitted"); } // check for annotated order $order_anno_tag = null; if ($qe->type !== "then" && ($sort = $qe->get_float("sort")) && ($tag = self::_check_sort_order_anno($sort))) { $dt = TagInfo::make_defined_tag($tag); if (count($dt->order_anno_list())) { $order_anno_tag = $dt; } } // add permissions tables if we will filter the results $need_filter = $this->needflags & self::F_XVIEW || $Conf->has_tracks() || $qe->type === "then" || $qe->get_float("heading") || $limit === "rable" || $order_anno_tag; if ($need_filter) { $sqi->add_rights_columns(); if ($Conf->submission_blindness() == Conf::BLIND_OPTIONAL) { $sqi->add_column("paperBlind", "Paper.blind"); } } // XXX some of this should be shared with paperQuery if ($need_filter && $Conf->has_track_tags() || get($this->_query_options, "tags") || $order_anno_tag) { $sqi->add_column("paperTags", "(select group_concat(' ', tag, '#', tagIndex separator '') from PaperTag where PaperTag.paperId=Paper.paperId)"); } if (get($this->_query_options, "scores") || get($this->_query_options, "reviewTypes") || get($this->_query_options, "reviewContactIds")) { $j = "group_concat(contactId order by reviewId) reviewContactIds"; $sqi->add_column("reviewContactIds", "R_submitted.reviewContactIds"); if (get($this->_query_options, "reviewTypes")) { $j .= ", group_concat(reviewType order by reviewId) reviewTypes"; $sqi->add_column("reviewTypes", "R_submitted.reviewTypes"); } foreach (get($this->_query_options, "scores") ?: array() as $f) { $j .= ", group_concat({$f} order by reviewId) {$f}Scores"; $sqi->add_column("{$f}Scores", "R_submitted.{$f}Scores"); } $sqi->add_table("R_submitted", array("left join", "(select paperId, {$j} from PaperReview where reviewSubmitted>0 group by paperId)")); } // create query $q = "select "; foreach ($sqi->columns as $colname => $value) { $q .= $value . " " . $colname . ", "; } $q = substr($q, 0, strlen($q) - 2) . "\n from "; foreach ($sqi->tables as $tabname => $value) { if (!$value) { $q .= $tabname; } else { $joiners = array("{$tabname}.paperId=Paper.paperId"); for ($i = 2; $i < count($value); ++$i) { $joiners[] = "(" . $value[$i] . ")"; } $q .= "\n " . $value[0] . " " . $value[1] . " as " . $tabname . " on (" . join("\n and ", $joiners) . ")"; } } if (count($filters)) { $q .= "\n where " . join("\n and ", $filters); } $q .= "\n group by Paper.paperId"; //Conf::msg_info(Ht::pre_text_wrap($q)); // actually perform query $result = Dbl::qe_raw($q); if (!$result) { return $this->_matches = false; } $this->_matches = array(); // correct query, create thenmap, groupmap, highlightmap $need_then = $qe->type === "then"; $this->thenmap = null; if ($need_then && $qe->nthen > 1) { $this->thenmap = array(); } $this->highlightmap = array(); if ($need_filter) { $tag_order = []; while ($row = PaperInfo::fetch($result, $this->cid)) { if (!$this->contact->can_view_paper($row) || $limit === "rable" && !$limitcontact->can_accept_review_assignment_ignore_conflict($row)) { $x = false; } else { if ($need_then) { $x = false; for ($i = 0; $i < $qe->nthen && $x === false; ++$i) { if ($this->_clauseTermCheck($qe->value[$i], $row)) { $x = $i; } } } else { $x = !!$this->_clauseTermCheck($qe, $row); } } if ($x === false) { continue; } $this->_matches[] = $row->paperId; if ($this->thenmap !== null) { $this->thenmap[$row->paperId] = $x; } if ($need_then) { for ($j = $qe->nthen; $j < count($qe->value); ++$j) { if ($this->_clauseTermCheck($qe->value[$j], $row) && $qe->highlights[$j - $qe->nthen] & 1 << $x) { $this->highlightmap[$row->paperId] = $qe->highlight_types[$j - $qe->nthen] . "highlight"; break; } } } if ($order_anno_tag) { if ($row->has_viewable_tag($order_anno_tag->tag, $this->contact)) { $tag_order[] = [$row->paperId, $row->tag_value($order_anno_tag->tag)]; } else { $tag_order[] = [$row->paperId, TAG_INDEXBOUND]; } } } } else { while ($row = $result->fetch_object()) { $this->_matches[] = (int) $row->paperId; } } Dbl::free($result); // add deleted papers explicitly listed by number (e.g. action log) if ($this->_allow_deleted) { $this->_add_deleted_papers($qe); } // view and sort information $this->viewmap = $qe->get_float("view", array()); $this->sorters = array(); $this->_add_sorters($qe, null); if ($qe->type === "then") { for ($i = 0; $i < $qe->nthen; ++$i) { $this->_add_sorters($qe->value[$i], $this->thenmap ? $i : null); } } $this->groupmap = []; if ($qe->type === "then") { for ($i = 0; $i < $qe->nthen; ++$i) { $h = $qe->value[$i]->get_float("heading"); $this->groupmap[$i] = (object) ["heading" => $h, "annoFormat" => 0]; } } else { if ($h = $qe->get_float("heading")) { $this->groupmap[0] = (object) ["heading" => $h, "annoFormat" => 0]; } else { if ($order_anno_tag) { $this->_assign_order_anno($order_anno_tag, $tag_order); $this->is_order_anno = $order_anno_tag->tag; } } } // extract regular expressions and set _reviewer if the query is // about exactly one reviewer, and warn about contradictions $contradictions = array(); $this->_queryExtractInfo($qe, true, false, $contradictions); foreach ($contradictions as $contradiction => $garbage) { $this->warn($contradiction); } // set $this->matchPreg from $this->regex if (!$this->overrideMatchPreg) { $this->matchPreg = array(); foreach (array("ti" => "title", "au" => "authorInformation", "ab" => "abstract", "co" => "collaborators") as $k => $v) { if (isset($this->regex[$k]) && count($this->regex[$k])) { $a = $b = array(); foreach ($this->regex[$k] as $x) { $a[] = $x->preg_utf8; if (isset($x->preg_raw)) { $b[] = $x->preg_raw; } } $x = (object) array("preg_utf8" => join("|", $a)); if (count($a) == count($b)) { $x->preg_raw = join("|", $b); } $this->matchPreg[$v] = $x; } } } return true; }
function save_review($req, $rrow, $prow, $contact, &$tf = null) { global $Conf, $Opt; $newsubmit = @$req["ready"] && !@$req["unready"] && (!$rrow || !$rrow->reviewSubmitted); $submit = $newsubmit || $rrow && $rrow->reviewSubmitted; $admin = $contact->allow_administer($prow); if (!$contact->timeReview($prow, $rrow) && (!isset($req['override']) || !$admin)) { return Conf::msg_error("The <a href='" . hoturl("deadlines") . "'>deadline</a> for entering this review has passed." . ($admin ? " Select the “Override deadlines” checkbox and try again if you really want to override the deadline." : "")); } $q = array(); $diff_view_score = VIEWSCORE_FALSE; $wc = 0; foreach ($this->forder as $field => $f) { if (isset($req[$field]) && (!$f->round_mask || $f->is_round_visible($rrow))) { $fval = $req[$field]; if ($f->has_options) { if ($f->parse_is_empty($fval)) { $fval = 0; } else { if (!($fval = $f->parse_value($fval, false))) { continue; } } } else { $fval = rtrim($fval); if ($fval != "") { $fval .= "\n"; } // Check for valid UTF-8; re-encode from Windows-1252 or Mac OS $fval = convert_to_utf8($fval); if ($f->include_word_count()) { $wc += count_words($fval); } } if ($rrow && strcmp($rrow->{$field}, $fval) != 0 && strcmp(cleannl($rrow->{$field}), cleannl($fval)) != 0) { $diff_view_score = max($diff_view_score, $f->view_score); } $q[] = "{$field}='" . sqlq($fval) . "'"; } } // get the current time $now = time(); if ($rrow && $rrow->reviewModified && $rrow->reviewModified > $now) { $now = $rrow->reviewModified + 1; } // potentially assign review ordinal (requires table locking since // mySQL is stupid) $locked = false; if ($newsubmit) { $diff_view_score = max($diff_view_score, VIEWSCORE_AUTHOR); $q[] = "reviewSubmitted={$now}, reviewNeedsSubmit=0"; if (!$rrow || !$rrow->reviewOrdinal) { $result = $Conf->qe("lock tables PaperReview write"); if (!$result) { return $result; } $locked = true; $result = $Conf->qe("select coalesce(max(reviewOrdinal), 0) from PaperReview where paperId={$prow->paperId} group by paperId"); if ($result) { $crow = edb_row($result); $q[] = "reviewOrdinal=coalesce(reviewOrdinal, " . ($crow[0] + 1) . ")"; } Dbl::free($result); $q[] = "timeDisplayed={$now}"; } } // check whether used a review token $usedReviewToken = $contact->review_token_cid($prow, $rrow); // blind? reviewer type? edit version? $reviewBlind = $Conf->is_review_blind(!!@$req["blind"]); if ($rrow && $reviewBlind != $rrow->reviewBlind) { $diff_view_score = max($diff_view_score, VIEWSCORE_ADMINONLY); } $q[] = "reviewBlind=" . ($reviewBlind ? 1 : 0); if ($rrow && $rrow->reviewType == REVIEW_EXTERNAL && $contact->contactId == $rrow->contactId && $contact->isPC && !$usedReviewToken) { $q[] = "reviewType=" . REVIEW_PC; } if ($rrow && $diff_view_score > VIEWSCORE_FALSE && isset($req["version"]) && ctype_digit($req["version"]) && $req["version"] > defval($rrow, "reviewEditVersion")) { $q[] = "reviewEditVersion=" . ($req["version"] + 0); } if ($diff_view_score > VIEWSCORE_FALSE && $Conf->sversion >= 98) { $q[] = "reviewWordCount=" . $wc; } if (isset($req["reviewFormat"]) && $Conf->sversion >= 104 && @$Opt["formatInfo"]) { $fmt = null; foreach ($Opt["formatInfo"] as $k => $f) { if (@$f["name"] && strcasecmp($f["name"], $req["reviewFormat"]) == 0) { $fmt = (int) $k; } } if (!$fmt && $req["reviewFormat"] && preg_match('/\\A(?:plain\\s*)?(?:text)?\\z/i', $f["reviewFormat"])) { $fmt = 0; } $q[] = "reviewFormat=" . ($fmt === null ? "null" : $fmt); } // notification $notification_bound = $now - 10800; $notify = $notify_author = false; if (!$rrow || $diff_view_score > VIEWSCORE_FALSE) { $q[] = "reviewModified=" . $now; // do not notify on updates within 3 hours if ($submit && $diff_view_score > VIEWSCORE_ADMINONLY) { if (!$rrow || !$rrow->reviewNotified || $rrow->reviewNotified < $notification_bound) { $q[] = $notify = "reviewNotified=" . $now; } if ((!$rrow || !$rrow->reviewAuthorNotified || $rrow->reviewAuthorNotified < $notification_bound) && $diff_view_score >= VIEWSCORE_AUTHOR && Contact::can_some_author_view_submitted_review($prow)) { $q[] = $notify_author = "reviewAuthorNotified=" . $now; } } } // actually affect database if ($rrow) { $result = $Conf->qe("update PaperReview set " . join(", ", $q) . " where reviewId={$rrow->reviewId}"); $reviewId = $rrow->reviewId; $contactId = $rrow->contactId; } else { $result = Dbl::qe_raw("insert into PaperReview set paperId={$prow->paperId}, contactId={$contact->contactId}, reviewType=" . REVIEW_PC . ", requestedBy={$contact->contactId}, reviewRound=" . $Conf->current_round() . ", " . join(", ", $q)); $reviewId = $result ? $result->insert_id : null; $contactId = $contact->contactId; } // unlock tables even if problem if ($locked) { $Conf->qe("unlock tables"); } if (!$result) { return $result; } // update caches Contact::update_rights(); // look up review ID if (!$reviewId) { return $reviewId; } $req['reviewId'] = $reviewId; // log updates -- but not if review token is used if (!$usedReviewToken && $diff_view_score > VIEWSCORE_FALSE) { $text = "Review {$reviewId} "; if ($rrow && $contact->contactId != $rrow->contactId) { $text .= "by {$rrow->email} "; } $text .= $newsubmit ? "submitted" : ($submit ? "updated" : "saved draft"); $contact->log_activity($text, $prow); } // potentially email chair, reviewers, and authors if ($submit) { $rrow = $Conf->reviewRow(["reviewId" => $reviewId]); } if ($submit && ($notify || $notify_author) && $rrow) { $tmpl = $newsubmit ? "@reviewsubmit" : "@reviewupdate"; $submitter = $contact; if ($contactId != $submitter->contactId) { $submitter = Contact::find_by_id($contactId); } // construct mail $this->mailer_info = array("template" => $tmpl, "rrow" => $rrow, "reviewer_contact" => $submitter, "reviewNumber" => $prow->paperId . unparseReviewOrdinal($rrow->reviewOrdinal), "check_function" => "HotCRPMailer::check_can_view_review", "diff_view_score" => $diff_view_score); $this->mailer_preps = array(); if ($Conf->timeEmailChairAboutReview()) { HotCRPMailer::send_manager($tmpl, $prow, $this->mailer_info); } $prow->notify(WATCHTYPE_REVIEW, array($this, "review_watch_callback"), $contact); if (count($this->mailer_preps)) { HotCRPMailer::send_combined_preparations($this->mailer_preps); } unset($this->mailer_info, $this->mailer_preps); } // if external, forgive the requestor from finishing their review if ($rrow && $rrow->reviewType < REVIEW_SECONDARY && $rrow->requestedBy && $submit) { $Conf->q("update PaperReview set reviewNeedsSubmit=0 where paperId={$prow->paperId} and contactId={$rrow->requestedBy} and reviewType=" . REVIEW_SECONDARY . " and reviewSubmitted is null"); } if ($tf !== null) { $what = "#{$prow->paperId}" . ($rrow && $rrow->reviewSubmitted ? unparseReviewOrdinal($rrow->reviewOrdinal) : ""); if ($newsubmit) { $tf["newlySubmitted"][] = $what; } else { if ($diff_view_score > VIEWSCORE_FALSE && $submit) { $tf["updated"][] = $what; } else { if ($diff_view_score > VIEWSCORE_FALSE) { $tf["savedDraft"][] = $what; } else { $tf["unchanged"][] = $what; } } } if ($notify_author) { $tf["authorNotified"][] = $what; } } return $result; }
static function alltags_api($user, $qreq, $prow) { global $Conf; if (!$user->isPC) { json_exit(["ok" => false]); } $need_paper = $conflict_where = false; $where = $args = array(); if ($user->allow_administer(null)) { $need_paper = true; if ($Conf->has_any_manager() && !$Conf->setting("tag_seeall")) { $conflict_where = "(p.managerContactId=0 or p.managerContactId={$user->contactId} or pc.conflictType is null)"; } } else { if ($Conf->check_track_sensitivity(Track::VIEW)) { $where[] = "t.paperId ?a"; $args[] = $user->list_submitted_papers_with_viewable_tags(); } else { $need_paper = true; if ($Conf->has_any_manager() && !$Conf->setting("tag_seeall")) { $conflict_where = "(p.managerContactId={$user->contactId} or pc.conflictType is null)"; } else { if (!$Conf->setting("tag_seeall")) { $conflict_where = "pc.conflictType is null"; } } } } $q = "select distinct tag from PaperTag t"; if ($need_paper) { $q .= " join Paper p on (p.paperId=t.paperId)"; $where[] = "p.timeSubmitted>0"; } if ($conflict_where) { $q .= " left join PaperConflict pc on (pc.paperId=t.paperId and pc.contactId={$user->contactId})"; $where[] = $conflict_where; } $q .= " where " . join(" and ", $where); $tags = array(); $result = Dbl::qe_apply($q, $args); while ($row = edb_row($result)) { $twiddle = strpos($row[0], "~"); if ($twiddle === false || $twiddle == 0 && $row[0][1] === "~" && $user->privChair) { $tags[] = $row[0]; } else { if ($twiddle > 0 && substr($row[0], 0, $twiddle) == $user->contactId) { $tags[] = substr($row[0], $twiddle); } } } Dbl::free($result); json_exit(["ok" => true, "tags" => $tags]); }
public function run_discussion_order($tag, $sequential = false) { global $Conf; $this->mcmf_round_descriptor = ""; $this->mcmf_optimizing_for = "Optimizing assignment"; // load conflicts $cflt = array(); foreach ($this->papersel as $pid) { $cflt[$pid] = array(); } $result = Dbl::qe("select paperId, contactId from PaperConflict where paperId ?a and contactId ?a and conflictType>0", $this->papersel, array_keys($this->pcm)); while ($row = edb_row($result)) { $cflt[(int) $row[0]][] = (int) $row[1]; } Dbl::free($result); // run max-flow $result = $this->papersel; for ($roundno = 0; !$roundno || count($result) > 1; ++$roundno) { $this->mcmf_round_descriptor = $roundno ? ", round " . ($roundno + 1) : ""; $result = $this->run_discussion_order_once($cflt, $result); if (!$roundno) { $groupmap = array(); foreach ($result as $i => $pids) { foreach ($pids as $pid) { $groupmap[$pid] = $i; } } } } // make assignments $this->set_progress("Completing assignment"); $this->ass = array("paper,action,tag", "# hotcrp_assign_display_search", "# hotcrp_assign_show pcconf", "all,cleartag,{$tag}"); $curgroup = -1; $index = 0; $search = array("HEADING:none"); foreach ($result[0] as $pid) { if ($groupmap[$pid] != $curgroup && $curgroup != -1) { $search[] = "THEN HEADING:none"; } $curgroup = $groupmap[$pid]; $index += TagInfo::value_increment($sequential ? "aos" : "ao"); $this->ass[] = "{$pid},tag,{$tag}#{$index}"; $search[] = $pid; } $this->ass[1] = "# hotcrp_assign_display_search " . join(" ", $search); //global $Conf; $Conf->echoScript("$('#propass').before(" . json_encode(Ht::pre_text_wrap($m->debug_info(true) . "\n")) . ")"); }
public function data() { global $Conf, $Me; // load data $paperIds = array_keys($this->papermap); $queryOptions = array("paperId" => $paperIds, "tags" => true); $this->fx->add_query_options($queryOptions, $Me); $this->fy->add_query_options($queryOptions, $Me); if ($this->fx->needs_review() || $this->fy->needs_review()) { $queryOptions["reviewOrdinals"] = true; } $result = Dbl::qe_raw($Conf->paperQuery($Me, $queryOptions)); if ($this->type == self::CDF) { $data = $this->_cdf_data($result); } else { if ($this->type & self::BARCHART) { $data = $this->_combine_data($result); } else { $data = $this->_scatter_data($result); } } $this->_reviewer_reformat($data); $this->_revround_reformat($data); Dbl::free($result); return $data; }
public function save($sv, $si) { global $Conf; if ($sv->update("review_form", json_encode($this->nrfj))) { $rf = ReviewForm::get(); $scoreModified = array(); foreach ($this->nrfj as $fid => $fj) { if (get($fj, "position") && get($fj, "options")) { $result = Dbl::qe_raw("update PaperReview set {$fid}=0 where {$fid}>" . count($fj->options)); if ($result && $result->affected_rows > 0) { $scoreModified[] = htmlspecialchars($fj->name); } Dbl::free($result); } } foreach ($rf->fmap as $fid => $f) { foreach (self::$setting_prefixes as $fx) { unset($sv->req["{$fx}{$fid}"]); } } if (count($scoreModified)) { $sv->set_warning(null, "Your changes invalidated some existing review scores. The invalid scores have been reset to “Unknown”. The relevant fields were: " . join(", ", $scoreModified) . "."); } $Conf->invalidateCaches(array("rf" => true)); // reset all word counts in case author visibility changed Dbl::qe("update PaperReview set reviewWordCount=null"); } }
public function fetch_comments($where) { $result = Dbl::qe("select PaperComment.*, firstName reviewFirstName, lastName reviewLastName, email reviewEmail\n from PaperComment join ContactInfo on (ContactInfo.contactId=PaperComment.contactId)\n where {$where} order by commentId"); $comments = array(); while ($c = CommentInfo::fetch($result, $this)) { $comments[$c->commentId] = $c; } Dbl::free($result); return $comments; }
fwrite(STDERR, "Need `_facefetch_script` configuration option or argument.\n"); exit(1); } if (!isset($arg["limit"])) { $arg["limit"] = get($arg, "l"); } $limit = (int) $arg["limit"]; $result = Dbl::qe("select contactId, email, huid from ContactInfo" . (isset($arg["all"]) || isset($arg["a"]) ? "" : " where contactImageId is null")); $rows = array(); while ($row = edb_row($result)) { $rows[] = $row; } if ($limit) { shuffle($rows); } Dbl::free($result); $n = $nworked = 0; foreach ($rows as $row) { $url = $facefetch_urlpattern; if ($row[1] === null && strpos($url, '${EMAIL}') !== false || $row[2] === null && strpos($url, '${ID}') !== false) { continue; } $url = str_replace('${EMAIL}', urlencode($row[1]), $url); $url = str_replace('${ID}', urlencode($row[2]), $url); // fwrite(STDOUT, "$row[1] $fetchscript " . escapeshellarg($url) . " "); fwrite(STDOUT, "{$row['1']} "); $handle = popen($fetchscript . " " . escapeshellarg($url), "r"); $data = stream_get_contents($handle); $status = pclose($handle); $content_type = ""; if ($data && ($nl = strpos($data, "\n")) !== false) {
function update_schema_review_word_counts($Conf) { $rf = new ReviewForm($Conf->review_form_json()); do { $q = array(); $result = Dbl::ql("select * from PaperReview where reviewWordCount is null limit 32"); while ($rrow = edb_orow($result)) { $q[] = "update PaperReview set reviewWordCount=" . $rf->word_count($rrow) . " where reviewId=" . $rrow->reviewId; } Dbl::free($result); $Conf->dblink->multi_query(join(";", $q)); while ($Conf->dblink->more_results()) { Dbl::free($Conf->dblink->next_result()); } } while (count($q) == 32); }
function do_setting_update($sv) { global $Conf, $Group, $Me, $Now, $Opt, $OptOverride; // parse settings foreach (Si::$all as $si) { account_value($sv, $si); } // check date relationships foreach (array("sub_reg" => "sub_sub", "final_soft" => "final_done") as $dn1 => $dn2) { list($dv1, $dv2) = [$sv->savedv($dn1), $sv->savedv($dn2)]; } if (!$dv1 && $dv2) { $sv->save($dn1, $dv2); } else { if ($dv2 && $dv1 > $dv2) { $sv->set_error($dn1, unparse_setting_error(Si::get($dn1), "Must come before " . Si::get($dn2, "short_description") . ".")); $sv->set_error($dn2); } } if ($sv->has_savedv("sub_sub")) { $sv->save("sub_update", $sv->savedv("sub_sub")); } if (get($Opt, "defaultSiteContact")) { if ($sv->has_savedv("opt.contactName") && get($Opt, "contactName") === $sv->savedv("opt.contactName")) { $sv->save("opt.contactName", null); } if ($sv->has_savedv("opt.contactEmail") && get($Opt, "contactEmail") === $sv->savedv("opt.contactEmail")) { $sv->save("opt.contactEmail", null); } } if ($sv->has_savedv("resp_active") && $sv->savedv("resp_active")) { foreach (explode(" ", $sv->newv("resp_rounds")) as $i => $rname) { $isuf = $i ? "_{$i}" : ""; if ($sv->newv("resp_open{$isuf}") > $sv->newv("resp_done{$isuf}")) { $sv->set_error("resp_open{$isuf}", unparse_setting_error(Si::get("resp_open"), "Must come before " . Si::get("resp_done", "short_description") . ".")); $sv->set_error("resp_done{$isuf}"); } } } // update 'papersub' if ($sv->has_savedv("pc_seeall")) { // see also conference.php if ($sv->savedv("pc_seeall") <= 0) { $x = "timeSubmitted>0"; } else { $x = "timeWithdrawn<=0"; } $num = Dbl::fetch_ivalue("select paperId from Paper where {$x} limit 1") ? 1 : 0; if ($num != $Conf->setting("papersub")) { $sv->save("papersub", $num); } } // Setting relationships if ($sv->has_savedv("sub_open") && $sv->newv("sub_open", 1) <= 0 && $sv->oldv("sub_open") > 0 && $sv->newv("sub_sub") <= 0) { $sv->save("sub_close", $Now); } if ($sv->has_savedv("msg.clickthrough_submit")) { $sv->save("clickthrough_submit", null); } // make settings $changedn = []; if (!$sv->has_errors() && (count($sv->savedv) || count($sv->save_callbacks))) { $tables = "Settings write"; foreach ($sv->need_lock as $t => $need) { if ($need) { $tables .= ", {$t} write"; } } $Conf->qe("lock tables {$tables}"); // load db settings, pre-crosscheck $dbsettings = array(); $result = Dbl::qe("select name, value, data from Settings"); while ($row = edb_row($result)) { $dbsettings[$row[0]] = $row; } Dbl::free($result); // apply settings foreach ($sv->save_callbacks as $si) { $p = $sv->parser($si); $p->save($sv, $si); } $dv = $aq = $av = array(); foreach ($sv->savedv as $n => $v) { if (substr($n, 0, 4) === "opt." && $v !== null) { $okey = substr($n, 4); $oldv = array_key_exists($okey, $OptOverride) ? $OptOverride[$okey] : get($Opt, $okey); $Opt[$okey] = $v[1] === null ? $v[0] : $v[1]; if ($oldv === $Opt[$okey]) { $v = null; } else { if (!array_key_exists($okey, $OptOverride)) { $OptOverride[$okey] = $oldv; } } } if ($v === null ? !isset($dbsettings[$n]) : isset($dbsettings[$n]) && (int) $dbsettings[$n][1] === $v[0] && $dbsettings[$n][2] === $v[1]) { continue; } $changedn[] = $n; if ($v !== null) { $aq[] = "(?, ?, ?)"; array_push($av, $n, $v[0], $v[1]); } else { $dv[] = $n; } } if (count($dv)) { Dbl::qe_apply("delete from Settings where name?a", array($dv)); //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query_apply("delete from Settings where name?a", array($dv)))); } if (count($aq)) { Dbl::qe_apply("insert into Settings (name, value, data) values\n\t" . join(",\n\t", $aq) . "\n\ton duplicate key update value=values(value), data=values(data)", $av); //Conf::msg_info(Ht::pre_text_wrap(Dbl::format_query_apply("insert into Settings (name, value, data) values\n\t" . join(",\n\t", $aq) . "\n\ton duplicate key update value=values(value), data=values(data)", $av))); } $Conf->qe("unlock tables"); if (count($changedn)) { $Me->log_activity("Updated settings " . join(", ", $changedn)); } $Conf->load_settings(); // contactdb may need to hear about changes to shortName if ($sv->has_savedv("opt.shortName") && get($Opt, "contactdb_dsn") && ($cdb = Contact::contactdb())) { Dbl::ql($cdb, "update Conferences set shortName=? where dbName=?", $Opt["shortName"], $Opt["dbName"]); } } // update the review form in case it's changed ReviewForm::clear_cache(); if (!$sv->has_errors()) { $Conf->save_session("settings_highlight", $sv->error_fields()); if (count($changedn)) { $Conf->confirmMsg("Changes saved."); } else { $Conf->warnMsg("No changes."); } $sv->report(); redirectSelf(); } else { SettingGroup::crosscheck($sv, $Group); $sv->report(); } }
private function reviewer_set() { if ($this->reviewer_set === false) { $this->reviewer_set = array(); foreach (pcMembers() as $p) { $this->reviewer_set[$p->contactId] = $p; } $result = Dbl::qe("select " . AssignerContacts::$query . " from ContactInfo join PaperReview using (contactId) where (roles&" . Contact::ROLE_PC . ")=0 group by ContactInfo.contactId"); while ($result && ($row = Contact::fetch($result))) { $this->reviewer_set[$row->contactId] = $row; } Dbl::free($result); } return $this->reviewer_set; }
private function load_by_query($where) { $result = $this->conf->q_raw("select ContactInfo.* from ContactInfo where {$where}"); if ($row = $result ? $result->fetch_object() : null) { $this->merge($row); } Dbl::free($result); return !!$row; }
private static function try_list($opt, $listtype, $sort = null) { global $Conf, $Me; if ($listtype == "u" && $Me->privChair) { $searchtype = defval($opt, "t") === "all" ? "all" : "pc"; $q = "select contactId from ContactInfo"; if ($searchtype == "pc") { $q .= " where (roles&" . Contact::ROLE_PC . ")!=0"; } $result = Dbl::ql("{$q} order by lastName, firstName, email"); $a = array(); while ($row = edb_row($result)) { $a[] = (int) $row[0]; } Dbl::free($result); return self::create("u/" . $searchtype, $a, $searchtype == "pc" ? "Program committee" : "Users", hoturl_site_relative_raw("users", "t={$searchtype}")); } else { $search = new PaperSearch($Me, $opt); $x = $search->session_list_object($sort); if ($sort || $search->has_sort()) { $pl = new PaperList($search, array("sort" => $sort)); $x->ids = $pl->id_array(); } return $x; } }
function assign_review($pid, $reviewer_cid, $type, $extra = array()) { global $Conf, $Now; $result = Dbl::qe("select reviewId, reviewType, reviewRound, reviewModified, reviewToken, requestedBy, reviewSubmitted from PaperReview where paperId=? and contactId=?", $pid, $reviewer_cid); $rrow = edb_orow($result); Dbl::free($result); $reviewId = $rrow ? $rrow->reviewId : 0; // can't delete a review that's in progress if ($type <= 0 && $rrow && $rrow->reviewType && $rrow->reviewModified) { if ($rrow->reviewType >= REVIEW_SECONDARY) { $type = REVIEW_PC; } else { return $reviewId; } } // change database if ($type > 0 && ($round = get($extra, "round_number")) === null) { $round = $Conf->current_round(); } if ($type > 0 && (!$rrow || !$rrow->reviewType)) { $qa = ""; if (get($extra, "mark_notify")) { $qa .= ", timeRequestNotified={$Now}"; } if (get($extra, "token")) { $qa .= self::unassigned_review_token(); } $new_requester_cid = $this->contactId; if ($new_requester = get($extra, "requester_contact")) { $new_requester_cid = $new_requester->contactId; } $q = "insert into PaperReview set paperId={$pid}, contactId={$reviewer_cid}, reviewType={$type}, reviewRound={$round}, timeRequested={$Now}{$qa}, requestedBy={$new_requester_cid}"; } else { if ($type > 0 && ($rrow->reviewType != $type || $rrow->reviewRound != $round)) { $q = "update PaperReview set reviewType={$type}, reviewRound={$round}"; if (!$rrow->reviewSubmitted) { $q .= ", reviewNeedsSubmit=1"; } $q .= " where reviewId={$reviewId}"; } else { if ($type <= 0 && $rrow && $rrow->reviewType) { $q = "delete from PaperReview where reviewId={$reviewId}"; } else { return $reviewId; } } } if (!($result = Dbl::qe_raw($q))) { return false; } if ($q[0] == "d") { $msg = "Removed " . ReviewForm::$revtype_names[$rrow->reviewType] . " review"; $reviewId = 0; } else { if ($q[0] == "u") { $msg = "Changed " . ReviewForm::$revtype_names[$rrow->reviewType] . " review to " . ReviewForm::$revtype_names[$type]; } else { $msg = "Added " . ReviewForm::$revtype_names[$type] . " review"; $reviewId = $result->insert_id; } } $Conf->log($msg . " by " . $this->email, $reviewer_cid, $pid); // on new review, update PaperReviewRefused, ReviewRequest, delegation if ($q[0] == "i") { Dbl::ql("delete from PaperReviewRefused where paperId={$pid} and contactId={$reviewer_cid}"); if ($req_email = get($extra, "requested_email")) { Dbl::qe("delete from ReviewRequest where paperId={$pid} and email=?", $req_email); } if ($type < REVIEW_SECONDARY) { self::update_review_delegation($pid, $new_requester_cid, 1); } } else { if ($q[0] == "d") { if ($rrow->reviewType < REVIEW_SECONDARY && $rrow->requestedBy > 0) { self::update_review_delegation($pid, $rrow->requestedBy, -1); } } else { if ($type == REVIEW_SECONDARY && $rrow->reviewType != REVIEW_SECONDARY && !$rrow->reviewSubmitted) { self::update_review_delegation($pid, $reviewer_cid, 0); } } } // Mark rev_tokens setting for future update by update_rev_tokens_setting if ($rrow && get($rrow, "reviewToken") && $type <= 0) { $Conf->settings["rev_tokens"] = -1; } // Set pcrev_assigntime if ($q[0] == "i" && $type >= REVIEW_PC && $Conf->setting("pcrev_assigntime", 0) < $Now) { $Conf->save_setting("pcrev_assigntime", $Now); } Contact::update_rights(); return $reviewId; }
function pc_members() { if ($this->_pc_members_cache === null) { $pc = $pca = array(); $result = $this->q("select firstName, lastName, affiliation, email, contactId, roles, contactTags, disabled from ContactInfo where roles!=0 and (roles&" . Contact::ROLE_PCLIKE . ")!=0"); $by_name_text = $by_first_text = []; $this->_pc_tags_cache = ["pc" => "pc"]; while ($result && ($row = Contact::fetch($result, $this))) { $pca[$row->contactId] = $row; if ($row->roles & Contact::ROLE_PC) { $pc[$row->contactId] = $row; } if ($row->firstName || $row->lastName) { $name_text = Text::name_text($row); if (isset($by_name_text[$name_text])) { $row->nameAmbiguous = $by_name_text[$name_text]->nameAmbiguous = true; } $by_name_text[$name_text] = $row; } if ($row->firstName) { if (isset($by_first_text[$row->firstName])) { $row->firstNameAmbiguous = $by_first_text[$row->firstName]->firstNameAmbiguous = true; } $by_first_text[$row->firstName] = $row; } if ($row->contactTags) { foreach (explode(" ", $row->contactTags) as $t) { list($tag, $value) = TagInfo::split_index($t); if ($tag) { $this->_pc_tags_cache[strtolower($tag)] = $tag; } } } } Dbl::free($result); uasort($pc, "Contact::compare"); $order = 0; foreach ($pc as $row) { $row->sort_position = $order; ++$order; } $this->_pc_members_cache = $pc; uasort($pca, "Contact::compare"); $this->_pc_members_and_admins_cache = $pca; ksort($this->_pc_tags_cache); } return $this->_pc_members_cache; }
private static function load_optdata($pid) { $result = Dbl::qe("select optionId, value, data from PaperOption where paperId=?", $pid); $optdata = array(); while ($row = edb_row($result)) { $optdata[$row[0] . "." . $row[1]] = $row[2]; } Dbl::free($result); return $optdata; }
if (!$Conf->dblink->multi_query(file_get_contents("{$ConfSitePATH}/src/schema.sql"))) { die_hard("* Can't reinitialize database.\n" . $Conf->dblink->error); } while ($Conf->dblink->more_results()) { Dbl::free($Conf->dblink->next_result()); } // No setup phase. $Conf->qe("delete from Settings where name='setupPhase'"); $Conf->load_settings(); // Contactdb. if ($cdb = Contact::contactdb()) { if (!$cdb->multi_query(file_get_contents("{$ConfSitePATH}/test/cdb-schema.sql"))) { die_hard("* Can't reinitialize contact database.\n" . $cdb->error); } while ($cdb->more_results()) { Dbl::free($cdb->next_result()); } } // Create initial administrator user. $Admin = Contact::create(array("email" => "chair@_.com", "name" => "Jane Chair", "password" => "testchair")); $Admin->save_roles(Contact::ROLE_ADMIN | Contact::ROLE_CHAIR | Contact::ROLE_PC, $Admin); // Load data. $json = json_decode(file_get_contents("{$ConfSitePATH}/test/db.json")); if (!$json) { die_hard("* test/testdb.json error: " . json_last_error_msg() . "\n"); } foreach ($json->contacts as $c) { $us = new UserStatus(); if (!$us->save($c)) { die_hard("* failed to create user {$c->email}\n"); }
private function _rows($field_list) { global $Conf; if (!$field_list) { return null; } // prepare query text $this->qopts["scores"] = array_keys($this->qopts["scores"]); if (empty($this->qopts["scores"])) { unset($this->qopts["scores"]); } $pq = $Conf->paperQuery($this->contact, $this->qopts); // make query $result = Dbl::qe_raw($pq); if (!$result) { return null; } // fetch rows $rows = array(); while ($row = PaperInfo::fetch($result, $this->contact)) { $rows[$row->paperId] = $row; } // prepare review query (see also search > getfn == "reviewers") $this->review_list = array(); if (isset($this->qopts["reviewList"]) && !empty($rows)) { $result = Dbl::qe("select Paper.paperId, reviewId, reviewType,\n reviewSubmitted, reviewModified, reviewNeedsSubmit, reviewRound,\n reviewOrdinal,\n PaperReview.contactId, lastName, firstName, email\n from Paper\n join PaperReview using (paperId)\n join ContactInfo on (PaperReview.contactId=ContactInfo.contactId)\n where paperId?a", array_keys($rows)); while ($row = edb_orow($result)) { Contact::set_sorter($row); $this->review_list[$row->paperId][] = $row; } foreach ($this->review_list as &$revlist) { usort($revlist, "PaperList::review_list_compar"); } unset($revlist); } // prepare PC topic interests if (isset($this->qopts["allReviewerPreference"])) { $ord = 0; $pcm = pcMembers(); foreach ($pcm as $pc) { $pc->prefOrdinal = sprintf("-0.%04d", $ord++); $pc->topicInterest = array(); } $result = Dbl::qe("select contactId, topicId, " . $Conf->query_topic_interest() . " from TopicInterest"); while ($row = edb_row($result)) { $pcm[$row[0]]->topicInterest[$row[1]] = $row[2]; } } // analyze rows (usually noop) foreach ($field_list as $fdef) { $fdef->analyze($this, $rows); } // sort rows if (!empty($this->sorters)) { $rows = $this->_sort($rows); if (isset($this->qopts["allReviewScores"])) { $this->_sortReviewOrdinal($rows); } } // set `any->optID` if ($nopts = PaperOption::count_option_list()) { foreach ($rows as $prow) { foreach ($prow->options() as $o) { if (!$this->any["opt{$o->id}"] && $this->contact->can_view_paper_option($prow, $o->option)) { $this->any["opt{$o->id}"] = true; --$nopts; } } if (!$nopts) { break; } } } Dbl::free($result); return $rows; }
function load_settings() { global $Opt, $OptOverride, $Now, $OK; // load settings from database $this->settings = array(); $this->settingTexts = array(); $this->_pc_seeall_cache = null; $this->deadlineCache = null; $result = $this->q("select name, value, data from Settings"); while ($result && ($row = $result->fetch_row())) { $this->settings[$row[0]] = (int) $row[1]; if ($row[2] !== null) { $this->settingTexts[$row[0]] = $row[2]; } if (substr($row[0], 0, 4) == "opt.") { $okey = substr($row[0], 4); if (!array_key_exists($okey, $OptOverride)) { $OptOverride[$okey] = @$Opt[$okey]; } $Opt[$okey] = $row[2] === null ? $row[1] : $row[2]; } } Dbl::free($result); // update schema if ($this->settings["allowPaperOption"] < 91) { require_once "updateschema.php"; $oldOK = $OK; updateSchema($this); $OK = $oldOK; } $this->sversion = $this->settings["allowPaperOption"]; // invalidate caches after loading from backup if (isset($this->settings["frombackup"]) && $this->invalidateCaches()) { $this->qe("delete from Settings where name='frombackup' and value=" . $this->settings["frombackup"]); unset($this->settings["frombackup"]); } // update options if (isset($Opt["ldapLogin"]) && !$Opt["ldapLogin"]) { unset($Opt["ldapLogin"]); } if (isset($Opt["httpAuthLogin"]) && !$Opt["httpAuthLogin"]) { unset($Opt["httpAuthLogin"]); } // set conferenceKey if (!isset($Opt["conferenceKey"])) { if (!isset($this->settingTexts["conf_key"]) && ($key = hotcrp_random_bytes(32)) !== false) { $this->save_setting("conf_key", 1, $key); } $Opt["conferenceKey"] = defval($this->settingTexts, "conf_key", ""); } // set capability key if (!@$this->settings["cap_key"] && !@$Opt["disableCapabilities"] && !(($key = hotcrp_random_bytes(16)) !== false && ($key = base64_encode($key)) && $this->save_setting("cap_key", 1, $key))) { $Opt["disableCapabilities"] = true; } // GC old capabilities if ($this->sversion >= 58 && defval($this->settings, "__capability_gc", 0) < $Now - 86400) { foreach (array($this->dblink, Contact::contactdb()) as $db) { if ($db) { Dbl::ql($db, "delete from Capability where timeExpires>0 and timeExpires<{$Now}"); Dbl::ql($db, "delete from CapabilityMap where timeExpires>0 and timeExpires<{$Now}"); } } $this->q("insert into Settings (name, value) values ('__capability_gc', {$Now}) on duplicate key update value=values(value)"); $this->settings["__capability_gc"] = $Now; } $this->crosscheck_settings(); $this->crosscheck_options(); }