function apply($pid, $contact, &$req, AssignmentState $state) { if (!($tag = get($req, "tag"))) { return "Tag missing."; } // index argument $xindex = get($req, "index"); if ($xindex === null) { $xindex = get($req, "value"); } if ($xindex !== null && ($xindex = trim($xindex)) !== "") { $tag = preg_replace(',\\A(#?.+)(?:[=!<>]=?|#|≠|≤|≥)(?:|-?\\d+(?:\\.\\d*)?|-?\\.\\d+|any|all|none|clear)\\z,i', '$1', $tag); if (!preg_match(',\\A(?:[=!<>]=?|#|≠|≤|≥),i', $xindex)) { $xindex = "#" . $xindex; } $tag .= $xindex; } // tag parsing; see also PaperSearch::_check_tag if ($tag[0] === "#") { $tag = substr($tag, 1); } $m = array(null, "", "", "", ""); $xtag = $tag; if (preg_match(',\\A(.*?)([=!<>]=?|#|≠|≤|≥)(.*?)\\z,', $xtag, $xm)) { list($xtag, $m[3], $m[4]) = array($xm[1], $xm[2], $xm[3]); } if (!preg_match(',\\A(|[^#]*~)([a-zA-Z!@*_:.]+[-a-zA-Z0-9!@*_:.\\/]*)\\z,i', $xtag, $xm)) { return "Invalid tag “" . htmlspecialchars($xtag) . "”."; } else { if ($m[3] && $m[4] === "") { return "Value missing."; } else { if ($m[3] && !preg_match(',\\A([-+]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)|any|all|none|clear)\\z,', $m[4])) { return "Value must be a number."; } else { list($m[1], $m[2]) = array($xm[1], $xm[2]); } } } if ($m[1] == "~" || strcasecmp($m[1], "me~") == 0) { $m[1] = ($contact && $contact->contactId ?: $state->contact->contactId) . "~"; } // ignore attempts to change vote tags if (!$m[1] && TagInfo::is_votish($m[2])) { return false; } // add and remove use different paths $isadd = $this->isadd && $m[4] !== "none" && $m[4] !== "clear"; if ($isadd && strpos($tag, "*") !== false) { return "Tag wildcards aren’t allowed when adding tags."; } if (!$isadd) { return $this->apply_remove($pid, $contact, $state, $m); } // resolve twiddle portion if ($m[1] && $m[1] != "~~" && !ctype_digit(substr($m[1], 0, strlen($m[1]) - 1))) { $c = substr($m[1], 0, strlen($m[1]) - 1); $twiddlecids = ContactSearch::make_pc($c, $state->contact->contactId)->ids; if (count($twiddlecids) == 0) { return "“" . htmlspecialchars($c) . "” doesn’t match a PC member."; } else { if (count($twiddlecids) > 1) { return "“" . htmlspecialchars($c) . "” matches more than one PC member; be more specific to disambiguate."; } } $m[1] = $twiddlecids[0] . "~"; } // resolve tag portion if (preg_match(',\\A(?:none|any|all)\\z,i', $m[2])) { return "Tag “{$tag}” is reserved."; } $tag = $m[1] . $m[2]; // resolve index portion if ($m[3] && $m[3] != "#" && $m[3] != "=" && $m[3] != "==") { return "“" . htmlspecialchars($m[3]) . "” isn’t allowed when adding tags."; } if ($this->isadd === self::NEXT || $this->isadd === self::NEXTSEQ) { $index = $this->apply_next_index($pid, $tag, $state, $m); } else { $index = $m[3] ? cvtnum($m[4], 0) : null; } // if you can't view the tag, you can't set the tag // (information exposure) if (!$state->contact->can_view_tag($state->prow($pid), $tag, $state->override)) { return $this->cannot_view_error($state, $pid, $tag); } // save assignment $ltag = strtolower($tag); if ($index === null && ($x = $state->query(array("type" => "tag", "pid" => $pid, "ltag" => $ltag)))) { $index = $x[0]["_index"]; } $vtag = TagInfo::votish_base($tag); if ($vtag && TagInfo::is_vote($vtag) && !$index) { $state->remove(array("type" => "tag", "pid" => $pid, "ltag" => $ltag)); } else { $state->add(array("type" => "tag", "pid" => $pid, "ltag" => $ltag, "_tag" => $tag, "_index" => $index ?: 0)); } if ($vtag) { $this->account_votes($pid, $vtag, $state); } }
function can_view_any_peruser_tags($tag) { return $this->privChair || $this->isPC && TagInfo::is_votish($tag); }
public function link($tag) { if (ctype_digit($tag[0])) { $x = strlen($this->_contactId); if (substr($tag, 0, $x) != $this->_contactId || $tag[$x] !== "~") { return false; } $tag = substr($tag, $x); } $base = TagInfo::base($tag); if (TagInfo::has_votish() && (TagInfo::is_votish($base) || $base[0] === "~" && TagInfo::is_vote(substr($base, 1)))) { $q = "#{$base} showsort:-#{$base}"; } else { if ($base === $tag) { $q = "#{$base}"; } else { $q = "order:#{$base}"; } } return hoturl("search", ["q" => $q]); }