Skip to content

Commit

Permalink
Add preference_min and preference_max advanced settings.
Browse files Browse the repository at this point in the history
  • Loading branch information
kohler committed Feb 14, 2024
1 parent ea5adc1 commit 6f34d8b
Show file tree
Hide file tree
Showing 5 changed files with 122 additions and 56 deletions.
1 change: 1 addition & 0 deletions batch/makedist.sh
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ src/settings/s_json.php
src/settings/s_messages.php
src/settings/s_namedsearch.php
src/settings/s_options.php
src/settings/s_preference.php
src/settings/s_response.php
src/settings/s_review.php
src/settings/s_reviewfieldcondition.php
Expand Down
12 changes: 12 additions & 0 deletions etc/settinginfo.json
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,18 @@
"type": "htmlstring", "size": 20, "default_value": "auto",
"parser_class": "Messages_SettingParser"
},
{
"name": "preference_min", "storage": "pref_min",
"title": "Minimum allowed review preference",
"type": "int", "default_value": -1000000,
"parser_class": "Preference_SettingParser"
},
{
"name": "preference_max", "storage": "pref_max",
"title": "Maximum allowed review preference",
"type": "int", "default_value": 1000000,
"parser_class": "Preference_SettingParser"
},
{
"name": "submission_edit_message", "storage": "msg.submit",
"title": "Submission edit message",
Expand Down
98 changes: 61 additions & 37 deletions src/assigners/a_preference.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,53 +69,66 @@ function allow_user(PaperInfo $prow, Contact $user, $req, AssignmentState $state
static private function make_exp($exp) {
return $exp === null ? "N" : +$exp;
}
/** @return ?array{int,?int} */
static function parse($str) {
if ($str === "" || strcasecmp($str, "none") == 0) {
return [0, null];
} else if (is_numeric($str)) {
$str = (float) $str;
if ($str <= 1000000) {
return [(int) round($str), null];
} else {
return null;
}
/** @return ?array{float,?int} */
static function parsef($str) {
$str = trim($str);
if ($str === "") {
return [0.0, null];
}

$str = rtrim(preg_replace('{(?:\A\s*[\"\'`]\s*|\s*[\"\'`]\s*\z|\s+(?=[-+\d.xyz]))}i', "", $str));
if ($str === "" || strcasecmp($str, "none") == 0 || strcasecmp($str, "n/a") == 0) {
return [0, null];
} else if (strspn($str, "-") === strlen($str)) {
return [-strlen($str), null];
} else if (strspn($str, "+") === strlen($str)) {
return [strlen($str), null];
} else if (preg_match('{\A(?:--?(?=-[\d.])|\+(?=\+?[\d.])|)([-+]?(?:\d+(?:\.\d*)?|\.\d+)|)([xyz]?)(?:[-+]|)\z}i', $str, $m)) {
if ($m[1] === "") {
$p = 0;
} else if ((float) $m[1] <= 1000000) {
$p = (int) round((float) $m[1]);
} else {
return null;
if (is_numeric($str)) {
return [floatval($str), null];
}
if (strpos($str, "\xE2") !== false) {
$str = preg_replace('/\xE2(?:\x88\x92|\x80\x93|\x80\x94)/', "-", $str);
}
if (preg_match('/\A(?:[\"\'`]\s*+|)(-\s*+(?:-\s*+|)(?=[\d.])|\+\s*+(?:\+\s*+|)(?=[\d.])|)(\d++(?:\.\d*+|)|\.\d++|(?=[cnx-z]))\s*([x-z]?|c|conflict|none|n\/a|)(?:\s*+[\"\'`]|)\z/i', $str, $m)) {
// $m[1] sign; $m[2] preference; $m[3] expertise
$exp = null;
if ($m[3] !== "") {
$exps = strtolower($m[3]);
if ($exps >= "x" && $exps <= "z") {
$exp = 9 - (ord($exps) & 15);
} else if ($exps === "none" || $exps === "n/a") {
return [0.0, null];
} else {
return [-100.0, null];
}
}
if ($m[2] === "") {
$e = null;
$pref = 0.0;
} else {
$e = 9 - (ord($m[2]) & 15);
$pref = floatval($m[2]);
if ($m[1] !== "" && str_starts_with($m[1], "-")) {
$pref = -$pref;
}
}
return [$p, $e];
} else if (strcasecmp($str, "conflict") == 0) {
return [-100, null];
return [$pref, $exp];
}
$str = preg_replace('/\s++(?=[-+])/', "", $str);
if (strspn($str, "-") === strlen($str)) {
return [(float) -strlen($str), null];
} else if (strspn($str, "+") === strlen($str)) {
return [(float) strlen($str), null];
} else {
$str2 = str_replace(["\xE2\x88\x92", "", ""], ["-", "-", "-"], $str);
return $str === $str2 ? null : self::parse($str2);
return null;
}
}
/** @return ?array{int,?int} */
static function parse($str) {
$x = self::parsef($str);
if ($x !== null && $x[0] > -1000000.5 && $x[0] < 1000000.5) {
return [(int) round($x[0]), $x[1]];
} else {
return null;
}
}
function apply(PaperInfo $prow, Contact $contact, $req, AssignmentState $state) {
$pref = $req["preference"];
if ($pref === null) {
return new AssignmentError("<0>Preference missing");
}
$ppref = self::parse($pref);

$ppref = self::parsef($pref);
if ($ppref === null) {
if (preg_match('/([+-]?)\s*(\d+)\s*([xyz]?)/i', $pref, $m)) {
$msg = $state->conf->_("<0>Invalid preference ‘{}’. Did you mean ‘{}’?", $pref, $m[1] . $m[2] . strtoupper($m[3]));
Expand All @@ -125,6 +138,15 @@ function apply(PaperInfo $prow, Contact $contact, $req, AssignmentState $state)
$state->user_error($msg);
return false;
}

$min = $prow->conf->setting("pref_min") ?? -1000000;
$max = $prow->conf->setting("pref_max") ?? 1000000;
if ($ppref[0] !== -100.0 && ($ppref[0] < $min || $ppref[0] > $max)) {
$state->user_error($state->conf->_("<0>Preference ‘{}’ out of range (must be between {} and {})", $ppref[0], $min, $max));
return false;
}
$prefv = (int) round($ppref[0]);

if ($prow->timeWithdrawn > 0) {
$state->warning("<5>" . $prow->make_whynot(["withdrawn" => 1])->unparse_html());
}
Expand All @@ -135,12 +157,14 @@ function apply(PaperInfo $prow, Contact $contact, $req, AssignmentState $state)
$state->user_error($state->conf->_("<0>Invalid expertise ‘{}’", $exp));
return false;
}
$ppref[1] = $pexp[1];
$expv = $pexp[1];
} else {
$expv = $ppref[1];
}

$state->remove(new Preference_Assignable($prow->paperId, $contact->contactId));
if ($ppref[0] || $ppref[1] !== null) {
$state->add(new Preference_Assignable($prow->paperId, $contact->contactId, $ppref[0], self::make_exp($ppref[1])));
if ($prefv !== 0 || $expv !== null) {
$state->add(new Preference_Assignable($prow->paperId, $contact->contactId, $prefv, self::make_exp($expv)));
}
return true;
}
Expand Down
24 changes: 24 additions & 0 deletions src/settings/s_preference.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php
// settings/s_preference.php -- HotCRP preference settings
// Copyright (c) 2006-2024 Eddie Kohler; see LICENSE.

class Preference_SettingParser extends SettingParser {
function apply_req(Si $si, SettingValues $sv) {
if ($si->name === "preference_min") {
$v = $sv->newv($si);
if ($v < -1000000) {
$sv->error_at($si->name, "<0>Minimum preference must be at least -1000000");
} else if ($v > 0) {
$sv->error_at($si->name, "<0>Minimum preference cannot be greater than 0");
}
} else if ($si->name === "preference_max") {
$v = $sv->newv($si);
if ($v > 1000000) {
$sv->error_at($si->name, "<0>Maximum preference must be at most 1000000");
} else if ($v < 0) {
$sv->error_at($si->name, "<0>Maximum preference cannot be less than 0");
}
}
return false;
}
}
43 changes: 24 additions & 19 deletions test/t_unit.php
Original file line number Diff line number Diff line change
Expand Up @@ -740,25 +740,30 @@ function test_parse_interval() {
}

function test_parse_preference() {
xassert_eqq(Preference_AssignmentParser::parse("--2"), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse("--3 "), [-3, null]);
xassert_eqq(Preference_AssignmentParser::parse("\"--2\""), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse("\"-2-\""), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse("`-2-`"), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse(" - 2"), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse(" – 2"), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse(" — 2"), [-2, null]);
xassert_eqq(Preference_AssignmentParser::parse(" — 2--"), null);
xassert_eqq(Preference_AssignmentParser::parse("+0.2"), [0, null]);
xassert_eqq(Preference_AssignmentParser::parse("-2x"), [-2, 1]);
xassert_eqq(Preference_AssignmentParser::parse("-2 Y"), [-2, 0]);
xassert_eqq(Preference_AssignmentParser::parse("- - - -Y"), null);
xassert_eqq(Preference_AssignmentParser::parse("- - - -"), [-4, null]);
xassert_eqq(Preference_AssignmentParser::parse("++"), [2, null]);
xassert_eqq(Preference_AssignmentParser::parse("+ 2+"), [2, null]);
xassert_eqq(Preference_AssignmentParser::parse("xsaonaif"), null);
xassert_eqq(Preference_AssignmentParser::parse("NONE"), [0, null]);
xassert_eqq(Preference_AssignmentParser::parse("CONFLICT"), [-100, null]);
xassert_eqq(Preference_AssignmentParser::parsef("--2"), [-2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("--3 "), [-3.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("\"--2\""), [-2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("\"-2-\""), null);
xassert_eqq(Preference_AssignmentParser::parsef("`-2-`"), null);
xassert_eqq(Preference_AssignmentParser::parsef(" - 2"), [-2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef(" – 2"), [-2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef(" — 2"), [-2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef(" — 2--"), null);
xassert_eqq(Preference_AssignmentParser::parsef("+0.2"), [0.2, null]);
xassert_eqq(Preference_AssignmentParser::parsef("-2x"), [-2.0, 1]);
xassert_eqq(Preference_AssignmentParser::parsef("-2 Y"), [-2.0, 0]);
xassert_eqq(Preference_AssignmentParser::parsef("- 3z "), [-3.0, -1]);
xassert_eqq(Preference_AssignmentParser::parsef("- - - -Y"), null);
xassert_eqq(Preference_AssignmentParser::parsef("- - - -"), [-4.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("++"), [2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("+ 2"), [2.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("+ 2+"), null);
xassert_eqq(Preference_AssignmentParser::parsef("xsaonaif"), null);
xassert_eqq(Preference_AssignmentParser::parsef("NONE"), [0.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("n/a"), [0.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("x"), [0.0, 1]);
xassert_eqq(Preference_AssignmentParser::parsef("c"), [-100.0, null]);
xassert_eqq(Preference_AssignmentParser::parsef("CONFLICT"), [-100.0, null]);
}

function test_span_balanced_parens() {
Expand Down

0 comments on commit 6f34d8b

Please sign in to comment.