mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-30 01:10:58 +01:00
Require a viewer to load handles
Summary: Unmuck almost all of the we-sort-of-have-viewers-some-of-the-time mess. There are a few notable cases here: - I used Omnipotent users when indexing objects for search. I think this is correct; we do policy filtering when showing results. - I cheated in a bad way in the Remarkup object rule, but fixing this requires fixing all the PhabricatorRemarkupEngine callsites (there are 85). I'll do that in the next diff. - I cheated in a few random places, like when sending mail about package edits. These aren't a big deal. Test Plan: - Grepped for all PhabricatorObjectHandleData references. - Gave them viewers. Reviewers: vrana Reviewed By: vrana CC: aran, edward Maniphest Tasks: T603 Differential Revision: https://secure.phabricator.com/D5151
This commit is contained in:
parent
e3567b2d4d
commit
0a069cb55a
66 changed files with 206 additions and 72 deletions
|
@ -1001,6 +1001,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php',
|
||||
'PhabricatorMacroTransactionType' => 'applications/macro/constants/PhabricatorMacroTransactionType.php',
|
||||
'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php',
|
||||
'PhabricatorMail' => 'applications/metamta/PhabricatorMail.php',
|
||||
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php',
|
||||
'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php',
|
||||
|
@ -1846,6 +1847,7 @@ phutil_register_library_map(array(
|
|||
'DifferentialLinesFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialLintFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialLocalCommitsView' => 'AphrontView',
|
||||
'DifferentialMail' => 'PhabricatorMail',
|
||||
'DifferentialManiphestTasksFieldSpecification' => 'DifferentialFieldSpecification',
|
||||
'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail',
|
||||
'DifferentialParseRenderTestCase' => 'PhabricatorTestCase',
|
||||
|
@ -2120,6 +2122,7 @@ phutil_register_library_map(array(
|
|||
'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler',
|
||||
'PackageCreateMail' => 'PackageMail',
|
||||
'PackageDeleteMail' => 'PackageMail',
|
||||
'PackageMail' => 'PhabricatorMail',
|
||||
'PackageModifyMail' => 'PackageMail',
|
||||
'Phabricator404Controller' => 'PhabricatorController',
|
||||
'PhabricatorAWSConfigOptions' => 'PhabricatorApplicationConfigOptions',
|
||||
|
@ -3017,6 +3020,7 @@ phutil_register_library_map(array(
|
|||
'PonderController' => 'PhabricatorController',
|
||||
'PonderDAO' => 'PhabricatorLiskDAO',
|
||||
'PonderFeedController' => 'PonderController',
|
||||
'PonderMail' => 'PhabricatorMail',
|
||||
'PonderMentionMail' => 'PonderMail',
|
||||
'PonderPostBodyView' => 'AphrontView',
|
||||
'PonderQuestion' =>
|
||||
|
|
|
@ -437,7 +437,9 @@ final class PhabricatorAuditCommentEditor extends PhabricatorEditor {
|
|||
$email_cc = array_keys($email_cc);
|
||||
|
||||
$phids = array_merge($email_to, $email_cc);
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
|
||||
// NOTE: Always set $is_new to false, because the "first" mail in the
|
||||
// thread is the Herald notification of the commit.
|
||||
|
|
|
@ -157,6 +157,7 @@ class DifferentialReplyHandler extends PhabricatorMailReplyHandler {
|
|||
$ex,
|
||||
$error_body);
|
||||
|
||||
$exception_mail->setActor($this->getActor());
|
||||
$exception_mail->setToPHIDs(array($this->getActor()->getPHID()));
|
||||
$exception_mail->send();
|
||||
|
||||
|
|
|
@ -49,6 +49,7 @@ final class ConduitAPI_differential_getcommitmessage_Method
|
|||
->getFieldSpecifications();
|
||||
|
||||
foreach ($aux_fields as $key => $aux_field) {
|
||||
$aux_field->setUser($request->getUser());
|
||||
$aux_field->setRevision($revision);
|
||||
if (!$aux_field->shouldAppearOnCommitMessage()) {
|
||||
unset($aux_fields[$key]);
|
||||
|
@ -87,7 +88,9 @@ final class ConduitAPI_differential_getcommitmessage_Method
|
|||
$aux_phids[$field_key] = $field->getRequiredHandlePHIDsForCommitMessage();
|
||||
}
|
||||
$phids = array_unique(array_mergev($aux_phids));
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($request->getUser())
|
||||
->loadHandles();
|
||||
foreach ($aux_fields as $field_key => $field) {
|
||||
$field->setHandles(array_select_keys($handles, $aux_phids[$field_key]));
|
||||
}
|
||||
|
|
|
@ -61,6 +61,7 @@ final class ConduitAPI_differential_getrevision_Method
|
|||
$commit_dicts = array();
|
||||
$commit_phids = $revision->loadCommitPHIDs();
|
||||
$handles = id(new PhabricatorObjectHandleData($commit_phids))
|
||||
->setViewer($request->getUser())
|
||||
->loadHandles();
|
||||
|
||||
foreach ($commit_phids as $commit_phid) {
|
||||
|
@ -70,7 +71,9 @@ final class ConduitAPI_differential_getrevision_Method
|
|||
);
|
||||
}
|
||||
|
||||
$auxiliary_fields = $this->loadAuxiliaryFields($revision);
|
||||
$auxiliary_fields = $this->loadAuxiliaryFields(
|
||||
$revision,
|
||||
$request->getUser());
|
||||
|
||||
$dict = array(
|
||||
'id' => $revision->getID(),
|
||||
|
@ -94,10 +97,13 @@ final class ConduitAPI_differential_getrevision_Method
|
|||
return $dict;
|
||||
}
|
||||
|
||||
private function loadAuxiliaryFields(DifferentialRevision $revision) {
|
||||
private function loadAuxiliaryFields(
|
||||
DifferentialRevision $revision,
|
||||
PhabricatorUser $user) {
|
||||
$aux_fields = DifferentialFieldSelector::newSelector()
|
||||
->getFieldSpecifications();
|
||||
foreach ($aux_fields as $key => $aux_field) {
|
||||
$aux_field->setUser($user);
|
||||
if (!$aux_field->shouldAppearOnConduitView()) {
|
||||
unset($aux_fields[$key]);
|
||||
}
|
||||
|
|
|
@ -36,10 +36,10 @@ final class ConduitAPI_differential_parsecommitmessage_Method
|
|||
->getFieldSpecifications();
|
||||
|
||||
foreach ($aux_fields as $key => $aux_field) {
|
||||
$aux_field->setUser($request->getUser());
|
||||
if (!$aux_field->shouldAppearOnCommitMessage()) {
|
||||
unset($aux_fields[$key]);
|
||||
}
|
||||
$aux_field->setUser($request->getUser());
|
||||
}
|
||||
|
||||
$aux_fields = mpull($aux_fields, null, 'getCommitMessageKey');
|
||||
|
|
|
@ -430,7 +430,7 @@ final class DifferentialRevisionListController extends DifferentialController {
|
|||
|
||||
$template = id(new DifferentialRevisionListView())
|
||||
->setUser($user)
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields());
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields($user));
|
||||
|
||||
$views = array();
|
||||
switch ($filter) {
|
||||
|
@ -462,6 +462,7 @@ final class DifferentialRevisionListController extends DifferentialController {
|
|||
// looking at your own requests.
|
||||
if (in_array($user->getPHID(), $user_phids)) {
|
||||
$flags = id(new PhabricatorFlagQuery())
|
||||
->setViewer($user)
|
||||
->withOwnerPHIDs(array($user->getPHID()))
|
||||
->withTypes(array(PhabricatorPHIDConstants::PHID_TYPE_DREV))
|
||||
->needHandles(true)
|
||||
|
|
|
@ -846,10 +846,12 @@ final class DifferentialRevisionViewController extends DifferentialController {
|
|||
private function renderOtherRevisions(array $revisions) {
|
||||
assert_instances_of($revisions, 'DifferentialRevision');
|
||||
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$view = id(new DifferentialRevisionListView())
|
||||
->setRevisions($revisions)
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields())
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields($user))
|
||||
->setUser($user)
|
||||
->loadAssets();
|
||||
|
||||
$phids = $view->getRequiredHandlePHIDs();
|
||||
|
|
|
@ -553,6 +553,7 @@ final class DifferentialCommentEditor extends PhabricatorEditor {
|
|||
|
||||
$phids = array($actor_phid);
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
$actor_handle = $handles[$actor_phid];
|
||||
|
||||
|
@ -567,6 +568,7 @@ final class DifferentialCommentEditor extends PhabricatorEditor {
|
|||
$comment,
|
||||
$changesets,
|
||||
$inline_comments))
|
||||
->setActor($this->getActor())
|
||||
->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())
|
||||
->setToPHIDs(
|
||||
array_merge(
|
||||
|
|
|
@ -346,6 +346,7 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
|||
$phids = array($this->getActorPHID());
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
$actor_handle = $handles[$this->getActorPHID()];
|
||||
|
||||
|
@ -362,6 +363,7 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
|||
$revision,
|
||||
$actor_handle,
|
||||
$changesets))
|
||||
->setActor($this->getActor())
|
||||
->setIsFirstMailAboutRevision($is_new)
|
||||
->setIsFirstMailToRecipients($is_new)
|
||||
->setComments($this->getComments())
|
||||
|
@ -456,6 +458,7 @@ final class DifferentialRevisionEditor extends PhabricatorEditor {
|
|||
$revision,
|
||||
$actor_handle,
|
||||
$changesets))
|
||||
->setActor($this->getActor())
|
||||
->setIsFirstMailToRecipients(true)
|
||||
->setToPHIDs(array_keys($add['ccs']));
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ final class DifferentialArcanistProjectFieldSpecification
|
|||
if ($diff) {
|
||||
$phid = $diff->getArcanistProjectPHID();
|
||||
if ($phid) {
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle($phid);
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle(
|
||||
$phid,
|
||||
$this->getUser());
|
||||
return "ARCANIST PROJECT\n ".$handle->getName();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -163,6 +163,7 @@ final class DifferentialManiphestTasksFieldSpecification
|
|||
}
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($this->maniphestTasks))
|
||||
->setViewer($this->getUser())
|
||||
->loadHandles();
|
||||
$body = array();
|
||||
$body[] = 'MANIPHEST TASKS';
|
||||
|
|
|
@ -182,6 +182,7 @@ final class DifferentialReviewersFieldSpecification
|
|||
}
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($this->reviewers))
|
||||
->setViewer($this->getUser())
|
||||
->loadHandles();
|
||||
$handles = array_select_keys(
|
||||
$handles,
|
||||
|
|
|
@ -104,7 +104,9 @@ final class DifferentialCommentMail extends DifferentialMail {
|
|||
array());
|
||||
$load = array_merge($m_reviewers, $m_cc);
|
||||
if ($load) {
|
||||
$handles = id(new PhabricatorObjectHandleData($load))->loadHandles();
|
||||
$handles = id(new PhabricatorObjectHandleData($load))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
if ($m_reviewers) {
|
||||
$this->addedReviewers = $this->renderHandleList($handles, $m_reviewers);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
abstract class DifferentialMail {
|
||||
abstract class DifferentialMail extends PhabricatorMail {
|
||||
|
||||
protected $to = array();
|
||||
protected $cc = array();
|
||||
|
@ -133,6 +133,7 @@ abstract class DifferentialMail {
|
|||
|
||||
$reason_phids = ipull($raw, 'reasonPHID');
|
||||
$reason_handles = id(new PhabricatorObjectHandleData($reason_phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
|
||||
$explicit_cc = array();
|
||||
|
@ -172,8 +173,12 @@ abstract class DifferentialMail {
|
|||
}
|
||||
$phids = array_keys($phids);
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$objects = id(new PhabricatorObjectHandleData($phids))->loadObjects();
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
$objects = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadObjects();
|
||||
|
||||
$to_handles = array_select_keys($handles, $to_phids);
|
||||
$cc_handles = array_select_keys($handles, $cc_phids);
|
||||
|
@ -398,7 +403,7 @@ abstract class DifferentialMail {
|
|||
|
||||
$body = array();
|
||||
foreach ($aux_fields as $field) {
|
||||
$field->setUser(id(new PhabricatorUser())->setPHID('PHID-USER-XXX'));
|
||||
$field->setUser($this->getActor());
|
||||
$field->setRevision($this->getRevision());
|
||||
// TODO: Introduce and use getRequiredHandlePHIDsForMail() and load all
|
||||
// handles in prepareBody().
|
||||
|
|
|
@ -23,6 +23,7 @@ final class DifferentialSearchIndexer
|
|||
$aux_fields = DifferentialFieldSelector::newSelector()
|
||||
->getFieldSpecifications();
|
||||
foreach ($aux_fields as $key => $aux_field) {
|
||||
$aux_field->setUser(PhabricatorUser::getOmnipotentUser());
|
||||
if (!$aux_field->shouldAddToSearchIndex()) {
|
||||
unset($aux_fields[$key]);
|
||||
}
|
||||
|
@ -103,6 +104,7 @@ final class DifferentialSearchIndexer
|
|||
|
||||
$ccphids = $rev->getCCPHIDs();
|
||||
$handles = id(new PhabricatorObjectHandleData($ccphids))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles();
|
||||
|
||||
foreach ($handles as $phid => $handle) {
|
||||
|
|
|
@ -55,6 +55,7 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
}
|
||||
|
||||
$this->flags = id(new PhabricatorFlagQuery())
|
||||
->setViewer($user)
|
||||
->withOwnerPHIDs(array($user->getPHID()))
|
||||
->withObjectPHIDs(mpull($this->revisions, 'getPHID'))
|
||||
->execute();
|
||||
|
@ -184,10 +185,11 @@ final class DifferentialRevisionListView extends AphrontView {
|
|||
return $table->render();
|
||||
}
|
||||
|
||||
public static function getDefaultFields() {
|
||||
public static function getDefaultFields(PhabricatorUser $user) {
|
||||
$selector = DifferentialFieldSelector::newSelector();
|
||||
$fields = $selector->getFieldSpecifications();
|
||||
foreach ($fields as $key => $field) {
|
||||
$field->setUser($user);
|
||||
if (!$field->shouldAppearOnRevisionList()) {
|
||||
unset($fields[$key]);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ final class DiffusionBrowseController extends DiffusionController {
|
|||
$is_file = true;
|
||||
} else {
|
||||
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$browse_query->setViewer($this->getRequest()->getUser());
|
||||
$results = $browse_query->loadPaths();
|
||||
$reason = $browse_query->getReasonForEmptyResultSet();
|
||||
$is_file = ($reason == DiffusionBrowseQuery::REASON_IS_FILE);
|
||||
|
|
|
@ -98,6 +98,8 @@ abstract class DiffusionController extends PhabricatorController {
|
|||
}
|
||||
|
||||
protected function buildOpenRevisions() {
|
||||
$user = $this->getRequest()->getUser();
|
||||
|
||||
$drequest = $this->getDiffusionRequest();
|
||||
$repository = $drequest->getRepository();
|
||||
$path = $drequest->getPath();
|
||||
|
@ -122,7 +124,7 @@ abstract class DiffusionController extends PhabricatorController {
|
|||
|
||||
$view = id(new DifferentialRevisionListView())
|
||||
->setRevisions($revisions)
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields())
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields($user))
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->loadAssets();
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@ final class DiffusionPathCompleteController extends DiffusionController {
|
|||
));
|
||||
|
||||
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$browse_query->setViewer($request->getUser());
|
||||
$paths = $browse_query->loadPaths();
|
||||
|
||||
$output = array();
|
||||
|
|
|
@ -27,6 +27,7 @@ final class DiffusionPathValidateController extends DiffusionController {
|
|||
));
|
||||
|
||||
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$browse_query->setUser($request->getUser());
|
||||
$browse_query->needValidityOnly(true);
|
||||
$valid = $browse_query->loadPaths();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ final class DiffusionRepositoryController extends DiffusionController {
|
|||
$history = $history_query->loadHistory();
|
||||
|
||||
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$browse_query->setUser($this->getRequest()->getUser());
|
||||
$browse_results = $browse_query->loadPaths();
|
||||
|
||||
$phids = array();
|
||||
|
|
|
@ -8,6 +8,16 @@ abstract class DiffusionBrowseQuery {
|
|||
protected $existedAtCommit;
|
||||
protected $deletedAtCommit;
|
||||
protected $validityOnly;
|
||||
private $viewer;
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getViewer() {
|
||||
return $this->viewer;
|
||||
}
|
||||
|
||||
const REASON_IS_FILE = 'is-file';
|
||||
const REASON_IS_DELETED = 'is-deleted';
|
||||
|
@ -107,6 +117,7 @@ abstract class DiffusionBrowseQuery {
|
|||
|
||||
$content_query = DiffusionFileContentQuery::newFromDiffusionRequest(
|
||||
$readme_request);
|
||||
$content_query->setViewer($this->getViewer());
|
||||
$content_query->loadFileContent();
|
||||
$readme_content = $content_query->getRawData();
|
||||
|
||||
|
|
|
@ -85,9 +85,7 @@ abstract class DiffusionFileContentQuery extends DiffusionQuery {
|
|||
}
|
||||
|
||||
$loader = new PhabricatorObjectHandleData(array_unique($phids));
|
||||
if ($this->viewer) {
|
||||
$loader->setViewer($this->viewer);
|
||||
}
|
||||
$loader->setViewer($this->viewer);
|
||||
$handles = $loader->loadHandles();
|
||||
|
||||
foreach ($commits_data as $data) {
|
||||
|
|
|
@ -210,7 +210,7 @@ final class PhabricatorDirectoryMainController
|
|||
$revision_view = id(new DifferentialRevisionListView())
|
||||
->setHighlightAge(true)
|
||||
->setRevisions(array_merge($blocking, $active))
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields())
|
||||
->setFields(DifferentialRevisionListView::getDefaultFields($user))
|
||||
->setUser($user)
|
||||
->loadAssets();
|
||||
$phids = array_merge(
|
||||
|
|
|
@ -28,6 +28,7 @@ final class PhabricatorApplicationFlags extends PhabricatorApplication {
|
|||
$status = array();
|
||||
|
||||
$flags = id(new PhabricatorFlagQuery())
|
||||
->setViewer($user)
|
||||
->withOwnerPHIDs(array($user->getPHID()))
|
||||
->execute();
|
||||
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
*/
|
||||
abstract class ConduitAPI_flag_Method extends ConduitAPIMethod {
|
||||
|
||||
protected function attachHandleToFlag($flag) {
|
||||
protected function attachHandleToFlag($flag, PhabricatorUser $user) {
|
||||
$flag->attachHandle(
|
||||
PhabricatorObjectHandleData::loadOneHandle($flag->getObjectPHID()));
|
||||
PhabricatorObjectHandleData::loadOneHandle(
|
||||
$flag->getObjectPHID(),
|
||||
$user));
|
||||
}
|
||||
|
||||
protected function buildFlagInfoDictionary($flag) {
|
||||
|
|
|
@ -50,7 +50,7 @@ final class ConduitAPI_flag_delete_Method extends ConduitAPI_flag_Method {
|
|||
} else {
|
||||
throw new ConduitException('ERR_NEED_PARAM');
|
||||
}
|
||||
$this->attachHandleToFlag($flag);
|
||||
$this->attachHandleToFlag($flag, $request->getUser());
|
||||
$ret = $this->buildFlagInfoDictionary($flag);
|
||||
$flag->delete();
|
||||
return $ret;
|
||||
|
|
|
@ -54,7 +54,7 @@ final class ConduitAPI_flag_edit_Method extends ConduitAPI_flag_Method {
|
|||
->setNote($request->getValue('note', ''));
|
||||
$new = true;
|
||||
}
|
||||
$this->attachHandleToFlag($flag);
|
||||
$this->attachHandleToFlag($flag, $request->getUser());
|
||||
$flag->save();
|
||||
$ret = $this->buildFlagInfoDictionary($flag);
|
||||
$ret['new'] = $new;
|
||||
|
|
|
@ -84,9 +84,7 @@ final class PhabricatorFlagQuery {
|
|||
if ($this->needHandles || $this->needObjects) {
|
||||
$phids = ipull($data, 'objectPHID');
|
||||
$query = new PhabricatorObjectHandleData($phids);
|
||||
if ($this->viewer) {
|
||||
$query->setViewer($this->viewer);
|
||||
}
|
||||
$query->setViewer($this->viewer);
|
||||
|
||||
if ($this->needHandles) {
|
||||
$handles = $query->loadHandles();
|
||||
|
|
|
@ -25,7 +25,9 @@ abstract class HeraldObjectAdapter {
|
|||
'Object already flagged.');
|
||||
}
|
||||
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle($phid);
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle(
|
||||
$phid,
|
||||
$user);
|
||||
|
||||
$flag = new PhabricatorFlag();
|
||||
$flag->setOwnerPHID($user->getPHID());
|
||||
|
|
|
@ -126,8 +126,11 @@ final class HeraldHomeController extends HeraldController {
|
|||
}
|
||||
|
||||
private function renderAuthorFilter($phid) {
|
||||
$user = $this->getRequest()->getUser();
|
||||
if ($phid) {
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle($phid);
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle(
|
||||
$phid,
|
||||
$user);
|
||||
$tokens = array(
|
||||
$phid => $handle->getFullName(),
|
||||
);
|
||||
|
@ -136,7 +139,7 @@ final class HeraldHomeController extends HeraldController {
|
|||
}
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($this->getRequest()->getUser())
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
id(new AphrontFormTokenizerControl())
|
||||
->setName('set_phid')
|
||||
|
|
|
@ -76,6 +76,7 @@ final class HeraldRule extends HeraldDAO {
|
|||
}
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData(array_keys($users)))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles();
|
||||
|
||||
foreach ($rules as $key => $rule) {
|
||||
|
|
|
@ -611,7 +611,11 @@ final class ManiphestTaskQuery extends PhabricatorQuery {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: This should use the query's viewer once this class extends
|
||||
// PhabricatorPolicyQuery (T603).
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData(array_keys($project_phids)))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles();
|
||||
|
||||
$max = 1;
|
||||
|
|
|
@ -73,7 +73,9 @@ final class ManiphestExportController extends ManiphestController {
|
|||
$query->setParameter('order', 'p');
|
||||
$query->setParameter('group', 'n');
|
||||
|
||||
list($tasks, $handles) = ManiphestTaskListController::loadTasks($query);
|
||||
list($tasks, $handles) = ManiphestTaskListController::loadTasks(
|
||||
$query,
|
||||
$user);
|
||||
// Ungroup tasks.
|
||||
$tasks = array_mergev($tasks);
|
||||
|
||||
|
|
|
@ -89,7 +89,9 @@ final class ManiphestTaskListController extends ManiphestController {
|
|||
|
||||
// Execute the query.
|
||||
|
||||
list($tasks, $handles, $total_count) = self::loadTasks($query);
|
||||
list($tasks, $handles, $total_count) = self::loadTasks(
|
||||
$query,
|
||||
$user);
|
||||
|
||||
// Extract information we need to render the filters from the query.
|
||||
|
||||
|
@ -416,7 +418,10 @@ final class ManiphestTaskListController extends ManiphestController {
|
|||
));
|
||||
}
|
||||
|
||||
public static function loadTasks(PhabricatorSearchQuery $search_query) {
|
||||
public static function loadTasks(
|
||||
PhabricatorSearchQuery $search_query,
|
||||
PhabricatorUser $viewer) {
|
||||
|
||||
$any_project = false;
|
||||
$search_text = $search_query->getParameter('fullTextSearch');
|
||||
$user_phids = $search_query->getParameter('userPHIDs', array());
|
||||
|
@ -552,6 +557,7 @@ final class ManiphestTaskListController extends ManiphestController {
|
|||
$any_project_phids,
|
||||
array_mergev(mpull($data, 'getProjectPHIDs')));
|
||||
$handles = id(new PhabricatorObjectHandleData($handle_phids))
|
||||
->setViewer($viewer)
|
||||
->loadHandles();
|
||||
|
||||
switch ($search_query->getParameter('group')) {
|
||||
|
|
|
@ -130,6 +130,7 @@ final class ManiphestTransactionEditor extends PhabricatorEditor {
|
|||
case ManiphestTransactionType::TYPE_OWNER:
|
||||
if ($new) {
|
||||
$handles = id(new PhabricatorObjectHandleData(array($new)))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
$task->setOwnerOrdering($handles[$new]->getName());
|
||||
} else {
|
||||
|
|
|
@ -111,6 +111,7 @@ final class ManiphestSearchIndexer
|
|||
// We need to load handles here since non-users may subscribe (mailing
|
||||
// lists, e.g.)
|
||||
$handles = id(new PhabricatorObjectHandleData(array_keys($ccs)))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles();
|
||||
foreach ($ccs as $cc => $time) {
|
||||
$doc->addRelationship(
|
||||
|
|
16
src/applications/metamta/PhabricatorMail.php
Normal file
16
src/applications/metamta/PhabricatorMail.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
abstract class PhabricatorMail {
|
||||
|
||||
private $actor;
|
||||
|
||||
public function setActor(PhabricatorUser $actor) {
|
||||
$this->actor = $actor;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getActor() {
|
||||
return $this->actor;
|
||||
}
|
||||
|
||||
}
|
|
@ -88,7 +88,10 @@ abstract class PhabricatorMailReplyHandler {
|
|||
$template->setRelatedPHID($mail->getRelatedPHID());
|
||||
$phid = $this->getActor()->getPHID();
|
||||
$tos = array(
|
||||
$phid => PhabricatorObjectHandleData::loadOneHandle($phid)
|
||||
$phid => PhabricatorObjectHandleData::loadOneHandle(
|
||||
$phid,
|
||||
// TODO: This could be cleaner (T603).
|
||||
PhabricatorUser::getOmnipotentUser()),
|
||||
);
|
||||
$mails = $this->multiplexMail($template, $tos, array());
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
abstract class PackageMail {
|
||||
abstract class PackageMail extends PhabricatorMail {
|
||||
|
||||
protected $package;
|
||||
protected $handles;
|
||||
|
@ -80,7 +80,9 @@ abstract class PackageMail {
|
|||
$this->mailTo,
|
||||
array($package->getActorPHID()),
|
||||
array_keys($this->paths));
|
||||
$this->handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$this->handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
}
|
||||
|
||||
final protected function renderSummarySection() {
|
||||
|
|
|
@ -59,7 +59,9 @@ final class PackageModifyMail extends PackageMail {
|
|||
array(
|
||||
$this->getPackage()->getActorPHID(),
|
||||
));
|
||||
$this->handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||
$this->handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
}
|
||||
|
||||
protected function renderDescriptionSection() {
|
||||
|
|
|
@ -214,6 +214,12 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
return $ids;
|
||||
}
|
||||
|
||||
private function getActor() {
|
||||
// TODO: This should be cleaner, but we'd likely need to move the whole
|
||||
// thing to an Editor (T603).
|
||||
return PhabricatorUser::getOmnipotentUser();
|
||||
}
|
||||
|
||||
public function save() {
|
||||
|
||||
if ($this->getID()) {
|
||||
|
@ -294,6 +300,7 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
'path' => $path,
|
||||
));
|
||||
$query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);
|
||||
$query->setViewer($this->getActor());
|
||||
$query->needValidityOnly(true);
|
||||
$valid = $query->loadPaths();
|
||||
$is_directory = true;
|
||||
|
@ -344,13 +351,16 @@ final class PhabricatorOwnersPackage extends PhabricatorOwnersDAO
|
|||
$add_paths,
|
||||
$remove_paths);
|
||||
}
|
||||
$mail->setActor($this->getActor());
|
||||
$mail->send();
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public function delete() {
|
||||
$mails = id(new PackageDeleteMail($this))->prepareMails();
|
||||
$mails = id(new PackageDeleteMail($this))
|
||||
->setActor($this->getActor())
|
||||
->prepareMails();
|
||||
|
||||
$this->openTransaction();
|
||||
foreach ($this->loadOwners() as $owner) {
|
||||
|
|
|
@ -295,6 +295,7 @@ abstract class PhameBasicBlogSkin extends PhameBlogSkin {
|
|||
}
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($user)
|
||||
->loadHandles();
|
||||
|
||||
$engine->process();
|
||||
|
|
|
@ -131,6 +131,8 @@ final class PhameBlog extends PhameDAO
|
|||
}
|
||||
|
||||
$bloggers = id(new PhabricatorObjectHandleData($blogger_phids))
|
||||
// TODO: This should be Query-based (T603).
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles();
|
||||
|
||||
$this->attachBloggers($bloggers);
|
||||
|
|
|
@ -39,6 +39,7 @@ final class ConduitAPI_phid_info_Method
|
|||
$phid = $request->getValue('phid');
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData(array($phid)))
|
||||
->setViewer($request->getUser())
|
||||
->loadHandles();
|
||||
|
||||
$handle = $handles[$phid];
|
||||
|
|
|
@ -35,7 +35,9 @@ final class ConduitAPI_phid_lookup_Method
|
|||
}
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($request->getUser())
|
||||
->loadHandles();
|
||||
|
||||
$result = array();
|
||||
foreach ($phids as $name => $phid) {
|
||||
if (isset($handles[$phid]) && $handles[$phid]->isComplete()) {
|
||||
|
|
|
@ -29,6 +29,7 @@ final class ConduitAPI_phid_query_Method
|
|||
$phids = $request->getValue('phids');
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($phids))
|
||||
->setViewer($request->getUser())
|
||||
->loadHandles();
|
||||
|
||||
$result = array();
|
||||
|
|
|
@ -14,13 +14,9 @@ final class PhabricatorObjectHandleData {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public static function loadOneHandle($phid, $viewer = null) {
|
||||
public static function loadOneHandle($phid, PhabricatorUser $viewer) {
|
||||
$query = new PhabricatorObjectHandleData(array($phid));
|
||||
|
||||
if ($viewer) {
|
||||
$query->setViewer($viewer);
|
||||
}
|
||||
|
||||
$query->setViewer($viewer);
|
||||
$handles = $query->loadHandles();
|
||||
return $handles[$phid];
|
||||
}
|
||||
|
@ -37,6 +33,11 @@ final class PhabricatorObjectHandleData {
|
|||
}
|
||||
|
||||
private function loadObjectsOfType($type, array $phids) {
|
||||
if (!$this->viewer) {
|
||||
throw new Exception(
|
||||
"You must provide a viewer to load handles or objects.");
|
||||
}
|
||||
|
||||
switch ($type) {
|
||||
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_USER:
|
||||
|
@ -73,15 +74,10 @@ final class PhabricatorObjectHandleData {
|
|||
return mpull($files, null, 'getPHID');
|
||||
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_PROJ:
|
||||
$object = new PhabricatorProject();
|
||||
if ($this->viewer) {
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer($this->viewer)
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
} else {
|
||||
$projects = $object->loadAllWhere('phid IN (%Ls)', $phids);
|
||||
}
|
||||
$projects = id(new PhabricatorProjectQuery())
|
||||
->setViewer($this->viewer)
|
||||
->withPHIDs($phids)
|
||||
->execute();
|
||||
return mpull($projects, null, 'getPHID');
|
||||
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_REPO:
|
||||
|
@ -260,10 +256,8 @@ final class PhabricatorObjectHandleData {
|
|||
$handle->setComplete(true);
|
||||
if (isset($statuses[$phid])) {
|
||||
$handle->setStatus($statuses[$phid]->getTextStatus());
|
||||
if ($this->viewer) {
|
||||
$handle->setTitle(
|
||||
$statuses[$phid]->getTerseSummary($this->viewer));
|
||||
}
|
||||
$handle->setTitle(
|
||||
$statuses[$phid]->getTerseSummary($this->viewer));
|
||||
}
|
||||
$handle->setDisabled($user->getIsDisabled());
|
||||
|
||||
|
|
|
@ -22,8 +22,7 @@ final class PholioInlineController extends PholioController {
|
|||
$user->getPHID());
|
||||
|
||||
$author_phids = mpull($inline_comments, 'getAuthorPHID');
|
||||
$authors = id(new PhabricatorObjectHandleData($author_phids))
|
||||
->loadHandles();
|
||||
$authors = $this->loadViewerHandles($author_phids);
|
||||
|
||||
$inlines = array();
|
||||
|
||||
|
|
|
@ -63,7 +63,9 @@ final class PholioInlineSaveController extends PholioController {
|
|||
->setInlineComment($draft)
|
||||
->setEditable(true)
|
||||
->setHandle(
|
||||
PhabricatorObjectHandleData::loadOneHandle($user->getPHID()));
|
||||
PhabricatorObjectHandleData::loadOneHandle(
|
||||
$user->getPHID(),
|
||||
$user));
|
||||
|
||||
return id(new AphrontAjaxResponse())
|
||||
->setContent(
|
||||
|
|
|
@ -17,7 +17,8 @@ final class PholioInlineViewController extends PholioController {
|
|||
|
||||
$inline_comment = id(new PholioTransactionComment())->load($this->id);
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle(
|
||||
$inline_comment->getAuthorPHID());
|
||||
$inline_comment->getAuthorPHID(),
|
||||
$user);
|
||||
|
||||
$inline_view = id(new PholioInlineCommentView())
|
||||
->setHandle($handle)
|
||||
|
|
|
@ -10,6 +10,7 @@ final class PonderAnsweredMail extends PonderMail {
|
|||
$this->setQuestion($question);
|
||||
$this->setTarget($target);
|
||||
$this->setActorHandle($actor);
|
||||
$this->setActor($actor);
|
||||
}
|
||||
|
||||
protected function renderVaryPrefix() {
|
||||
|
|
|
@ -10,6 +10,7 @@ final class PonderCommentMail extends PonderMail {
|
|||
$this->setQuestion($question);
|
||||
$this->setTarget($target);
|
||||
$this->setActorHandle($actor);
|
||||
$this->setActor($actor);
|
||||
}
|
||||
|
||||
protected function renderVaryPrefix() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?php
|
||||
|
||||
abstract class PonderMail {
|
||||
abstract class PonderMail extends PhabricatorMail {
|
||||
|
||||
protected $to = array();
|
||||
protected $actorHandle;
|
||||
|
@ -8,9 +8,6 @@ abstract class PonderMail {
|
|||
protected $target;
|
||||
|
||||
protected $isFirstMailAboutQuestion;
|
||||
|
||||
// protected $replyHandler;
|
||||
|
||||
protected $parentMessageID;
|
||||
|
||||
protected function renderSubject() {
|
||||
|
@ -87,6 +84,7 @@ abstract class PonderMail {
|
|||
$thread_id = $this->getThreadID();
|
||||
|
||||
$handles = id(new PhabricatorObjectHandleData($email_to))
|
||||
->setViewer($this->getActor())
|
||||
->loadHandles();
|
||||
|
||||
$reply_handler = new PonderReplyHandler();
|
||||
|
|
|
@ -10,6 +10,7 @@ final class PonderMentionMail extends PonderMail {
|
|||
$this->setQuestion($question);
|
||||
$this->setTarget($target);
|
||||
$this->setActorHandle($actor);
|
||||
$this->setActor($actor);
|
||||
}
|
||||
|
||||
protected function renderVaryPrefix() {
|
||||
|
|
|
@ -55,6 +55,7 @@ final class PonderSearchIndexer
|
|||
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$question->getPHID());
|
||||
$handles = id(new PhabricatorObjectHandleData($subscribers))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles();
|
||||
|
||||
foreach ($handles as $phid => $handle) {
|
||||
|
|
|
@ -157,7 +157,9 @@ final class PhabricatorRepositoryCommitHeraldWorker
|
|||
|
||||
$mails = $reply_handler->multiplexMail(
|
||||
$template,
|
||||
id(new PhabricatorObjectHandleData($email_phids))->loadHandles(),
|
||||
id(new PhabricatorObjectHandleData($email_phids))
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadHandles(),
|
||||
array());
|
||||
|
||||
foreach ($mails as $mail) {
|
||||
|
|
|
@ -168,11 +168,13 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
|||
|
||||
$committer_name = $this->loadUserName(
|
||||
$committer_phid,
|
||||
$data->getCommitDetail('committer'));
|
||||
$data->getCommitDetail('committer'),
|
||||
$actor);
|
||||
|
||||
$author_name = $this->loadUserName(
|
||||
$author_phid,
|
||||
$data->getAuthorName());
|
||||
$data->getAuthorName(),
|
||||
$actor);
|
||||
|
||||
$info = array();
|
||||
$info[] = "authored by {$author_name}";
|
||||
|
@ -211,11 +213,13 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
|||
$data->save();
|
||||
}
|
||||
|
||||
private function loadUserName($user_phid, $default) {
|
||||
private function loadUserName($user_phid, $default, PhabricatorUser $actor) {
|
||||
if (!$user_phid) {
|
||||
return $default;
|
||||
}
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle($user_phid);
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle(
|
||||
$user_phid,
|
||||
$actor);
|
||||
return '@'.$handle->getName();
|
||||
}
|
||||
|
||||
|
@ -332,6 +336,7 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
|||
'path' => $path,
|
||||
));
|
||||
$corpus = DiffusionFileContentQuery::newFromDiffusionRequest($drequest)
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->loadFileContent()
|
||||
->getCorpus();
|
||||
if ($files[$file_phid]->loadFileData() != $corpus) {
|
||||
|
|
|
@ -27,6 +27,7 @@ final class PhabricatorSearchAttachController
|
|||
$user = $request->getUser();
|
||||
|
||||
$handle_data = new PhabricatorObjectHandleData(array($this->phid));
|
||||
$handle_data->setViewer($user);
|
||||
$handles = $handle_data->loadHandles();
|
||||
$handle = $handles[$this->phid];
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ final class PhabricatorSearchEngineElastic extends PhabricatorSearchEngine {
|
|||
|
||||
$type = $doc->getDocumentType();
|
||||
$phid = $doc->getPHID();
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle($phid);
|
||||
$handle = PhabricatorObjectHandleData::loadOneHandle(
|
||||
$phid,
|
||||
PhabricatorUser::getOmnipotentUser());
|
||||
|
||||
// URL is not used internally but it can be useful externally.
|
||||
$spec = array(
|
||||
|
|
|
@ -98,6 +98,7 @@ final class PhabricatorSlowvotePollController
|
|||
));
|
||||
|
||||
$query = new PhabricatorObjectHandleData($phids);
|
||||
$query->setViewer($user);
|
||||
$handles = $query->loadHandles();
|
||||
$objects = $query->loadObjects();
|
||||
|
||||
|
|
|
@ -93,6 +93,7 @@ final class PhabricatorTokenUIEventListener
|
|||
|
||||
$author_phids = mpull($tokens_given, 'getAuthorPHID');
|
||||
$handles = id(new PhabricatorObjectHandleData($author_phids))
|
||||
->setViewer($user)
|
||||
->loadHandles();
|
||||
|
||||
$list = array();
|
||||
|
|
|
@ -23,7 +23,9 @@ final class PhabricatorXHProfSampleListView extends AphrontView {
|
|||
}
|
||||
|
||||
$user_phids = mpull($this->samples, 'getUserPHID');
|
||||
$users = id(new PhabricatorObjectHandleData($user_phids))->loadObjects();
|
||||
$users = id(new PhabricatorObjectHandleData($user_phids))
|
||||
->setViewer($this->getUser())
|
||||
->loadObjects();
|
||||
foreach ($this->samples as $sample) {
|
||||
$sample_link = phutil_tag(
|
||||
'a',
|
||||
|
|
|
@ -213,6 +213,7 @@ final class PhabricatorEdgeQuery extends PhabricatorQuery {
|
|||
* write code like this:
|
||||
*
|
||||
* $query = new PhabricatorEdgeQuery();
|
||||
* $query->setViewer($viewer);
|
||||
* $query->withSourcePHIDs(mpull($objects, 'getPHID'));
|
||||
* $query->withEdgeTypes(array($some_type));
|
||||
* $query->execute();
|
||||
|
@ -220,6 +221,7 @@ final class PhabricatorEdgeQuery extends PhabricatorQuery {
|
|||
* // Gets all of the destinations.
|
||||
* $all_phids = $query->getDestinationPHIDs();
|
||||
* $handles = id(new PhabricatorObjectHandleData($all_phids))
|
||||
* ->setViewer($viewer)
|
||||
* ->loadHandles();
|
||||
*
|
||||
* foreach ($objects as $object) {
|
||||
|
|
|
@ -26,6 +26,11 @@ abstract class PhabricatorRemarkupRuleObject
|
|||
$viewer = $this->getEngine()->getConfig('viewer');
|
||||
if ($viewer) {
|
||||
$query->setViewer($viewer);
|
||||
} else {
|
||||
// TODO: This needs to be fixed; all markup engines need to set viewers --
|
||||
// but there are a lot of them (T603).
|
||||
$query->setViewer(PhabricatorUser::getOmnipotentUser());
|
||||
phlog("Warning: Loading handles without a viewing user.");
|
||||
}
|
||||
$handles = $query->loadHandles();
|
||||
|
||||
|
|
Loading…
Reference in a new issue