function _search()
 {
     global $Conf;
     if ($this->_matches === false) {
         return false;
     }
     assert($this->_matches === null);
     if ($this->limitName === "x") {
         $this->_matches = array();
         return true;
     }
     // parse and clean the query
     $qe = $this->_searchQueryType($this->q);
     //Conf::msg_info(Ht::pre_text(var_export($qe, true)));
     if (!$qe) {
         $qe = new SearchTerm("t");
     }
     // apply complex limiters (only current example: "acc" for non-chairs)
     $limit = $this->limitName;
     if ($limit === "acc" && !$this->privChair) {
         $qe = SearchTerm::make_op("and", array($qe, $this->_searchQueryWord("dec:yes", false)));
     }
     // apply review rounds (top down, needs separate step)
     if ($this->reviewAdjust) {
         $qe = $this->_query_adjust_reviews($qe, null);
         if ($this->_reviewAdjustError) {
             $this->warn("Unexpected use of “round:” or “rate:” ignored.  Stick to the basics, such as “re:reviewername round:roundname”.");
         }
     }
     //Conf::msg_info(Ht::pre_text(var_export($qe, true)));
     // collect clauses into tables, columns, and filters
     $sqi = new SearchQueryInfo();
     $sqi->add_table("Paper");
     $sqi->add_column("paperId", "Paper.paperId");
     // always include columns needed by rights machinery
     $sqi->add_column("timeSubmitted", "Paper.timeSubmitted");
     $sqi->add_column("timeWithdrawn", "Paper.timeWithdrawn");
     $sqi->add_column("outcome", "Paper.outcome");
     $filters = array();
     $this->_clauseTermSet($qe, $sqi, $filters);
     //Conf::msg_info(Ht::pre_text(var_export($filters, true)));
     // status limitation parts
     if ($limit === "rable") {
         $limitcontact = $this->_reviewer_fixed ? $this->reviewer() : $this->contact;
         if ($limitcontact->can_accept_review_assignment_ignore_conflict(null)) {
             $limit = $Conf->can_pc_see_all_submissions() ? "act" : "s";
         } else {
             if (!$limitcontact->isPC) {
                 $limit = "r";
             }
         }
     }
     if ($limit === "s" || $limit === "req" || $limit === "acc" || $limit === "und" || $limit === "unm" || $limit === "rable" && !$Conf->can_pc_see_all_submissions()) {
         $filters[] = "Paper.timeSubmitted>0";
     } else {
         if ($limit === "act" || $limit === "r" || $limit === "rable") {
             $filters[] = "Paper.timeWithdrawn<=0";
         } else {
             if ($limit === "unsub") {
                 $filters[] = "(Paper.timeSubmitted<=0 and Paper.timeWithdrawn<=0)";
             } else {
                 if ($limit === "lead") {
                     $filters[] = "Paper.leadContactId=" . $this->cid;
                 } else {
                     if ($limit === "manager") {
                         if ($this->privChair) {
                             $filters[] = "(Paper.managerContactId=" . $this->cid . " or Paper.managerContactId=0)";
                         } else {
                             $filters[] = "Paper.managerContactId=" . $this->cid;
                         }
                         $filters[] = "Paper.timeSubmitted>0";
                     }
                 }
             }
         }
     }
     // decision limitation parts
     if ($limit === "acc") {
         $filters[] = "Paper.outcome>0";
     } else {
         if ($limit === "und") {
             $filters[] = "Paper.outcome=0";
         }
     }
     // other search limiters
     if ($limit === "a") {
         $filters[] = $this->contact->actAuthorSql("PaperConflict");
         $this->needflags |= self::F_AUTHOR;
     } else {
         if ($limit === "r") {
             $filters[] = "MyReview.reviewType is not null";
             $this->needflags |= self::F_REVIEWER;
         } else {
             if ($limit === "ar") {
                 $filters[] = "(" . $this->contact->actAuthorSql("PaperConflict") . " or (Paper.timeWithdrawn<=0 and MyReview.reviewType is not null))";
                 $this->needflags |= self::F_AUTHOR | self::F_REVIEWER;
             } else {
                 if ($limit === "rout") {
                     $filters[] = "MyReview.reviewNeedsSubmit!=0";
                     $this->needflags |= self::F_REVIEWER;
                 } else {
                     if ($limit === "revs") {
                         $sqi->add_table("Limiter", array("join", "PaperReview"));
                     } else {
                         if ($limit === "req") {
                             $sqi->add_table("Limiter", array("join", "PaperReview", "Limiter.requestedBy={$this->cid} and Limiter.reviewType=" . REVIEW_EXTERNAL));
                         } else {
                             if ($limit === "unm") {
                                 $filters[] = "Paper.managerContactId=0";
                             }
                         }
                     }
                 }
             }
         }
     }
     // add common tables: conflicts, my own review, paper blindness
     if ($this->needflags & (self::F_MANAGER | self::F_NONCONFLICT | self::F_AUTHOR)) {
         $sqi->add_table("PaperConflict", array("left join", "PaperConflict", "PaperConflict.contactId={$this->cid}"));
         $sqi->add_column("conflictType", "PaperConflict.conflictType");
     }
     if ($this->needflags & self::F_REVIEWER) {
         if ($Conf->submission_blindness() == Conf::BLIND_OPTIONAL) {
             $sqi->add_column("paperBlind", "Paper.blind");
         }
         $qb = "";
         if ($tokens = $this->contact->review_tokens()) {
             $qb = " or MyReview.reviewToken in (" . join(",", $tokens) . ")";
         }
         $sqi->add_table("MyReview", array("left join", "PaperReview", "(MyReview.contactId={$this->cid}{$qb})"));
         $sqi->add_column("myReviewType", "MyReview.reviewType");
         $sqi->add_column("myReviewNeedsSubmit", "MyReview.reviewNeedsSubmit");
         $sqi->add_column("myReviewSubmitted", "MyReview.reviewSubmitted");
     }
     // check for annotated order
     $order_anno_tag = null;
     if ($qe->type !== "then" && ($sort = $qe->get_float("sort")) && ($tag = self::_check_sort_order_anno($sort))) {
         $dt = TagInfo::make_defined_tag($tag);
         if (count($dt->order_anno_list())) {
             $order_anno_tag = $dt;
         }
     }
     // add permissions tables if we will filter the results
     $need_filter = $this->needflags & self::F_XVIEW || $Conf->has_tracks() || $qe->type === "then" || $qe->get_float("heading") || $limit === "rable" || $order_anno_tag;
     if ($need_filter) {
         $sqi->add_rights_columns();
         if ($Conf->submission_blindness() == Conf::BLIND_OPTIONAL) {
             $sqi->add_column("paperBlind", "Paper.blind");
         }
     }
     // XXX some of this should be shared with paperQuery
     if ($need_filter && $Conf->has_track_tags() || get($this->_query_options, "tags") || $order_anno_tag) {
         $sqi->add_column("paperTags", "(select group_concat(' ', tag, '#', tagIndex separator '') from PaperTag where PaperTag.paperId=Paper.paperId)");
     }
     if (get($this->_query_options, "scores") || get($this->_query_options, "reviewTypes") || get($this->_query_options, "reviewContactIds")) {
         $j = "group_concat(contactId order by reviewId) reviewContactIds";
         $sqi->add_column("reviewContactIds", "R_submitted.reviewContactIds");
         if (get($this->_query_options, "reviewTypes")) {
             $j .= ", group_concat(reviewType order by reviewId) reviewTypes";
             $sqi->add_column("reviewTypes", "R_submitted.reviewTypes");
         }
         foreach (get($this->_query_options, "scores") ?: array() as $f) {
             $j .= ", group_concat({$f} order by reviewId) {$f}Scores";
             $sqi->add_column("{$f}Scores", "R_submitted.{$f}Scores");
         }
         $sqi->add_table("R_submitted", array("left join", "(select paperId, {$j} from PaperReview where reviewSubmitted>0 group by paperId)"));
     }
     // create query
     $q = "select ";
     foreach ($sqi->columns as $colname => $value) {
         $q .= $value . " " . $colname . ", ";
     }
     $q = substr($q, 0, strlen($q) - 2) . "\n    from ";
     foreach ($sqi->tables as $tabname => $value) {
         if (!$value) {
             $q .= $tabname;
         } else {
             $joiners = array("{$tabname}.paperId=Paper.paperId");
             for ($i = 2; $i < count($value); ++$i) {
                 $joiners[] = "(" . $value[$i] . ")";
             }
             $q .= "\n    " . $value[0] . " " . $value[1] . " as " . $tabname . " on (" . join("\n        and ", $joiners) . ")";
         }
     }
     if (count($filters)) {
         $q .= "\n    where " . join("\n        and ", $filters);
     }
     $q .= "\n    group by Paper.paperId";
     //Conf::msg_info(Ht::pre_text_wrap($q));
     // actually perform query
     $result = Dbl::qe_raw($q);
     if (!$result) {
         return $this->_matches = false;
     }
     $this->_matches = array();
     // correct query, create thenmap, groupmap, highlightmap
     $need_then = $qe->type === "then";
     $this->thenmap = null;
     if ($need_then && $qe->nthen > 1) {
         $this->thenmap = array();
     }
     $this->highlightmap = array();
     if ($need_filter) {
         $tag_order = [];
         while ($row = PaperInfo::fetch($result, $this->cid)) {
             if (!$this->contact->can_view_paper($row) || $limit === "rable" && !$limitcontact->can_accept_review_assignment_ignore_conflict($row)) {
                 $x = false;
             } else {
                 if ($need_then) {
                     $x = false;
                     for ($i = 0; $i < $qe->nthen && $x === false; ++$i) {
                         if ($this->_clauseTermCheck($qe->value[$i], $row)) {
                             $x = $i;
                         }
                     }
                 } else {
                     $x = !!$this->_clauseTermCheck($qe, $row);
                 }
             }
             if ($x === false) {
                 continue;
             }
             $this->_matches[] = $row->paperId;
             if ($this->thenmap !== null) {
                 $this->thenmap[$row->paperId] = $x;
             }
             if ($need_then) {
                 for ($j = $qe->nthen; $j < count($qe->value); ++$j) {
                     if ($this->_clauseTermCheck($qe->value[$j], $row) && $qe->highlights[$j - $qe->nthen] & 1 << $x) {
                         $this->highlightmap[$row->paperId] = $qe->highlight_types[$j - $qe->nthen] . "highlight";
                         break;
                     }
                 }
             }
             if ($order_anno_tag) {
                 if ($row->has_viewable_tag($order_anno_tag->tag, $this->contact)) {
                     $tag_order[] = [$row->paperId, $row->tag_value($order_anno_tag->tag)];
                 } else {
                     $tag_order[] = [$row->paperId, TAG_INDEXBOUND];
                 }
             }
         }
     } else {
         while ($row = $result->fetch_object()) {
             $this->_matches[] = (int) $row->paperId;
         }
     }
     Dbl::free($result);
     // add deleted papers explicitly listed by number (e.g. action log)
     if ($this->_allow_deleted) {
         $this->_add_deleted_papers($qe);
     }
     // view and sort information
     $this->viewmap = $qe->get_float("view", array());
     $this->sorters = array();
     $this->_add_sorters($qe, null);
     if ($qe->type === "then") {
         for ($i = 0; $i < $qe->nthen; ++$i) {
             $this->_add_sorters($qe->value[$i], $this->thenmap ? $i : null);
         }
     }
     $this->groupmap = [];
     if ($qe->type === "then") {
         for ($i = 0; $i < $qe->nthen; ++$i) {
             $h = $qe->value[$i]->get_float("heading");
             $this->groupmap[$i] = (object) ["heading" => $h, "annoFormat" => 0];
         }
     } else {
         if ($h = $qe->get_float("heading")) {
             $this->groupmap[0] = (object) ["heading" => $h, "annoFormat" => 0];
         } else {
             if ($order_anno_tag) {
                 $this->_assign_order_anno($order_anno_tag, $tag_order);
                 $this->is_order_anno = $order_anno_tag->tag;
             }
         }
     }
     // extract regular expressions and set _reviewer if the query is
     // about exactly one reviewer, and warn about contradictions
     $contradictions = array();
     $this->_queryExtractInfo($qe, true, false, $contradictions);
     foreach ($contradictions as $contradiction => $garbage) {
         $this->warn($contradiction);
     }
     // set $this->matchPreg from $this->regex
     if (!$this->overrideMatchPreg) {
         $this->matchPreg = array();
         foreach (array("ti" => "title", "au" => "authorInformation", "ab" => "abstract", "co" => "collaborators") as $k => $v) {
             if (isset($this->regex[$k]) && count($this->regex[$k])) {
                 $a = $b = array();
                 foreach ($this->regex[$k] as $x) {
                     $a[] = $x->preg_utf8;
                     if (isset($x->preg_raw)) {
                         $b[] = $x->preg_raw;
                     }
                 }
                 $x = (object) array("preg_utf8" => join("|", $a));
                 if (count($a) == count($b)) {
                     $x->preg_raw = join("|", $b);
                 }
                 $this->matchPreg[$v] = $x;
             }
         }
     }
     return true;
 }
예제 #2
0
 static function taganno_api($user, $qreq, $prow)
 {
     global $Conf;
     $tagger = new Tagger($user);
     if (!($tag = $tagger->check($qreq->tag, Tagger::NOVALUE))) {
         json_exit(["ok" => false, "error" => $tagger->error_html]);
     }
     $j = ["ok" => true, "tag" => $tag, "editable" => $user->can_change_tag_anno($tag), "anno" => []];
     $dt = TagInfo::make_defined_tag($tag);
     foreach ($dt->order_anno_list() as $oa) {
         if ($oa->annoId !== null) {
             $j["anno"][] = TagInfo::unparse_anno_json($oa);
         }
     }
     json_exit($j);
 }