2011-03-25 05:32:26 +01:00
|
|
|
<?php
|
|
|
|
|
2012-03-10 00:46:25 +01:00
|
|
|
final class HeraldTranscriptController extends HeraldController {
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
const FILTER_AFFECTED = 'affected';
|
|
|
|
const FILTER_OWNED = 'owned';
|
|
|
|
const FILTER_ALL = 'all';
|
|
|
|
|
|
|
|
private $id;
|
|
|
|
private $filter;
|
|
|
|
private $handles;
|
2013-08-02 21:23:13 +02:00
|
|
|
private $adapter;
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
public function willProcessRequest(array $data) {
|
|
|
|
$this->id = $data['id'];
|
|
|
|
$map = $this->getFilterMap();
|
|
|
|
$this->filter = idx($data, 'filter');
|
|
|
|
if (empty($map[$this->filter])) {
|
|
|
|
$this->filter = self::FILTER_AFFECTED;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
private function getAdapter() {
|
|
|
|
return $this->adapter;
|
|
|
|
}
|
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
public function processRequest() {
|
2013-10-05 00:17:18 +02:00
|
|
|
$request = $this->getRequest();
|
|
|
|
$viewer = $request->getUser();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-10-05 00:17:18 +02:00
|
|
|
$xscript = id(new HeraldTranscriptQuery())
|
|
|
|
->setViewer($viewer)
|
|
|
|
->withIDs(array($this->id))
|
|
|
|
->executeOne();
|
2011-03-25 05:32:26 +01:00
|
|
|
if (!$xscript) {
|
2013-10-05 00:17:18 +02:00
|
|
|
return new Aphront404Response();
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
require_celerity_resource('herald-test-css');
|
|
|
|
|
|
|
|
$nav = $this->buildSideNav();
|
|
|
|
|
2011-07-03 18:47:31 +02:00
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
if (!$object_xscript) {
|
|
|
|
$notice = id(new AphrontErrorView())
|
|
|
|
->setSeverity(AphrontErrorView::SEVERITY_NOTICE)
|
2013-05-20 17:24:07 +02:00
|
|
|
->setTitle(pht('Old Transcript'))
|
2013-02-07 01:53:49 +01:00
|
|
|
->appendChild(phutil_tag(
|
|
|
|
'p',
|
|
|
|
array(),
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Details of this transcript have been garbage collected.')));
|
2011-07-03 18:47:31 +02:00
|
|
|
$nav->appendChild($notice);
|
|
|
|
} else {
|
2013-10-05 00:17:18 +02:00
|
|
|
$map = HeraldAdapter::getEnabledAdapterMap($viewer);
|
|
|
|
$object_type = $object_xscript->getType();
|
|
|
|
if (empty($map[$object_type])) {
|
|
|
|
// TODO: We should filter these out in the Query, but we have to load
|
|
|
|
// the objectTranscript right now, which is potentially enormous. We
|
|
|
|
// should denormalize the object type, or move the data into a separate
|
|
|
|
// table, and then filter this earlier (and thus raise a better error).
|
|
|
|
// For now, just block access so we don't violate policies.
|
|
|
|
throw new Exception(
|
|
|
|
pht("This transcript has an invalid or inaccessible adapter."));
|
|
|
|
}
|
2013-08-02 21:23:13 +02:00
|
|
|
|
2013-10-05 00:17:18 +02:00
|
|
|
$this->adapter = HeraldAdapter::getAdapterForContentType($object_type);
|
2013-08-02 21:23:13 +02:00
|
|
|
|
2011-07-03 18:47:31 +02:00
|
|
|
$filter = $this->getFilterPHIDs();
|
|
|
|
$this->filterTranscript($xscript, $filter);
|
|
|
|
$phids = array_merge($filter, $this->getTranscriptPHIDs($xscript));
|
|
|
|
$phids = array_unique($phids);
|
|
|
|
$phids = array_filter($phids);
|
|
|
|
|
2012-09-05 04:02:56 +02:00
|
|
|
$handles = $this->loadViewerHandles($phids);
|
2011-07-03 18:47:31 +02:00
|
|
|
$this->handles = $handles;
|
|
|
|
|
General Herald refactoring pass
Summary:
**Who can delete global rules?**: I discussed this with @jungejason. The current behavior is that the rule author or any administrator can delete a global rule, but this
isn't consistent with who can edit a rule (anyone) and doesn't really make much sense (it's an artifact of the global/personal split). I proposed that anyone can delete a
rule but we don't actually delete them, and log the deletion. However, when it came time to actually write the code for this I backed off a bit and continued actually
deleting the rules -- I think this does a reasonable job of balancing accountability with complexity. So the new impelmentation is:
- Personal rules can be deleted only by their owners.
- Global rules can be deleted by any user.
- All deletes are logged.
- Logs are more detailed.
- All logged actions can be viewed in aggregate.
**Minor Cleanup**
- Merged `HomeController` and `AllController`.
- Moved most queries to Query classes.
- Use AphrontFormSelectControl::renderSelectTag() where appropriate (this is a fairly recent addition).
- Use an AphrontErrorView to render the dry run notice (this didn't exist when I ported).
- Reenable some transaction code (this works again now).
- Removed the ability for admins to change rule authors (this was a little buggy, messy, and doesn't make tons of sense after the personal/global rule split).
- Rules which depend on other rules now display the right options (all global rules, all your personal rules for personal rules).
- Fix a bug in AphrontTableView where the "no data" cell would be rendered too wide if some columns are not visible.
- Allow selectFilter() in AphrontNavFilterView to be called without a 'default' argument.
Test Plan:
- Browsed, created, edited, deleted personal and gules.
- Verified generated logs.
- Did some dry runs.
- Verified transcript list and transcript details.
- Created/edited all/any rules; created/edited once/every time rules.
- Filtered admin views by users.
Reviewers: jungejason, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D2040
2012-03-30 19:49:55 +02:00
|
|
|
if ($xscript->getDryRun()) {
|
|
|
|
$notice = new AphrontErrorView();
|
|
|
|
$notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE);
|
2013-05-20 17:24:07 +02:00
|
|
|
$notice->setTitle(pht('Dry Run'));
|
|
|
|
$notice->appendChild(pht('This was a dry run to test Herald '.
|
|
|
|
'rules, no actions were executed.'));
|
General Herald refactoring pass
Summary:
**Who can delete global rules?**: I discussed this with @jungejason. The current behavior is that the rule author or any administrator can delete a global rule, but this
isn't consistent with who can edit a rule (anyone) and doesn't really make much sense (it's an artifact of the global/personal split). I proposed that anyone can delete a
rule but we don't actually delete them, and log the deletion. However, when it came time to actually write the code for this I backed off a bit and continued actually
deleting the rules -- I think this does a reasonable job of balancing accountability with complexity. So the new impelmentation is:
- Personal rules can be deleted only by their owners.
- Global rules can be deleted by any user.
- All deletes are logged.
- Logs are more detailed.
- All logged actions can be viewed in aggregate.
**Minor Cleanup**
- Merged `HomeController` and `AllController`.
- Moved most queries to Query classes.
- Use AphrontFormSelectControl::renderSelectTag() where appropriate (this is a fairly recent addition).
- Use an AphrontErrorView to render the dry run notice (this didn't exist when I ported).
- Reenable some transaction code (this works again now).
- Removed the ability for admins to change rule authors (this was a little buggy, messy, and doesn't make tons of sense after the personal/global rule split).
- Rules which depend on other rules now display the right options (all global rules, all your personal rules for personal rules).
- Fix a bug in AphrontTableView where the "no data" cell would be rendered too wide if some columns are not visible.
- Allow selectFilter() in AphrontNavFilterView to be called without a 'default' argument.
Test Plan:
- Browsed, created, edited, deleted personal and gules.
- Verified generated logs.
- Did some dry runs.
- Verified transcript list and transcript details.
- Created/edited all/any rules; created/edited once/every time rules.
- Filtered admin views by users.
Reviewers: jungejason, btrahan
Reviewed By: btrahan
CC: aran, epriestley
Differential Revision: https://secure.phabricator.com/D2040
2012-03-30 19:49:55 +02:00
|
|
|
$nav->appendChild($notice);
|
|
|
|
}
|
|
|
|
|
2011-07-03 18:47:31 +02:00
|
|
|
$apply_xscript_panel = $this->buildApplyTranscriptPanel(
|
|
|
|
$xscript);
|
|
|
|
$nav->appendChild($apply_xscript_panel);
|
|
|
|
|
|
|
|
$action_xscript_panel = $this->buildActionTranscriptPanel(
|
|
|
|
$xscript);
|
|
|
|
$nav->appendChild($action_xscript_panel);
|
|
|
|
|
|
|
|
$object_xscript_panel = $this->buildObjectTranscriptPanel(
|
|
|
|
$xscript);
|
|
|
|
$nav->appendChild($object_xscript_panel);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-01-21 16:46:13 +01:00
|
|
|
$crumbs = id($this->buildApplicationCrumbs())
|
|
|
|
->addCrumb(
|
|
|
|
id(new PhabricatorCrumbView())
|
|
|
|
->setName(pht('Transcripts'))
|
|
|
|
->setHref($this->getApplicationURI('/transcript/')))
|
|
|
|
->addCrumb(
|
|
|
|
id(new PhabricatorCrumbView())
|
|
|
|
->setName($xscript->getID()));
|
|
|
|
$nav->setCrumbs($crumbs);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-05-20 17:24:07 +02:00
|
|
|
return $this->buildApplicationPage(
|
2013-01-21 16:46:13 +01:00
|
|
|
$nav,
|
2011-03-25 05:32:26 +01:00
|
|
|
array(
|
2013-05-20 17:24:07 +02:00
|
|
|
'title' => pht('Transcript'),
|
|
|
|
'device' => true,
|
2011-03-25 05:32:26 +01:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function renderConditionTestValue($condition, $handles) {
|
|
|
|
$value = $condition->getTestValue();
|
|
|
|
if (!is_scalar($value) && $value !== null) {
|
|
|
|
foreach ($value as $key => $phid) {
|
|
|
|
$handle = idx($handles, $phid);
|
|
|
|
if ($handle) {
|
|
|
|
$value[$key] = $handle->getName();
|
|
|
|
} else {
|
|
|
|
// This shouldn't ever really happen as we are supposed to have
|
|
|
|
// grabbed handles for everything, but be super liberal in what
|
|
|
|
// we accept here since we expect all sorts of weird issues as we
|
|
|
|
// version the system.
|
|
|
|
$value[$key] = 'Unknown Object #'.$phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
sort($value);
|
|
|
|
$value = implode(', ', $value);
|
|
|
|
}
|
|
|
|
|
2013-11-11 18:23:23 +01:00
|
|
|
return phutil_tag('span', array('class' => 'condition-test-value'), $value);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private function buildSideNav() {
|
2012-12-07 22:30:31 +01:00
|
|
|
$nav = new AphrontSideNavFilterView();
|
|
|
|
$nav->setBaseURI(new PhutilURI('/herald/transcript/'.$this->id.'/'));
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$items = array();
|
|
|
|
$filters = $this->getFilterMap();
|
|
|
|
foreach ($filters as $key => $name) {
|
2012-12-07 22:30:31 +01:00
|
|
|
$nav->addFilter($key, $name);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
2012-12-07 22:30:31 +01:00
|
|
|
$nav->selectFilter($this->filter, null);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
return $nav;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getFilterMap() {
|
|
|
|
return array(
|
2013-05-20 17:24:07 +02:00
|
|
|
self::FILTER_AFFECTED => pht('Rules that Affected Me'),
|
|
|
|
self::FILTER_OWNED => pht('Rules I Own'),
|
|
|
|
self::FILTER_ALL => pht('All Rules'),
|
2011-03-25 05:32:26 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected function getFilterPHIDs() {
|
|
|
|
return array($this->getRequest()->getUser()->getPHID());
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getTranscriptPHIDs($xscript) {
|
|
|
|
$phids = array();
|
|
|
|
|
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
if (!$object_xscript) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
|
|
|
$phids[] = $object_xscript->getPHID();
|
|
|
|
|
|
|
|
foreach ($xscript->getApplyTranscripts() as $apply_xscript) {
|
|
|
|
// TODO: This is total hacks. Add another amazing layer of abstraction.
|
|
|
|
$target = (array)$apply_xscript->getTarget();
|
|
|
|
foreach ($target as $phid) {
|
|
|
|
if ($phid) {
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($xscript->getRuleTranscripts() as $rule_xscript) {
|
|
|
|
$phids[] = $rule_xscript->getRuleOwner();
|
|
|
|
}
|
|
|
|
|
|
|
|
$condition_xscripts = $xscript->getConditionTranscripts();
|
|
|
|
if ($condition_xscripts) {
|
|
|
|
$condition_xscripts = call_user_func_array(
|
|
|
|
'array_merge',
|
|
|
|
$condition_xscripts);
|
|
|
|
}
|
|
|
|
foreach ($condition_xscripts as $condition_xscript) {
|
|
|
|
$value = $condition_xscript->getTestValue();
|
|
|
|
// TODO: Also total hacks.
|
|
|
|
if (is_array($value)) {
|
|
|
|
foreach ($value as $phid) {
|
|
|
|
if ($phid) { // TODO: Probably need to make sure this "looks like" a
|
|
|
|
// PHID or decrease the level of hacks here; this used
|
|
|
|
// to be an is_numeric() check in Facebook land.
|
|
|
|
$phids[] = $phid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $phids;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function filterTranscript($xscript, $filter_phids) {
|
|
|
|
$filter_owned = ($this->filter == self::FILTER_OWNED);
|
|
|
|
$filter_affected = ($this->filter == self::FILTER_AFFECTED);
|
|
|
|
|
|
|
|
if (!$filter_owned && !$filter_affected) {
|
|
|
|
// No filtering to be done.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$xscript->getObjectTranscript()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$user_phid = $this->getRequest()->getUser()->getPHID();
|
|
|
|
|
|
|
|
$keep_apply_xscripts = array();
|
|
|
|
$keep_rule_xscripts = array();
|
|
|
|
|
|
|
|
$filter_phids = array_fill_keys($filter_phids, true);
|
|
|
|
|
|
|
|
$rule_xscripts = $xscript->getRuleTranscripts();
|
|
|
|
foreach ($xscript->getApplyTranscripts() as $id => $apply_xscript) {
|
|
|
|
$rule_id = $apply_xscript->getRuleID();
|
|
|
|
if ($filter_owned) {
|
2011-07-03 18:47:31 +02:00
|
|
|
if (empty($rule_xscripts[$rule_id])) {
|
2011-03-25 05:32:26 +01:00
|
|
|
// No associated rule so you can't own this effect.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ($rule_xscripts[$rule_id]->getRuleOwner() != $user_phid) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if ($filter_affected) {
|
|
|
|
$targets = (array)$apply_xscript->getTarget();
|
|
|
|
if (!array_select_keys($filter_phids, $targets)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$keep_apply_xscripts[$id] = true;
|
|
|
|
if ($rule_id) {
|
|
|
|
$keep_rule_xscripts[$rule_id] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
foreach ($rule_xscripts as $rule_id => $rule_xscript) {
|
|
|
|
if ($filter_owned && $rule_xscript->getRuleOwner() == $user_phid) {
|
|
|
|
$keep_rule_xscripts[$rule_id] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$xscript->setRuleTranscripts(
|
|
|
|
array_intersect_key(
|
|
|
|
$xscript->getRuleTranscripts(),
|
|
|
|
$keep_rule_xscripts));
|
|
|
|
|
|
|
|
$xscript->setApplyTranscripts(
|
|
|
|
array_intersect_key(
|
|
|
|
$xscript->getApplyTranscripts(),
|
|
|
|
$keep_apply_xscripts));
|
|
|
|
|
|
|
|
$xscript->setConditionTranscripts(
|
|
|
|
array_intersect_key(
|
|
|
|
$xscript->getConditionTranscripts(),
|
|
|
|
$keep_rule_xscripts));
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildApplyTranscriptPanel($xscript) {
|
|
|
|
$handles = $this->handles;
|
2013-08-02 21:23:13 +02:00
|
|
|
$adapter = $this->getAdapter();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
$rule_type_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL;
|
|
|
|
$action_names = $adapter->getActionNameMap($rule_type_global);
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$rows = array();
|
|
|
|
foreach ($xscript->getApplyTranscripts() as $apply_xscript) {
|
2012-03-30 22:51:54 +02:00
|
|
|
|
|
|
|
$target = $apply_xscript->getTarget();
|
|
|
|
switch ($apply_xscript->getAction()) {
|
2013-08-06 20:23:01 +02:00
|
|
|
case HeraldAdapter::ACTION_NOTHING:
|
2011-03-25 05:32:26 +01:00
|
|
|
$target = '';
|
2012-03-30 22:51:54 +02:00
|
|
|
break;
|
2013-08-06 20:23:01 +02:00
|
|
|
case HeraldAdapter::ACTION_FLAG:
|
2012-03-30 22:51:54 +02:00
|
|
|
$target = PhabricatorFlagColor::getColorName($target);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if ($target) {
|
|
|
|
foreach ($target as $k => $phid) {
|
|
|
|
$target[$k] = $handles[$phid]->getName();
|
|
|
|
}
|
|
|
|
$target = implode("\n", $target);
|
|
|
|
} else {
|
|
|
|
$target = '<empty>';
|
|
|
|
}
|
|
|
|
break;
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($apply_xscript->getApplied()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$outcome = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'outcome-success'),
|
|
|
|
pht('SUCCESS'));
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
2013-11-11 18:23:23 +01:00
|
|
|
$outcome = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'outcome-failure'),
|
|
|
|
pht('FAILURE'));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$rows[] = array(
|
2013-08-02 21:23:13 +02:00
|
|
|
idx($action_names, $apply_xscript->getAction(), pht('Unknown')),
|
2013-02-13 23:50:15 +01:00
|
|
|
$target,
|
2013-02-08 21:07:44 +01:00
|
|
|
hsprintf(
|
|
|
|
'<strong>Taken because:</strong> %s<br />'.
|
|
|
|
'<strong>Outcome:</strong> %s %s',
|
|
|
|
$apply_xscript->getReason(),
|
|
|
|
$outcome,
|
|
|
|
$apply_xscript->getAppliedReason()),
|
2011-03-25 05:32:26 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$table = new AphrontTableView($rows);
|
2013-05-20 17:24:07 +02:00
|
|
|
$table->setNoDataString(pht('No actions were taken.'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$table->setHeaders(
|
|
|
|
array(
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Action'),
|
|
|
|
pht('Target'),
|
|
|
|
pht('Details'),
|
2011-03-25 05:32:26 +01:00
|
|
|
));
|
|
|
|
$table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
'',
|
|
|
|
'',
|
|
|
|
'wide',
|
|
|
|
));
|
|
|
|
|
|
|
|
$panel = new AphrontPanelView();
|
2013-01-19 21:15:41 +01:00
|
|
|
$panel->setHeader(pht('Actions Taken'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$panel->appendChild($table);
|
2013-01-19 21:15:41 +01:00
|
|
|
$panel->setNoBackground();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
return $panel;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildActionTranscriptPanel($xscript) {
|
|
|
|
$action_xscript = mgroup($xscript->getApplyTranscripts(), 'getRuleID');
|
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
$adapter = $this->getAdapter();
|
|
|
|
|
|
|
|
|
|
|
|
$field_names = $adapter->getFieldNameMap();
|
|
|
|
$condition_names = $adapter->getConditionNameMap();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$handles = $this->handles;
|
|
|
|
|
|
|
|
$rule_markup = array();
|
|
|
|
foreach ($xscript->getRuleTranscripts() as $rule_id => $rule) {
|
|
|
|
$cond_markup = array();
|
|
|
|
foreach ($xscript->getConditionTranscriptsForRule($rule_id) as $cond) {
|
|
|
|
if ($cond->getNote()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$note = phutil_tag_div('herald-condition-note', $cond->getNote());
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
|
|
|
$note = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($cond->getResult()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome condition-pass'),
|
|
|
|
"\xE2\x9C\x93");
|
2011-03-25 05:32:26 +01:00
|
|
|
} else {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome condition-fail'),
|
|
|
|
"\xE2\x9C\x98");
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2013-02-08 21:07:44 +01:00
|
|
|
$cond_markup[] = phutil_tag(
|
|
|
|
'li',
|
|
|
|
array(),
|
2013-05-20 17:24:07 +02:00
|
|
|
pht(
|
2013-02-08 21:07:44 +01:00
|
|
|
'%s Condition: %s %s %s%s',
|
|
|
|
$result,
|
2013-08-02 21:23:13 +02:00
|
|
|
idx($field_names, $cond->getFieldName(), pht('Unknown')),
|
|
|
|
idx($condition_names, $cond->getCondition(), pht('Unknown')),
|
2013-02-08 21:07:44 +01:00
|
|
|
$this->renderConditionTestValue($cond, $handles),
|
|
|
|
$note));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($rule->getResult()) {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome rule-pass'),
|
|
|
|
pht('PASS'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$class = 'herald-rule-pass';
|
|
|
|
} else {
|
2013-11-11 18:23:23 +01:00
|
|
|
$result = phutil_tag(
|
|
|
|
'span',
|
|
|
|
array('class' => 'herald-outcome rule-fail'),
|
|
|
|
pht('FAIL'));
|
2011-03-25 05:32:26 +01:00
|
|
|
$class = 'herald-rule-fail';
|
|
|
|
}
|
|
|
|
|
2013-11-11 18:23:23 +01:00
|
|
|
$cond_markup[] = phutil_tag(
|
|
|
|
'li',
|
|
|
|
array(),
|
|
|
|
array($result, $rule->getReason()));
|
2011-03-25 05:32:26 +01:00
|
|
|
$user_phid = $this->getRequest()->getUser()->getPHID();
|
|
|
|
|
|
|
|
$name = $rule->getRuleName();
|
|
|
|
|
|
|
|
$rule_markup[] =
|
2013-02-08 21:07:44 +01:00
|
|
|
phutil_tag(
|
2011-03-25 05:32:26 +01:00
|
|
|
'li',
|
|
|
|
array(
|
|
|
|
'class' => $class,
|
|
|
|
),
|
2013-11-11 18:23:23 +01:00
|
|
|
phutil_tag_div('rule-name', array(
|
|
|
|
phutil_tag('strong', array(), $name),
|
|
|
|
' ',
|
|
|
|
phutil_tag('ul', array(), $cond_markup),
|
|
|
|
)));
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2013-05-20 17:24:07 +02:00
|
|
|
$panel = '';
|
|
|
|
if ($rule_markup) {
|
|
|
|
$panel = new AphrontPanelView();
|
|
|
|
$panel->setHeader(pht('Rule Details'));
|
|
|
|
$panel->setNoBackground();
|
|
|
|
$panel->appendChild(phutil_tag(
|
|
|
|
'ul',
|
|
|
|
array('class' => 'herald-explain-list'),
|
|
|
|
$rule_markup));
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
return $panel;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildObjectTranscriptPanel($xscript) {
|
|
|
|
|
2013-08-02 21:23:13 +02:00
|
|
|
$adapter = $this->getAdapter();
|
|
|
|
$field_names = $adapter->getFieldNameMap();
|
2011-03-25 05:32:26 +01:00
|
|
|
|
|
|
|
$object_xscript = $xscript->getObjectTranscript();
|
|
|
|
|
|
|
|
$data = array();
|
|
|
|
if ($object_xscript) {
|
2011-04-12 04:32:46 +02:00
|
|
|
$phid = $object_xscript->getPHID();
|
2012-09-05 04:02:56 +02:00
|
|
|
$handles = $this->loadViewerHandles(array($phid));
|
2011-04-12 04:32:46 +02:00
|
|
|
|
2011-03-25 05:32:26 +01:00
|
|
|
$data += array(
|
2013-05-20 17:24:07 +02:00
|
|
|
pht('Object Name') => $object_xscript->getName(),
|
|
|
|
pht('Object Type') => $object_xscript->getType(),
|
|
|
|
pht('Object PHID') => $phid,
|
|
|
|
pht('Object Link') => $handles[$phid]->renderLink(),
|
2011-03-25 05:32:26 +01:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
$data += $xscript->getMetadataMap();
|
|
|
|
|
|
|
|
if ($object_xscript) {
|
|
|
|
foreach ($object_xscript->getFields() as $field => $value) {
|
|
|
|
$field = idx($field_names, $field, '['.$field.'?]');
|
|
|
|
$data['Field: '.$field] = $value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$rows = array();
|
|
|
|
foreach ($data as $name => $value) {
|
Fix every HTML issue I could find
Summary:
I attempted to test every interface. I probably missed some stuff, but I at least have some level of confidence that the `phutil_tag` branch is fairly stable.
Fixed these issues:
[1] Fixed a Herald issue with object links in transcripts. Some actions return
links; this was previously hard-coded.
[2] DarkConsole refactoring created an issue where the "`" event handler registered too many times.
[3] Fixed a bug where `strlen($value)` was being checked, but fields may now return array(). Possibly we should implement phutil_is_empty_html() or similar.
[4] Fixed a undefined variable issue for image edit transactions.
[5] Fixed an issue with rendering participant transactions. This required phutil_safe_html() because `pht()` can't handle `array()` for `%s`.
[6] Fixed an issue where feed was entirely overescaped by reverting an overly ambitious render_tag -> tag.
[7] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[8] Fixed an issue where • was shown escaped.
[9] Fixed an issue where "no data" was overescaped.
[10] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[11] Fixed an issue with strict tables and inserting `''`.
[12] Fixed an issue with missing space after ":" for mini panels.
Encountered (but did not fix) these issues:
[X1] "e" works incorrectly on comments you are not allowed to edit. Did not fix.
[X2] Coverage currently interacts incorrectly with "--everything" for Phutil tests.
Test Plan:
- Viewed Differential.
- Created a diff via copy/paste.
- Viewed standalone diff.
- Jumped to diff via changeset table.
- Created a revision.
- Updated revision.
- Added a comment.
- Edited revision dependencies.
- Edited revision tasks.
- Viewed MetaMTA transcripts.
- Viewed Herald transcripts [1].
- Downloaded raw diff.
- Flagged / unflagged revision.
- Added/edited/deleted inline comment.
- Collapsed/expanded file.
- Did show raw left.
- Did show raw right.
- Checked previews for available actions.
- Clicked remarkup buttons
- Used filetree view.
- Used keyboard: F, j, k, J, K, n, p, t, h, "?" [2] [X1].
- Created a meme.
- Uploaded a file via drag and drop.
- Viewed a revision with no reviewers.
- Viewed a revision with >100 files.
- Viewed various other revisions [3].
- Viewed an image diff.
- Added image diff inline comments.
- Viewed Maniphest.
- Ran various queries.
- Created task.
- Created similar task.
- Added comments to tasks.
- Ran custom query.
- Saved custom query.
- Edited custom queries.
- Drag-reordered tasks.
- Batch edited tasks.
- Exported tasks to excel.
- Looked at reports (issue in T2311 notwithstanding).
- Viewed Diffusion.
- Browsed Git, SVN, HG repositories.
- Looked at history, browse, change, commit views.
- Viewed audit.
- Performed various audit searches.
- Viewed Paste.
- Performed paste searches.
- Created, edited, forked paste.
- Viewed Phriction.
- Edited a page.
- Viewed edit history.
- Used search typeahead to search for user / application.
- Used search to search for text.
- Viewed Phame.
- Viewed Blog, Post.
- Viewed live post.
- Published/unpublished post.
- Previewed post.
- Viewed Pholio.
- Edited/commented mock.
- Viewed ponder.
- Viewed question.
- Added answer/comment.
- Viewed Diviner.
- Viewed Conpherence [4] [5].
- Made Conpherence updates.
- Viewed calendar.
- Created status.
- Viewed status.
- Viewed Feed [6].
- Viewed Projects.
- Viewed project detail.
- Edited project.
- Viewed Owners.
- Viewed package detail.
- Edited package [7].
- Viewed flags.
- Edited flag.
- Deleted flag.
- Viewed Herald.
- Viewed rules.
- Created rule.
- Edited rule.
- Viewed edit log.
- Viewed transcripts.
- Inspected a transcript.
- Viewed People.
- Viewed list.
- Administrated user.
- Checked username/delete stuff.
- Looked at create/import LDAP/activity logs.
- Looked at a user profile.
- Looked at user about page.
- Looked at Repositories.
- Edited repository.
- Edited arcanist project.
- Looked at daemons.
- Looked at all daemons [8].
- Viewed combined log.
- Looked at configuration.
- Edited configuration.
- Looked at setup issues [9].
- Looked at current settings.
- Looked at application list.
- Installed / uninstalled applications [10].
- Looked at mailing lists.
- Created a mailing list.
- Edited a mailing list.
- Looked at sent mail.
- Looked at received mail.
- Looked at send/receive tests.
- Looked at settings.
- Clicked through all the panels.
- Looked at slowvote.
- Created a slowvote [11].
- Voted in a slowvote.
- Looked at Macro.
- Created a macro.
- Edited a macro.
- Commented on a macro.
- Looked at Countdown.
- Created a Countdown.
- Looked at it.
- Looked at Drydock.
- Poked around a bit.
- Looked at Fact.
- Poked around a bit.
- Looked at files.
- Looked at a file.
- Uploaded a file.
- Looked at Conduit.
- Made a Conduit call.
- Looked at UIExamples.
- Looked at PHPAST.
- Looked at PHIDs.
- Looked at notification menu.
- Looked at notification detail.
- Logged out.
- Logged in.
- Looked at homepage [12].
- Ran `arc unit --everything --no-coverage` [X2].
Reviewers: vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4807
2013-02-05 02:06:34 +01:00
|
|
|
if (!($value instanceof PhutilSafeHTML)) {
|
|
|
|
if (!is_scalar($value) && !is_null($value)) {
|
|
|
|
$value = implode("\n", $value);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
|
Fix every HTML issue I could find
Summary:
I attempted to test every interface. I probably missed some stuff, but I at least have some level of confidence that the `phutil_tag` branch is fairly stable.
Fixed these issues:
[1] Fixed a Herald issue with object links in transcripts. Some actions return
links; this was previously hard-coded.
[2] DarkConsole refactoring created an issue where the "`" event handler registered too many times.
[3] Fixed a bug where `strlen($value)` was being checked, but fields may now return array(). Possibly we should implement phutil_is_empty_html() or similar.
[4] Fixed a undefined variable issue for image edit transactions.
[5] Fixed an issue with rendering participant transactions. This required phutil_safe_html() because `pht()` can't handle `array()` for `%s`.
[6] Fixed an issue where feed was entirely overescaped by reverting an overly ambitious render_tag -> tag.
[7] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[8] Fixed an issue where • was shown escaped.
[9] Fixed an issue where "no data" was overescaped.
[10] Fixed an issue with strict tables and inserting `''` instead of `0` into an integer column.
[11] Fixed an issue with strict tables and inserting `''`.
[12] Fixed an issue with missing space after ":" for mini panels.
Encountered (but did not fix) these issues:
[X1] "e" works incorrectly on comments you are not allowed to edit. Did not fix.
[X2] Coverage currently interacts incorrectly with "--everything" for Phutil tests.
Test Plan:
- Viewed Differential.
- Created a diff via copy/paste.
- Viewed standalone diff.
- Jumped to diff via changeset table.
- Created a revision.
- Updated revision.
- Added a comment.
- Edited revision dependencies.
- Edited revision tasks.
- Viewed MetaMTA transcripts.
- Viewed Herald transcripts [1].
- Downloaded raw diff.
- Flagged / unflagged revision.
- Added/edited/deleted inline comment.
- Collapsed/expanded file.
- Did show raw left.
- Did show raw right.
- Checked previews for available actions.
- Clicked remarkup buttons
- Used filetree view.
- Used keyboard: F, j, k, J, K, n, p, t, h, "?" [2] [X1].
- Created a meme.
- Uploaded a file via drag and drop.
- Viewed a revision with no reviewers.
- Viewed a revision with >100 files.
- Viewed various other revisions [3].
- Viewed an image diff.
- Added image diff inline comments.
- Viewed Maniphest.
- Ran various queries.
- Created task.
- Created similar task.
- Added comments to tasks.
- Ran custom query.
- Saved custom query.
- Edited custom queries.
- Drag-reordered tasks.
- Batch edited tasks.
- Exported tasks to excel.
- Looked at reports (issue in T2311 notwithstanding).
- Viewed Diffusion.
- Browsed Git, SVN, HG repositories.
- Looked at history, browse, change, commit views.
- Viewed audit.
- Performed various audit searches.
- Viewed Paste.
- Performed paste searches.
- Created, edited, forked paste.
- Viewed Phriction.
- Edited a page.
- Viewed edit history.
- Used search typeahead to search for user / application.
- Used search to search for text.
- Viewed Phame.
- Viewed Blog, Post.
- Viewed live post.
- Published/unpublished post.
- Previewed post.
- Viewed Pholio.
- Edited/commented mock.
- Viewed ponder.
- Viewed question.
- Added answer/comment.
- Viewed Diviner.
- Viewed Conpherence [4] [5].
- Made Conpherence updates.
- Viewed calendar.
- Created status.
- Viewed status.
- Viewed Feed [6].
- Viewed Projects.
- Viewed project detail.
- Edited project.
- Viewed Owners.
- Viewed package detail.
- Edited package [7].
- Viewed flags.
- Edited flag.
- Deleted flag.
- Viewed Herald.
- Viewed rules.
- Created rule.
- Edited rule.
- Viewed edit log.
- Viewed transcripts.
- Inspected a transcript.
- Viewed People.
- Viewed list.
- Administrated user.
- Checked username/delete stuff.
- Looked at create/import LDAP/activity logs.
- Looked at a user profile.
- Looked at user about page.
- Looked at Repositories.
- Edited repository.
- Edited arcanist project.
- Looked at daemons.
- Looked at all daemons [8].
- Viewed combined log.
- Looked at configuration.
- Edited configuration.
- Looked at setup issues [9].
- Looked at current settings.
- Looked at application list.
- Installed / uninstalled applications [10].
- Looked at mailing lists.
- Created a mailing list.
- Edited a mailing list.
- Looked at sent mail.
- Looked at received mail.
- Looked at send/receive tests.
- Looked at settings.
- Clicked through all the panels.
- Looked at slowvote.
- Created a slowvote [11].
- Voted in a slowvote.
- Looked at Macro.
- Created a macro.
- Edited a macro.
- Commented on a macro.
- Looked at Countdown.
- Created a Countdown.
- Looked at it.
- Looked at Drydock.
- Poked around a bit.
- Looked at Fact.
- Poked around a bit.
- Looked at files.
- Looked at a file.
- Uploaded a file.
- Looked at Conduit.
- Made a Conduit call.
- Looked at UIExamples.
- Looked at PHPAST.
- Looked at PHIDs.
- Looked at notification menu.
- Looked at notification detail.
- Logged out.
- Logged in.
- Looked at homepage [12].
- Ran `arc unit --everything --no-coverage` [X2].
Reviewers: vrana, btrahan
Reviewed By: vrana
CC: aran
Maniphest Tasks: T2432
Differential Revision: https://secure.phabricator.com/D4807
2013-02-05 02:06:34 +01:00
|
|
|
if (strlen($value) > 256) {
|
|
|
|
$value = phutil_tag(
|
|
|
|
'textarea',
|
|
|
|
array(
|
|
|
|
'class' => 'herald-field-value-transcript',
|
|
|
|
),
|
|
|
|
$value);
|
|
|
|
}
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
2013-02-13 23:50:15 +01:00
|
|
|
$rows[] = array($name, $value);
|
2011-03-25 05:32:26 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
$table = new AphrontTableView($rows);
|
|
|
|
$table->setColumnClasses(
|
|
|
|
array(
|
|
|
|
'header',
|
|
|
|
'wide',
|
|
|
|
));
|
|
|
|
|
|
|
|
$panel = new AphrontPanelView();
|
2013-05-20 17:24:07 +02:00
|
|
|
$panel->setHeader(pht('Object Transcript'));
|
|
|
|
$panel->setNoBackground();
|
2011-03-25 05:32:26 +01:00
|
|
|
$panel->appendChild($table);
|
|
|
|
|
|
|
|
return $panel;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|