function requestReview($email)
{
    global $Conf, $Me, $Error, $prow;
    $Them = Contact::create(array("name" => @$_REQUEST["name"], "email" => $email));
    if (!$Them) {
        if (trim($email) === "" || !validate_email($email)) {
            Conf::msg_error("“" . htmlspecialchars(trim($email)) . "” is not a valid email address.");
            $Error["email"] = true;
        } else {
            Conf::msg_error("Error while finding account for “" . htmlspecialchars(trim($email)) . ".”");
        }
        return false;
    }
    $reason = trim(defval($_REQUEST, "reason", ""));
    $round = $Conf->current_round();
    if (isset($_REQUEST["round"]) && $_REQUEST["round"] != "" && ($rname = $Conf->sanitize_round_name($_REQUEST["round"])) !== false) {
        $round = $Conf->round_number($rname, false);
    }
    // look up the requester
    $Requester = $Me;
    if ($Conf->setting("extrev_chairreq")) {
        $result = Dbl::qe("select firstName, lastName, u.email, u.contactId from ReviewRequest rr join ContactInfo u on (u.contactId=rr.requestedBy) where paperId={$prow->paperId} and rr.email=?", $Them->email);
        if ($result && ($recorded_requester = Contact::fetch($result))) {
            $Requester = $recorded_requester;
        }
    }
    Dbl::qe_raw("lock tables PaperReview write, PaperReviewRefused write, ReviewRequest write, ContactInfo read, PaperConflict read, ActionLog write");
    // NB caller unlocks tables on error
    // check for outstanding review request
    if (!($result = requestReviewChecks(Text::user_html($Them), $Them->contactId))) {
        return $result;
    }
    // at this point, we think we've succeeded.
    // store the review request
    $Me->assign_review($prow->paperId, $Them->contactId, REVIEW_EXTERNAL, ["mark_notify" => true, "requester_contact" => $Requester, "requested_email" => $Them->email, "round_number" => $round]);
    Dbl::qx_raw("unlock tables");
    // send confirmation email
    HotCRPMailer::send_to($Them, "@requestreview", $prow, array("requester_contact" => $Requester, "other_contact" => $Requester, "reason" => $reason));
    $Conf->confirmMsg("Created a request to review paper #{$prow->paperId}.");
    return true;
}
function final_submit_watch_callback($prow, $minic)
{
    if ($minic->can_view_paper($prow)) {
        HotCRPMailer::send_to($minic, "@finalsubmitnotify", $prow);
    }
}
function crpmerge($MiniMe)
{
    global $Conf, $Me, $MergeError;
    if (!$MiniMe->contactId && !$Me->contactId) {
        return $MergeError = "Neither of those accounts has any data associated with this conference.";
    }
    // XXX `act as` merging might be useful?
    if (strcasecmp($Me->email, $_SESSION["trueuser"]->email)) {
        return $MergeError = "You can’t merge accounts when acting as a different user.";
    }
    // determine old & new users
    if (@$_REQUEST["prefer"]) {
        list($old_user, $new_user) = [$Me, $MiniMe];
    } else {
        list($old_user, $new_user) = [$MiniMe, $Me];
    }
    // send mail at start of process
    HotCRPMailer::send_to($old_user, "@mergeaccount", null, array("cc" => Text::user_email_to($new_user), "other_contact" => $new_user));
    // actually merge users or change email
    if ($old_user->contactId && $new_user->contactId) {
        crpmerge_database($old_user, $new_user);
    } else {
        if ($old_user->contactId) {
            $user_status = new UserStatus(["send_email" => false]);
            $user_status->save($user_status->user_to_json($new_user), $old_user);
        }
    }
    // update trueuser
    if (strcasecmp($_SESSION["trueuser"]->email, $new_user->email)) {
        $_SESSION["trueuser"] = (object) ["email" => $new_user->email];
    }
    if ($MergeError == "") {
        $Conf->confirmMsg("Merged account " . htmlspecialchars($old_user->email) . ".");
        $new_user->log_activity("Merged account {$old_user->email}");
        go(hoturl("index"));
    } else {
        $new_user->log_activity("Merged account {$old_user->email} with errors");
        $MergeError .= $Conf->db_error_html(true);
    }
}
 function cleanup(AssignmentSet $aset)
 {
     global $Conf;
     if ($this->notify) {
         $reviewer = Contact::find_by_id($this->cid);
         $prow = $Conf->paperRow(array("paperId" => $this->pid, "reviewer" => $this->cid), $reviewer);
         HotCRPMailer::send_to($reviewer, $this->notify, $prow);
     }
 }
 static function watch_callback($prow, $minic)
 {
     $ctype = self::$watching->commentType;
     if ($ctype & COMMENTTYPE_RESPONSE && $ctype & COMMENTTYPE_DRAFT) {
         $tmpl = "@responsedraftnotify";
     } else {
         if ($ctype & COMMENTTYPE_RESPONSE) {
             $tmpl = "@responsenotify";
         } else {
             $tmpl = "@commentnotify";
         }
     }
     if ($minic->can_view_comment($prow, self::$watching, false) && ($tmpl !== "@responsedraftnotify" || $minic->act_author_view($prow))) {
         HotCRPMailer::send_to($minic, $tmpl, $prow, array("comment_row" => self::$watching));
     }
 }
function refuseReview()
{
    global $Conf, $Opt, $Me, $prow, $paperTable;
    Dbl::qe_raw("lock tables PaperReview write, PaperReviewRefused write");
    $rrow = $paperTable->editrrow;
    $hadToken = defval($rrow, "reviewToken", 0) != 0;
    $result = Dbl::qe("delete from PaperReview where reviewId={$rrow->reviewId}");
    if (!$result) {
        return;
    }
    $reason = defval($_REQUEST, "reason", "");
    if ($reason == "Optional explanation") {
        $reason = "";
    }
    $result = Dbl::qe("insert into PaperReviewRefused set paperId={$rrow->paperId}, contactId={$rrow->contactId}, requestedBy={$rrow->requestedBy}, reason=?", trim($reason));
    if (!$result) {
        return;
    }
    // now the requester must potentially complete their review
    if ($rrow->reviewType < REVIEW_SECONDARY && $rrow->requestedBy > 0) {
        Contact::update_review_delegation($rrow->paperId, $rrow->requestedBy, -1);
    }
    Dbl::qe_raw("unlock tables");
    // send confirmation email
    $Requester = Contact::find_by_id($rrow->requestedBy);
    $reqprow = $Conf->paperRow($prow->paperId, $rrow->requestedBy);
    HotCRPMailer::send_to($Requester, "@refusereviewrequest", $reqprow, array("reviewer_contact" => $rrow, "reason" => $reason));
    // confirmation message
    $Conf->confirmMsg("The request that you review paper #{$prow->paperId} has been removed.  Mail was sent to the person who originally requested the review.");
    if ($hadToken) {
        $Conf->update_rev_tokens_setting(true);
    }
    $prow = null;
    confHeader();
    $Conf->footer();
    exit;
}