mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-23 22:10:55 +01:00
Add "Resign from Audit" and "Close Audit" actions to Diffusion
Summary: See some discussion in D2002. Add two new actions: - Resign: (auditor only) closes your open request (user request ONLY) by putting it in a "resigned" state. - Close: (author only) closes all open requests by putting them in a "closed" state. @davidreuss, this is probably conflict-city with D2002 -- I'll wait for you to land first and then handle the merge on my end. Test Plan: Resigned from and closed audits. Reviewers: 20after4, davidreuss, btrahan Reviewed By: btrahan CC: aran, epriestley Maniphest Tasks: T904 Differential Revision: https://secure.phabricator.com/D2013
This commit is contained in:
parent
638627cea5
commit
2044e51206
13 changed files with 339 additions and 86 deletions
|
@ -21,33 +21,35 @@ final class PhabricatorAuditActionConstants {
|
||||||
const CONCERN = 'concern';
|
const CONCERN = 'concern';
|
||||||
const ACCEPT = 'accept';
|
const ACCEPT = 'accept';
|
||||||
const COMMENT = 'comment';
|
const COMMENT = 'comment';
|
||||||
|
const RESIGN = 'resign';
|
||||||
|
const CLOSE = 'close';
|
||||||
|
|
||||||
public static function getActionNameMap() {
|
public static function getActionNameMap() {
|
||||||
static $map = array(
|
static $map = array(
|
||||||
self::COMMENT => 'Comment',
|
self::COMMENT => 'Comment',
|
||||||
self::CONCERN => 'Raise Concern',
|
self::CONCERN => 'Raise Concern',
|
||||||
self::ACCEPT => 'Accept Commit',
|
self::ACCEPT => 'Accept Commit',
|
||||||
|
self::RESIGN => 'Resign from Audit',
|
||||||
|
self::CLOSE => 'Close Audit',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $map;
|
return $map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getActionName($constant) {
|
||||||
|
$map = self::getActionNameMap();
|
||||||
|
return idx($map, $constant, 'Unknown');
|
||||||
|
}
|
||||||
|
|
||||||
public static function getActionPastTenseVerb($action) {
|
public static function getActionPastTenseVerb($action) {
|
||||||
static $map = array(
|
static $map = array(
|
||||||
self::COMMENT => 'commented on',
|
self::COMMENT => 'commented on',
|
||||||
self::CONCERN => 'raised a concern with',
|
self::CONCERN => 'raised a concern with',
|
||||||
self::ACCEPT => 'accepted',
|
self::ACCEPT => 'accepted',
|
||||||
|
self::RESIGN => 'resigned from',
|
||||||
|
self::CLOSE => 'closed',
|
||||||
);
|
);
|
||||||
return idx($map, $action, 'updated');
|
return idx($map, $action, 'updated');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getStatusNameMap() {
|
|
||||||
static $map = array(
|
|
||||||
self::CONCERN => PhabricatorAuditStatusConstants::CONCERNED,
|
|
||||||
self::ACCEPT => PhabricatorAuditStatusConstants::ACCEPTED,
|
|
||||||
);
|
|
||||||
|
|
||||||
return $map;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'applications/audit/constants/status');
|
|
||||||
|
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ final class PhabricatorAuditStatusConstants {
|
||||||
const CONCERNED = 'concerned';
|
const CONCERNED = 'concerned';
|
||||||
const ACCEPTED = 'accepted';
|
const ACCEPTED = 'accepted';
|
||||||
const AUDIT_REQUESTED = 'requested';
|
const AUDIT_REQUESTED = 'requested';
|
||||||
|
const RESIGNED = 'resigned';
|
||||||
|
const CLOSED = 'closed';
|
||||||
|
|
||||||
public static function getStatusNameMap() {
|
public static function getStatusNameMap() {
|
||||||
static $map = array(
|
static $map = array(
|
||||||
|
@ -33,6 +35,8 @@ final class PhabricatorAuditStatusConstants {
|
||||||
self::CONCERNED => 'Concern Raised',
|
self::CONCERNED => 'Concern Raised',
|
||||||
self::ACCEPTED => 'Accepted',
|
self::ACCEPTED => 'Accepted',
|
||||||
self::AUDIT_REQUESTED => 'Audit Requested',
|
self::AUDIT_REQUESTED => 'Audit Requested',
|
||||||
|
self::RESIGNED => 'Resigned',
|
||||||
|
self::CLOSED => 'Closed',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $map;
|
return $map;
|
||||||
|
@ -42,4 +46,16 @@ final class PhabricatorAuditStatusConstants {
|
||||||
return idx(self::getStatusNameMap(), $code, 'Unknown');
|
return idx(self::getStatusNameMap(), $code, 'Unknown');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function getOpenStatusConstants() {
|
||||||
|
return array(
|
||||||
|
self::AUDIT_REQUIRED,
|
||||||
|
self::AUDIT_REQUESTED,
|
||||||
|
self::CONCERNED,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isOpenStatus($status) {
|
||||||
|
return in_array($status, self::getOpenStatusConstants());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -301,6 +301,8 @@ final class PhabricatorAuditListController extends PhabricatorAuditController {
|
||||||
$query->setLimit($pager->getPageSize() + 1);
|
$query->setLimit($pager->getPageSize() + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$awaiting = null;
|
||||||
|
|
||||||
$phids = null;
|
$phids = null;
|
||||||
switch ($this->filter) {
|
switch ($this->filter) {
|
||||||
case 'user':
|
case 'user':
|
||||||
|
@ -312,6 +314,7 @@ final class PhabricatorAuditListController extends PhabricatorAuditController {
|
||||||
throw new Exception("Invalid user!");
|
throw new Exception("Invalid user!");
|
||||||
}
|
}
|
||||||
$phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($obj);
|
$phids = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($obj);
|
||||||
|
$awaiting = $obj;
|
||||||
break;
|
break;
|
||||||
case 'project':
|
case 'project':
|
||||||
case 'package':
|
case 'package':
|
||||||
|
@ -327,6 +330,10 @@ final class PhabricatorAuditListController extends PhabricatorAuditController {
|
||||||
$query->withAuditorPHIDs($phids);
|
$query->withAuditorPHIDs($phids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($awaiting) {
|
||||||
|
$query->withAwaitingUser($awaiting);
|
||||||
|
}
|
||||||
|
|
||||||
switch ($this->filter) {
|
switch ($this->filter) {
|
||||||
case 'audits':
|
case 'audits':
|
||||||
case 'user':
|
case 'user':
|
||||||
|
|
|
@ -83,37 +83,103 @@ final class PhabricatorAuditCommentEditor {
|
||||||
$commit->getPHID());
|
$commit->getPHID());
|
||||||
|
|
||||||
$action = $comment->getAction();
|
$action = $comment->getAction();
|
||||||
$status_map = PhabricatorAuditActionConstants::getStatusNameMap();
|
|
||||||
$status = idx($status_map, $action, null);
|
|
||||||
|
|
||||||
// Status may be empty for updates which don't affect status, like
|
|
||||||
// "comment".
|
// TODO: We should validate the action, currently we allow anyone to, e.g.,
|
||||||
|
// close an audit if they muck with form parameters. I'll followup with this
|
||||||
|
// and handle the no-effect cases (e.g., closing and already-closed audit).
|
||||||
|
|
||||||
|
|
||||||
|
$user_is_author = ($user->getPHID() == $commit->getAuthorPHID());
|
||||||
|
|
||||||
|
if ($action == PhabricatorAuditActionConstants::CLOSE) {
|
||||||
|
// "Close" means wipe out all the concerns.
|
||||||
|
$concerned_status = PhabricatorAuditStatusConstants::CONCERNED;
|
||||||
|
foreach ($requests as $request) {
|
||||||
|
if ($request->getAuditStatus() == $concerned_status) {
|
||||||
|
$request->setAuditStatus(PhabricatorAuditStatusConstants::CLOSED);
|
||||||
|
$request->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
$have_any_requests = false;
|
$have_any_requests = false;
|
||||||
foreach ($requests as $request) {
|
foreach ($requests as $request) {
|
||||||
if (empty($audit_phids[$request->getAuditorPHID()])) {
|
if (empty($audit_phids[$request->getAuditorPHID()])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$request_is_for_user = ($request->getAuditorPHID() == $user->getPHID());
|
||||||
|
|
||||||
$have_any_requests = true;
|
$have_any_requests = true;
|
||||||
if ($status) {
|
$new_status = null;
|
||||||
$request->setAuditStatus($status);
|
switch ($action) {
|
||||||
|
case PhabricatorAuditActionConstants::COMMENT:
|
||||||
|
// Comments don't change audit statuses.
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::ACCEPT:
|
||||||
|
if (!$user_is_author || $request_is_for_user) {
|
||||||
|
// When modifying your own commits, you act only on behalf of
|
||||||
|
// yourself, not your packages/projects -- the idea being that
|
||||||
|
// you can't accept your own commits.
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::ACCEPTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::CONCERN:
|
||||||
|
if (!$user_is_author || $request_is_for_user) {
|
||||||
|
// See above.
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::CONCERNED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::RESIGN:
|
||||||
|
// NOTE: Resigning resigns ONLY your user request, not the requests
|
||||||
|
// of any projects or packages you are a member of.
|
||||||
|
if ($request_is_for_user) {
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::RESIGNED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown action '{$action}'!");
|
||||||
|
}
|
||||||
|
if ($new_status !== null) {
|
||||||
|
$request->setAuditStatus($new_status);
|
||||||
$request->save();
|
$request->save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!$have_any_requests) {
|
|
||||||
// If the user has no current authority over any audit trigger, make a
|
// If the user has no current authority over any audit trigger, make a
|
||||||
// new one to represent their audit state.
|
// new one to represent their audit state.
|
||||||
|
if (!$have_any_requests) {
|
||||||
|
$new_status = null;
|
||||||
|
switch ($action) {
|
||||||
|
case PhabricatorAuditActionConstants::COMMENT:
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED;
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::ACCEPT:
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::ACCEPTED;
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::CONCERN:
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::CONCERNED;
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::RESIGN:
|
||||||
|
// If you're on an audit because of a package, we write an explicit
|
||||||
|
// resign row to remove it from your queue.
|
||||||
|
$new_status = PhabricatorAuditStatusConstants::RESIGNED;
|
||||||
|
break;
|
||||||
|
case PhabricatorAuditActionConstants::CLOSE:
|
||||||
|
// Impossible to reach this block with 'close'.
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown or invalid action '{$action}'!");
|
||||||
|
}
|
||||||
|
|
||||||
$request = id(new PhabricatorRepositoryAuditRequest())
|
$request = id(new PhabricatorRepositoryAuditRequest())
|
||||||
->setCommitPHID($commit->getPHID())
|
->setCommitPHID($commit->getPHID())
|
||||||
->setAuditorPHID($user->getPHID())
|
->setAuditorPHID($user->getPHID())
|
||||||
->setAuditStatus(
|
->setAuditStatus($new_status)
|
||||||
$status
|
|
||||||
? $status
|
|
||||||
: PhabricatorAuditStatusConstants::AUDIT_NOT_REQUIRED)
|
|
||||||
->setAuditReasons(array("Voluntary Participant"))
|
->setAuditReasons(array("Voluntary Participant"))
|
||||||
->save();
|
->save();
|
||||||
$requests[] = $request;
|
$requests[] = $request;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
$commit->updateAuditStatus($requests);
|
$commit->updateAuditStatus($requests);
|
||||||
$commit->save();
|
$commit->save();
|
||||||
|
@ -206,6 +272,8 @@ final class PhabricatorAuditCommentEditor {
|
||||||
$map = array(
|
$map = array(
|
||||||
PhabricatorAuditActionConstants::CONCERN => 'Raised Concern',
|
PhabricatorAuditActionConstants::CONCERN => 'Raised Concern',
|
||||||
PhabricatorAuditActionConstants::ACCEPT => 'Accepted',
|
PhabricatorAuditActionConstants::ACCEPT => 'Accepted',
|
||||||
|
PhabricatorAuditActionConstants::RESIGN => 'Resigned',
|
||||||
|
PhabricatorAuditActionConstants::CLOSE => 'Closed',
|
||||||
);
|
);
|
||||||
$verb = idx($map, $comment->getAction(), 'Commented On');
|
$verb = idx($map, $comment->getAction(), 'Commented On');
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ final class PhabricatorAuditQuery {
|
||||||
private $needCommits;
|
private $needCommits;
|
||||||
private $needCommitData;
|
private $needCommitData;
|
||||||
|
|
||||||
|
private $awaitingUser;
|
||||||
|
|
||||||
private $status = 'status-any';
|
private $status = 'status-any';
|
||||||
const STATUS_ANY = 'status-any';
|
const STATUS_ANY = 'status-any';
|
||||||
const STATUS_OPEN = 'status-open';
|
const STATUS_OPEN = 'status-open';
|
||||||
|
@ -43,6 +45,11 @@ final class PhabricatorAuditQuery {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function withAwaitingUser(PhabricatorUser $user) {
|
||||||
|
$this->awaitingUser = $user;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function withStatus($status) {
|
public function withStatus($status) {
|
||||||
$this->status = $status;
|
$this->status = $status;
|
||||||
return $this;
|
return $this;
|
||||||
|
@ -72,14 +79,16 @@ final class PhabricatorAuditQuery {
|
||||||
$table = new PhabricatorRepositoryAuditRequest();
|
$table = new PhabricatorRepositoryAuditRequest();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn_r = $table->establishConnection('r');
|
||||||
|
|
||||||
|
$joins = $this->buildJoinClause($conn_r);
|
||||||
$where = $this->buildWhereClause($conn_r);
|
$where = $this->buildWhereClause($conn_r);
|
||||||
$order = $this->buildOrderClause($conn_r);
|
$order = $this->buildOrderClause($conn_r);
|
||||||
$limit = $this->buildLimitClause($conn_r);
|
$limit = $this->buildLimitClause($conn_r);
|
||||||
|
|
||||||
$data = queryfx_all(
|
$data = queryfx_all(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
'SELECT * FROM %T %Q %Q %Q',
|
'SELECT req.* FROM %T req %Q %Q %Q %Q',
|
||||||
$table->getTableName(),
|
$table->getTableName(),
|
||||||
|
$joins,
|
||||||
$where,
|
$where,
|
||||||
$order,
|
$order,
|
||||||
$limit);
|
$limit);
|
||||||
|
@ -112,34 +121,77 @@ final class PhabricatorAuditQuery {
|
||||||
return $this->commits;
|
return $this->commits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function buildJoinClause($conn_r) {
|
||||||
|
|
||||||
|
$joins = array();
|
||||||
|
|
||||||
|
if ($this->awaitingUser) {
|
||||||
|
// Join the request table on the awaiting user's requests, so we can
|
||||||
|
// filter out package and project requests which the user has resigned
|
||||||
|
// from.
|
||||||
|
$joins[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'LEFT JOIN %T awaiting ON req.commitPHID = awaiting.commitPHID AND
|
||||||
|
awaiting.auditorPHID = %s',
|
||||||
|
id(new PhabricatorRepositoryAuditRequest())->getTableName(),
|
||||||
|
$this->awaitingUser->getPHID());
|
||||||
|
|
||||||
|
// Join the commit table so we can get the commit author into the result
|
||||||
|
// row and filter by it later.
|
||||||
|
$joins[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'JOIN %T commit ON req.commitPHID = commit.phid',
|
||||||
|
id(new PhabricatorRepositoryCommit())->getTableName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($joins) {
|
||||||
|
return implode(' ', $joins);
|
||||||
|
} else {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function buildWhereClause($conn_r) {
|
private function buildWhereClause($conn_r) {
|
||||||
$where = array();
|
$where = array();
|
||||||
|
|
||||||
if ($this->commitPHIDs) {
|
if ($this->commitPHIDs) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
'commitPHID IN (%Ls)',
|
'req.commitPHID IN (%Ls)',
|
||||||
$this->commitPHIDs);
|
$this->commitPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->auditorPHIDs) {
|
if ($this->auditorPHIDs) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
'auditorPHID IN (%Ls)',
|
'req.auditorPHID IN (%Ls)',
|
||||||
$this->auditorPHIDs);
|
$this->auditorPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->awaitingUser) {
|
||||||
|
// Exclude package and project audits associated with commits where
|
||||||
|
// the user is the author.
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn_r,
|
||||||
|
'(commit.authorPHID IS NULL OR commit.authorPHID != %s)
|
||||||
|
OR (req.auditorPHID = %s)',
|
||||||
|
$this->awaitingUser->getPHID(),
|
||||||
|
$this->awaitingUser->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
$status = $this->status;
|
$status = $this->status;
|
||||||
switch ($status) {
|
switch ($status) {
|
||||||
case self::STATUS_OPEN:
|
case self::STATUS_OPEN:
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
'auditStatus in (%Ls)',
|
'req.auditStatus in (%Ls)',
|
||||||
array(
|
PhabricatorAuditStatusConstants::getOpenStatusConstants());
|
||||||
PhabricatorAuditStatusConstants::AUDIT_REQUIRED,
|
if ($this->awaitingUser) {
|
||||||
PhabricatorAuditStatusConstants::CONCERNED,
|
$where[] = qsprintf(
|
||||||
PhabricatorAuditStatusConstants::AUDIT_REQUESTED,
|
$conn_r,
|
||||||
));
|
'awaiting.auditStatus IS NULL OR awaiting.auditStatus != %s',
|
||||||
|
PhabricatorAuditStatusConstants::RESIGNED);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case self::STATUS_ANY:
|
case self::STATUS_ANY:
|
||||||
break;
|
break;
|
||||||
|
@ -169,7 +221,7 @@ final class PhabricatorAuditQuery {
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildOrderClause($conn_r) {
|
private function buildOrderClause($conn_r) {
|
||||||
return 'ORDER BY id DESC';
|
return 'ORDER BY req.id DESC';
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
phutil_require_module('phabricator', 'applications/audit/constants/status');
|
phutil_require_module('phabricator', 'applications/audit/constants/status');
|
||||||
phutil_require_module('phabricator', 'applications/audit/query/commit');
|
phutil_require_module('phabricator', 'applications/audit/query/commit');
|
||||||
phutil_require_module('phabricator', 'applications/repository/storage/auditrequest');
|
phutil_require_module('phabricator', 'applications/repository/storage/auditrequest');
|
||||||
|
phutil_require_module('phabricator', 'applications/repository/storage/commit');
|
||||||
phutil_require_module('phabricator', 'storage/qsprintf');
|
phutil_require_module('phabricator', 'storage/qsprintf');
|
||||||
phutil_require_module('phabricator', 'storage/queryfx');
|
phutil_require_module('phabricator', 'storage/queryfx');
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ final class PhabricatorAuditListView extends AphrontView {
|
||||||
private $authorityPHIDs = array();
|
private $authorityPHIDs = array();
|
||||||
private $noDataString;
|
private $noDataString;
|
||||||
private $commits;
|
private $commits;
|
||||||
|
private $user;
|
||||||
|
private $showDescriptions = true;
|
||||||
|
|
||||||
public function setAudits(array $audits) {
|
public function setAudits(array $audits) {
|
||||||
$this->audits = $audits;
|
$this->audits = $audits;
|
||||||
|
@ -53,6 +55,16 @@ final class PhabricatorAuditListView extends AphrontView {
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setUser(PhabricatorUser $user) {
|
||||||
|
$this->user = $user;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setShowDescriptions($show_descriptions) {
|
||||||
|
$this->showDescriptions = $show_descriptions;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
public function getRequiredHandlePHIDs() {
|
public function getRequiredHandlePHIDs() {
|
||||||
$phids = array();
|
$phids = array();
|
||||||
foreach ($this->audits as $audit) {
|
foreach ($this->audits as $audit) {
|
||||||
|
@ -84,6 +96,7 @@ final class PhabricatorAuditListView extends AphrontView {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function render() {
|
public function render() {
|
||||||
|
$user = $this->user;
|
||||||
|
|
||||||
$authority = array_fill_keys($this->authorityPHIDs, true);
|
$authority = array_fill_keys($this->authorityPHIDs, true);
|
||||||
|
|
||||||
|
@ -120,13 +133,26 @@ final class PhabricatorAuditListView extends AphrontView {
|
||||||
$reasons,
|
$reasons,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (empty($authority[$audit->getAuditorPHID()])) {
|
$row_class = null;
|
||||||
$rowc[] = null;
|
|
||||||
} else {
|
$has_authority = !empty($authority[$audit->getAuditorPHID()]);
|
||||||
$rowc[] = 'highlighted';
|
if ($has_authority) {
|
||||||
|
$commit_author = $this->commits[$commit_phid]->getAuthorPHID();
|
||||||
|
|
||||||
|
// You don't have authority over package and project audits on your own
|
||||||
|
// commits.
|
||||||
|
|
||||||
|
$auditor_is_user = ($audit->getAuditorPHID() == $user->getPHID());
|
||||||
|
$user_is_author = ($commit_author == $user->getPHID());
|
||||||
|
|
||||||
|
if ($auditor_is_user || !$user_is_author) {
|
||||||
|
$row_class = 'highlighted';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$rowc[] = $row_class;
|
||||||
|
}
|
||||||
|
|
||||||
$table = new AphrontTableView($rows);
|
$table = new AphrontTableView($rows);
|
||||||
$table->setHeaders(
|
$table->setHeaders(
|
||||||
array(
|
array(
|
||||||
|
@ -139,16 +165,16 @@ final class PhabricatorAuditListView extends AphrontView {
|
||||||
$table->setColumnClasses(
|
$table->setColumnClasses(
|
||||||
array(
|
array(
|
||||||
'pri',
|
'pri',
|
||||||
(($this->commits === null) ? '' : 'wide'),
|
($this->showDescriptions ? 'wide' : ''),
|
||||||
'',
|
'',
|
||||||
'',
|
'',
|
||||||
(($this->commits === null) ? 'wide' : ''),
|
($this->showDescriptions ? '' : 'wide'),
|
||||||
));
|
));
|
||||||
$table->setRowClasses($rowc);
|
$table->setRowClasses($rowc);
|
||||||
$table->setColumnVisibility(
|
$table->setColumnVisibility(
|
||||||
array(
|
array(
|
||||||
true,
|
$this->showDescriptions,
|
||||||
($this->commits !== null),
|
$this->showDescriptions,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
|
|
|
@ -20,6 +20,8 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
|
|
||||||
const CHANGES_LIMIT = 100;
|
const CHANGES_LIMIT = 100;
|
||||||
|
|
||||||
|
private $auditAuthorityPHIDs;
|
||||||
|
|
||||||
public function willProcessRequest(array $data) {
|
public function willProcessRequest(array $data) {
|
||||||
// This controller doesn't use blob/path stuff, just pass the dictionary
|
// This controller doesn't use blob/path stuff, just pass the dictionary
|
||||||
// in directly instead of using the AphrontRequest parsing mechanism.
|
// in directly instead of using the AphrontRequest parsing mechanism.
|
||||||
|
@ -50,6 +52,7 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
}
|
}
|
||||||
|
|
||||||
$commit_data = $drequest->loadCommitData();
|
$commit_data = $drequest->loadCommitData();
|
||||||
|
$commit->attachCommitData($commit_data);
|
||||||
|
|
||||||
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
|
$is_foreign = $commit_data->getCommitDetail('foreign-svn-stub');
|
||||||
if ($is_foreign) {
|
if ($is_foreign) {
|
||||||
|
@ -93,7 +96,14 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
$content[] = $detail_panel;
|
$content[] = $detail_panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
$content[] = $this->buildAuditTable($commit);
|
$query = new PhabricatorAuditQuery();
|
||||||
|
$query->withCommitPHIDs(array($commit->getPHID()));
|
||||||
|
$audit_requests = $query->execute();
|
||||||
|
|
||||||
|
$this->auditAuthorityPHIDs =
|
||||||
|
PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user);
|
||||||
|
|
||||||
|
$content[] = $this->buildAuditTable($commit, $audit_requests);
|
||||||
$content[] = $this->buildComments($commit);
|
$content[] = $this->buildComments($commit);
|
||||||
|
|
||||||
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
|
$change_query = DiffusionPathChangeQuery::newFromDiffusionRequest(
|
||||||
|
@ -247,7 +257,7 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
$content[] = $change_list;
|
$content[] = $change_list;
|
||||||
}
|
}
|
||||||
|
|
||||||
$content[] = $this->buildAddCommentView($commit);
|
$content[] = $this->buildAddCommentView($commit, $audit_requests);
|
||||||
|
|
||||||
return $this->buildStandardPageResponse(
|
return $this->buildStandardPageResponse(
|
||||||
$content,
|
$content,
|
||||||
|
@ -331,21 +341,19 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
'</table>';
|
'</table>';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildAuditTable($commit) {
|
private function buildAuditTable($commit, $audits) {
|
||||||
$user = $this->getRequest()->getUser();
|
$user = $this->getRequest()->getUser();
|
||||||
|
|
||||||
$query = new PhabricatorAuditQuery();
|
|
||||||
$query->withCommitPHIDs(array($commit->getPHID()));
|
|
||||||
$audits = $query->execute();
|
|
||||||
|
|
||||||
$view = new PhabricatorAuditListView();
|
$view = new PhabricatorAuditListView();
|
||||||
$view->setAudits($audits);
|
$view->setAudits($audits);
|
||||||
|
$view->setCommits(array($commit));
|
||||||
|
$view->setUser($user);
|
||||||
|
$view->setShowDescriptions(false);
|
||||||
|
|
||||||
$phids = $view->getRequiredHandlePHIDs();
|
$phids = $view->getRequiredHandlePHIDs();
|
||||||
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
|
||||||
$view->setHandles($handles);
|
$view->setHandles($handles);
|
||||||
$view->setAuthorityPHIDs(
|
$view->setAuthorityPHIDs($this->auditAuthorityPHIDs);
|
||||||
PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user));
|
|
||||||
|
|
||||||
$panel = new AphrontPanelView();
|
$panel = new AphrontPanelView();
|
||||||
$panel->setHeader('Audits');
|
$panel->setHeader('Audits');
|
||||||
|
@ -387,7 +395,7 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildAddCommentView($commit) {
|
private function buildAddCommentView($commit, array $audit_requests) {
|
||||||
$user = $this->getRequest()->getUser();
|
$user = $this->getRequest()->getUser();
|
||||||
|
|
||||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||||
|
@ -409,6 +417,8 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
$draft = null;
|
$draft = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$actions = $this->getAuditActions($commit, $audit_requests);
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
$form = id(new AphrontFormView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setAction('/audit/addcomment/')
|
->setAction('/audit/addcomment/')
|
||||||
|
@ -418,7 +428,7 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
->setLabel('Action')
|
->setLabel('Action')
|
||||||
->setName('action')
|
->setName('action')
|
||||||
->setID('audit-action')
|
->setID('audit-action')
|
||||||
->setOptions(PhabricatorAuditActionConstants::getActionNameMap()))
|
->setOptions($actions))
|
||||||
->appendChild(
|
->appendChild(
|
||||||
id(new AphrontFormTextAreaControl())
|
id(new AphrontFormTextAreaControl())
|
||||||
->setLabel('Comments')
|
->setLabel('Comments')
|
||||||
|
@ -466,6 +476,80 @@ final class DiffusionCommitController extends DiffusionController {
|
||||||
return $view;
|
return $view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return a map of available audit actions for rendering into a <select />.
|
||||||
|
* This shows the user valid actions, and does not show nonsense/invalid
|
||||||
|
* actions (like closing an already-closed commit, or resigning from a commit
|
||||||
|
* you have no association with).
|
||||||
|
*/
|
||||||
|
private function getAuditActions(
|
||||||
|
PhabricatorRepositoryCommit $commit,
|
||||||
|
array $audit_requests) {
|
||||||
|
$user = $this->getRequest()->getUser();
|
||||||
|
|
||||||
|
$user_is_author = ($commit->getAuthorPHID() == $user->getPHID());
|
||||||
|
|
||||||
|
$user_request = null;
|
||||||
|
foreach ($audit_requests as $audit_request) {
|
||||||
|
if ($audit_request->getAuditorPHID() == $user->getPHID()) {
|
||||||
|
$user_request = $audit_request;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$actions = array();
|
||||||
|
$actions[PhabricatorAuditActionConstants::COMMENT] = true;
|
||||||
|
|
||||||
|
// We allow you to accept your own commits. A use case here is that you
|
||||||
|
// notice an issue with your own commit and "Raise Concern" as an indicator
|
||||||
|
// to other auditors that you're on top of the issue, then later resolve it
|
||||||
|
// and "Accept". You can not accept on behalf of projects or packages,
|
||||||
|
// however.
|
||||||
|
$actions[PhabricatorAuditActionConstants::ACCEPT] = true;
|
||||||
|
$actions[PhabricatorAuditActionConstants::CONCERN] = true;
|
||||||
|
|
||||||
|
|
||||||
|
// To resign, a user must have authority on some request and not be the
|
||||||
|
// commit's author.
|
||||||
|
if (!$user_is_author) {
|
||||||
|
$may_resign = false;
|
||||||
|
foreach ($audit_requests as $request) {
|
||||||
|
if (empty($this->auditAuthorityPHIDs[$request->getAuditorPHID()])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$may_resign = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user has already resigned, don't show "Resign...".
|
||||||
|
$status_resigned = PhabricatorAuditStatusConstants::RESIGNED;
|
||||||
|
if ($user_request) {
|
||||||
|
if ($user_request->getAuditStatus() == $status_resigned) {
|
||||||
|
$may_resign = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($may_resign) {
|
||||||
|
$actions[PhabricatorAuditActionConstants::RESIGN] = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$status_concern = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED;
|
||||||
|
$concern_raised = ($commit->getAuditStatus() == $status_concern);
|
||||||
|
|
||||||
|
if ($user_is_author && $concern_raised) {
|
||||||
|
$actions[PhabricatorAuditActionConstants::CLOSE] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($actions as $constant => $ignored) {
|
||||||
|
$actions[$constant] =
|
||||||
|
PhabricatorAuditActionConstants::getActionName($constant);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $actions;
|
||||||
|
}
|
||||||
|
|
||||||
private function buildMergesTable(PhabricatorRepositoryCommit $commit) {
|
private function buildMergesTable(PhabricatorRepositoryCommit $commit) {
|
||||||
$drequest = $this->getDiffusionRequest();
|
$drequest = $this->getDiffusionRequest();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
phutil_require_module('phabricator', 'applications/audit/constants/action');
|
phutil_require_module('phabricator', 'applications/audit/constants/action');
|
||||||
phutil_require_module('phabricator', 'applications/audit/constants/commitstatus');
|
phutil_require_module('phabricator', 'applications/audit/constants/commitstatus');
|
||||||
|
phutil_require_module('phabricator', 'applications/audit/constants/status');
|
||||||
phutil_require_module('phabricator', 'applications/audit/editor/comment');
|
phutil_require_module('phabricator', 'applications/audit/editor/comment');
|
||||||
phutil_require_module('phabricator', 'applications/audit/query/audit');
|
phutil_require_module('phabricator', 'applications/audit/query/audit');
|
||||||
phutil_require_module('phabricator', 'applications/audit/storage/auditcomment');
|
phutil_require_module('phabricator', 'applications/audit/storage/auditcomment');
|
||||||
|
|
|
@ -110,19 +110,11 @@ final class DiffusionCommentView extends AphrontView {
|
||||||
$author = $this->getHandle($comment->getActorPHID());
|
$author = $this->getHandle($comment->getActorPHID());
|
||||||
$author_link = $author->renderLink();
|
$author_link = $author->renderLink();
|
||||||
|
|
||||||
|
$action = $comment->getAction();
|
||||||
|
$verb = PhabricatorAuditActionConstants::getActionPastTenseVerb($action);
|
||||||
|
|
||||||
$actions = array();
|
$actions = array();
|
||||||
switch ($comment->getAction()) {
|
$actions[] = "{$author_link} ".phutil_escape_html($verb)." this commit.";
|
||||||
case PhabricatorAuditActionConstants::ACCEPT:
|
|
||||||
$actions[] = "{$author_link} accepted this commit.";
|
|
||||||
break;
|
|
||||||
case PhabricatorAuditActionConstants::CONCERN:
|
|
||||||
$actions[] = "{$author_link} raised concerns with this commit.";
|
|
||||||
break;
|
|
||||||
case PhabricatorAuditActionConstants::COMMENT:
|
|
||||||
default:
|
|
||||||
$actions[] = "{$author_link} commented on this commit.";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($actions as $key => $action) {
|
foreach ($actions as $key => $action) {
|
||||||
$actions[$key] = '<div>'.$action.'</div>';
|
$actions[$key] = '<div>'.$action.'</div>';
|
||||||
|
@ -135,12 +127,16 @@ final class DiffusionCommentView extends AphrontView {
|
||||||
$comment = $this->comment;
|
$comment = $this->comment;
|
||||||
$engine = $this->getEngine();
|
$engine = $this->getEngine();
|
||||||
|
|
||||||
|
if (!strlen($comment->getContent())) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
return
|
return
|
||||||
'<div class="phabricator-remarkup">'.
|
'<div class="phabricator-remarkup">'.
|
||||||
$engine->markupText($comment->getContent()).
|
$engine->markupText($comment->getContent()).
|
||||||
$this->renderSingleView($this->renderInlines()).
|
$this->renderSingleView($this->renderInlines()).
|
||||||
'</div>';
|
'</div>';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private function renderInlines() {
|
private function renderInlines() {
|
||||||
if (!$this->inlineComments) {
|
if (!$this->inlineComments) {
|
||||||
|
|
|
@ -12,6 +12,7 @@ phutil_require_module('phabricator', 'infrastructure/diff/view/inline');
|
||||||
phutil_require_module('phabricator', 'view/base');
|
phutil_require_module('phabricator', 'view/base');
|
||||||
phutil_require_module('phabricator', 'view/layout/transaction');
|
phutil_require_module('phabricator', 'view/layout/transaction');
|
||||||
|
|
||||||
|
phutil_require_module('phutil', 'markup');
|
||||||
phutil_require_module('phutil', 'utils');
|
phutil_require_module('phutil', 'utils');
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -576,6 +576,7 @@ final class PhabricatorDirectoryMainController
|
||||||
$query = new PhabricatorAuditQuery();
|
$query = new PhabricatorAuditQuery();
|
||||||
$query->withAuditorPHIDs($phids);
|
$query->withAuditorPHIDs($phids);
|
||||||
$query->withStatus(PhabricatorAuditQuery::STATUS_OPEN);
|
$query->withStatus(PhabricatorAuditQuery::STATUS_OPEN);
|
||||||
|
$query->withAwaitingUser($user);
|
||||||
$query->needCommitData(true);
|
$query->needCommitData(true);
|
||||||
$query->setLimit(10);
|
$query->setLimit(10);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue