function __construct($source_tag, $dest_tag, $papersel, $strict, $header_title = null, $header_id = null)
 {
     global $Conf;
     $this->dest_tag = $dest_tag;
     $this->ordertype = $strict ? "aos" : "ao";
     $this->papersel = $papersel;
     $this->userrank = array();
     $this->info_printed = false;
     $this->header_title = $header_title;
     $this->header_id = $header_id;
     $this->starttime = time();
     // generate random order for paper comparisons
     if (count($papersel)) {
         $range = range(0, count($papersel) - 1);
         shuffle($range);
         $this->papershuffle = array_combine($papersel, $range);
     } else {
         $this->papershuffle = array();
     }
     // load current ranks: $userrank maps user => [rank, paper]
     $result = $Conf->qe("select paperId, tag, tagIndex from PaperTag where tag like '%~" . sqlq_for_like($source_tag) . "' and paperId in (" . join(",", $papersel) . ")");
     $len = strlen($source_tag) + 1;
     while ($row = edb_row($result)) {
         $l = (int) substr($row[1], 0, strlen($row[1]) - $len);
         $this->userrank[$l][] = array((int) $row[2], (int) $row[0]);
     }
     // sort $userrank[$user] by descending rank order
     foreach ($this->userrank as $user => &$ranks) {
         usort($ranks, array($this, "_comparUserrank"));
     }
     $this->rank = array();
     $this->currank = 0;
 }
Example #2
0
function _update_schema_haslinenotes($conf)
{
    $conf->ql("lock tables CommitNotes write");
    $hashes = array(array(), array(), array(), array());
    $result = $conf->ql("select hash, notes from CommitNotes");
    while ($row = edb_row($result)) {
        $x = PsetView::notes_haslinenotes(json_decode($row[1]));
        $hashes[$x][] = $row[0];
    }
    foreach ($hashes as $x => $h) {
        if (count($h)) {
            $conf->ql("update CommitNotes set haslinenotes={$x} where hash in ('" . join("','", $h) . "')");
        }
    }
    $conf->ql("unlock tables");
    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 render($sv)
 {
     global $Conf, $Opt;
     echo "<h3 class=\"settings\">Abstract and PDF</h3>\n";
     echo Ht::select("sub_noabstract", [0 => "Abstract required", 2 => "Abstract optional", 1 => "No abstract"], opt_yes_no_optional("noAbstract"));
     echo " <span class=\"barsep\">·</span> ", Ht::select("sub_nopapers", array(0 => "PDF upload required", 2 => "PDF upload optional", 1 => "No PDF"), opt_yes_no_optional("noPapers"));
     if (is_executable("src/banal")) {
         echo "<div class='g'></div>", Ht::hidden("has_sub_banal", 1), "<table id='foldbanal' class='", $sv->curv("sub_banal") ? "foldo" : "foldc", "'>";
         $sv->echo_checkbox_row("sub_banal", "PDF format checker<span class='fx'>:</span>", "void fold('banal',!this.checked)");
         echo '<tr class="fx"><td></td><td class="top"><table class="secondary-settings"><tbody>';
         $bsetting = explode(";", preg_replace("/>.*/", "", $Conf->setting_data("sub_banal", "")));
         foreach (["papersize", "pagelimit", "columns", "textblock", "bodyfontsize", "bodyleading"] as $i => $name) {
             $val = get($bsetting, $i, "");
             $sv->set_oldv("sub_banal_{$name}", $val == "" ? "N/A" : $val);
         }
         $sv->echo_entry_row("sub_banal_papersize", "Paper size", "Examples: “letter”, “A4”, “8.5in&nbsp;x&nbsp;14in”,<br />“letter OR A4”");
         $sv->echo_entry_row("sub_banal_pagelimit", "Page limit");
         $sv->echo_entry_row("sub_banal_textblock", "Text block", "Examples: “6.5in&nbsp;x&nbsp;9in”, “1in&nbsp;margins”");
         echo '</tbody></table></td>', '<td><span class="sep"></span></td>', '<td class="top"><table class="secondary-settings"><tbody>';
         $sv->echo_entry_row("sub_banal_bodyfontsize", "Minimum body font size", null, "&nbsp;pt");
         $sv->echo_entry_row("sub_banal_bodyleading", "Minimum leading", null, "&nbsp;pt");
         $sv->echo_entry_row("sub_banal_columns", "Columns");
         echo "</tbody></table></td></tr></table>";
     }
     echo "<h3 class=\"settings\">Conflicts &amp; collaborators</h3>\n", "<table id=\"foldpcconf\" class=\"fold", $sv->curv("sub_pcconf") ? "o" : "c", "\">\n";
     $sv->echo_checkbox_row("sub_pcconf", "Collect authors’ PC conflicts", "void fold('pcconf',!this.checked)");
     echo "<tr class='fx'><td></td><td>";
     $conf = array();
     foreach (Conflict::$type_descriptions as $n => $d) {
         if ($n) {
             $conf[] = "“{$d}”";
         }
     }
     $sv->echo_checkbox("sub_pcconfsel", "Require conflict descriptions (" . commajoin($conf, "or") . ")");
     echo "</td></tr>\n";
     $sv->echo_checkbox_row("sub_collab", "Collect authors’ other collaborators as text");
     echo "</table>\n";
     echo "<h3 class=\"settings\">Submission options</h3>\n";
     echo "Options are selected by authors at submission time.  Examples have included “PC-authored paper,” “Consider this paper for a Best Student Paper award,” and “Allow the shadow PC to see this paper.”  The “option name” should be brief (“PC paper,” “Best Student Paper,” “Shadow PC”).  The optional description can explain further and may use XHTML.  ";
     echo "Add options one at a time.\n";
     echo "<div class='g'></div>\n", Ht::hidden("has_options", 1);
     $sep = "";
     $all_options = array_merge(PaperOption::nonfixed_option_list());
     // get our own iterator
     foreach ($all_options as $o) {
         echo $sep;
         $this->render_option($sv, $o);
         $sep = "\n<div style=\"margin-top:3em\"></div>\n";
     }
     echo $sep;
     $this->render_option($sv, null);
     // Topics
     // load topic interests
     $qinterest = $Conf->query_topic_interest();
     $result = $Conf->q("select topicId, if({$qinterest}>0,1,0), count(*) from TopicInterest where {$qinterest}!=0 group by topicId, {$qinterest}>0");
     $interests = array();
     $ninterests = 0;
     while ($row = edb_row($result)) {
         if (!isset($interests[$row[0]])) {
             $interests[$row[0]] = array();
         }
         $interests[$row[0]][$row[1]] = $row[2];
         $ninterests += $row[2] ? 1 : 0;
     }
     echo "<h3 class=\"settings g\">Topics</h3>\n";
     echo "Enter topics one per line.  Authors select the topics that apply to their papers; PC members use this information to find papers they'll want to review.  To delete a topic, delete its name.\n";
     echo "<div class='g'></div>", Ht::hidden("has_topics", 1), "<table id='newtoptable' class='", $ninterests ? "foldo" : "foldc", "'>";
     echo "<tr><th colspan='2'></th><th class='fx'><small>Low</small></th><th class='fx'><small>High</small></th></tr>";
     $td1 = '<td class="lcaption">Current</td>';
     foreach ($Conf->topic_map() as $tid => $tname) {
         if ($sv->use_req() && isset($sv->req["top{$tid}"])) {
             $tname = $sv->req["top{$tid}"];
         }
         echo '<tr>', $td1, '<td class="lentry">', Ht::entry("top{$tid}", $tname, array("size" => 40, "style" => "width:20em")), '</td>';
         $tinterests = defval($interests, $tid, array());
         echo '<td class="fx rpentry">', get($tinterests, 0) ? '<span class="topic-2">' . $tinterests[0] . "</span>" : "", "</td>", '<td class="fx rpentry">', get($tinterests, 1) ? '<span class="topic2">' . $tinterests[1] . "</span>" : "", "</td>";
         if ($td1 !== "<td></td>") {
             // example search
             echo "<td class='llentry' style='vertical-align:top' rowspan='40'><div class='f-i'>", "<div class='f-c'>Example search</div>";
             $oabbrev = strtolower($tname);
             if (strstr($oabbrev, " ") !== false) {
                 $oabbrev = "\"{$oabbrev}\"";
             }
             echo "“<a href=\"", hoturl("search", "q=topic:" . urlencode($oabbrev)), "\">", "topic:", htmlspecialchars($oabbrev), "</a>”", "<div class='hint'>Topic abbreviations are also allowed.</div>";
             if ($ninterests) {
                 echo "<a class='hint fn' href=\"#\" onclick=\"return fold('newtoptable')\">Show PC interest counts</a>", "<a class='hint fx' href=\"#\" onclick=\"return fold('newtoptable')\">Hide PC interest counts</a>";
             }
             echo "</div></td>";
         }
         echo "</tr>\n";
         $td1 = "<td></td>";
     }
     echo '<tr><td class="lcaption top">New<br><span class="hint">Enter one topic per line.</span></td><td class="lentry top">', Ht::textarea("topnew", $sv->use_req() ? get($sv->req, "topnew") : "", array("cols" => 40, "rows" => 2, "style" => "width:20em")), '</td></tr></table>';
 }
 private function load_topics()
 {
     $result = Dbl::qe_raw("select group_concat(topicId) from PaperTopic where paperId={$this->paperId}");
     $row = edb_row($result);
     $this->topicIds = $row ? $row[0] : "";
     Dbl::free($result);
 }
function updateSchema($Conf)
{
    global $Opt, $OK;
    // avoid error message abut timezone, set to $Opt
    // (which might be overridden by database values later)
    if (function_exists("date_default_timezone_set") && isset($Opt["timezone"]) && $Opt["timezone"]) {
        date_default_timezone_set($Opt["timezone"]);
    }
    while (($result = Dbl::ql("insert into Settings set name='__schema_lock', value=1 on duplicate key update value=1")) && $result->affected_rows == 0) {
        time_nanosleep(0, 200000000);
    }
    $Conf->update_schema_version(null);
    error_log($Opt["dbName"] . ": updating schema from version " . $Conf->sversion);
    if ($Conf->sversion == 6 && Dbl::ql("alter table ReviewRequest add `reason` text")) {
        $Conf->update_schema_version(7);
    }
    if ($Conf->sversion == 7 && Dbl::ql("alter table PaperReview add `textField7` mediumtext NOT NULL") && Dbl::ql("alter table PaperReview add `textField8` mediumtext NOT NULL") && Dbl::ql("insert into ReviewFormField set fieldName='textField7', shortName='Additional text field'") && Dbl::ql("insert into ReviewFormField set fieldName='textField8', shortName='Additional text field'")) {
        $Conf->update_schema_version(8);
    }
    if ($Conf->sversion == 8 && Dbl::ql("alter table ReviewFormField add `levelChar` tinyint(1) NOT NULL default '0'") && Dbl::ql("alter table PaperReviewArchive add `textField7` mediumtext NOT NULL") && Dbl::ql("alter table PaperReviewArchive add `textField8` mediumtext NOT NULL")) {
        $Conf->update_schema_version(9);
    }
    if ($Conf->sversion == 9 && Dbl::ql("alter table Paper add `sha1` varbinary(20) NOT NULL default ''")) {
        $Conf->update_schema_version(10);
    }
    if ($Conf->sversion == 10 && Dbl::ql("alter table PaperReview add `reviewRound` tinyint(1) NOT NULL default '0'") && Dbl::ql("alter table PaperReviewArchive add `reviewRound` tinyint(1) NOT NULL default '0'") && Dbl::ql("alter table PaperReview add key `reviewRound` (`reviewRound`)") && $Conf->update_schema_version(11)) {
        if (count($Conf->round_list()) > 1) {
            // update review rounds (XXX locking)
            $result = Dbl::ql("select paperId, tag from PaperTag where tag like '%~%'");
            $rrs = array();
            while ($row = edb_row($result)) {
                list($contact, $round) = explode("~", $row[1]);
                if ($round = array_search($round, $Conf->round_list())) {
                    if (!isset($rrs[$round])) {
                        $rrs[$round] = array();
                    }
                    $rrs[$round][] = "(contactId={$contact} and paperId={$row['0']})";
                }
            }
            foreach ($rrs as $round => $pairs) {
                $q = "update PaperReview set reviewRound={$round} where " . join(" or ", $pairs);
                Dbl::ql($q);
            }
            $x = trim(preg_replace('/(\\S+)\\s*/', "tag like '%~\$1' or ", $Conf->setting_data("tag_rounds")));
            Dbl::ql("delete from PaperTag where " . substr($x, 0, strlen($x) - 3));
        }
    }
    if ($Conf->sversion == 11 && Dbl::ql("create table `ReviewRating` (\n  `reviewId` int(11) NOT NULL,\n  `contactId` int(11) NOT NULL,\n  `rating` tinyint(1) NOT NULL default '0',\n  UNIQUE KEY `reviewContact` (`reviewId`,`contactId`),\n  UNIQUE KEY `reviewContactRating` (`reviewId`,`contactId`,`rating`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8")) {
        $Conf->update_schema_version(12);
    }
    if ($Conf->sversion == 12 && Dbl::ql("alter table PaperReview add `reviewToken` int(11) NOT NULL default '0'")) {
        $Conf->update_schema_version(13);
    }
    if ($Conf->sversion == 13 && Dbl::ql("alter table OptionType add `optionValues` text NOT NULL default ''")) {
        $Conf->update_schema_version(14);
    }
    if ($Conf->sversion == 14 && Dbl::ql("insert into Settings (name, value) select 'rev_tokens', count(reviewId) from PaperReview where reviewToken!=0 on duplicate key update value=values(value)")) {
        $Conf->update_schema_version(15);
    }
    if ($Conf->sversion == 15) {
        // It's OK if this fails!  Update 11 added reviewRound to
        // PaperReviewArchive (so old databases have the column), but I forgot
        // to upgrade schema.sql (so new databases lack the column).
        Dbl::ql("alter table PaperReviewArchive add `reviewRound` tinyint(1) NOT NULL default '0'");
        $OK = true;
        $Conf->update_schema_version(16);
    }
    if ($Conf->sversion == 16 && Dbl::ql("alter table PaperReview add `reviewEditVersion` int(1) NOT NULL default '0'")) {
        $Conf->update_schema_version(17);
    }
    if ($Conf->sversion == 17 && Dbl::ql("alter table PaperReviewPreference add key `paperId` (`paperId`)") && Dbl::ql("create table PaperRank (\n  `paperId` int(11) NOT NULL,\n  `contactId` int(11) NOT NULL,\n  `rank` int(11) NOT NULL,\n  UNIQUE KEY `contactPaper` (`contactId`,`paperId`),\n  KEY `paperId` (`paperId`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8;")) {
        $Conf->update_schema_version(18);
    }
    if ($Conf->sversion == 18 && Dbl::ql("alter table PaperComment add `replyTo` int(11) NOT NULL")) {
        $Conf->update_schema_version(19);
    }
    if ($Conf->sversion == 19 && Dbl::ql("drop table PaperRank")) {
        $Conf->update_schema_version(20);
    }
    if ($Conf->sversion == 20 && Dbl::ql("alter table PaperComment add `timeNotified` int(11) NOT NULL default '0'")) {
        $Conf->update_schema_version(21);
    }
    if ($Conf->sversion == 21 && Dbl::ql("update PaperConflict set conflictType=8 where conflictType=3")) {
        $Conf->update_schema_version(22);
    }
    if ($Conf->sversion == 22 && Dbl::ql("insert into ChairAssistant (contactId) select contactId from Chair on duplicate key update ChairAssistant.contactId=ChairAssistant.contactId") && Dbl::ql("update ContactInfo set roles=roles+2 where roles=5")) {
        $Conf->update_schema_version(23);
    }
    if ($Conf->sversion == 23) {
        $Conf->update_schema_version(24);
    }
    if ($Conf->sversion == 24 && Dbl::ql("alter table ContactInfo add `preferredEmail` varchar(120)")) {
        $Conf->update_schema_version(25);
    }
    if ($Conf->sversion == 25) {
        if ($Conf->settings["final_done"] > 0 && !isset($Conf->settings["final_soft"]) && Dbl::ql("insert into Settings (name, value) values ('final_soft', " . $Conf->settings["final_done"] . ") on duplicate key update value=values(value)")) {
            $Conf->settings["final_soft"] = $Conf->settings["final_done"];
        }
        $Conf->update_schema_version(26);
    }
    if ($Conf->sversion == 26 && Dbl::ql("alter table PaperOption add `data` text") && Dbl::ql("alter table OptionType add `type` tinyint(1) NOT NULL default '0'") && Dbl::ql("update OptionType set type=2 where optionValues='i'") && Dbl::ql("update OptionType set type=1 where type=0 and optionValues!=''")) {
        $Conf->update_schema_version(27);
    }
    if ($Conf->sversion == 27 && Dbl::ql("alter table PaperStorage add `sha1` varbinary(20) NOT NULL default ''") && Dbl::ql("alter table PaperStorage add `documentType` int(3) NOT NULL default '0'") && Dbl::ql("update PaperStorage s, Paper p set s.sha1=p.sha1 where s.paperStorageId=p.paperStorageId and p.finalPaperStorageId=0 and s.paperStorageId>0") && Dbl::ql("update PaperStorage s, Paper p set s.sha1=p.sha1, s.documentType=" . DTYPE_FINAL . " where s.paperStorageId=p.finalPaperStorageId and s.paperStorageId>0")) {
        $Conf->update_schema_version(28);
    }
    if ($Conf->sversion == 28 && Dbl::ql("alter table OptionType add `sortOrder` tinyint(1) NOT NULL default '0'")) {
        $Conf->update_schema_version(29);
    }
    if ($Conf->sversion == 29 && Dbl::ql("delete from Settings where name='pldisplay_default'")) {
        $Conf->update_schema_version(30);
    }
    if ($Conf->sversion == 30 && Dbl::ql("DROP TABLE IF EXISTS `Formula`") && Dbl::ql("CREATE TABLE `Formula` (\n  `formulaId` int(11) NOT NULL auto_increment,\n  `name` varchar(200) NOT NULL,\n  `heading` varchar(200) NOT NULL default '',\n  `headingTitle` text NOT NULL default '',\n  `expression` text NOT NULL,\n  `authorView` tinyint(1) NOT NULL default '1',\n  PRIMARY KEY  (`formulaId`),\n  UNIQUE KEY `formulaId` (`formulaId`),\n  UNIQUE KEY `name` (`name`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8")) {
        $Conf->update_schema_version(31);
    }
    if ($Conf->sversion == 31 && Dbl::ql("alter table Formula add `createdBy` int(11) NOT NULL default '0'") && Dbl::ql("alter table Formula add `timeModified` int(11) NOT NULL default '0'") && Dbl::ql("alter table Formula drop index `name`")) {
        $Conf->update_schema_version(32);
    }
    if ($Conf->sversion == 32 && Dbl::ql("alter table PaperComment add key `timeModified` (`timeModified`)")) {
        $Conf->update_schema_version(33);
    }
    if ($Conf->sversion == 33 && Dbl::ql("alter table PaperComment add `paperStorageId` int(11) NOT NULL default '0'")) {
        $Conf->update_schema_version(34);
    }
    if ($Conf->sversion == 34 && Dbl::ql("alter table ContactInfo add `contactTags` text")) {
        $Conf->update_schema_version(35);
    }
    if ($Conf->sversion == 35 && Dbl::ql("alter table ContactInfo modify `defaultWatch` int(11) NOT NULL default '2'") && Dbl::ql("alter table PaperWatch modify `watch` int(11) NOT NULL default '0'")) {
        $Conf->update_schema_version(36);
    }
    if ($Conf->sversion == 36 && Dbl::ql("alter table PaperReview add `reviewNotified` int(1) default NULL") && Dbl::ql("alter table PaperReviewArchive add `reviewNotified` int(1) default NULL")) {
        $Conf->update_schema_version(37);
    }
    if ($Conf->sversion == 37 && Dbl::ql("alter table OptionType add `displayType` tinyint(1) NOT NULL default '0'")) {
        $Conf->update_schema_version(38);
    }
    if ($Conf->sversion == 38 && Dbl::ql("update PaperComment set forReviewers=1 where forReviewers=-1")) {
        $Conf->update_schema_version(39);
    }
    if ($Conf->sversion == 39 && Dbl::ql("CREATE TABLE `MailLog` (\n  `mailId` int(11) NOT NULL auto_increment,\n  `recipients` varchar(200) NOT NULL,\n  `paperIds` text,\n  `cc` text,\n  `replyto` text,\n  `subject` text,\n  `emailBody` text,\n  PRIMARY KEY  (`mailId`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8")) {
        $Conf->update_schema_version(40);
    }
    if ($Conf->sversion == 40 && Dbl::ql("alter table Paper add `capVersion` int(1) NOT NULL default '0'")) {
        $Conf->update_schema_version(41);
    }
    if ($Conf->sversion == 41 && Dbl::ql("alter table Paper modify `mimetype` varchar(80) NOT NULL default ''") && Dbl::ql("alter table PaperStorage modify `mimetype` varchar(80) NOT NULL default ''")) {
        $Conf->update_schema_version(42);
    }
    if ($Conf->sversion == 42 && Dbl::ql("alter table PaperComment add `ordinal` int(11) NOT NULL default '0'")) {
        $Conf->update_schema_version(43);
    }
    if ($Conf->sversion == 42 && ($result = Dbl::ql("describe PaperComment `ordinal`")) && ($o = edb_orow($result)) && substr($o->Type, 0, 3) == "int" && (!$o->Null || $o->Null == "NO") && (!$o->Default || $o->Default == "0")) {
        $Conf->update_schema_version(43);
    }
    if ($Conf->sversion == 43 && Dbl::ql("alter table Paper add `withdrawReason` text")) {
        $Conf->update_schema_version(44);
    }
    if ($Conf->sversion == 44 && Dbl::ql("alter table PaperStorage add `filename` varchar(255)")) {
        $Conf->update_schema_version(45);
    }
    if ($Conf->sversion == 45 && Dbl::ql("alter table PaperReview add `timeRequested` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReview add `timeRequestNotified` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReviewArchive add `timeRequested` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReviewArchive add `timeRequestNotified` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReview drop column `requestedOn`") && Dbl::ql("alter table PaperReviewArchive drop column `requestedOn`")) {
        $Conf->update_schema_version(46);
    }
    if ($Conf->sversion == 46 && Dbl::ql("alter table ContactInfo add `disabled` tinyint(1) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(47);
    }
    if ($Conf->sversion == 47 && Dbl::ql("delete from ti using TopicInterest ti left join TopicArea ta using (topicId) where ta.topicId is null")) {
        $Conf->update_schema_version(48);
    }
    if ($Conf->sversion == 48 && Dbl::ql("alter table PaperReview add `reviewAuthorNotified` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReviewArchive add `reviewAuthorNotified` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReviewArchive add `reviewToken` int(11) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(49);
    }
    if ($Conf->sversion == 49 && Dbl::ql("alter table PaperOption drop index `paperOption`") && Dbl::ql("alter table PaperOption add index `paperOption` (`paperId`,`optionId`,`value`)")) {
        $Conf->update_schema_version(50);
    }
    if ($Conf->sversion == 50 && Dbl::ql("alter table Paper add `managerContactId` int(11) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(51);
    }
    if ($Conf->sversion == 51 && Dbl::ql("alter table Paper drop column `numComments`") && Dbl::ql("alter table Paper drop column `numAuthorComments`")) {
        $Conf->update_schema_version(52);
    }
    // Due to a bug in the schema updater, some databases might have
    // sversion>=53 but no `PaperComment.commentType` column. Fix them.
    if (($Conf->sversion == 52 || $Conf->sversion >= 53 && ($result = Dbl::ql("show columns from PaperComment like 'commentType'")) && edb_nrows($result) == 0) && Dbl::ql("lock tables PaperComment write, Settings write") && Dbl::ql("alter table PaperComment add `commentType` int(11) NOT NULL DEFAULT '0'")) {
        $new_sversion = max($Conf->sversion, 53);
        $result = Dbl::ql("show columns from PaperComment like 'forAuthors'");
        if (!$result || edb_nrows($result) == 0 || Dbl::ql("update PaperComment set commentType=" . (COMMENTTYPE_AUTHOR | COMMENTTYPE_RESPONSE) . " where forAuthors=2") && Dbl::ql("update PaperComment set commentType=commentType|" . COMMENTTYPE_DRAFT . " where forAuthors=2 and forReviewers=0") && Dbl::ql("update PaperComment set commentType=" . COMMENTTYPE_ADMINONLY . " where forAuthors=0 and forReviewers=2") && Dbl::ql("update PaperComment set commentType=" . COMMENTTYPE_PCONLY . " where forAuthors=0 and forReviewers=0") && Dbl::ql("update PaperComment set commentType=" . COMMENTTYPE_REVIEWER . " where forAuthors=0 and forReviewers=1") && Dbl::ql("update PaperComment set commentType=" . COMMENTTYPE_AUTHOR . " where forAuthors!=0 and forAuthors!=2") && Dbl::ql("update PaperComment set commentType=commentType|" . COMMENTTYPE_BLIND . " where blind=1")) {
            $Conf->update_schema_version($new_sversion);
        }
    }
    if ($Conf->sversion < 53) {
        Dbl::qx_raw($Conf->dblink, "alter table PaperComment drop column `commentType`");
    }
    Dbl::ql("unlock tables");
    if ($Conf->sversion == 53 && Dbl::ql("alter table PaperComment drop column `forReviewers`") && Dbl::ql("alter table PaperComment drop column `forAuthors`") && Dbl::ql("alter table PaperComment drop column `blind`")) {
        $Conf->update_schema_version(54);
    }
    if ($Conf->sversion == 54 && Dbl::ql("alter table PaperStorage add `infoJson` varchar(255) DEFAULT NULL")) {
        $Conf->update_schema_version(55);
    }
    if ($Conf->sversion == 55 && Dbl::ql("alter table ContactInfo modify `password` varbinary(2048) NOT NULL")) {
        $Conf->update_schema_version(56);
    }
    if ($Conf->sversion == 56 && Dbl::ql("alter table Settings modify `data` blob")) {
        $Conf->update_schema_version(57);
    }
    if ($Conf->sversion == 57 && Dbl::ql("DROP TABLE IF EXISTS `Capability`") && Dbl::ql("CREATE TABLE `Capability` (\n  `capabilityId` int(11) NOT NULL AUTO_INCREMENT,\n  `capabilityType` int(11) NOT NULL,\n  `contactId` int(11) NOT NULL,\n  `paperId` int(11) NOT NULL,\n  `timeExpires` int(11) NOT NULL,\n  `salt` varbinary(255) NOT NULL,\n  `data` blob,\n  PRIMARY KEY (`capabilityId`),\n  UNIQUE KEY `capabilityId` (`capabilityId`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8") && Dbl::ql("DROP TABLE IF EXISTS `CapabilityMap`") && Dbl::ql("CREATE TABLE `CapabilityMap` (\n  `capabilityValue` varbinary(255) NOT NULL,\n  `capabilityId` int(11) NOT NULL,\n  `timeExpires` int(11) NOT NULL,\n  PRIMARY KEY (`capabilityValue`),\n  UNIQUE KEY `capabilityValue` (`capabilityValue`)\n) ENGINE=MyISAM DEFAULT CHARSET=utf8")) {
        $Conf->update_schema_version(58);
    }
    if ($Conf->sversion == 58 && Dbl::ql("alter table PaperReview modify `paperSummary` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `commentsToAuthor` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `commentsToPC` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `commentsToAddress` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `weaknessOfPaper` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `strengthOfPaper` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `textField7` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReview modify `textField8` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `paperSummary` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `commentsToAuthor` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `commentsToPC` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `commentsToAddress` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `weaknessOfPaper` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `strengthOfPaper` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `textField7` mediumtext DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive modify `textField8` mediumtext DEFAULT NULL")) {
        $Conf->update_schema_version(59);
    }
    if ($Conf->sversion == 59 && Dbl::ql("alter table ActionLog modify `action` varbinary(4096) NOT NULL") && Dbl::ql("alter table ContactInfo modify `note` varbinary(4096) DEFAULT NULL") && Dbl::ql("alter table ContactInfo modify `collaborators` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table ContactInfo modify `contactTags` varbinary(4096) DEFAULT NULL") && Dbl::ql("alter table Formula modify `headingTitle` varbinary(4096) NOT NULL") && Dbl::ql("alter table Formula modify `expression` varbinary(4096) NOT NULL") && Dbl::ql("alter table OptionType modify `description` varbinary(8192) DEFAULT NULL") && Dbl::ql("alter table OptionType modify `optionValues` varbinary(8192) NOT NULL") && Dbl::ql("alter table PaperReviewRefused modify `reason` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table ReviewFormField modify `description` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table ReviewFormOptions modify `description` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table ReviewRequest modify `reason` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table Settings modify `data` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table ContactAddress modify `addressLine1` varchar(2048) NOT NULL") && Dbl::ql("alter table ContactAddress modify `addressLine2` varchar(2048) NOT NULL") && Dbl::ql("alter table ContactAddress modify `city` varchar(2048) NOT NULL") && Dbl::ql("alter table ContactAddress modify `state` varchar(2048) NOT NULL") && Dbl::ql("alter table ContactAddress modify `zipCode` varchar(2048) NOT NULL") && Dbl::ql("alter table ContactAddress modify `country` varchar(2048) NOT NULL") && Dbl::ql("alter table PaperTopic modify `topicId` int(11) NOT NULL") && Dbl::ql("alter table PaperTopic modify `paperId` int(11) NOT NULL") && Dbl::ql("drop table if exists ChairTag")) {
        $Conf->update_schema_version(60);
    }
    if ($Conf->sversion == 60 && Dbl::ql("insert into Settings (name,value,data) select concat('msg.',substr(name,1,length(name)-3)), value, data from Settings where name='homemsg' or name='conflictdefmsg'") && $Conf->update_schema_version(61)) {
        foreach (array("conflictdef", "home") as $k) {
            if (isset($Conf->settingTexts["{$k}msg"])) {
                $Conf->settingTexts["msg.{$k}"] = $Conf->settingTexts["{$k}msg"];
            }
        }
        $Conf->settings["allowPaperOption"] = 61;
    }
    if ($Conf->sversion == 61 && Dbl::ql("alter table Capability modify `data` varbinary(4096) DEFAULT NULL")) {
        $Conf->update_schema_version(62);
    }
    if (!isset($Conf->settings["outcome_map"])) {
        $ojson = array();
        $result = Dbl::ql("select * from ReviewFormOptions where fieldName='outcome'");
        while ($row = edb_orow($result)) {
            $ojson[$row->level] = $row->description;
        }
        $Conf->save_setting("outcome_map", 1, $ojson);
    }
    if ($Conf->sversion == 62 && isset($Conf->settings["outcome_map"])) {
        $Conf->update_schema_version(63);
    }
    if (!isset($Conf->settings["review_form"]) && $Conf->sversion < 65) {
        update_schema_create_review_form($Conf);
    }
    if ($Conf->sversion == 63 && isset($Conf->settings["review_form"])) {
        $Conf->update_schema_version(64);
    }
    if ($Conf->sversion == 64 && Dbl::ql("drop table if exists `ReviewFormField`") && Dbl::ql("drop table if exists `ReviewFormOptions`")) {
        $Conf->update_schema_version(65);
    }
    if (!isset($Conf->settings["options"]) && $Conf->sversion < 67) {
        update_schema_create_options($Conf);
    }
    if ($Conf->sversion == 65 && isset($Conf->settings["options"])) {
        $Conf->update_schema_version(66);
    }
    if ($Conf->sversion == 66 && Dbl::ql("drop table if exists `OptionType`")) {
        $Conf->update_schema_version(67);
    }
    if ($Conf->sversion == 67 && Dbl::ql("alter table PaperComment modify `comment` varbinary(32767) DEFAULT NULL") && Dbl::ql("alter table PaperComment add `commentTags` varbinary(1024) DEFAULT NULL")) {
        $Conf->update_schema_version(68);
    }
    if ($Conf->sversion == 68 && Dbl::ql("alter table PaperReviewPreference add `expertise` int(4) DEFAULT NULL")) {
        $Conf->update_schema_version(69);
    }
    if ($Conf->sversion == 69 && Dbl::ql("alter table Paper drop column `pcPaper`")) {
        $Conf->update_schema_version(70);
    }
    if ($Conf->sversion == 70 && Dbl::ql("alter table ContactInfo modify `voicePhoneNumber` varbinary(256) DEFAULT NULL") && Dbl::ql("alter table ContactInfo modify `faxPhoneNumber` varbinary(256) DEFAULT NULL") && Dbl::ql("alter table ContactInfo modify `collaborators` varbinary(8192) DEFAULT NULL") && Dbl::ql("alter table ContactInfo drop column `note`") && Dbl::ql("alter table ContactInfo add `data` varbinary(32767) DEFAULT NULL")) {
        $Conf->update_schema_version(71);
    }
    if ($Conf->sversion == 71 && Dbl::ql("alter table Settings modify `name` varbinary(256) DEFAULT NULL") && Dbl::ql("update Settings set name=rtrim(name)")) {
        $Conf->update_schema_version(72);
    }
    if ($Conf->sversion == 72 && Dbl::ql("update TopicInterest set interest=-2 where interest=0") && Dbl::ql("update TopicInterest set interest=4 where interest=2") && Dbl::ql("delete from TopicInterest where interest=1")) {
        $Conf->update_schema_version(73);
    }
    if ($Conf->sversion == 73 && Dbl::ql("alter table PaperStorage add `size` bigint(11) DEFAULT NULL") && Dbl::ql("update PaperStorage set `size`=length(paper) where paper is not null")) {
        $Conf->update_schema_version(74);
    }
    if ($Conf->sversion == 74 && Dbl::ql("alter table ContactInfo drop column `visits`")) {
        $Conf->update_schema_version(75);
    }
    if ($Conf->sversion == 75) {
        foreach (array("capability_gc", "s3_scope", "s3_signing_key") as $k) {
            if (isset($Conf->settings[$k])) {
                $Conf->save_setting("__" . $k, $Conf->settings[$k], get($Conf->settingTexts, $k));
                $Conf->save_setting($k, null);
            }
        }
        $Conf->update_schema_version(76);
    }
    if ($Conf->sversion == 76 && Dbl::ql("update PaperReviewPreference set expertise=-expertise")) {
        $Conf->update_schema_version(77);
    }
    if ($Conf->sversion == 77 && Dbl::ql("alter table MailLog add `q` varchar(4096)")) {
        $Conf->update_schema_version(78);
    }
    if ($Conf->sversion == 78 && Dbl::ql("alter table MailLog add `t` varchar(200)")) {
        $Conf->update_schema_version(79);
    }
    if ($Conf->sversion == 79 && Dbl::ql("alter table ContactInfo add `passwordTime` int(11) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(80);
    }
    if ($Conf->sversion == 80 && Dbl::ql("alter table PaperReview modify `reviewRound` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperReviewArchive modify `reviewRound` int(11) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(81);
    }
    if ($Conf->sversion == 81 && Dbl::ql("alter table PaperStorage add `filterType` int(3) DEFAULT NULL") && Dbl::ql("alter table PaperStorage add `originalStorageId` int(11) DEFAULT NULL")) {
        $Conf->update_schema_version(82);
    }
    if ($Conf->sversion == 82 && Dbl::ql("update Settings set name='msg.resp_instrux' where name='msg.responseinstructions'")) {
        $Conf->update_schema_version(83);
    }
    if ($Conf->sversion == 83 && Dbl::ql("alter table PaperComment add `commentRound` int(11) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(84);
    }
    if ($Conf->sversion == 84 && Dbl::ql("insert ignore into Settings (name, value) select 'resp_active', value from Settings where name='resp_open'")) {
        $Conf->update_schema_version(85);
    }
    if ($Conf->sversion == 85 && Dbl::ql("DROP TABLE IF EXISTS `PCMember`") && Dbl::ql("DROP TABLE IF EXISTS `ChairAssistant`") && Dbl::ql("DROP TABLE IF EXISTS `Chair`")) {
        $Conf->update_schema_version(86);
    }
    if ($Conf->sversion == 86 && update_schema_transfer_address($Conf)) {
        $Conf->update_schema_version(87);
    }
    if ($Conf->sversion == 87 && Dbl::ql("DROP TABLE IF EXISTS `ContactAddress`")) {
        $Conf->update_schema_version(88);
    }
    if ($Conf->sversion == 88 && Dbl::ql("alter table ContactInfo drop key `name`") && Dbl::ql("alter table ContactInfo drop key `affiliation`") && Dbl::ql("alter table ContactInfo drop key `email_3`") && Dbl::ql("alter table ContactInfo drop key `firstName_2`") && Dbl::ql("alter table ContactInfo drop key `lastName`")) {
        $Conf->update_schema_version(89);
    }
    if ($Conf->sversion == 89 && update_schema_unaccented_name($Conf)) {
        $Conf->update_schema_version(90);
    }
    if ($Conf->sversion == 90 && Dbl::ql("alter table PaperReview add `reviewAuthorSeen` int(11) DEFAULT NULL")) {
        $Conf->update_schema_version(91);
    }
    if ($Conf->sversion == 91 && Dbl::ql("alter table PaperReviewArchive add `reviewAuthorSeen` int(11) DEFAULT NULL")) {
        $Conf->update_schema_version(92);
    }
    if ($Conf->sversion == 92 && Dbl::ql("alter table Paper drop key `titleAbstractText`") && Dbl::ql("alter table Paper drop key `allText`") && Dbl::ql("alter table Paper drop key `authorText`") && Dbl::ql("alter table Paper modify `authorInformation` varbinary(8192) DEFAULT NULL") && Dbl::ql("alter table Paper modify `abstract` varbinary(16384) DEFAULT NULL") && Dbl::ql("alter table Paper modify `collaborators` varbinary(8192) DEFAULT NULL") && Dbl::ql("alter table Paper modify `withdrawReason` varbinary(1024) DEFAULT NULL")) {
        $Conf->update_schema_version(93);
    }
    if ($Conf->sversion == 93 && Dbl::ql("alter table TopicArea modify `topicName` varchar(200) DEFAULT NULL")) {
        $Conf->update_schema_version(94);
    }
    if ($Conf->sversion == 94 && Dbl::ql("alter table PaperOption modify `data` varbinary(32768) DEFAULT NULL")) {
        foreach (PaperOption::nonfixed_option_list($Conf) as $xopt) {
            if ($xopt->type === "text") {
                Dbl::ql("delete from PaperOption where optionId={$xopt->id} and data=''");
            }
        }
        $Conf->update_schema_version(95);
    }
    if ($Conf->sversion == 95 && Dbl::ql("alter table Capability add unique key `salt` (`salt`)") && Dbl::ql("update Capability join CapabilityMap using (capabilityId) set Capability.salt=CapabilityMap.capabilityValue") && Dbl::ql("drop table if exists `CapabilityMap`")) {
        $Conf->update_schema_version(96);
    }
    if ($Conf->sversion == 96 && Dbl::ql("alter table ContactInfo add `passwordIsCdb` tinyint(1) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(97);
    }
    if ($Conf->sversion == 97 && Dbl::ql("alter table PaperReview add `reviewWordCount` int(11) DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive add `reviewWordCount` int(11)  DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive drop key `reviewId`") && Dbl::ql("alter table PaperReviewArchive drop key `contactPaper`") && Dbl::ql("alter table PaperReviewArchive drop key `reviewSubmitted`") && Dbl::ql("alter table PaperReviewArchive drop key `reviewNeedsSubmit`") && Dbl::ql("alter table PaperReviewArchive drop key `reviewType`") && Dbl::ql("alter table PaperReviewArchive drop key `requestedBy`")) {
        $Conf->update_schema_version(98);
    }
    if ($Conf->sversion == 98) {
        update_schema_review_word_counts($Conf);
        $Conf->update_schema_version(99);
    }
    if ($Conf->sversion == 99 && Dbl::ql("alter table ContactInfo ENGINE=InnoDB") && Dbl::ql("alter table Paper ENGINE=InnoDB") && Dbl::ql("alter table PaperComment ENGINE=InnoDB") && Dbl::ql("alter table PaperConflict ENGINE=InnoDB") && Dbl::ql("alter table PaperOption ENGINE=InnoDB") && Dbl::ql("alter table PaperReview ENGINE=InnoDB") && Dbl::ql("alter table PaperStorage ENGINE=InnoDB") && Dbl::ql("alter table PaperTag ENGINE=InnoDB") && Dbl::ql("alter table PaperTopic ENGINE=InnoDB") && Dbl::ql("alter table Settings ENGINE=InnoDB")) {
        $Conf->update_schema_version(100);
    }
    if ($Conf->sversion == 100 && Dbl::ql("alter table ActionLog ENGINE=InnoDB") && Dbl::ql("alter table Capability ENGINE=InnoDB") && Dbl::ql("alter table Formula ENGINE=InnoDB") && Dbl::ql("alter table MailLog ENGINE=InnoDB") && Dbl::ql("alter table PaperReviewArchive ENGINE=InnoDB") && Dbl::ql("alter table PaperReviewPreference ENGINE=InnoDB") && Dbl::ql("alter table PaperReviewRefused ENGINE=InnoDB") && Dbl::ql("alter table PaperWatch ENGINE=InnoDB") && Dbl::ql("alter table ReviewRating ENGINE=InnoDB") && Dbl::ql("alter table ReviewRequest ENGINE=InnoDB") && Dbl::ql("alter table TopicArea ENGINE=InnoDB") && Dbl::ql("alter table TopicInterest ENGINE=InnoDB")) {
        $Conf->update_schema_version(101);
    }
    if ($Conf->sversion == 101 && Dbl::ql("alter table ActionLog modify `ipaddr` varbinary(32) DEFAULT NULL") && Dbl::ql("alter table MailLog modify `recipients` varbinary(200) NOT NULL") && Dbl::ql("alter table MailLog modify `q` varbinary(4096) DEFAULT NULL") && Dbl::ql("alter table MailLog modify `t` varbinary(200) DEFAULT NULL") && Dbl::ql("alter table Paper modify `mimetype` varbinary(80) NOT NULL DEFAULT ''") && Dbl::ql("alter table PaperStorage modify `mimetype` varbinary(80) NOT NULL DEFAULT ''") && Dbl::ql("alter table PaperStorage modify `filename` varbinary(255) DEFAULT NULL") && Dbl::ql("alter table PaperStorage modify `infoJson` varbinary(8192) DEFAULT NULL")) {
        $Conf->update_schema_version(102);
    }
    if ($Conf->sversion == 102 && Dbl::ql("alter table PaperReview modify `paperSummary` mediumblob") && Dbl::ql("alter table PaperReview modify `commentsToAuthor` mediumblob") && Dbl::ql("alter table PaperReview modify `commentsToPC` mediumblob") && Dbl::ql("alter table PaperReview modify `commentsToAddress` mediumblob") && Dbl::ql("alter table PaperReview modify `weaknessOfPaper` mediumblob") && Dbl::ql("alter table PaperReview modify `strengthOfPaper` mediumblob") && Dbl::ql("alter table PaperReview modify `textField7` mediumblob") && Dbl::ql("alter table PaperReview modify `textField8` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `paperSummary` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `commentsToAuthor` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `commentsToPC` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `commentsToAddress` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `weaknessOfPaper` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `strengthOfPaper` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `textField7` mediumblob") && Dbl::ql("alter table PaperReviewArchive modify `textField8` mediumblob")) {
        $Conf->update_schema_version(103);
    }
    if ($Conf->sversion == 103 && Dbl::ql("alter table Paper modify `title` varbinary(256) DEFAULT NULL") && Dbl::ql("alter table Paper drop key `title`")) {
        $Conf->update_schema_version(104);
    }
    if ($Conf->sversion == 104 && Dbl::ql("alter table PaperReview add `reviewFormat` tinyint(1) DEFAULT NULL") && Dbl::ql("alter table PaperReviewArchive add `reviewFormat` tinyint(1) DEFAULT NULL")) {
        $Conf->update_schema_version(105);
    }
    if ($Conf->sversion == 105 && Dbl::ql("alter table PaperComment add `commentFormat` tinyint(1) DEFAULT NULL")) {
        $Conf->update_schema_version(106);
    }
    if ($Conf->sversion == 106 && Dbl::ql("alter table PaperComment add `authorOrdinal` int(11) NOT NULL default '0'") && Dbl::ql("update PaperComment set authorOrdinal=ordinal where commentType>=" . COMMENTTYPE_AUTHOR)) {
        $Conf->update_schema_version(107);
    }
    // repair missing comment ordinals; reset incorrect `ordinal`s for
    // author-visible comments
    if ($Conf->sversion == 107) {
        $result = Dbl::ql("select paperId, commentId from PaperComment where ordinal=0 and (commentType&" . (COMMENTTYPE_RESPONSE | COMMENTTYPE_DRAFT) . ")=0 and commentType>=" . COMMENTTYPE_PCONLY . " and commentType<" . COMMENTTYPE_AUTHOR . " order by commentId");
        while ($row = edb_row($result)) {
            Dbl::ql("update PaperComment,\n(select coalesce(count(commentId),0) commentCount from Paper\n    left join PaperComment on (PaperComment.paperId=Paper.paperId and (commentType&" . (COMMENTTYPE_RESPONSE | COMMENTTYPE_DRAFT) . ")=0 and commentType>=" . COMMENTTYPE_PCONLY . " and commentType<" . COMMENTTYPE_AUTHOR . " and commentId<{$row['1']})\n    where Paper.paperId={$row['0']} group by Paper.paperId) t\nset ordinal=(t.commentCount+1) where commentId={$row['1']}");
        }
        $result = Dbl::ql("select paperId, commentId from PaperComment where ordinal=0 and (commentType&" . (COMMENTTYPE_RESPONSE | COMMENTTYPE_DRAFT) . ")=0 and commentType>=" . COMMENTTYPE_AUTHOR . " order by commentId");
        while ($row = edb_row($result)) {
            Dbl::ql("update PaperComment,\n(select coalesce(count(commentId),0) commentCount from Paper\n    left join PaperComment on (PaperComment.paperId=Paper.paperId and (commentType&" . (COMMENTTYPE_RESPONSE | COMMENTTYPE_DRAFT) . ")=0 and commentType>=" . COMMENTTYPE_AUTHOR . " and commentId<{$row['1']})\n    where Paper.paperId={$row['0']} group by Paper.paperId) t\nset authorOrdinal=(t.commentCount+1) where commentId={$row['1']}");
        }
        $result = Dbl::ql("select paperId, commentId from PaperComment where ordinal=authorOrdinal and (commentType&" . (COMMENTTYPE_RESPONSE | COMMENTTYPE_DRAFT) . ")=0 and commentType>=" . COMMENTTYPE_AUTHOR . " order by commentId");
        while ($row = edb_row($result)) {
            Dbl::ql("update PaperComment,\n(select coalesce(max(ordinal),0) maxOrdinal from Paper\n    left join PaperComment on (PaperComment.paperId=Paper.paperId and (commentType&" . (COMMENTTYPE_RESPONSE | COMMENTTYPE_DRAFT) . ")=0 and commentType>=" . COMMENTTYPE_PCONLY . " and commentType<" . COMMENTTYPE_AUTHOR . " and commentId<{$row['1']})\n    where Paper.paperId={$row['0']} group by Paper.paperId) t\nset ordinal=(t.maxOrdinal+1) where commentId={$row['1']}");
        }
        $Conf->update_schema_version(108);
    }
    // contact tags format change
    if ($Conf->sversion == 108 && Dbl::ql("update ContactInfo set contactTags=substr(replace(contactTags, ' ', '#0 ') from 3)") && Dbl::ql("update ContactInfo set contactTags=replace(contactTags, '#0#0 ', '#0 ')")) {
        $Conf->update_schema_version(109);
    }
    if ($Conf->sversion == 109 && Dbl::ql("alter table PaperTag modify `tagIndex` float NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(110);
    }
    if ($Conf->sversion == 110 && Dbl::ql("alter table ContactInfo drop `faxPhoneNumber`") && Dbl::ql("alter table ContactInfo add `country` varbinary(256) default null") && update_schema_transfer_country($Conf)) {
        $Conf->update_schema_version(111);
    }
    if ($Conf->sversion == 111) {
        update_schema_review_word_counts($Conf);
        $Conf->update_schema_version(112);
    }
    if ($Conf->sversion == 112 && Dbl::ql("alter table ContactInfo add `passwordUseTime` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table ContactInfo add `updateTime` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("update ContactInfo set passwordUseTime=lastLogin where passwordUseTime=0")) {
        $Conf->update_schema_version(113);
    }
    if ($Conf->sversion == 113 && Dbl::ql("drop table if exists `PaperReviewArchive`")) {
        $Conf->update_schema_version(114);
    }
    if ($Conf->sversion == 114 && Dbl::ql("alter table PaperReview add `timeDisplayed` int(11) NOT NULL DEFAULT '0'") && Dbl::ql("alter table PaperComment add `timeDisplayed` int(11) NOT NULL DEFAULT '0'")) {
        $Conf->update_schema_version(115);
    }
    if ($Conf->sversion == 115 && Dbl::ql("alter table Formula drop column `authorView`")) {
        $Conf->update_schema_version(116);
    }
    if ($Conf->sversion == 116 && Dbl::ql("alter table PaperComment add `commentOverflow` longblob DEFAULT NULL")) {
        $Conf->update_schema_version(117);
    }
    if ($Conf->sversion == 117 && update_schema_drop_keys_if_exist("PaperTopic", ["paperTopic", "PRIMARY"]) && Dbl::ql("alter table PaperTopic add primary key (`paperId`,`topicId`)") && update_schema_drop_keys_if_exist("TopicInterest", ["contactTopic", "PRIMARY"]) && Dbl::ql("alter table TopicInterest add primary key (`contactId`,`topicId`)")) {
        $Conf->update_schema_version(118);
    }
    if ($Conf->sversion == 118 && update_schema_drop_keys_if_exist("PaperTag", ["paperTag", "PRIMARY"]) && Dbl::ql("alter table PaperTag add primary key (`paperId`,`tag`)") && update_schema_drop_keys_if_exist("PaperReviewPreference", ["paperId", "PRIMARY"]) && Dbl::ql("alter table PaperReviewPreference add primary key (`paperId`,`contactId`)") && update_schema_drop_keys_if_exist("PaperConflict", ["contactPaper", "contactPaperConflict", "PRIMARY"]) && Dbl::ql("alter table PaperConflict add primary key (`contactId`,`paperId`)") && Dbl::ql("alter table MailLog modify `paperIds` blob") && Dbl::ql("alter table MailLog modify `cc` blob") && Dbl::ql("alter table MailLog modify `replyto` blob") && Dbl::ql("alter table MailLog modify `subject` blob") && Dbl::ql("alter table MailLog modify `emailBody` blob")) {
        $Conf->update_schema_version(119);
    }
    if ($Conf->sversion == 119 && update_schema_drop_keys_if_exist("PaperWatch", ["contactPaper", "contactPaperWatch", "PRIMARY"]) && Dbl::ql("alter table PaperWatch add primary key (`paperId`,`contactId`)")) {
        $Conf->update_schema_version(120);
    }
    if ($Conf->sversion == 120 && Dbl::ql("alter table Paper add `paperFormat` tinyint(1) DEFAULT NULL")) {
        $Conf->update_schema_version(121);
    }
    if ($Conf->sversion == 121 && Dbl::ql_raw("update PaperReview r, Paper p set r.reviewNeedsSubmit=1 where p.paperId=r.paperId and p.timeSubmitted<=0 and r.reviewSubmitted is null") && Dbl::ql_raw("update PaperReview r, Paper p, PaperReview rq set r.reviewNeedsSubmit=0 where p.paperId=r.paperId and p.paperId=rq.paperId and p.timeSubmitted<=0 and r.reviewType=" . REVIEW_SECONDARY . " and r.contactId=rq.requestedBy and rq.reviewType<" . REVIEW_SECONDARY . " and rq.reviewSubmitted is not null") && Dbl::ql_raw("update PaperReview r, Paper p, PaperReview rq set r.reviewNeedsSubmit=-1 where p.paperId=r.paperId and p.paperId=rq.paperId and p.timeSubmitted<=0 and r.reviewType=" . REVIEW_SECONDARY . " and r.contactId=rq.requestedBy and rq.reviewType<" . REVIEW_SECONDARY . " and r.reviewNeedsSubmit=0")) {
        $Conf->update_schema_version(122);
    }
    if ($Conf->sversion == 122 && Dbl::ql("alter table ReviewRequest add `reviewRound` int(1) DEFAULT NULL")) {
        $Conf->update_schema_version(123);
    }
    if ($Conf->sversion == 123 && Dbl::ql("update ContactInfo set disabled=1 where password='' and email regexp '^anonymous[0-9]*\$'")) {
        $Conf->update_schema_version(124);
    }
    if ($Conf->sversion == 124 && Dbl::ql("update ContactInfo set password='' where password='******' or passwordIsCdb")) {
        $Conf->update_schema_version(125);
    }
    if ($Conf->sversion == 125 && Dbl::ql("alter table ContactInfo drop column `passwordIsCdb`")) {
        $Conf->update_schema_version(126);
    }
    if ($Conf->sversion == 126 && Dbl::ql("update ContactInfo set disabled=1, password='' where email regexp '^anonymous[0-9]*\$'")) {
        $Conf->update_schema_version(127);
    }
    if ($Conf->sversion == 127 && Dbl::ql("update PaperReview set reviewWordCount=null")) {
        $Conf->update_schema_version(128);
    }
    if ($Conf->sversion == 128 && update_schema_bad_comment_timeDisplayed($Conf)) {
        $Conf->update_schema_version(129);
    }
    if ($Conf->sversion == 129 && Dbl::ql("update PaperComment set timeDisplayed=1 where timeDisplayed=0 and timeNotified>0")) {
        $Conf->update_schema_version(130);
    }
    if ($Conf->sversion == 130 && Dbl::ql("DROP TABLE IF EXISTS `PaperTagAnno`") && Dbl::ql("CREATE TABLE `PaperTagAnno` (\n  `tag` varchar(40) NOT NULL,   # see TAG_MAXLEN in header.php\n  `annoId` int(11) NOT NULL,\n  `tagIndex` float NOT NULL DEFAULT '0',\n  `heading` varbinary(8192) DEFAULT NULL,\n  `annoFormat` tinyint(1) DEFAULT NULL,\n  `infoJson` varbinary(32768) DEFAULT NULL,\n  PRIMARY KEY (`tag`,`annoId`)\n) ENGINE=InnoDB DEFAULT CHARSET=utf8")) {
        $Conf->update_schema_version(131);
    }
    if ($Conf->sversion == 131 && Dbl::ql("alter table PaperStorage modify `infoJson` varbinary(32768) DEFAULT NULL")) {
        $Conf->update_schema_version(132);
    }
    Dbl::ql("delete from Settings where name='__schema_lock'");
}
Example #7
0
// face.php -- Peteramati face page
// HotCRP and Peteramati are Copyright (c) 2006-2015 Eddie Kohler and others
// See LICENSE for open-source distribution terms
require_once "src/initweb.php";
ContactView::set_path_request(array("/u"));
if ($Me->is_empty()) {
    $Me->escape();
}
global $User, $Pset, $Info;
$User = $Me;
if (isset($_REQUEST["u"])) {
    $User = ContactView::prepare_user($_REQUEST["u"]);
}
if (isset($_REQUEST["imageid"])) {
    if ($User && ($User === $Me || $Me->isPC) && $_REQUEST["imageid"] && ($result = Dbl::qe("select mimetype, `data` from ContactImage where contactId=? and contactImageId=?", $User->contactId, $_REQUEST["imageid"])) && ($row = edb_row($result))) {
        header("Content-Type: {$row['0']}");
        header("Cache-Control: public, max-age=31557600");
        header("Expires: " . gmdate("D, d M Y H:i:s", $Now + 31557600) . " GMT");
        if (!$zlib_output_compression) {
            header("Content-Length: " . strlen($row[1]));
        }
        print $row[1];
    } else {
        header("Content-Type: image/gif");
        if (!$zlib_output_compression) {
            header("Content-Length: 43");
        }
        print "GIF89a€!ù,D;";
    }
    exit;
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 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();
 }
Example #10
0
}
$fetchscript = get($PsetInfo, "_facefetch_script");
if (count($arg["_"])) {
    $fetchscript = $arg["_"][0];
}
if (!$fetchscript) {
    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) . " ");
Example #11
0
function echo_commit($Info)
{
    global $Conf, $Me, $User, $Pset;
    global $TABWIDTH, $WDIFF;
    $Notes = $Info->commit_info();
    $TABWIDTH = $Info->commit_info("tabwidth") ?: 4;
    $WDIFF = isset($Notes->wdiff) ? $Notes->wdiff : false;
    // current commit and commit selector
    $sel = array();
    $curhead = $grouphead = null;
    foreach ($Info->recent_commits() as $k) {
        // visually separate older heads
        if ($curhead === null) {
            $curhead = $k->fromhead;
        }
        if ($curhead != $k->fromhead) {
            if (!$grouphead) {
                $sel["from.{$k->fromhead}"] = (object) array("type" => "optgroup", "label" => "Other snapshots");
            } else {
                $sel["from.{$k->fromhead}"] = null;
            }
            $curhead = $grouphead = $k->fromhead;
        }
        // actual option
        $x = UnicodeHelper::utf8_prefix($k->subject, 72);
        if (strlen($x) != strlen($k->subject)) {
            $x .= "...";
        }
        $sel[$k->hash] = substr($k->hash, 0, 7) . " " . htmlspecialchars($x);
    }
    $result = $Conf->qe("select hash from CommitNotes where (haslinenotes & ?)!=0 and pset=? and hash ?a", $Me == $User && !$Info->can_see_grades ? HASNOTES_COMMENT : HASNOTES_ANY, $Pset->psetid, array_keys($sel));
    while ($row = edb_row($result)) {
        $sel[$row[0]] .= " &nbsp;♪";
    }
    if (($h = $Info->grading_hash()) && isset($sel[$h])) {
        $sel[$h] = preg_replace('_(.*?)(?: &nbsp;)?(♪?)\\z_', '$1 &nbsp;✱$2', $sel[$h]);
    }
    if ($Info->is_grading_commit()) {
        $key = "grading commit";
    } else {
        $key = "this commit";
    }
    $value = Ht::select("newcommit", $sel, $Info->commit_hash(), array("onchange" => "jQuery(this).closest('form').submit()"));
    if ($Me != $User) {
        $x = $Info->is_grading_commit() ? "" : "font-weight:bold";
        $value .= " " . Ht::submit("grade", "Grade", array("style" => $x));
    }
    // view options
    $fold_viewoptions = !isset($_REQUEST["tab"]) && !isset($_REQUEST["wdiff"]);
    $value .= '<div class="viewoptions61">' . '<a class="q" href="#" onclick="return fold61(this.nextSibling,this.parentNode)">' . '<span class="foldarrow">' . ($fold_viewoptions ? '&#x25B6;' : '&#x25BC;') . '</span>&nbsp;options</a><span style="padding-left:1em' . ($fold_viewoptions ? ';display:none' : '') . '">tab width:';
    foreach (array(2, 4, 8) as $i) {
        $value .= '&nbsp;<a href="' . self_href(array("tab" => $i)) . '"' . ($TABWIDTH == $i ? " class=\"q\"><strong>{$i}</strong>" : '>' . $i) . '</a>';
    }
    $value .= '<span style="padding-left:1em">wdiff:';
    foreach (array("no", "yes") as $i => $t) {
        $value .= '&nbsp;<a href="' . self_href(array("wdiff" => $i)) . '"' . (!$WDIFF == !$i ? " class=\"q\"><strong>{$t}</strong>" : '>' . $t) . '</a>';
    }
    $value .= '</span></span></div>';
    // warnings
    $remarks = array();
    if (!$Info->grading_hash() && $Me != $User && !$Pset->gitless_grades) {
        $remarks[] = array(true, "No commit has been marked for grading.");
    } else {
        if (!$Info->is_grading_commit() && $Info->grading_hash()) {
            $remarks[] = array(true, "This is not " . "<a class=\"uu\" href=\"" . $Info->hoturl("pset", array("commit" => $Info->grading_hash())) . "\">the commit currently marked for grading</a>" . " <span style=\"font-weight:normal\">(<a href=\"" . $Info->hoturl("diff", array("commit1" => $Info->grading_hash())) . "\">see diff</a>)</span>.");
        }
    }
    if (!$Info->is_latest_commit()) {
        $remarks[] = array(true, "This is not " . "<a class=\"uu\" href=\"" . $Info->hoturl("pset", array("commit" => $Info->latest_hash())) . "\">the latest commit</a>" . " <span style=\"font-weight:normal\">(<a href=\"" . $Info->hoturl("diff", array("commit1" => $Info->latest_hash())) . "\">see diff</a>)</span>.");
    }
    if (($lh = $Info->late_hours()) && $lh->hours > 0) {
        $extra = array();
        if (get($lh, "commitat")) {
            $extra[] = "commit at " . $Conf->printableTimestamp($lh->commitat);
        }
        if (get($lh, "deadline")) {
            $extra[] = "deadline " . $Conf->printableTimestamp($lh->deadline);
        }
        $extra = count($extra) ? ' <span style="font-weight:normal">(' . join(", ", $extra) . ')</span>' : "";
        $remarks[] = array(true, "This commit uses " . plural($lh->hours, "late hour") . $extra . ".");
    }
    if (($Info->is_latest_commit() || $Me->isPC) && $Pset->handout_repo_url) {
        $Pset->latest_handout_commit();
        $last_handout = $Pset->latest_handout_commit();
        $last_myhandout = $last_handout ? $Info->derived_handout_hash() : false;
        if ($last_handout && $last_myhandout && $last_handout->hash == $last_myhandout) {
            /* this is ideal: they have the latest handout commit */
        } else {
            if ($last_handout && $last_myhandout) {
                // they don't have the latest updates
                $remarks[] = array(true, "Updates are available for this problem set <span style=\"font-weight:normal\">(<a href=\"" . $Info->hoturl("diff", array("commit" => $last_myhandout, "commit1" => $last_handout->hash)) . "\">see diff</a>)</span>. Run <code>git pull handout master</code> to merge these updates.");
            } else {
                if ($last_handout) {
                    $remarks[] = array(true, "Please create your repository by cloning our repository. Creating your repository from scratch makes it harder for you to get pset updates.");
                } else {
                    if (!$last_handout && $Me->isPC) {
                        $handout_files = $Pset->handout_repo()->ls_files("master");
                        if (!count($handout_files)) {
                            $remarks[] = array(true, "The handout repository, " . htmlspecialchars($Pset->handout_repo_url) . ", contains no files; perhaps handout_repo_url is misconfigured.");
                        } else {
                            $remarks[] = array(true, "The handout repository, " . htmlspecialchars($Pset->handout_repo_url) . ", does not contain problem set code yet.");
                        }
                    }
                }
            }
        }
    }
    // actually print
    echo Ht::form($Info->hoturl_post("pset", array("commit" => null, "setcommit" => 1)), array("class" => "commitcontainer61", "data-pa-pset" => $Info->pset->urlkey, "data-pa-commit" => $Info->latest_hash())), "<div class=\"f-contain\">";
    ContactView::echo_group($key, $value, $remarks);
    echo "</div></form>\n";
}
Example #12
0
function genericWatch($prow, $watchtype, $callback)
{
    global $Conf, $Me;
    $q = "select C.contactId, firstName, lastName, email,\n\t\tpassword, roles, defaultWatch,\n\t\tR.reviewType as myReviewType,\n\t\tR.reviewSubmitted as myReviewSubmitted,\n\t\tR.reviewNeedsSubmit as myReviewNeedsSubmit,\n\t\tconflictType, watch, preferredEmail";
    if ($Conf->sversion >= 47) {
        $q .= ", disabled";
    }
    $q .= "\nfrom ContactInfo C\n\t\tleft join PaperConflict Conf on (Conf.paperId={$prow->paperId} and Conf.contactId=C.contactId)\n\t\tleft join PaperWatch W on (W.paperId={$prow->paperId} and W.contactId=C.contactId)\n\t\tleft join PaperReview R on (R.paperId={$prow->paperId} and R.contactId=C.contactId)\n\t\tleft join PaperComment Cmt on (Cmt.paperId={$prow->paperId} and Cmt.contactId=C.contactId)\n";
    $q .= "where watch is not null" . " or conflictType>=" . CONFLICT_AUTHOR . " or reviewType is not null or commentId is not null" . " or (defaultWatch & " . ($watchtype << WATCHSHIFT_ALL) . ")!=0";
    // save review information since we modify $prow
    $saveProw = (object) null;
    setReviewInfo($saveProw, $prow);
    $result = $Conf->qe($q, "while processing email notifications");
    $watchers = array();
    $lastContactId = 0;
    while ($row = edb_orow($result)) {
        if ($row->contactId == $lastContactId || $row->contactId == $Me->contactId || preg_match('/\\Aanonymous\\d*\\z/', $row->email)) {
            continue;
        }
        $lastContactId = $row->contactId;
        if ($row->watch && $row->watch & $watchtype << WATCHSHIFT_EXPLICIT) {
            if (!($row->watch & $watchtype << WATCHSHIFT_NORMAL)) {
                continue;
            }
        } else {
            if (!($row->defaultWatch & ($watchtype << WATCHSHIFT_NORMAL | $watchtype << WATCHSHIFT_ALL))) {
                continue;
            }
        }
        $watchers[$row->contactId] = $row;
    }
    // Need to check for outstanding reviews if the settings might prevent a
    // person with outstanding reviews from seeing a comment.
    if (count($watchers) && ($Conf->timePCViewAllReviews(false, false) && !$Conf->timePCViewAllReviews(false, true) || $Conf->timeAuthorViewReviews(false) && !$Conf->timeAuthorViewReviews(true))) {
        $result = $Conf->qe("select C.contactId, R.contactId, max(R.reviewNeedsSubmit) from ContactInfo C\n \t\tleft join PaperReview R on (R.contactId=C.contactId)\n\t\twhere C.contactId in (" . join(",", array_keys($watchers)) . ")\n\t\tgroup by C.contactId", "while processing email notifications");
        while ($row = edb_row($result)) {
            $watchers[$row[0]]->isReviewer = $row[1] > 0;
            $watchers[$row[0]]->reviewsOutstanding = $row[2] > 0;
        }
    }
    $method = is_array($callback) ? $callback[1] : null;
    foreach ($watchers as $row) {
        $minic = Contact::make($row);
        setReviewInfo($prow, $row);
        if ($method) {
            $callback[0]->{$method}($prow, $minic);
        } else {
            $callback($prow, $minic);
        }
    }
    setReviewInfo($prow, $saveProw);
}
 private function set_my_conflicts()
 {
     $this->my_conflicts = array();
     $result = Dbl::qe("select Paper.paperId, managerContactId from Paper join PaperConflict on (PaperConflict.paperId=Paper.paperId) where conflictType>0 and PaperConflict.contactId=" . $this->contact->contactId);
     while ($row = edb_row($result)) {
         $this->my_conflicts[$row[0]] = $row[1] ? $row[1] : true;
     }
     Dbl::free($result);
 }
Example #14
0
 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;
     }
 }
Example #15
0
function _tryNewList($opt, $listtype)
{
    global $Conf, $ConfSiteSuffix, $Me;
    if ($listtype == "u" && $Me->privChair) {
        $searchtype = defval($opt, "t") === "all" ? "all" : "pc";
        $q = "select email from ContactInfo";
        if ($searchtype == "pc") {
            $q .= " where (roles&" . Contact::ROLE_PC . ")!=0";
        }
        $result = $Conf->qx("{$q} order by lastName, firstName, email");
        $a = array();
        while ($row = edb_row($result)) {
            $a[] = $row[0];
        }
        $a["description"] = $searchtype == "pc" ? "Program committee" : "Users";
        $a["listid"] = "u:" . $searchtype . "::";
        $a["url"] = "users{$ConfSiteSuffix}?t=" . $searchtype;
        return $a;
    } else {
        require_once "search.inc";
        $search = new PaperSearch($Me, $opt);
        return $search->sessionList();
    }
}
function databaseTracks($who)
{
    global $Conf;
    $tracks = (object) array("soleAuthor" => array(), "author" => array(), "review" => array(), "comment" => array());
    // find authored papers
    $result = $Conf->qe("select Paper.paperId, count(pc.contactId)\n        from Paper\n        join PaperConflict c on (c.paperId=Paper.paperId and c.contactId={$who} and c.conflictType>=" . CONFLICT_AUTHOR . ")\n        join PaperConflict pc on (pc.paperId=Paper.paperId and pc.conflictType>=" . CONFLICT_AUTHOR . ")\n        group by Paper.paperId order by Paper.paperId");
    while ($row = edb_row($result)) {
        if ($row[1] == 1) {
            $tracks->soleAuthor[] = $row[0];
        }
        $tracks->author[] = $row[0];
    }
    // find reviews
    $result = $Conf->qe("select paperId from PaperReview\n        where PaperReview.contactId={$who}\n        group by paperId order by paperId");
    while ($row = edb_row($result)) {
        $tracks->review[] = $row[0];
    }
    // find comments
    $result = $Conf->qe("select paperId from PaperComment\n        where PaperComment.contactId={$who}\n        group by paperId order by paperId");
    while ($row = edb_row($result)) {
        $tracks->comment[] = $row[0];
    }
    return $tracks;
}
 function render($sv)
 {
     global $Conf, $Opt;
     echo "Can <b>authors see reviews and author-visible comments</b> for their papers?<br />";
     if ($Conf->setting("resp_active")) {
         $no_text = "No, unless responses are open";
     } else {
         $no_text = "No";
     }
     if (!$Conf->setting("au_seerev", 0) && $Conf->timeAuthorViewReviews()) {
         $no_text .= '<div class="hint">Authors are currently able to see reviews since responses are open.</div>';
     }
     $opts = array(Conf::AUSEEREV_NO => $no_text, Conf::AUSEEREV_YES => "Yes");
     if ($sv->newv("au_seerev") == Conf::AUSEEREV_UNLESSINCOMPLETE && !get($Opt, "allow_auseerev_unlessincomplete")) {
         $Conf->save_setting("opt.allow_auseerev_unlessincomplete", 1);
     }
     if (get($Opt, "allow_auseerev_unlessincomplete")) {
         $opts[Conf::AUSEEREV_UNLESSINCOMPLETE] = "Yes, after completing any assigned reviews for other papers";
     }
     $opts[Conf::AUSEEREV_TAGS] = "Yes, for papers with any of these tags:&nbsp; " . $sv->render_entry("tag_au_seerev", ["onfocus" => "\$('#au_seerev_" . Conf::AUSEEREV_TAGS . "').click()"]);
     $sv->echo_radio_table("au_seerev", $opts);
     echo Ht::hidden("has_tag_au_seerev", 1);
     // Authors' response
     echo '<div class="g"></div><table id="foldauresp" class="fold2o">';
     $sv->echo_checkbox_row('resp_active', "<b>Collect authors’ responses to the reviews<span class='fx2'>:</span></b>", "void fold('auresp',!this.checked,2)");
     echo '<tr class="fx2"><td></td><td><div id="auresparea">', Ht::hidden("has_resp_rounds", 1);
     // Response rounds
     if ($sv->use_req()) {
         $rrounds = array(1);
         for ($i = 1; isset($sv->req["resp_roundname_{$i}"]); ++$i) {
             $rrounds[$i] = $sv->req["resp_roundname_{$i}"];
         }
     } else {
         $rrounds = $Conf->resp_round_list();
     }
     $rrounds["n"] = "";
     foreach ($rrounds as $i => $rname) {
         $isuf = $i ? "_{$i}" : "";
         $rname_si = $sv->si("resp_roundname{$isuf}");
         if (!$i) {
             $rname = $rname == "1" ? "none" : $rname;
             $rname_si->placeholder = "none";
         }
         $sv->set_oldv("resp_roundname{$isuf}", $rname);
         echo '<div id="response', $isuf;
         if ($i) {
             echo '" style="padding-top:1em';
         }
         if ($i === "n") {
             echo ';display:none';
         }
         echo '"><table class="secondary-settings"><tbody>';
         $sv->echo_entry_row("resp_roundname{$isuf}", "Response name");
         if ($sv->curv("resp_open{$isuf}") === 1 && ($x = $sv->curv("resp_done{$isuf}"))) {
             $Conf->settings["resp_open{$isuf}"] = $x - 7 * 86400;
         }
         $sv->echo_entry_row("resp_open{$isuf}", "Start time");
         $sv->echo_entry_row("resp_done{$isuf}", "Hard deadline");
         $sv->echo_entry_row("resp_grace{$isuf}", "Grace period");
         $sv->echo_entry_row("resp_words{$isuf}", "Word limit", $i ? null : "This is a soft limit: authors may submit longer responses. 0 means no limit.");
         echo '</tbody></table><div style="padding-top:4px">';
         $sv->echo_message_minor("msg.resp_instrux{$isuf}", "Instructions");
         echo '</div></div>', "\n";
     }
     echo '</div><div style="padding-top:1em">', '<button type="button" onclick="settings_add_resp_round()">Add response round</button>', '</div></td></tr></table>';
     $Conf->footerScript("fold('auresp',!\$\$('cbresp_active').checked,2)");
     echo "<div class='g'></div>\n<hr class='hr' />\n", "Who can see paper <b>decisions</b> (accept/reject)?<br />\n";
     $sv->echo_radio_table("seedec", array(Conf::SEEDEC_ADMIN => "Only administrators", Conf::SEEDEC_NCREV => "Reviewers and non-conflicted PC members", Conf::SEEDEC_REV => "Reviewers and <em>all</em> PC members", Conf::SEEDEC_ALL => "<b>Authors</b>, reviewers, and all PC members (and reviewers can see accepted papers’ author lists)"));
     echo "<div class='g'></div>\n";
     echo "<table>\n";
     $decs = $Conf->decision_map();
     krsort($decs);
     // count papers per decision
     $decs_pcount = array();
     $result = $Conf->qe("select outcome, count(*) from Paper where timeSubmitted>0 group by outcome");
     while ($row = edb_row($result)) {
         $decs_pcount[$row[0]] = $row[1];
     }
     // real decisions
     $n_real_decs = 0;
     foreach ($decs as $k => $v) {
         $n_real_decs += $k ? 1 : 0;
     }
     $caption = "<td class='lcaption' rowspan='{$n_real_decs}'>Current decision types</td>";
     foreach ($decs as $k => $v) {
         if ($k) {
             if ($sv->use_req()) {
                 $v = defval($sv->req, "dec{$k}", $v);
             }
             echo "<tr>", $caption, '<td class="lentry nw">', Ht::entry("dec{$k}", $v, array("size" => 35)), " &nbsp; ", $k > 0 ? "Accept class" : "Reject class", "</td>";
             if (isset($decs_pcount[$k]) && $decs_pcount[$k]) {
                 echo '<td class="lentry nw">', plural($decs_pcount[$k], "paper"), "</td>";
             }
             echo "</tr>\n";
             $caption = "";
         }
     }
     // new decision
     $v = "";
     $vclass = 1;
     if ($sv->use_req()) {
         $v = defval($sv->req, "decn", $v);
         $vclass = defval($sv->req, "dtypn", $vclass);
     }
     echo '<tr><td class="lcaption">', $sv->label("decn", "New decision type"), '<br /></td>', '<td class="lentry nw">', Ht::hidden("has_decisions", 1), Ht::entry("decn", $v, array("id" => "decn", "size" => 35)), ' &nbsp; ', Ht::select("dtypn", array(1 => "Accept class", -1 => "Reject class"), $vclass), "<br /><small>Examples: “Accepted as short paper”, “Early reject”</small>", "</td></tr>";
     if ($sv->has_error("decn")) {
         echo '<tr><td></td><td class="lentry nw">', Ht::checkbox("decn_confirm", 1, false), '&nbsp;<span class="error">', Ht::label("Confirm"), "</span></td></tr>";
     }
     echo "</table>\n";
     // Final versions
     echo "<h3 class=\"settings g\">Final versions</h3>\n";
     echo '<table id="foldfinal" class="fold2o">';
     $sv->echo_checkbox_row('final_open', '<b>Collect final versions of accepted papers<span class="fx">:</span></b>', "void fold('final',!this.checked,2)");
     echo '<tr class="fx2"><td></td><td><table class="secondary-settings"><tbody>';
     $sv->echo_entry_row("final_soft", "Deadline");
     $sv->echo_entry_row("final_done", "Hard deadline");
     $sv->echo_entry_row("final_grace", "Grace period");
     echo "</tbody></table><div class='g'></div>";
     $sv->echo_message_minor("msg.finalsubmit", "Instructions");
     echo "<div class='g'></div>", "<small>To collect <em>multiple</em> final versions, such as one in 9pt and one in 11pt, add “Alternate final version” options via <a href='", hoturl("settings", "group=opt"), "'>Settings &gt; Submission options</a>.</small>", "</td></tr></table>\n\n";
     $Conf->footerScript("fold('final',!\$\$('cbfinal_open').checked)");
 }
 public function load_content($doc)
 {
     global $Conf;
     $ok = false;
     $result = null;
     if (!opt("dbNoPapers") && get_i($doc, "paperStorageId") > 1) {
         $result = Dbl::q("select paper, compression from PaperStorage where paperStorageId=" . $doc->paperStorageId);
     }
     if (!$result || !($row = edb_row($result)) || $row[0] === null) {
         $doc->content = "";
     } else {
         if ($row[1] == 1) {
             $doc->content = gzinflate($row[0]);
             $ok = true;
         } else {
             $doc->content = $row[0];
             $ok = true;
         }
     }
     if (!$ok && ($s3 = self::s3_document()) && ($filename = self::s3_filename($doc))) {
         $filename = self::s3_filename($doc);
         $content = $s3->load($filename);
         if ($content !== "" && $content !== null) {
             $doc->content = $content;
             $ok = true;
         } else {
             if ($s3->status != 200) {
                 error_log("S3 error: GET {$filename}: {$s3->status} {$s3->status_text} " . json_encode($s3->response_headers));
             }
         }
     }
     if (!$ok) {
         $num = get($doc, "paperId") ? " #{$doc->paperId}" : "";
         $doc->error = true;
         if ($this->dtype == DTYPE_SUBMISSION) {
             $doc->error_text = "Paper{$num} has not been uploaded.";
         } else {
             if ($this->dtype == DTYPE_FINAL) {
                 $doc->error_text = "Paper{$num}’s final copy has not been uploaded.";
             }
         }
     }
     $doc->size = strlen($doc->content);
     $this->store_filestore($doc, true);
     // silently does nothing if error || !filestore
     return $ok;
 }
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();
    }
}
Example #20
0
function change_review_tokens()
{
    global $Conf, $Me;
    $cleared = $Me->change_review_token(false, false);
    $tokeninfo = array();
    foreach (preg_split('/\\s+/', $_REQUEST["token"]) as $x) {
        if ($x == "") {
            /* no complaints */
        } else {
            if (!($token = decode_token($x, "V"))) {
                Conf::msg_error("Invalid review token &ldquo;" . htmlspecialchars($x) . "&rdquo;.  Check your typing and try again.");
            } else {
                if ($Conf->session("rev_token_fail", 0) >= 5) {
                    Conf::msg_error("Too many failed attempts to use a review token.  <a href='" . hoturl("index", "signout=1") . "'>Sign out</a> and in to try again.");
                } else {
                    $result = Dbl::qe("select paperId from PaperReview where reviewToken=" . $token);
                    if ($row = edb_row($result)) {
                        $tokeninfo[] = "Review token “" . htmlspecialchars($x) . "” lets you review <a href='" . hoturl("paper", "p={$row['0']}") . "'>paper #" . $row[0] . "</a>.";
                        $Me->change_review_token($token, true);
                    } else {
                        Conf::msg_error("Review token “" . htmlspecialchars($x) . "” hasn’t been assigned.");
                        $nfail = $Conf->session("rev_token_fail", 0) + 1;
                        $Conf->save_session("rev_token_fail", $nfail);
                    }
                }
            }
        }
    }
    if ($cleared && !count($tokeninfo)) {
        $tokeninfo[] = "Review tokens cleared.";
    }
    if (count($tokeninfo)) {
        $Conf->infoMsg(join("<br />\n", $tokeninfo));
    }
    redirectSelf();
}
Example #21
0
 private function load_links()
 {
     $result = $this->conf->qe("select type, pset, link from ContactLink where cid=?", $this->contactId);
     $this->links = [1 => [], 2 => [], 3 => [], 4 => []];
     while ($row = edb_row($result)) {
         $this->links[(int) $row[0]][(int) $row[1]][] = (int) $row[2];
     }
 }
function admin_home_messages()
{
    global $Opt, $Conf;
    $m = array();
    $errmarker = "<span class=\"error\">Error:</span> ";
    if (preg_match("/^(?:[1-4]\\.|5\\.[0123])/", phpversion())) {
        $m[] = $errmarker . "HotCRP requires PHP version 5.4 or higher.  You are running PHP version " . htmlspecialchars(phpversion()) . ".";
    }
    if (get_magic_quotes_gpc()) {
        $m[] = $errmarker . "The PHP <code>magic_quotes_gpc</code> feature is on, which is a bad idea.  Check that your Web server is using HotCRP’s <code>.htaccess</code> file.  You may also want to disable <code>magic_quotes_gpc</code> in your <code>php.ini</code> configuration file.";
    }
    if (get_magic_quotes_runtime()) {
        $m[] = $errmarker . "The PHP <code>magic_quotes_runtime</code> feature is on, which is a bad idea.  Check that your Web server is using HotCRP’s <code>.htaccess</code> file.  You may also want to disable <code>magic_quotes_runtime</code> in your <code>php.ini</code> configuration file.";
    }
    if (defined("JSON_HOTCRP")) {
        $m[] = "Your PHP was built without JSON functionality. HotCRP is using its built-in replacements; the native functions would be faster.";
    }
    if ((int) $Opt["globalSessionLifetime"] < $Opt["sessionLifetime"]) {
        $m[] = "PHP’s systemwide <code>session.gc_maxlifetime</code> setting, which is " . htmlspecialchars($Opt["globalSessionLifetime"]) . " seconds, is less than HotCRP’s preferred session expiration time, which is " . $Opt["sessionLifetime"] . " seconds.  You should update <code>session.gc_maxlifetime</code> in the <code>php.ini</code> file or users may be booted off the system earlier than you expect.";
    }
    if (!function_exists("imagecreate") && $Conf->setting("__gd_required")) {
        $m[] = $errmarker . "This PHP installation lacks support for the GD library, so HotCRP can’t generate backup score charts for old browsers. Some of your users require this backup. You should update your PHP installation. For example, on Ubuntu Linux, install the <code>php" . PHP_MAJOR_VERSION . "-gd</code> package.";
    }
    $result = Dbl::qx_raw("show variables like 'max_allowed_packet'");
    $max_file_size = ini_get_bytes("upload_max_filesize");
    if (($row = edb_row($result)) && $row[1] < $max_file_size && !get($Opt, "dbNoPapers")) {
        $m[] = $errmarker . "MySQL’s <code>max_allowed_packet</code> setting, which is " . htmlspecialchars($row[1]) . "&nbsp;bytes, is less than the PHP upload file limit, which is {$max_file_size}&nbsp;bytes.  You should update <code>max_allowed_packet</code> in the system-wide <code>my.cnf</code> file or the system may not be able to handle large papers.";
    }
    // Conference names
    if (get($Opt, "shortNameDefaulted")) {
        $m[] = "<a href=\"" . hoturl("settings", "group=basics") . "\">Set the conference abbreviation</a> to a short name for your conference, such as “OSDI ’14”.";
    } else {
        if (simplify_whitespace(Conf::$gShortName) != Conf::$gShortName) {
            $m[] = "The <a href=\"" . hoturl("settings", "group=basics") . "\">conference abbreviation</a> setting has a funny value. To fix it, remove leading and trailing spaces, use only space characters (no tabs or newlines), and make sure words are separated by single spaces (never two or more).";
        }
    }
    $site_contact = Contact::site_contact();
    if (!$site_contact->email || $site_contact->email == "*****@*****.**") {
        $m[] = "<a href=\"" . hoturl("settings", "group=basics") . "\">Set the conference contact’s name and email</a> so submitters can reach someone if things go wrong.";
    }
    // Any -100 preferences around?
    $result = Dbl::ql_raw($Conf->preferenceConflictQuery(false, "limit 1"));
    if ($row = edb_row($result)) {
        $m[] = "PC members have indicated paper conflicts (using review preferences of &#8722;100 or less) that aren’t yet confirmed. <a href='" . hoturl_post("autoassign", "a=prefconflict&amp;assign=1") . "' class='nw'>Confirm these conflicts</a>";
    }
    // Weird URLs?
    foreach (array("conferenceSite", "paperSite") as $k) {
        if (isset($Opt[$k]) && $Opt[$k] && !preg_match('`\\Ahttps?://(?:[-.~\\w:/?#\\[\\]@!$&\'()*+,;=]|%[0-9a-fA-F][0-9a-fA-F])*\\z`', $Opt[$k])) {
            $m[] = $errmarker . "The <code>\$Opt[\"{$k}\"]</code> setting, ‘<code>" . htmlspecialchars($Opt[$k]) . "</code>’, is not a valid URL.  Edit the <code>conf/options.php</code> file to fix this problem.";
        }
    }
    // Unnotified reviews?
    if ($Conf->setting("pcrev_assigntime", 0) > $Conf->setting("pcrev_informtime", 0)) {
        $assigntime = $Conf->setting("pcrev_assigntime");
        $result = Dbl::qe_raw("select paperId from PaperReview where reviewType>" . REVIEW_PC . " and timeRequested>timeRequestNotified and reviewSubmitted is null and reviewNeedsSubmit!=0 limit 1");
        if (edb_nrows($result)) {
            $m[] = "PC review assignments have changed.&nbsp; <a href=\"" . hoturl("mail", "template=newpcrev") . "\">Send review assignment notifications</a> <span class=\"barsep\">·</span> <a href=\"" . hoturl_post("index", "clearnewpcrev={$assigntime}") . "\">Clear this message</a>";
        } else {
            $Conf->save_setting("pcrev_informtime", $assigntime);
        }
    }
    // Review round expired?
    if (count($Conf->round_list()) > 1 && $Conf->time_review_open() && $Conf->missed_review_deadline($Conf->current_round(), true, false)) {
        $any_rounds_open = false;
        foreach ($Conf->defined_round_list() as $i => $rname) {
            if (!$any_rounds_open && !$Conf->missed_review_deadline($i, true, false) && $Conf->setting($Conf->review_deadline($i, true, false))) {
                $any_rounds_open = $rname;
            }
        }
        if ($any_rounds_open) {
            $m[] = "The deadline for the current review round, " . htmlspecialchars($Conf->current_round_name()) . ", has passed. You may want to <a href=\"" . hoturl("settings", "group=reviews") . "\">change the current round</a> to " . htmlspecialchars($any_rounds_open) . ".";
        }
    }
    if (count($m)) {
        $Conf->warnMsg('<div class="multimessage"><div>' . join('</div><div>', $m) . "</div></div>");
    }
}
 function list_submitted_papers_with_viewable_tags()
 {
     global $Conf;
     $pids = array();
     $tag_seeall = $Conf->setting("tag_seeall");
     if (!$this->isPC) {
         return $pids;
     } else {
         if (!$this->privChair && $Conf->check_track_sensitivity(Track::VIEW)) {
             $q = "select p.paperId, pt.paperTags, r.reviewType from Paper p\n                left join (select paperId, group_concat(' ', tag, '#', tagIndex order by tag separator '') as paperTags from PaperTag where tag ?a group by paperId) as pt on (pt.paperId=p.paperId)\n                left join PaperReview r on (r.paperId=p.paperId and r.contactId={$this->contactId})";
             if ($tag_seeall) {
                 $q .= "\nwhere p.timeSubmitted>0";
             } else {
                 $q .= "\nleft join PaperConflict pc on (pc.paperId=p.paperId and pc.contactId={$this->contactId})\n                where p.timeSubmitted>0 and (pc.conflictType is null or p.managerContactId={$this->contactId})";
             }
             $result = Dbl::qe($q, $Conf->track_tags());
             while ($result && ($prow = PaperInfo::fetch($result, $this))) {
                 if ((int) $prow->reviewType >= REVIEW_PC || $Conf->check_tracks($prow, $this, Track::VIEW)) {
                     $pids[] = (int) $prow->paperId;
                 }
             }
             Dbl::free($result);
             return $pids;
         } else {
             if (!$this->privChair && !$tag_seeall) {
                 $q = "select p.paperId from Paper p\n                left join PaperConflict pc on (pc.paperId=p.paperId and pc.contactId={$this->contactId})\n                where p.timeSubmitted>0 and ";
                 if ($Conf->has_any_manager()) {
                     $q .= "(pc.conflictType is null or p.managerContactId={$this->contactId})";
                 } else {
                     $q .= "pc.conflictType is null";
                 }
             } else {
                 if ($this->privChair && $Conf->has_any_manager() && !$tag_seeall) {
                     $q = "select p.paperId from Paper p\n                left join PaperConflict pc on (pc.paperId=p.paperId and pc.contactId={$this->contactId})\n                where p.timeSubmitted>0 and (pc.conflictType is null or p.managerContactId={$this->contactId} or p.managerContactId=0)";
                 } else {
                     $q = "select p.paperId from Paper p where p.timeSubmitted>0";
                 }
             }
         }
     }
     $result = Dbl::qe($q);
     while ($row = edb_row($result)) {
         $pids[] = (int) $row[0];
     }
     Dbl::free($result);
     return $pids;
 }
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 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;
 }
Example #26
0
function admin_home_messages()
{
    global $Opt, $Conf;
    $m = array();
    $errmarker = "<span class=\"error\">Error:</span> ";
    if (preg_match("/^(?:[1-4]\\.|5\\.[012])/", phpversion())) {
        $m[] = $errmarker . "HotCRP requires PHP version 5.3 or higher.  You are running PHP version " . htmlspecialchars(phpversion()) . ".";
    }
    if (get_magic_quotes_gpc()) {
        $m[] = $errmarker . "The PHP <code>magic_quotes_gpc</code> feature is on, which is a bad idea.  Check that your Web server is using HotCRP’s <code>.htaccess</code> file.  You may also want to disable <code>magic_quotes_gpc</code> in your <code>php.ini</code> configuration file.";
    }
    if (get_magic_quotes_runtime()) {
        $m[] = $errmarker . "The PHP <code>magic_quotes_runtime</code> feature is on, which is a bad idea.  Check that your Web server is using HotCRP’s <code>.htaccess</code> file.  You may also want to disable <code>magic_quotes_runtime</code> in your <code>php.ini</code> configuration file.";
    }
    if (defined("JSON_HOTCRP")) {
        $m[] = "Your PHP was built without JSON functionality. HotCRP is using its built-in replacements; the native functions would be faster.";
    }
    if ((int) $Opt["globalSessionLifetime"] < $Opt["sessionLifetime"]) {
        $m[] = "PHP’s systemwide <code>session.gc_maxlifetime</code> setting, which is " . htmlspecialchars($Opt["globalSessionLifetime"]) . " seconds, is less than HotCRP’s preferred session expiration time, which is " . $Opt["sessionLifetime"] . " seconds.  You should update <code>session.gc_maxlifetime</code> in the <code>php.ini</code> file or users may be booted off the system earlier than you expect.";
    }
    if (!function_exists("imagecreate")) {
        $m[] = $errmarker . "This PHP installation lacks support for the GD library, so HotCRP cannot generate score charts (as backup for browsers that don’t support &lt;canvas&gt;). You should update your PHP installation. For example, on Ubuntu Linux, install the <code>php5-gd</code> package.";
    }
    $result = $Conf->qx("show variables like 'max_allowed_packet'");
    $max_file_size = ini_get_bytes("upload_max_filesize");
    if (($row = edb_row($result)) && $row[1] < $max_file_size && !@$Opt["dbNoPapers"]) {
        $m[] = $errmarker . "MySQL’s <code>max_allowed_packet</code> setting, which is " . htmlspecialchars($row[1]) . "&nbsp;bytes, is less than the PHP upload file limit, which is {$max_file_size}&nbsp;bytes.  You should update <code>max_allowed_packet</code> in the system-wide <code>my.cnf</code> file or the system may not be able to handle large papers.";
    }
    // Conference names
    if (@$Opt["shortNameDefaulted"]) {
        $m[] = "<a href=\"" . hoturl("settings", "group=msg") . "\">Set the conference abbreviation</a> to a short name for your conference, such as “OSDI ’14”.";
    } else {
        if (simplify_whitespace($Opt["shortName"]) != $Opt["shortName"]) {
            $m[] = "The <a href=\"" . hoturl("settings", "group=msg") . "\">conference abbreviation</a> setting has a funny value. To fix it, remove leading and trailing spaces, use only space characters (no tabs or newlines), and make sure words are separated by single spaces (never two or more).";
        }
    }
    $site_contact = Contact::site_contact();
    if (!$site_contact->email || $site_contact->email == "*****@*****.**") {
        $m[] = "<a href=\"" . hoturl("settings", "group=msg") . "\">Set the conference contact’s name and email</a> so submitters can reach someone if things go wrong.";
    }
    // Backwards compatibility
    if (@$Conf->setting_data("clickthrough_submit")) {
        // delete 12/2014
        $m[] = "You need to recreate the <a href=\"" . hoturl("settings", "group=msg") . "\">clickthrough submission terms</a>.";
    }
    // Weird URLs?
    foreach (array("conferenceSite", "paperSite") as $k) {
        if (isset($Opt[$k]) && $Opt[$k] && !preg_match('`\\Ahttps?://(?:[-.~\\w:/?#\\[\\]@!$&\'()*+,;=]|%[0-9a-fA-F][0-9a-fA-F])*\\z`', $Opt[$k])) {
            $m[] = $errmarker . "The <code>\$Opt[\"{$k}\"]</code> setting, ‘<code>" . htmlspecialchars($Opt[$k]) . "</code>’, is not a valid URL.  Edit the <code>conf/options.php</code> file to fix this problem.";
        }
    }
    // Double-encoding bugs found?
    if ($Conf->setting("bug_doubleencoding")) {
        $m[] = "Double-encoded URLs have been detected. Incorrect uses of Apache’s <code>mod_rewrite</code>, and other middleware, can encode URL parameters twice. This can cause problems, for instance when users log in via links in email. (“<code>a@b.com</code>” should be encoded as “<code>a%40b.com</code>”; a double encoding will produce “<code>a%2540b.com</code>”.) HotCRP has tried to compensate, but you really should fix the problem. For <code>mod_rewrite</code> add <a href='http://httpd.apache.org/docs/current/mod/mod_rewrite.html'>the <code>[NE]</code> option</a> to the relevant RewriteRule. <a href=\"" . hoturl_post("index", "clearbug=doubleencoding") . "\">(Clear&nbsp;this&nbsp;message)</a>";
    }
    // Unnotified reviews?
    if ($Conf->setting("pcrev_assigntime", 0) > $Conf->setting("pcrev_informtime", 0)) {
        $assigntime = $Conf->setting("pcrev_assigntime");
        $result = $Conf->qe("select paperId from PaperReview where reviewType>" . REVIEW_PC . " and timeRequested>timeRequestNotified and reviewSubmitted is null and reviewNeedsSubmit!=0 limit 1");
        if (edb_nrows($result)) {
            $m[] = "PC review assignments have changed. You may want to <a href=\"" . hoturl("mail", "template=newpcrev") . "\">send mail about the new assignments</a>. <a href=\"" . hoturl_post("index", "clearnewpcrev={$assigntime}") . "\">(Clear&nbsp;this&nbsp;message)</a>";
        } else {
            $Conf->save_setting("pcrev_informtime", $assigntime);
        }
    }
    if (count($m)) {
        $Conf->warnMsg("<div>" . join('</div><div style="margin-top:0.5em">', $m) . "</div>");
    }
}
 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 user_to_json($user)
 {
     global $Conf, $Me;
     if (!$user) {
         return null;
     }
     $cj = (object) array();
     if ($user->contactId) {
         $cj->id = $user->contactId;
     }
     // keys that might come from user or contactdb
     $cdb_user = $user->contactdb_user();
     foreach (["email", "firstName", "lastName", "affiliation", "collaborators"] as $k) {
         if ($user->{$k} !== null && $user->{$k} !== "") {
             $cj->{$k} = $user->{$k};
         } else {
             if ($cdb_user && $cdb_user->{$k} !== null && $cdb_user->{$k} !== "") {
                 $cj->{$k} = $cdb_user->{$k};
             }
         }
     }
     // keys that come from user
     foreach (["preferredEmail" => "preferred_email", "voicePhoneNumber" => "phone"] as $uk => $jk) {
         if ($user->{$uk} !== null && $user->{$uk} !== "") {
             $cj->{$jk} = $user->{$uk};
         }
     }
     if ($user->disabled) {
         $cj->disabled = true;
     }
     foreach (array("address", "city", "state", "zip", "country") as $k) {
         if ($x = $user->data($k)) {
             $cj->{$k} = $x;
         }
     }
     if ($user->roles) {
         $cj->roles = (object) array();
         if ($user->roles & Contact::ROLE_CHAIR) {
             $cj->roles->chair = $cj->roles->pc = true;
         } else {
             if ($user->roles & Contact::ROLE_PC) {
                 $cj->roles->pc = true;
             }
         }
         if ($user->roles & Contact::ROLE_ADMIN) {
             $cj->roles->sysadmin = true;
         }
     }
     if ($user->defaultWatch) {
         $cj->follow = (object) array();
         if ($user->defaultWatch & (WATCH_COMMENT | WATCH_ALLCOMMENTS)) {
             $cj->follow->reviews = true;
         }
         if ($user->defaultWatch & WATCH_ALLCOMMENTS) {
             $cj->follow->allreviews = true;
         }
         if ($user->defaultWatch & WATCHTYPE_FINAL_SUBMIT << WATCHSHIFT_ALL) {
             $cj->follow->allfinal = true;
         }
     }
     if ($tags = $user->viewable_tags($Me)) {
         $tagger = new Tagger();
         $cj->tags = explode(" ", $tagger->unparse($tags));
     }
     if ($user->roles & Contact::ROLE_PC && $user->contactId && ($tm = $Conf->topic_map()) && count($tm)) {
         $result = $Conf->qe("select topicId, " . $Conf->query_topic_interest() . " from TopicInterest where contactId={$user->contactId}");
         $topics = (object) array();
         while ($row = edb_row($result)) {
             $k = $row[0];
             $topics->{$k} = (int) $row[1];
         }
         if (count(get_object_vars($topics))) {
             $cj->topics = $topics;
         }
     }
     return $cj;
 }
 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 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;
 }