public function save($sv, $si) { global $Conf; $tmap = $Conf->topic_map(); foreach ($sv->req as $k => $v) { if ($k === "topnew") { $news = array(); foreach (explode("\n", $v) as $n) { if (($n = simplify_whitespace($n)) !== "") { $news[] = "('" . sqlq($n) . "')"; } } if (count($news)) { $Conf->qe("insert into TopicArea (topicName) values " . join(",", $news)); } } else { if (strlen($k) > 3 && substr($k, 0, 3) === "top" && ctype_digit(substr($k, 3))) { $k = (int) substr($k, 3); $v = simplify_whitespace($v); if ($v == "") { $Conf->qe("delete from TopicArea where topicId={$k}"); $Conf->qe("delete from PaperTopic where topicId={$k}"); $Conf->qe("delete from TopicInterest where topicId={$k}"); } else { if (isset($tmap[$k]) && $v != $tmap[$k] && !ctype_digit($v)) { $Conf->qe("update TopicArea set topicName='" . sqlq($v) . "' where topicId={$k}"); } } } } } $Conf->invalidate_topics(); }
function clean_queue($qname, $qconf, $qid) { global $Conf, $Now; $runtimeout = isset($qconf->runtimeout) ? $qconf->runtimeout : 300; $result = $Conf->qe("select * from ExecutionQueue where queueclass='" . sqlq($qname) . "' and queueid<{$qid}"); while ($row = edb_orow($result)) { // remove dead items from queue // - lockfile contains "0\n": child has exited, remove it // - lockfile specified but not there // - no lockfile & last update < 30sec ago // - running for more than 5min (configurable) if ($row->lockfile && @file_get_contents($row->lockfile) === "0\n") { unlink($row->lockfile); $row->inputfifo && unlink($row->inputfifo); } if ($row->lockfile && !file_exists($row->lockfile) || $row->runat <= 0 && $row->updateat < $Now - 30 || $runtimeout && $row->runat > 0 && $row->runat < $Now - $runtimeout) { $Conf->qe("delete from ExecutionQueue where queueid={$row->queueid}"); } } }
<?php // checkupdates.php -- HotCRP update checker helper // HotCRP is Copyright (c) 2006-2016 Eddie Kohler and Regents of the UC // Distributed under an MIT-like license; see LICENSE require_once "src/initweb.php"; if (isset($_REQUEST["text"]) && $_REQUEST["text"]) { header("Content-Type: text/plain"); } else { header("Content-Type: application/json"); } if ($Me->privChair && isset($_REQUEST["ignore"])) { $when = time() + 86400 * 2; $Conf->qe("insert into Settings (name, value) values ('ignoreupdate_" . sqlq($_REQUEST["ignore"]) . "', {$when}) on duplicate key update value={$when}"); } $messages = array(); if ($Me->privChair && isset($_REQUEST["data"]) && ($data = json_decode($_REQUEST["data"], true)) && isset($data["updates"]) && is_array($data["updates"])) { foreach ($data["updates"] as $update) { $ok = true; if (isset($update["opt"]) && is_array($update["opt"])) { foreach ($update["opt"] as $k => $v) { $kk = $k[0] == "-" ? substr($k, 1) : $k; $test = defval($Opt, $kk, null) == $v; $ok = $ok && ($k[0] == "-" ? !$test : $test); } } if (isset($update["settings"]) && is_array($update["settings"])) { foreach ($update["settings"] as $k => $v) { if (preg_match('/\\A([!<>]?)(-?\\d+|now)\\z/', $v, $m)) { $setting = $Conf->setting($k, 0); if ($m[2] == "now") {
$contact->contactdb_update(); } Dbl::free($result); } if ($papers) { $result = Dbl::ql(Contact::contactdb(), "select confid from Conferences where `dbname`=?", $Opt["dbName"]); $row = Dbl::fetch_first_row($result); if (!$row) { fwrite(STDERR, "Conference is not recored in contactdb\n"); exit(1); } $confid = $row[0]; $result = Dbl::ql($Conf->dblink, "select paperId, title from Paper"); $q = array(); while ($row = edb_row($result)) { $q[] = "(" . $confid . "," . $row[0] . ",'" . sqlq($row[1]) . "')"; } Dbl::free($result); for ($i = 0; $i < count($q); $i += 25) { $xq = array_slice($q, $i, 25); Dbl::ql_raw(Contact::contactdb(), "insert into ConferencePapers (confid,paperId,title) values " . join(",", $xq) . " on duplicate key update title=values(title)"); } } if ($collaborators) { $result = Dbl::ql($Conf->dblink, "select email, collaborators, updateTime, lastLogin from ContactInfo where collaborators is not null and collaborators!=''"); while ($row = edb_row($result)) { $time = (int) $row[2] ?: (int) $row[3]; if ($time > 0) { Dbl::ql(Contact::contactdb(), "update ContactInfo set collaborators=?, updateTime=? where email=? and (collaborators is null or collaborators='' or updateTime<?)", $row[1], $time, $row[0], $time); } }
function log($text, $who, $pids = null) { if (!$who) { $who = 0; } else { if (!is_numeric($who)) { $who = $who->contactId; } } if (is_object($pids)) { $pids = array($pids->paperId); } else { if (!is_array($pids)) { $pids = $pids > 0 ? array($pids) : array(); } } $ps = array(); foreach ($pids as $p) { $ps[] = is_object($p) ? $p->paperId : $p; } if ($this->_save_logs !== false) { foreach ($ps as $p) { $this->_save_logs["{$who}|{$text}"][] = $p; } return; } if (count($ps) == 0) { $ps = "null"; } else { if (count($ps) == 1) { $ps = $ps[0]; } else { $text .= " (papers " . join(", ", $ps) . ")"; $ps = "null"; } } $this->q("insert into ActionLog (ipaddr, contactId, paperId, action) values ('" . sqlq(@$_SERVER["REMOTE_ADDR"]) . "', " . (int) $who . ", {$ps}, '" . sqlq(substr($text, 0, 4096)) . "')"); }
function save_paper_json($pj) { global $Conf, $Now; assert(!$this->hide_docids); $paperid = null; if (isset($pj->pid) && is_int($pj->pid) && $pj->pid > 0) { $paperid = $pj->pid; } else { if (!isset($pj->pid) && isset($pj->id) && is_int($pj->id) && $pj->id > 0) { $paperid = $pj->id; } else { if (isset($pj->pid) || isset($pj->id)) { $key = isset($pj->pid) ? "pid" : "id"; $this->set_error_html($key, "Format error [{$key}]"); return false; } } } if (get($pj, "error") || get($pj, "error_html")) { $this->set_error_html("error", "Refusing to save paper with error"); return false; } $this->prow = $old_pj = null; $this->paperid = $paperid ?: -1; if ($paperid) { $this->prow = $Conf->paperRow(["paperId" => $paperid, "topics" => true, "options" => true], $this->contact); } if ($this->prow) { $old_pj = $this->paper_json($this->prow, ["forceShow" => true]); } if ($pj && $old_pj && $paperid != $old_pj->pid) { $this->set_error_html("pid", "Saving paper with different ID"); return false; } $this->normalize($pj, $old_pj); if ($old_pj) { $this->normalize($old_pj, null); } if ($this->nerrors) { return false; } $this->check_invariants($pj, $old_pj); // store documents (options already stored) if (isset($pj->submission) && $pj->submission) { $this->upload_document($pj->submission, PaperOption::find_document(DTYPE_SUBMISSION)); } if (isset($pj->final) && $pj->final) { $this->upload_document($pj->final, PaperOption::find_document(DTYPE_FINAL)); } // create contacts foreach (self::contacts_array($pj) as $c) { $c->only_if_contactdb = !get($c, "contact"); $c->disabled = !!$this->disable_users; if (!Contact::create($c, !$this->no_email) && get($c, "contact")) { $this->set_error_html("contacts", "Could not create an account for contact " . Text::user_html($c) . "."); } } // catch errors if ($this->nerrors) { return false; } // update Paper table $q = array(); foreach (array("title", "abstract", "collaborators") as $k) { $v = convert_to_utf8((string) get($pj, $k)); if (!$old_pj || get($pj, $k) !== null && $v !== (string) get($old_pj, $k)) { $q[] = "{$k}='" . sqlq($v) . "'"; } } if (!$old_pj || get($pj, "authors") !== null) { $autext = convert_to_utf8(self::author_information($pj)); $old_autext = self::author_information($old_pj); if ($autext !== $old_autext || !$old_pj) { $q[] = "authorInformation='" . sqlq($autext) . "'"; } } if ($Conf->submission_blindness() == Conf::BLIND_OPTIONAL && (!$old_pj || get($pj, "nonblind") !== null && !$pj->nonblind != !$old_pj->nonblind)) { $q[] = "blind=" . (get($pj, "nonblind") ? 0 : 1); } if (!$old_pj || get($pj, "submission") !== null) { $new_id = get($pj, "submission") ? $pj->submission->docid : 1; $old_id = $old_pj && get($old_pj, "submission") ? $old_pj->submission->docid : 1; if (!$old_pj || $new_id != $old_id) { $q[] = "paperStorageId={$new_id}"; } } if (!$old_pj || get($pj, "final") !== null) { $new_id = get($pj, "final") ? $pj->final->docid : 0; $old_id = $old_pj && get($old_pj, "final") ? $old_pj->final->docid : 0; if (!$old_pj || $new_id != $old_id) { $q[] = "finalPaperStorageId={$new_id}"; } } if (get($pj, "withdrawn") !== null || get($pj, "submitted") !== null || get($pj, "draft") !== null) { if (get($pj, "submitted") !== null) { $submitted = $pj->submitted; } else { if (get($pj, "draft") !== null) { $submitted = !$pj->draft; } else { if ($old_pj) { $submitted = get($old_pj, "submitted_at") > 0; } else { $submitted = false; } } } if (get($pj, "withdrawn")) { if (!$old_pj || !get($old_pj, "withdrawn")) { $q[] = "timeWithdrawn=" . (get($pj, "withdrawn_at") ?: $Now); $q[] = "timeSubmitted=" . ($submitted ? -100 : 0); } else { if (get($old_pj, "submitted_at") > 0 !== $submitted) { $q[] = "timeSubmitted=" . ($submitted ? -100 : 0); } } } else { if ($submitted) { if (!$old_pj || !get($old_pj, "submitted")) { $q[] = "timeSubmitted=" . (get($pj, "submitted_at") ?: $Now); } if ($old_pj && get($old_pj, "withdrawn")) { $q[] = "timeWithdrawn=0"; } } else { if ($old_pj && (get($old_pj, "withdrawn") || get($old_pj, "submitted"))) { $q[] = "timeSubmitted=0"; $q[] = "timeWithdrawn=0"; } } } } if (get($pj, "final_submitted") !== null) { if ($pj->final_submitted) { $time = get($pj, "final_submitted_at") ?: $Now; } else { $time = 0; } if (!$old_pj || get($old_pj, "final_submitted_at") != $time) { $q[] = "timeFinalSubmitted={$time}"; } } if (!empty($q)) { if ($Conf->submission_blindness() == Conf::BLIND_NEVER) { $q[] = "blind=0"; } else { if ($Conf->submission_blindness() != Conf::BLIND_OPTIONAL) { $q[] = "blind=1"; } } $joindoc = $old_joindoc = null; if (get($pj, "final")) { $joindoc = $pj->final; $old_joindoc = $old_pj ? get($old_pj, "final") : null; } else { if (get($pj, "submission")) { $joindoc = $pj->submission; $old_joindoc = $old_pj ? get($old_pj, "submission") : null; } } if ($joindoc && (!$old_joindoc || $old_joindoc->docid != $joindoc->docid) && get($joindoc, "size") && get($joindoc, "timestamp")) { $q[] = "size=" . $joindoc->size; $q[] = "mimetype='" . sqlq($joindoc->mimetype) . "'"; $q[] = "sha1='" . sqlq($joindoc->sha1) . "'"; $q[] = "timestamp=" . $joindoc->timestamp; } else { if (!$joindoc) { $q[] = "size=0,mimetype='',sha1='',timestamp=0"; } } if ($paperid) { $result = Dbl::qe_raw("update Paper set " . join(",", $q) . " where paperId={$paperid}"); if ($result && $result->affected_rows === 0 && edb_nrows(Dbl::qe_raw("select paperId from Paper where paperId={$paperid}")) === 0) { $result = Dbl::qe_raw("insert into Paper set paperId={$paperid}, " . join(",", $q)); } } else { $result = Dbl::qe_raw("insert into Paper set " . join(",", $q)); if (!$result || !($paperid = $pj->pid = $result->insert_id)) { return $this->set_error_html(false, "Could not create paper."); } if (!empty($this->uploaded_documents)) { Dbl::qe_raw("update PaperStorage set paperId={$paperid} where paperStorageId in (" . join(",", $this->uploaded_documents) . ")"); } } // maybe update `papersub` settings $is_submitted = !get($pj, "withdrawn") && get($pj, "submitted"); $was_submitted = $old_pj && !get($old_pj, "withdrawn") && get($old_pj, "submitted"); if ($is_submitted != $was_submitted) { $Conf->update_papersub_setting($is_submitted); } } // update PaperTopics if (get($pj, "topics")) { $topics = self::topics_sql($pj, $paperid); $old_topics = self::topics_sql($old_pj, $paperid); if ($topics !== $old_topics) { $result = Dbl::qe_raw("delete from PaperTopic where paperId={$paperid}"); if ($topics) { $result = Dbl::qe_raw("insert into PaperTopic (topicId,paperId) values {$topics}"); } } } // update PaperOption if (get($pj, "options")) { $options = convert_to_utf8(self::options_sql($pj, $paperid)); $old_options = self::options_sql($old_pj, $paperid); if ($options !== $old_options) { $result = Dbl::qe("delete from PaperOption where paperId={$paperid} and optionId?a", array_keys($pj->parsed_options)); if ($options) { $result = Dbl::qe_raw("insert into PaperOption (paperId,optionId,value,data) values {$options}"); } } } // update PaperConflict $conflict = $this->conflicts_array($pj, $old_pj); $old_conflict = $this->conflicts_array($old_pj, null); if (join(",", array_keys($conflict)) !== join(",", array_keys($old_conflict)) || join(",", array_values($conflict)) !== join(",", array_values($old_conflict))) { $q = array(); foreach ($conflict as $email => $type) { $q[] = "'" . sqlq($email) . "'"; } $ins = array(); if (!empty($q)) { $result = Dbl::qe_raw("select contactId, email from ContactInfo where email in (" . join(",", $q) . ")"); while ($row = edb_row($result)) { $ins[] = "({$paperid},{$row['0']}," . $conflict[strtolower($row[1])] . ")"; } } $result = Dbl::qe_raw("delete from PaperConflict where paperId={$paperid}"); if (!empty($ins)) { $result = Dbl::qe_raw("insert into PaperConflict (paperId,contactId,conflictType) values " . join(",", $ins)); } } return $paperid; }
function _one_quicklink($id, $baseUrl, $urlrest, $listtype, $isprev) { global $Conf; if ($listtype == "u") { $result = $Conf->qx("select email from ContactInfo where email='" . sqlq($id) . "'"); $row = edb_row($result); $paperText = htmlspecialchars($row ? $row[0] : $id); $urlrest = "u=" . urlencode($id) . $urlrest; } else { $paperText = "#{$id}"; $urlrest = "p=" . $id . $urlrest; } return "<a id=\"quicklink_" . ($isprev ? "prev" : "next") . "\" href=\"" . hoturl($baseUrl, $urlrest) . "\" onclick=\"return !Miniajax.isoutstanding('revprevform', make_link_callback(this))\">" . ($isprev ? $Conf->cacheableImage("_.gif", "<-", null, "prev") : "") . $paperText . ($isprev ? "" : $Conf->cacheableImage("_.gif", "->", null, "next")) . "</a>"; }
function query() { global $Conf, $papersel, $checkReviewNeedsSubmit; $columns = array("firstName, lastName, email, password, roles, c.contactId, ((roles&" . Contact::ROLE_PC . ")!=0) as isPC, preferredEmail, extension"); // paper limit $where = $repojoin = array(); if ($this->usertype == "college") { $where[] = "(roles&" . Contact::ROLE_PCLIKE . ")=0 and not extension and not dropped"; } else { if ($this->usertype == "extension") { $where[] = "(roles&" . Contact::ROLE_PCLIKE . ")=0 and extension and not dropped"; } else { if ($this->usertype == "students") { $where[] = "(roles&" . Contact::ROLE_PCLIKE . ")=0 and not dropped"; } else { if ($this->usertype == "pc") { $where[] = "(roles&" . Contact::ROLE_PC . ")!=0"; } else { if (preg_match(',\\Apc:\\S+\\z,', $this->usertype)) { $where[] = "(roles&" . Contact::ROLE_PC . ")!=0"; $where[] = "contactTags like '% " . sqlq(substr($this->usertype, 3)) . " %'"; } } } } } // pset if ($this->pset) { $repojoin[] = "left join ContactLink l on (l.cid=c.contactId and l.type=" . LINK_REPO . " and l.pset=" . $this->pset->id . ")\n\tleft join Repository r on (r.repoid=l.link)\n\tleft join RepositoryGrade rg on (rg.repoid=r.repoid and rg.pset=" . $this->pset->id . " and not rg.placeholder)\n"; $columns[] = "r.repoid repoid, rg.gradehash gradehash"; if ($this->type == "openrepo") { $where[] = "r.open"; } else { if ($this->type == "brokenrepo") { $where[] = "not r.working"; } else { if ($this->type == "workingrepo") { $where[] = "r.working"; } else { if ($this->type == "repo") { $where[] = "r.repoid is not null"; } else { if ($this->type == "norepo") { $where[] = "r.repoid is null"; } else { if ($this->type == "partner") { $repojoin[] = "left join ContactLink pl on (pl.cid=c.contactId and pl.type=" . LINK_PARTNER . " and pl.pset=" . $this->pset->id . ")"; $where[] = "pl.cid is not null"; } else { if ($this->type == "nopartner") { $repojoin[] = "left join ContactLink pl on (pl.cid=c.contactId and pl.type=" . LINK_PARTNER . " and pl.pset=" . $this->pset->id . ")"; $where[] = "pl.cid is null"; } } } } } } } } // build query $where[] = "email not regexp '^anonymous[0-9]*\$'"; return "select " . join(", ", $columns) . " from ContactInfo c\n" . join(" ", $repojoin) . " where " . join(" and ", $where) . " order by email"; }
} } if ($Conf->setting("autoassign_badpairs")) { $Qreq->badpairs = 1; } } else { if (count($_POST) && isset($Qreq->assign) && check_post()) { $x = array(); for ($i = 1; isset($Qreq["bpa{$i}"]); ++$i) { if ($Qreq["bpa{$i}"] && $Qreq["bpb{$i}"] && isset($pcm[$Qreq["bpa{$i}"]]) && isset($pcm[$Qreq["bpb{$i}"]])) { $x[] = $Qreq["bpa{$i}"]; $x[] = $Qreq["bpb{$i}"]; } } if (count($x) || $Conf->setting_data("autoassign_badpairs") || !isset($Qreq->badpairs) != !$Conf->setting("autoassign_badpairs")) { $Conf->q("insert into Settings (name, value, data) values ('autoassign_badpairs', " . (isset($Qreq->badpairs) ? 1 : 0) . ", '" . sqlq(join(" ", $x)) . "') on duplicate key update data=values(data), value=values(value)"); } } } // set $badpairs array $badpairs = array(); if (isset($Qreq->badpairs)) { for ($i = 1; isset($Qreq["bpa{$i}"]); ++$i) { if ($Qreq["bpa{$i}"] && $Qreq["bpb{$i}"]) { if (!isset($badpairs[$Qreq["bpa{$i}"]])) { $badpairs[$Qreq["bpa{$i}"]] = array(); } $badpairs[$Qreq["bpa{$i}"]][$Qreq["bpb{$i}"]] = 1; } } }
function store_database($dbinfo, $doc) { global $Conf, $OK; $N = 400000; $idcol = $dbinfo->id_column; $while = "while storing document in database"; $a = $ks = $vs = array(); foreach ($dbinfo->columns as $k => $v) { if ($k !== $idcol) { $ks[] = "`{$k}`=?"; $vs[] = substr($v, 0, $N); } } if (isset($dbinfo->columns[$idcol])) { $q = "update {$dbinfo->table} set " . join(",", $ks) . " where {$idcol}=?"; $vs[] = $dbinfo->columns[$idcol]; } else { $q = "insert into {$dbinfo->table} set " . join(",", $ks); } if (!($result = Dbl::query_apply($q, $vs))) { set_error_html($doc, $Conf->db_error_html(true, $while)); return; } if (isset($dbinfo->columns[$idcol])) { $doc->{$idcol} = $dbinfo->columns[$idcol]; } else { $doc->{$idcol} = $result->insert_id; if (!$doc->{$idcol}) { set_error_html($doc, $Conf->db_error_html(true, $while)); $OK = false; return; } } for ($pos = $N; true; $pos += $N) { $a = array(); foreach ($dbinfo->columns as $k => $v) { if (strlen($v) > $pos) { $a[] = "`" . $k . "`=concat(`" . $k . "`,'" . sqlq(substr($v, $pos, $N)) . "')"; } } if (!count($a)) { break; } if (!$Conf->q("update {$dbinfo->table} set " . join(",", $a) . " where {$idcol}=" . $doc->{$idcol})) { set_error_html($doc, $Conf->db_error_html(true, $while)); return; } } // check that paper storage succeeded if ($dbinfo->check_contents && (!($result = $Conf->qe("select length({$dbinfo->check_contents}) from {$dbinfo->table} where {$idcol}=" . $doc->{$idcol})) || !($row = edb_row($result)) || $row[0] != strlen(self::content($doc)))) { set_error_html($doc, "Failed to store your document. Usually this is because the file you tried to upload was too big for our system. Please try again."); return; } }
function paperQuery($contact, $options = array()) { // Options: // "paperId" => $pid Only paperId $pid (if array, any of those) // "reviewId" => $rid Only paper reviewed by $rid // "commentId" => $c Only paper where comment is $c // "finalized" Only submitted papers // "unsub" Only unsubmitted papers // "accepted" Only accepted papers // "active" Only nonwithdrawn papers // "author" Only papers authored by $contactId // "myReviewRequests" Only reviews requested by $contactId // "myReviews" All reviews authored by $contactId // "myOutstandingReviews" All unsubmitted reviews auth by $contactId // "myReviewsOpt" myReviews, + include papers not yet reviewed // "allReviews" All reviews (multiple rows per paper) // "allReviewScores" All review scores (multiple rows per paper) // "allComments" All comments (multiple rows per paper) // "reviewerName" Include reviewer names // "commenterName" Include commenter names // "reviewer" => $cid Include reviewerConflictType/reviewerReviewType // "tags" Include paperTags // "tagIndex" => $tag Include tagIndex of named tag // "tagIndex" => tag array -- include tagIndex, tagIndex1, ... // "topics" // "options" // "scores" => array(fields to score) // "assignments" // "order" => $sql $sql is SQL 'order by' clause (or empty) global $Opt; $reviewerQuery = isset($options["myReviews"]) || isset($options["allReviews"]) || isset($options["myReviewRequests"]) || isset($options["myReviewsOpt"]) || isset($options["myOutstandingReviews"]); $allReviewerQuery = isset($options["allReviews"]) || isset($options["allReviewScores"]); $scoresQuery = !$reviewerQuery && isset($options["allReviewScores"]); if (is_object($contact)) { $contactId = $contact->contactId; } else { $contactId = (int) $contact; $contact = null; } if (isset($options["reviewer"]) && is_object($options["reviewer"])) { $reviewerContactId = $options["reviewer"]->contactId; } else { if (isset($options["reviewer"])) { $reviewerContactId = $options["reviewer"]; } else { $reviewerContactId = $contactId; } } if (get($options, "author")) { $myPaperReview = null; } else { if ($allReviewerQuery) { $myPaperReview = "MyPaperReview"; } else { $myPaperReview = "PaperReview"; } } // paper selection $paperset = array(); if (isset($options["paperId"])) { $paperset[] = self::_cvt_numeric_set($options["paperId"]); } if (isset($options["reviewId"])) { if (is_numeric($options["reviewId"])) { $result = Dbl::qe("select paperId from PaperReview where reviewId=" . $options["reviewId"]); $paperset[] = self::_cvt_numeric_set(edb_first_columns($result)); } else { if (preg_match('/^(\\d+)([A-Z][A-Z]?)$/i', $options["reviewId"], $m)) { $result = Dbl::qe("select paperId from PaperReview where paperId={$m['1']} and reviewOrdinal=" . parseReviewOrdinal($m[2])); $paperset[] = self::_cvt_numeric_set(edb_first_columns($result)); } else { $paperset[] = array(); } } } if (isset($options["commentId"])) { $result = Dbl::qe("select paperId from PaperComment where commentId" . sql_in_numeric_set(self::_cvt_numeric_set($options["commentId"]))); $paperset[] = self::_cvt_numeric_set(edb_first_columns($result)); } if (count($paperset) > 1) { $paperset = array(call_user_func_array("array_intersect", $paperset)); } $papersel = ""; if (count($paperset)) { $papersel = "paperId" . sql_in_numeric_set($paperset[0]) . " and "; } // prepare query: basic tables $where = array(); $joins = array("Paper"); $cols = array("Paper.*, PaperConflict.conflictType"); $aujoinwhere = null; if (get($options, "author") && $contact && ($aujoinwhere = $contact->actAuthorSql("PaperConflict", true))) { $where[] = $aujoinwhere; } if (get($options, "author") && !$aujoinwhere) { $joins[] = "join PaperConflict on (PaperConflict.paperId=Paper.paperId and PaperConflict.contactId={$contactId} and PaperConflict.conflictType>=" . CONFLICT_AUTHOR . ")"; } else { $joins[] = "left join PaperConflict on (PaperConflict.paperId=Paper.paperId and PaperConflict.contactId={$contactId})"; } // my review $qr = ""; if ($contact && ($tokens = $contact->review_tokens())) { $qr = " or PaperReview.reviewToken in (" . join(", ", $tokens) . ")"; } if (get($options, "myReviewRequests")) { $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId and PaperReview.requestedBy={$contactId} and PaperReview.reviewType=" . REVIEW_EXTERNAL . ")"; } else { if (get($options, "myReviews")) { $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}))"; } else { if (get($options, "myOutstandingReviews")) { $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}) and PaperReview.reviewNeedsSubmit!=0)"; } else { if (get($options, "myReviewsOpt")) { $joins[] = "left join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}))"; } else { if (get($options, "allReviews") || get($options, "allReviewScores")) { $x = get($options, "reviewLimitSql") ? " and (" . $options["reviewLimitSql"] . ")" : ""; $joins[] = "join PaperReview on (PaperReview.paperId=Paper.paperId{$x})"; } else { if (!get($options, "author")) { $joins[] = "left join PaperReview on (PaperReview.paperId=Paper.paperId and (PaperReview.contactId={$contactId}{$qr}))"; } } } } } } // started reviews if (get($options, "startedReviewCount")) { $joins[] = "left join (select paperId, count(*) count from PaperReview where {$papersel}(reviewSubmitted or reviewNeedsSubmit>0) group by paperId) R_started on (R_started.paperId=Paper.paperId)"; $cols[] = "coalesce(R_started.count,0) startedReviewCount"; } // submitted reviews $j = "select paperId, count(*) count"; $before_ncols = count($cols); if (get($options, "startedReviewCount")) { $cols[] = "coalesce(R_submitted.count,0) reviewCount"; } if (get($options, "scores")) { foreach ($options["scores"] as $fid) { $cols[] = "R_submitted.{$fid}Scores"; if ($myPaperReview) { $cols[] = "{$myPaperReview}.{$fid}"; } $j .= ", group_concat({$fid} order by reviewId) {$fid}Scores"; } } if (get($options, "reviewTypes") || get($options, "reviewIdentities")) { $cols[] = "R_submitted.reviewTypes"; $j .= ", group_concat(reviewType order by reviewId) reviewTypes"; } if (get($options, "reviewIdentities")) { $cols[] = "R_submitted.reviewRequestedBys"; $j .= ", group_concat(requestedBy order by reviewId) reviewRequestedBys"; if ($this->review_blindness() == self::BLIND_OPTIONAL) { $cols[] = "R_submitted.reviewBlinds"; $j .= ", group_concat(reviewBlind order by reviewId) reviewBlinds"; } if ($contact && $contact->review_tokens()) { $cols[] = "R_submitted.reviewTokens"; $j .= ", group_concat(reviewToken order by reviewId) reviewTokens"; } } if (get($options, "reviewRounds")) { $cols[] = "R_submitted.reviewRounds"; $j .= ", group_concat(reviewRound order by reviewId) reviewRounds"; } if (get($options, "reviewWordCounts") && $this->sversion >= 99) { $cols[] = "R_submitted.reviewWordCounts"; $j .= ", group_concat(reviewWordCount order by reviewId) reviewWordCounts"; } if (get($options, "reviewOrdinals")) { $cols[] = "R_submitted.reviewOrdinals"; $j .= ", group_concat(reviewOrdinal order by reviewId) reviewOrdinals"; } if (get($options, "reviewTypes") || get($options, "scores") || get($options, "reviewContactIds") || get($options, "reviewOrdinals") || get($options, "reviewIdentities")) { $cols[] = "R_submitted.reviewContactIds"; $j .= ", group_concat(contactId order by reviewId) reviewContactIds"; } if (count($cols) != $before_ncols) { $joins[] = "left join ({$j} from PaperReview where {$papersel}reviewSubmitted>0 group by paperId) R_submitted on (R_submitted.paperId=Paper.paperId)"; } // assignments if (get($options, "assignments")) { $j = "select paperId, group_concat(contactId order by reviewId) allReviewContactIds, group_concat(reviewType order by reviewId) allReviewTypes, group_concat(reviewRound order by reviewId) allReviewRounds"; $cols[] = "R_all.allReviewContactIds, R_all.allReviewTypes, R_all.allReviewRounds"; $joins[] = "left join ({$j} from PaperReview where {$papersel}true group by paperId) R_all on (R_all.paperId=Paper.paperId)"; } // fields if (get($options, "author")) { $cols[] = "null reviewType, null reviewId, null myReviewType"; } else { // see also papercolumn.php array_push($cols, "PaperReview.reviewType, PaperReview.reviewId", "PaperReview.reviewModified, PaperReview.reviewSubmitted", "PaperReview.reviewNeedsSubmit, PaperReview.reviewOrdinal", "PaperReview.reviewBlind, PaperReview.reviewToken", "PaperReview.contactId as reviewContactId, PaperReview.requestedBy", "max({$myPaperReview}.reviewType) as myReviewType", "max({$myPaperReview}.reviewSubmitted) as myReviewSubmitted", "min({$myPaperReview}.reviewNeedsSubmit) as myReviewNeedsSubmit", "{$myPaperReview}.contactId as myReviewContactId", "PaperReview.reviewRound"); } if ($reviewerQuery || $scoresQuery) { $cols[] = "PaperReview.reviewEditVersion as reviewEditVersion"; $cols[] = ($this->sversion >= 105 ? "PaperReview.reviewFormat" : "null") . " as reviewFormat"; foreach (ReviewForm::all_fields() as $f) { if ($reviewerQuery || $f->has_options) { $cols[] = "PaperReview.{$f->id} as {$f->id}"; } } } if ($myPaperReview == "MyPaperReview") { $joins[] = "left join PaperReview as MyPaperReview on (MyPaperReview.paperId=Paper.paperId and MyPaperReview.contactId={$contactId})"; } if (get($options, "topics")) { $cols[] = "(select group_concat(topicId) from PaperTopic where PaperTopic.paperId=Paper.paperId) topicIds"; } if (get($options, "options") && (isset($this->settingTexts["options"]) || isset($Opt["optionsInclude"])) && PaperOption::count_option_list()) { $cols[] = "(select group_concat(PaperOption.optionId, '#', value) from PaperOption where paperId=Paper.paperId) optionIds"; } else { if (get($options, "options")) { $cols[] = "'' as optionIds"; } } if (get($options, "tags")) { $cols[] = "(select group_concat(' ', tag, '#', tagIndex order by tag separator '') from PaperTag where PaperTag.paperId=Paper.paperId) paperTags"; } if (get($options, "tagIndex") && !is_array($options["tagIndex"])) { $options["tagIndex"] = array($options["tagIndex"]); } if (get($options, "tagIndex")) { foreach ($options["tagIndex"] as $i => $tag) { $cols[] = "(select tagIndex from PaperTag where PaperTag.paperId=Paper.paperId and PaperTag.tag='" . sqlq($tag) . "') tagIndex" . ($i ?: ""); } } if (get($options, "reviewerPreference")) { $joins[] = "left join PaperReviewPreference on (PaperReviewPreference.paperId=Paper.paperId and PaperReviewPreference.contactId={$reviewerContactId})"; $cols[] = "coalesce(PaperReviewPreference.preference, 0) as reviewerPreference"; $cols[] = "PaperReviewPreference.expertise as reviewerExpertise"; } if (get($options, "allReviewerPreference") || get($options, "desirability")) { $subq = "select paperId"; if (get($options, "allReviewerPreference")) { $subq .= ", " . $this->query_all_reviewer_preference() . " as allReviewerPreference"; $cols[] = "APRP.allReviewerPreference"; } if (get($options, "desirability")) { $subq .= ", sum(if(preference<=-100,0,greatest(least(preference,1),-1))) as desirability"; $cols[] = "coalesce(APRP.desirability,0) as desirability"; } $subq .= " from PaperReviewPreference where {$papersel}true group by paperId"; $joins[] = "left join ({$subq}) as APRP on (APRP.paperId=Paper.paperId)"; } if (get($options, "allConflictType")) { $joins[] = "left join (select paperId, group_concat(concat(contactId,' ',conflictType) separator ',') as allConflictType from PaperConflict where {$papersel}conflictType>0 group by paperId) as AllConflict on (AllConflict.paperId=Paper.paperId)"; $cols[] = "AllConflict.allConflictType"; } if (get($options, "reviewer")) { $joins[] = "left join PaperConflict RPC on (RPC.paperId=Paper.paperId and RPC.contactId={$reviewerContactId})"; $joins[] = "left join PaperReview RPR on (RPR.paperId=Paper.paperId and RPR.contactId={$reviewerContactId})"; $cols[] = "RPC.conflictType reviewerConflictType, RPR.reviewType reviewerReviewType"; } if (get($options, "allComments")) { $joins[] = "join PaperComment on (PaperComment.paperId=Paper.paperId)"; $joins[] = "left join PaperConflict as CommentConflict on (CommentConflict.paperId=PaperComment.paperId and CommentConflict.contactId=PaperComment.contactId)"; array_push($cols, "PaperComment.commentId, PaperComment.contactId as commentContactId", "CommentConflict.conflictType as commentConflictType", "PaperComment.timeModified, PaperComment.comment", "PaperComment.replyTo, PaperComment.commentType"); } if (get($options, "reviewerName")) { if ($options["reviewerName"] === "lead" || $options["reviewerName"] === "shepherd") { $joins[] = "left join ContactInfo as ReviewerContactInfo on (ReviewerContactInfo.contactId=Paper." . $options['reviewerName'] . "ContactId)"; } else { if (get($options, "allComments")) { $joins[] = "left join ContactInfo as ReviewerContactInfo on (ReviewerContactInfo.contactId=PaperComment.contactId)"; } else { if (get($options, "reviewerName")) { $joins[] = "left join ContactInfo as ReviewerContactInfo on (ReviewerContactInfo.contactId=PaperReview.contactId)"; } } } array_push($cols, "ReviewerContactInfo.firstName as reviewFirstName", "ReviewerContactInfo.lastName as reviewLastName", "ReviewerContactInfo.email as reviewEmail", "ReviewerContactInfo.lastLogin as reviewLastLogin"); } if (get($options, "foldall")) { $cols[] = "1 as folded"; } // conditions if (count($paperset)) { $where[] = "Paper.paperId" . sql_in_numeric_set($paperset[0]); } if (get($options, "finalized")) { $where[] = "timeSubmitted>0"; } else { if (get($options, "unsub")) { $where[] = "timeSubmitted<=0"; } } if (get($options, "accepted")) { $where[] = "outcome>0"; } if (get($options, "undecided")) { $where[] = "outcome=0"; } if (get($options, "active") || get($options, "myReviews") || get($options, "myReviewRequests")) { $where[] = "timeWithdrawn<=0"; } if (get($options, "myLead")) { $where[] = "leadContactId={$contactId}"; } if (get($options, "unmanaged")) { $where[] = "managerContactId=0"; } $pq = "select " . join(",\n ", $cols) . "\nfrom " . join("\n ", $joins); if (count($where)) { $pq .= "\nwhere " . join("\n and ", $where); } // grouping and ordering if (get($options, "allComments")) { $pq .= "\ngroup by Paper.paperId, PaperComment.commentId"; } else { if ($reviewerQuery || $scoresQuery) { $pq .= "\ngroup by Paper.paperId, PaperReview.reviewId"; } else { $pq .= "\ngroup by Paper.paperId"; } } if (get($options, "order") && $options["order"] != "order by Paper.paperId") { $pq .= "\n" . $options["order"]; } else { $pq .= "\norder by Paper.paperId"; if ($reviewerQuery || $scoresQuery) { $pq .= ", PaperReview.reviewOrdinal"; } if (isset($options["allComments"])) { $pq .= ", PaperComment.commentId"; } } //Conf::msg_debugt($pq); return $pq . "\n"; }
private function _clauseTermSet(&$t, $sqi, &$f) { $tt = $t->type; $thistab = null; // collect columns if ($tt === "ti") { $sqi->add_column("title", "Paper.title"); $this->_clauseTermSetField($t, "title", $sqi, $f); } else { if ($tt === "ab") { $sqi->add_column("abstract", "Paper.abstract"); $this->_clauseTermSetField($t, "abstract", $sqi, $f); } else { if ($tt === "au") { $sqi->add_column("authorInformation", "Paper.authorInformation"); $this->_clauseTermSetField($t, "authorInformation", $sqi, $f); } else { if ($tt === "co") { $sqi->add_column("collaborators", "Paper.collaborators"); $this->_clauseTermSetField($t, "collaborators", $sqi, $f); } else { if ($tt === "au_cid") { $this->_clauseTermSetTable($t, $t->value, null, "AuthorConflict", "PaperConflict", "contactId", " and " . $this->contact->actAuthorSql("%"), $sqi, $f); } else { if ($tt === "re") { $f[] = $this->_clauseTermSetReviews($t, $sqi); } else { if ($tt === "revpref") { $f[] = $this->_clauseTermSetRevpref($t, $sqi); } else { if ($tt === "conflict") { $this->_clauseTermSetTable($t, $t->value->contact_set(), $t->value->countexpr(), "Conflict", "PaperConflict", "contactId", "", $sqi, $f); } else { if ($tt === "cmt") { if ($t->value->has_contacts()) { $thistab = "Comments_" . count($sqi->tables); } else { $rtype = $t->flags & (self::F_ALLOWCOMMENT | self::F_ALLOWRESPONSE | self::F_AUTHORCOMMENT | self::F_ALLOWDRAFT | self::F_REQUIREDRAFT); $thistab = "Numcomments_" . $rtype; if (isset($t->commentRound)) { $thistab .= "_" . $t->commentRound; } } $f[] = $this->_clauseTermSetComments($thistab, $t->value->contact_match_sql("contactId"), $t, $sqi); } else { if ($tt === "cmttag") { $thistab = "TaggedComments_" . count($sqi->tables); if ($t->value->tag === "any") { $match = "is not null"; } else { $match = "like " . Dbl::utf8ci("'% " . sqlq($t->value->tag) . " %'"); } $f[] = $this->_clauseTermSetComments($thistab, "commentTags {$match}", $t, $sqi); } else { if ($tt === "pn") { $q = array(); if (count($t->value[0])) { $q[] = "Paper.paperId in (" . join(",", $t->value[0]) . ")"; } if (count($t->value[1])) { $q[] = "Paper.paperId not in (" . join(",", $t->value[1]) . ")"; } if (!count($q)) { $q[] = "false"; } $f[] = "(" . join(" and ", $q) . ")"; } else { if ($tt === "pf") { $q = array(); $this->_clauseTermSetFlags($t, $sqi, $q); for ($i = 0; $i < count($t->value); $i += 2) { if (is_array($t->value[$i + 1])) { $q[] = "Paper." . $t->value[$i] . " in (" . join(",", $t->value[$i + 1]) . ")"; } else { $q[] = "Paper." . $t->value[$i] . $t->value[$i + 1]; } } $f[] = "(" . join(" and ", $q) . ")"; for ($i = 0; $i < count($t->value); $i += 2) { $sqi->add_column($t->value[$i], "Paper." . $t->value[$i]); } } else { if ($tt === "tag") { $extra = ""; for ($i = 1; $i < count($t->value); ++$i) { $extra .= " and %.tagIndex" . $t->value[$i]; } $this->_clauseTermSetTable($t, $t->value[0], null, "Tag", "PaperTag", "tag", $extra, $sqi, $f); } else { if ($tt === "topic") { $this->_clauseTermSetTable($t, $t->value, null, "Topic", "PaperTopic", "topicId", "", $sqi, $f); } else { if ($tt === "option") { // expanded from _clauseTermSetTable $q = array(); $optionNum = count($sqi->tables); $this->_clauseTermSetFlags($t, $sqi, $q); $thistab = "Option_" . $optionNum; $t->link = $thistab . "_x"; if ($t->value->option->type == 'text') { $sqi->add_table($thistab, array("left join", "(select paperId, data d from PaperOption where optionId=" . $t->value->option->id . " group by paperId)")); $sqi->add_column($thistab . "_x", "LOWER(CONVERT(coalesce({$thistab}.d,0) USING utf8))" . $t->value->table_matcher()); $q[] = $sqi->columns[$t->link]; } else { $sqi->add_table($thistab, array("left join", "(select paperId, max(value) v from PaperOption where optionId=" . $t->value->option->id . " group by paperId)")); $sqi->add_column($thistab . "_x", "coalesce({$thistab}.v,0)" . $t->value->table_matcher()); $q[] = $sqi->columns[$t->link]; } $f[] = "(" . join(" and ", $q) . ")"; } else { if ($tt === "formula") { $q = array("true"); $this->_clauseTermSetFlags($t, $sqi, $q); $t->value->add_query_options($this->_query_options, $this->contact); if (!$t->link) { $t->link = $t->value->compile_function($this->contact); } $f[] = "(" . join(" and ", $q) . ")"; } else { if ($tt === "not") { $ff = array(); $sqi->negated = !$sqi->negated; $this->_clauseTermSet($t->value[0], $sqi, $ff); $sqi->negated = !$sqi->negated; if (!count($ff)) { $ff[] = "true"; } $f[] = "not (" . join(" or ", $ff) . ")"; } else { if ($tt === "and" || $tt === "and2") { $ff = array(); foreach ($t->value as $subt) { $this->_clauseTermSet($subt, $sqi, $ff); } if (!count($ff)) { $ff[] = "false"; } $f[] = "(" . join(" and ", $ff) . ")"; } else { if ($tt === "or" || $tt === "then") { $ff = array(); foreach ($t->value as $subt) { $this->_clauseTermSet($subt, $sqi, $ff); } if (!count($ff)) { $ff[] = "false"; } $f[] = "(" . join(" or ", $ff) . ")"; } else { if ($tt === "f") { $f[] = "false"; } else { if ($tt === "t") { $f[] = "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; }
public function save($sv, $si) { global $Conf; if ($si->name == "tag_vote" && $sv->has_savedv("tag_vote")) { // check allotments $pcm = pcMembers(); foreach (preg_split('/\\s+/', $sv->savedv("tag_vote")) as $t) { if ($t === "") { continue; } $base = substr($t, 0, strpos($t, "#")); $allotment = substr($t, strlen($base) + 1); $result = Dbl::q("select paperId, tag, tagIndex from PaperTag where tag like '%~" . sqlq_for_like($base) . "'"); $pvals = array(); $cvals = array(); $negative = false; while ($row = edb_row($result)) { $who = substr($row[1], 0, strpos($row[1], "~")); if ($row[2] < 0) { $sv->set_error(null, "Removed " . Text::user_html($pcm[$who]) . "’s negative “{$base}” vote for paper #{$row['0']}."); $negative = true; } else { $pvals[$row[0]] = defval($pvals, $row[0], 0) + $row[2]; $cvals[$who] = defval($cvals, $who, 0) + $row[2]; } } foreach ($cvals as $who => $what) { if ($what > $allotment) { $sv->set_error("tag_vote", Text::user_html($pcm[$who]) . " already has more than {$allotment} votes for tag “{$base}”."); } } $q = $negative ? " or (tag like '%~" . sqlq_for_like($base) . "' and tagIndex<0)" : ""; $Conf->qe("delete from PaperTag where tag='" . sqlq($base) . "'{$q}"); $q = array(); foreach ($pvals as $pid => $what) { $q[] = "({$pid}, '" . sqlq($base) . "', {$what})"; } if (count($q) > 0) { $Conf->qe("insert into PaperTag values " . join(", ", $q)); } } } if ($si->name == "tag_approval" && $sv->has_savedv("tag_approval")) { $pcm = pcMembers(); foreach (preg_split('/\\s+/', $sv->savedv("tag_approval")) as $t) { if ($t === "") { continue; } $result = $Conf->q("select paperId, tag, tagIndex from PaperTag where tag like '%~" . sqlq_for_like($t) . "'"); $pvals = array(); $negative = false; while ($row = edb_row($result)) { $who = substr($row[1], 0, strpos($row[1], "~")); if ($row[2] < 0) { $sv->set_error(null, "Removed " . Text::user_html($pcm[$who]) . "’s negative “{$t}” approval vote for paper #{$row['0']}."); $negative = true; } else { $pvals[$row[0]] = defval($pvals, $row[0], 0) + 1; } } $q = $negative ? " or (tag like '%~" . sqlq_for_like($t) . "' and tagIndex<0)" : ""; $Conf->qe("delete from PaperTag where tag='" . sqlq($t) . "'{$q}"); $q = array(); foreach ($pvals as $pid => $what) { $q[] = "({$pid}, '" . sqlq($t) . "', {$what})"; } if (count($q) > 0) { $Conf->qe("insert into PaperTag values " . join(", ", $q)); } } } TagInfo::invalidate_defined_tags(); }
function crpmerge_database($old_user, $new_user) { global $Conf, $MergeError; // Now, scan through all the tables that possibly // specify a contactID and change it from their 2nd // contactID to their first contactId $oldid = $old_user->contactId; $newid = $new_user->contactId; $Conf->q("lock tables Paper write, ContactInfo write, PaperConflict write, ActionLog write, TopicInterest write, PaperComment write, PaperReview write, PaperReview as B write, PaperReviewPreference write, PaperReviewRefused write, ReviewRequest write, PaperWatch write, ReviewRating write"); crpmergeone("Paper", "leadContactId", $oldid, $newid); crpmergeone("Paper", "shepherdContactId", $oldid, $newid); crpmergeone("Paper", "managerContactId", $oldid, $newid); // paper authorship $result = $Conf->qe("select paperId, authorInformation from Paper where authorInformation like " . Dbl::utf8ci("'%\t" . sqlq_for_like($old_user->email) . "\t%'")); $qs = array(); while ($row = PaperInfo::fetch($result, null)) { foreach ($row->author_list() as $au) { if (strcasecmp($au->email, $old_user->email) == 0) { $au->email = $new_user->email; } } $qs[] = "update Paper set authorInformation='" . sqlq($row->parse_author_list()) . "' where paperId={$row->paperId}"; } foreach ($qs as $q) { $Conf->qe($q); } // ensure uniqueness in PaperConflict $result = $Conf->qe("select paperId, conflictType from PaperConflict where contactId={$oldid}"); $values = ""; while ($row = edb_row($result)) { $values .= ", ({$row['0']}, {$newid}, {$row['1']})"; } if ($values) { $Conf->qe("insert into PaperConflict (paperId, contactId, conflictType) values " . substr($values, 2) . " on duplicate key update conflictType=greatest(conflictType, values(conflictType))"); } $Conf->qe("delete from PaperConflict where contactId={$oldid}"); if (($old_user->roles | $new_user->roles) != $new_user->roles) { $new_user->roles |= $old_user->roles; $Conf->qe("update ContactInfo set roles={$new_user->roles} where contactId={$newid}"); } crpmergeone("ActionLog", "contactId", $oldid, $newid); crpmergeoneignore("TopicInterest", "contactId", $oldid, $newid); crpmergeone("PaperComment", "contactId", $oldid, $newid); // archive duplicate reviews crpmergeoneignore("PaperReview", "contactId", $oldid, $newid); crpmergeone("PaperReview", "requestedBy", $oldid, $newid); crpmergeoneignore("PaperReviewPreference", "contactId", $oldid, $newid); crpmergeone("PaperReviewRefused", "contactId", $oldid, $newid); crpmergeone("PaperReviewRefused", "requestedBy", $oldid, $newid); crpmergeone("ReviewRequest", "requestedBy", $oldid, $newid); crpmergeoneignore("PaperWatch", "contactId", $oldid, $newid); crpmergeoneignore("ReviewRating", "contactId", $oldid, $newid); // Remove the old contact record if ($MergeError == "") { if (!$Conf->q("delete from ContactInfo where contactId={$oldid}")) { $MergeError .= $Conf->db_error_html(true); } } $Conf->qe("unlock tables"); // Update PC settings if we need to if ($old_user->isPC) { $Conf->invalidateCaches(array("pc" => 1)); } }
private function run() { global $Conf, $Opt, $Me, $Error, $subjectPrefix, $mailer_options; $subject = trim(defval($_REQUEST, "subject", "")); if (substr($subject, 0, strlen($subjectPrefix)) != $subjectPrefix) { $subject = $subjectPrefix . $subject; } $emailBody = $_REQUEST["emailBody"]; $template = array("subject" => $subject, "body" => $emailBody); $rest = array("cc" => $_REQUEST["cc"], "reply-to" => $_REQUEST["replyto"], "no_error_quit" => true); $rest = array_merge($rest, $mailer_options); // test whether this mail is paper-sensitive $mailer = new HotCRPMailer($Me, null, $rest); $prep = $mailer->make_preparation($template, $rest); $paper_sensitive = preg_match('/%[A-Z0-9]+[(%]/', $prep->subject . $prep->body); $q = $this->recip->query($paper_sensitive); if (!$q) { return Conf::msg_error("Bad recipients value"); } $result = $Conf->qe($q); if (!$result) { return; } $recipients = defval($_REQUEST, "recipients", ""); if ($this->sending) { $q = "recipients='" . sqlq($recipients) . "', cc='" . sqlq($_REQUEST["cc"]) . "', replyto='" . sqlq($_REQUEST["replyto"]) . "', subject='" . sqlq($_REQUEST["subject"]) . "', emailBody='" . sqlq($_REQUEST["emailBody"]) . "'"; if ($Conf->sversion >= 79) { $q .= ", q='" . sqlq($_REQUEST["q"]) . "', t='" . sqlq($_REQUEST["t"]) . "'"; } if ($log_result = Dbl::query_raw("insert into MailLog set {$q}")) { $this->mailid_text = " #" . $log_result->insert_id; } $Me->log_activity("Sending mail{$this->mailid_text} \"{$subject}\""); } else { $rest["no_send"] = true; } $mailer = new HotCRPMailer(); $mailer->combination_type = $this->recip->combination_type($paper_sensitive); $fake_prep = new HotCRPMailPreparation(); $fake_prep->fake = true; $last_prep = $fake_prep; $nrows_done = 0; $nrows_left = edb_nrows($result); $nwarnings = 0; $preperrors = array(); $revinform = $recipients == "newpcrev" ? array() : null; while ($row = PaperInfo::fetch($result, $Me)) { ++$nrows_done; $contact = new Contact($row); $rest["newrev_since"] = $this->recip->newrev_since; $mailer->reset($contact, $row, $rest); $prep = $mailer->make_preparation($template, $rest); if ($prep->errors) { foreach ($prep->errors as $lcfield => $hline) { $reqfield = $lcfield == "reply-to" ? "replyto" : $lcfield; $Error[$reqfield] = true; $emsg = Mailer::$email_fields[$lcfield] . " destination isn’t a valid email list: <blockquote><tt>" . htmlspecialchars($hline) . "</tt></blockquote> Make sure email address are separated by commas; put names in \"quotes\" and email addresses in <angle brackets>."; if (!isset($preperrors[$emsg])) { Conf::msg_error($emsg); } $preperrors[$emsg] = true; } } else { if ($this->process_prep($prep, $last_prep, $row)) { if ((!$Me->privChair || @$Opt["chairHidePasswords"]) && !@$last_prep->sensitive) { $srest = array_merge($rest, array("sensitivity" => "display")); $mailer->reset($contact, $row, $srest); $last_prep->sensitive = $mailer->make_preparation($template, $srest); } } } if ($nwarnings != $mailer->nwarnings() || $nrows_done % 5 == 0) { $this->echo_mailinfo($nrows_done, $nrows_left); } if ($nwarnings != $mailer->nwarnings()) { $this->echo_prologue(); $nwarnings = $mailer->nwarnings(); echo "<div id='foldmailwarn{$nwarnings}' class='hidden'><div class='warning'>", join("<br />", $mailer->warnings()), "</div></div>"; $Conf->echoScript("\$\$('mailwarnings').innerHTML = \$\$('foldmailwarn{$nwarnings}').innerHTML;"); } if ($this->sending && $revinform !== null) { $revinform[] = "(paperId={$row->paperId} and contactId={$row->contactId})"; } } $this->process_prep($fake_prep, $last_prep, (object) array("paperId" => -1)); $this->echo_mailinfo($nrows_done, $nrows_left); if (!$this->started && !count($preperrors)) { return Conf::msg_error("No users match “" . $this->recip->unparse() . "” for that search."); } else { if (!$this->started) { return false; } else { if (!$this->sending) { $this->echo_actions(); } } } if ($revinform) { $Conf->qe("update PaperReview set timeRequestNotified=" . time() . " where " . join(" or ", $revinform)); } echo "</div></form>"; $Conf->echoScript("fold('mail', null);"); $Conf->footer(); exit; }
$numreviews = Dbl::fetch_ivalue("select count(*) from PaperReview where paperId={$prow->paperId} and reviewNeedsSubmit!=0"); $Conf->update_papersub_setting(false); loadRows(); // email contact authors themselves if (!$Me->privChair || defval($_REQUEST, "doemail") > 0) { HotCRPMailer::send_contacts($prow->conflictType >= CONFLICT_AUTHOR ? "@authorwithdraw" : "@adminwithdraw", $prow, array("reason" => $reason, "infoNames" => 1)); } // email reviewers if ($numreviews > 0 && $Conf->time_review_open() || $prow->num_reviews_assigned() > 0) { HotCRPMailer::send_reviewers("@withdrawreviewer", $prow, array("reason" => $reason)); } // remove voting tags so people don't have phantom votes if (TagInfo::has_vote()) { $q = array(); foreach (TagInfo::vote_tags() as $t => $v) { $q[] = "tag='" . sqlq($t) . "' or tag like '%~" . sqlq_for_like($t) . "'"; } Dbl::qe_raw("delete from PaperTag where paperId={$prow->paperId} and (" . join(" or ", $q) . ")"); } $Me->log_activity("Withdrew", $prow->paperId); redirectSelf(); } else { Conf::msg_error(whyNotText($whyNot, "withdraw")); } } if (isset($_REQUEST["revive"]) && !$newPaper && check_post()) { if (!($whyNot = $Me->perm_revive_paper($prow))) { Dbl::qe("update Paper set timeWithdrawn=0, timeSubmitted=if(timeSubmitted=-100,{$Now},0), withdrawReason=null where paperId={$prow->paperId}"); $Conf->update_papersub_setting(true); loadRows(); $Me->log_activity("Revived", $prow->paperId);
function createAnonymousReview() { global $Conf, $Me, $Now, $prow, $rrows; Dbl::qe_raw("lock tables PaperReview write, PaperReviewRefused write, ContactInfo write, PaperConflict read, ActionLog write"); // find an unassigned anonymous review contact $contactemail = unassignedAnonymousContact(); $result = Dbl::qe_raw("select contactId from ContactInfo where email='" . sqlq($contactemail) . "'"); if (edb_nrows($result) == 1) { $row = edb_row($result); $reqId = $row[0]; } else { $result = Dbl::qe("insert into ContactInfo set firstName='Jane Q.', lastName='Public', unaccentedName='Jane Q. Public', email=?, affiliation='Unaffiliated', password='', disabled=1, creationTime={$Now}", $contactemail); if (!$result) { return $result; } $reqId = $result->insert_id; } // store the review request $reviewId = $Me->assign_review($prow->paperId, $reqId, REVIEW_EXTERNAL, array("mark_notify" => true, "token" => true)); if ($reviewId) { $result = Dbl::ql("select reviewToken from PaperReview where reviewId={$reviewId}"); $row = edb_row($result); $Conf->confirmMsg("Created a new anonymous review for paper #{$prow->paperId}. The review token is " . encode_token((int) $row[0]) . "."); } Dbl::qx_raw("unlock tables"); $Conf->update_rev_tokens_setting(true); return true; }
public function check_capability($capabilityText) { if ($capabilityText[0] != "1") { return false; } $value = base64_decode(str_replace(array("-", "_"), array("+", "/"), substr($capabilityText, 1))); if (strlen($value) >= 16 && ($result = $this->q("select * from CapabilityMap where capabilityValue='" . sqlq($value) . "'")) && ($row = edb_orow($result)) && ($row->timeExpires == 0 || $row->timeExpires >= time())) { $result = $this->q("select * from Capability where capabilityId=" . $row->capabilityId); if ($row = edb_orow($result)) { $row->capabilityValue = $value; return $row; } } return false; }