Rough cut of herald transcripts and Differential adapter.
This commit is contained in:
		| @@ -267,6 +267,7 @@ return array( | |||||||
|     'image/jpeg'  => 'image/jpeg', |     'image/jpeg'  => 'image/jpeg', | ||||||
|     'image/jpg'   => 'image/jpg', |     'image/jpg'   => 'image/jpg', | ||||||
|     'image/png'   => 'image/png', |     'image/png'   => 'image/png', | ||||||
|  |     'image/gif'   => 'image/gif', | ||||||
|     'text/plain'  => 'text/plain; charset=utf-8', |     'text/plain'  => 'text/plain; charset=utf-8', | ||||||
|   ), |   ), | ||||||
|  |  | ||||||
|   | |||||||
| @@ -188,6 +188,7 @@ phutil_register_library_map(array( | |||||||
|     'HeraldController' => 'applications/herald/controller/base', |     'HeraldController' => 'applications/herald/controller/base', | ||||||
|     'HeraldDAO' => 'applications/herald/storage/base', |     'HeraldDAO' => 'applications/herald/storage/base', | ||||||
|     'HeraldDeleteController' => 'applications/herald/controller/delete', |     'HeraldDeleteController' => 'applications/herald/controller/delete', | ||||||
|  |     'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/differential', | ||||||
|     'HeraldDryRunAdapter' => 'applications/herald/adapter/dryrun', |     'HeraldDryRunAdapter' => 'applications/herald/adapter/dryrun', | ||||||
|     'HeraldEffect' => 'applications/herald/engine/effect', |     'HeraldEffect' => 'applications/herald/engine/effect', | ||||||
|     'HeraldEngine' => 'applications/herald/engine/engine', |     'HeraldEngine' => 'applications/herald/engine/engine', | ||||||
| @@ -204,6 +205,8 @@ phutil_register_library_map(array( | |||||||
|     'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule', |     'HeraldRuleTranscript' => 'applications/herald/storage/transcript/rule', | ||||||
|     'HeraldTestConsoleController' => 'applications/herald/controller/test', |     'HeraldTestConsoleController' => 'applications/herald/controller/test', | ||||||
|     'HeraldTranscript' => 'applications/herald/storage/transcript/base', |     'HeraldTranscript' => 'applications/herald/storage/transcript/base', | ||||||
|  |     'HeraldTranscriptController' => 'applications/herald/controller/transcript', | ||||||
|  |     'HeraldTranscriptListController' => 'applications/herald/controller/transcriptlist', | ||||||
|     'HeraldValueTypeConfig' => 'applications/herald/config/valuetype', |     'HeraldValueTypeConfig' => 'applications/herald/config/valuetype', | ||||||
|     'Javelin' => 'infrastructure/javelin/api', |     'Javelin' => 'infrastructure/javelin/api', | ||||||
|     'LiskDAO' => 'storage/lisk/dao', |     'LiskDAO' => 'storage/lisk/dao', | ||||||
| @@ -539,6 +542,7 @@ phutil_register_library_map(array( | |||||||
|     'HeraldController' => 'PhabricatorController', |     'HeraldController' => 'PhabricatorController', | ||||||
|     'HeraldDAO' => 'PhabricatorLiskDAO', |     'HeraldDAO' => 'PhabricatorLiskDAO', | ||||||
|     'HeraldDeleteController' => 'HeraldController', |     'HeraldDeleteController' => 'HeraldController', | ||||||
|  |     'HeraldDifferentialRevisionAdapter' => 'HeraldObjectAdapter', | ||||||
|     'HeraldDryRunAdapter' => 'HeraldObjectAdapter', |     'HeraldDryRunAdapter' => 'HeraldObjectAdapter', | ||||||
|     'HeraldHomeController' => 'HeraldController', |     'HeraldHomeController' => 'HeraldController', | ||||||
|     'HeraldNewController' => 'HeraldController', |     'HeraldNewController' => 'HeraldController', | ||||||
| @@ -546,6 +550,8 @@ phutil_register_library_map(array( | |||||||
|     'HeraldRuleController' => 'HeraldController', |     'HeraldRuleController' => 'HeraldController', | ||||||
|     'HeraldTestConsoleController' => 'HeraldController', |     'HeraldTestConsoleController' => 'HeraldController', | ||||||
|     'HeraldTranscript' => 'HeraldDAO', |     'HeraldTranscript' => 'HeraldDAO', | ||||||
|  |     'HeraldTranscriptController' => 'HeraldController', | ||||||
|  |     'HeraldTranscriptListController' => 'HeraldController', | ||||||
|     'ManiphestController' => 'PhabricatorController', |     'ManiphestController' => 'PhabricatorController', | ||||||
|     'ManiphestDAO' => 'PhabricatorLiskDAO', |     'ManiphestDAO' => 'PhabricatorLiskDAO', | ||||||
|     'ManiphestTask' => 'ManiphestDAO', |     'ManiphestTask' => 'ManiphestDAO', | ||||||
|   | |||||||
| @@ -225,7 +225,8 @@ class AphrontDefaultApplicationConfiguration | |||||||
|         'delete/(?P<id>\d+)/$' => 'HeraldDeleteController', |         'delete/(?P<id>\d+)/$' => 'HeraldDeleteController', | ||||||
|         'test/$' => 'HeraldTestConsoleController', |         'test/$' => 'HeraldTestConsoleController', | ||||||
|         'transcript/$' => 'HeraldTranscriptListController', |         'transcript/$' => 'HeraldTranscriptListController', | ||||||
|         'transcript/(?P<id>\d+)/$' => 'HeraldTranscriptController', |         'transcript/(?P<id>\d+)/(?:(?P<filter>\w+)/)?$' | ||||||
|  |           => 'HeraldTranscriptController', | ||||||
|       ), |       ), | ||||||
|  |  | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -38,6 +38,11 @@ class DifferentialRevisionViewController extends DifferentialController { | |||||||
|  |  | ||||||
|     $diffs = $revision->loadDiffs(); |     $diffs = $revision->loadDiffs(); | ||||||
|  |  | ||||||
|  |     if (!$diffs) { | ||||||
|  |       throw new Exception( | ||||||
|  |         "This revision has no diffs. Something has gone quite wrong."); | ||||||
|  |     } | ||||||
|  |  | ||||||
|     $diff_vs = $request->getInt('vs'); |     $diff_vs = $request->getInt('vs'); | ||||||
|     $target = end($diffs); |     $target = end($diffs); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,257 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Copyright 2011 Facebook, Inc. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class HeraldDifferentialRevisionAdapter extends HeraldObjectAdapter { | ||||||
|  |  | ||||||
|  |   protected $revision; | ||||||
|  |   protected $changesets; | ||||||
|  |   protected $diff = null; | ||||||
|  |  | ||||||
|  |   protected $explicitCCs; | ||||||
|  |   protected $explicitReviewers; | ||||||
|  |   protected $forbiddenCCs; | ||||||
|  |   protected $forbiddenReviewers; | ||||||
|  |  | ||||||
|  |   protected $newCCs = array(); | ||||||
|  |   protected $remCCs = array(); | ||||||
|  |  | ||||||
|  |   public function __construct(DifferentialRevision $revision) { | ||||||
|  |     $revision->loadRelationships(); | ||||||
|  |     $this->revision = $revision; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function setDiff(Diff $diff) { | ||||||
|  |     $this->diff = $diff; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function setExplicitCCs($explicit_ccs) { | ||||||
|  |     $this->explicitCCs = $explicit_ccs; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function setExplicitReviewers($explicit_reviewers) { | ||||||
|  |     $this->explicitReviewers = $explicit_reviewers; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function setForbiddenCCs($forbidden_ccs) { | ||||||
|  |     $this->forbiddenCCs = $forbidden_ccs; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function setForbiddenReviewers($forbidden_reviewers) { | ||||||
|  |     $this->forbiddenReviewers = $forbidden_reviewers; | ||||||
|  |     return $this; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getCCsAddedByHerald() { | ||||||
|  |     return array_diff_key($this->newCCs, $this->remCCs); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getCCsRemovedByHerald() { | ||||||
|  |     return $this->remCCs; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getPHID() { | ||||||
|  |     return $this->revision->getPHID(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getHeraldName() { | ||||||
|  |     return $this->revision->getTitle(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getHeraldTypeName() { | ||||||
|  |     return HeraldContentTypeConfig::CONTENT_TYPE_DIFFERENTIAL; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function loadChangesets() { | ||||||
|  |     if ($this->changesets) { | ||||||
|  |       return $this->changesets; | ||||||
|  |     } | ||||||
|  |     $diff = $this->loadDiff(); | ||||||
|  |     $changes = $diff->getChangesets(); | ||||||
|  |     return ($this->changesets = $changes); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function loadDiff() { | ||||||
|  |     if ($this->diff === null) { | ||||||
|  |       $this->diff = $this->revision->getActiveDiff(); | ||||||
|  |     } | ||||||
|  |     return $this->diff; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function getContentDictionary() { | ||||||
|  |     $changes = $this->loadChangesets(); | ||||||
|  |  | ||||||
|  |     $hunks = array(); | ||||||
|  |     if ($changes) { | ||||||
|  |       $hunks = id(new DifferentialHunk())->loadAllwhere( | ||||||
|  |         'changesetID in (%Ld)', | ||||||
|  |         mpull($changes, 'getID')); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $dict = array(); | ||||||
|  |     $hunks = mgroup($hunks, 'getChangesetID'); | ||||||
|  |     $changes = mpull($changes, null, 'getID'); | ||||||
|  |     foreach ($changes as $id => $change) { | ||||||
|  |       $filename = $change->getFilename(); | ||||||
|  |       $content = array(); | ||||||
|  |       foreach (idx($hunks, $id, array()) as $hunk) { | ||||||
|  |         $content[] = $hunk->makeChanges(); | ||||||
|  |       } | ||||||
|  |       $dict[$filename] = implode("\n", $content); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $dict; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getHeraldField($field) { | ||||||
|  |     switch ($field) { | ||||||
|  |       case HeraldFieldConfig::FIELD_TITLE: | ||||||
|  |         return $this->revision->getTitle(); | ||||||
|  |         break; | ||||||
|  |       case HeraldFieldConfig::FIELD_BODY: | ||||||
|  |         return $this->revision->getSummary()."\n". | ||||||
|  |                $this->revision->getTestPlan(); | ||||||
|  |         break; | ||||||
|  |       case HeraldFieldConfig::FIELD_AUTHOR: | ||||||
|  |         return $this->revision->getAuthorPHID(); | ||||||
|  |         break; | ||||||
|  |       case HeraldFieldConfig::FIELD_DIFF_FILE: | ||||||
|  |         $changes = $this->loadChangesets(); | ||||||
|  |         return array_values(mpull($changes, 'getFilename')); | ||||||
|  |       case HeraldFieldConfig::FIELD_CC: | ||||||
|  |         if (isset($this->explicitCCs)) { | ||||||
|  |           return array_keys($this->explicitCCs); | ||||||
|  |         } else { | ||||||
|  |           return $this->revision->getCCPHIDs(); | ||||||
|  |         } | ||||||
|  |       case HeraldFieldConfig::FIELD_REVIEWERS: | ||||||
|  |         if (isset($this->explicitReviewers)) { | ||||||
|  |           return array_keys($this->explicitReviewers); | ||||||
|  |         } else { | ||||||
|  |           return $this->revision->getReviewers(); | ||||||
|  |         } | ||||||
|  | /* TODO | ||||||
|  |       case HeraldFieldConfig::FIELD_REPOSITORY: | ||||||
|  |         $id = $this->revision->getRepositoryID(); | ||||||
|  |         if (!$id) { | ||||||
|  |           return null; | ||||||
|  |         } | ||||||
|  |         require_module_lazy('intern/repository'); | ||||||
|  |         $repository = RepositoryRef::getByID($id); | ||||||
|  |         if (!$repository) { | ||||||
|  |           return null; | ||||||
|  |         } | ||||||
|  |         return $repository->getFBID(); | ||||||
|  | */ | ||||||
|  |       case HeraldFieldConfig::FIELD_DIFF_CONTENT: | ||||||
|  |         return $this->getContentDictionary(); | ||||||
|  | /* TODO | ||||||
|  |       case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE: | ||||||
|  |         return mpull( | ||||||
|  |           DiffOwners::getPackages($this->loadDiff()), | ||||||
|  |           'getFBID'); | ||||||
|  | */ | ||||||
|  | /* TODO | ||||||
|  |       case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE_OWNER: | ||||||
|  |         return DiffOwners::getOwners($this->loadDiff()); | ||||||
|  | */ | ||||||
|  |       default: | ||||||
|  |         throw new Exception("Invalid field '{$field}'."); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function applyHeraldEffects(array $effects) { | ||||||
|  |     $result = array(); | ||||||
|  |     if ($this->explicitCCs) { | ||||||
|  |       $effect = new HeraldEffect(); | ||||||
|  |       $effect->setAction(HeraldActionConfig::ACTION_ADD_CC); | ||||||
|  |       $effect->setTarget(array_keys($this->explicitCCs)); | ||||||
|  |       $effect->setReason( | ||||||
|  |         'CCs provided explicitly by revision author or carried over from a '. | ||||||
|  |         'previous version of the revision.'); | ||||||
|  |       $result[] = new HeraldApplyTranscript( | ||||||
|  |         $effect, | ||||||
|  |         true, | ||||||
|  |         'Added addresses to CC list.'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $forbidden_ccs = array_fill_keys( | ||||||
|  |       nonempty($this->forbiddenCCs, array()), | ||||||
|  |       true); | ||||||
|  |  | ||||||
|  |     foreach ($effects as $effect) { | ||||||
|  |       $action = $effect->getAction(); | ||||||
|  |       switch ($action) { | ||||||
|  |         case HeraldActionConfig::ACTION_NOTHING: | ||||||
|  |           $result[] = new HeraldApplyTranscript( | ||||||
|  |             $effect, | ||||||
|  |             true, | ||||||
|  |             'OK, did nothing.'); | ||||||
|  |           break; | ||||||
|  |         case HeraldActionConfig::ACTION_ADD_CC: | ||||||
|  |           $base_target = $effect->getTarget(); | ||||||
|  |           $forbidden = array(); | ||||||
|  |           foreach ($base_target as $key => $fbid) { | ||||||
|  |             if (isset($forbidden_ccs[$fbid])) { | ||||||
|  |               $forbidden[] = $fbid; | ||||||
|  |               unset($base_target[$key]); | ||||||
|  |             } else { | ||||||
|  |               $this->newCCs[$fbid] = true; | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |  | ||||||
|  |           if ($forbidden) { | ||||||
|  |             $failed = clone $effect; | ||||||
|  |             $failed->setTarget($forbidden); | ||||||
|  |             if ($base_target) { | ||||||
|  |               $effect->setTarget($base_target); | ||||||
|  |               $result[] = new HeraldApplyTranscript( | ||||||
|  |                 $effect, | ||||||
|  |                 true, | ||||||
|  |                 'Added these addresses to CC list. Others could not be added.'); | ||||||
|  |             } | ||||||
|  |             $result[] = new HeraldApplyTranscript( | ||||||
|  |               $failed, | ||||||
|  |               false, | ||||||
|  |               'CC forbidden, these addresses have unsubscribed.'); | ||||||
|  |           } else { | ||||||
|  |             $result[] = new HeraldApplyTranscript( | ||||||
|  |               $effect, | ||||||
|  |               true, | ||||||
|  |               'Added addresses to CC list.'); | ||||||
|  |           } | ||||||
|  |           break; | ||||||
|  |         case HeraldActionConfig::ACTION_REMOVE_CC: | ||||||
|  |           foreach ($effect->getTarget() as $fbid) { | ||||||
|  |             $this->remCCs[$fbid] = true; | ||||||
|  |           } | ||||||
|  |           $result[] = new HeraldApplyTranscript( | ||||||
|  |             $effect, | ||||||
|  |             true, | ||||||
|  |             'Removed addresses from CC list.'); | ||||||
|  |           break; | ||||||
|  |         default: | ||||||
|  |           throw new Exception("No rules to handle action '{$action}'."); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return $result; | ||||||
|  |   } | ||||||
|  | } | ||||||
							
								
								
									
										20
									
								
								src/applications/herald/adapter/differential/__init__.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/applications/herald/adapter/differential/__init__.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * This file is automatically generated. Lint this module to rebuild it. | ||||||
|  |  * @generated | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | phutil_require_module('phabricator', 'applications/differential/storage/hunk'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/adapter/base'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/config/action'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/config/contenttype'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/config/field'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/engine/effect'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/storage/transcript/apply'); | ||||||
|  |  | ||||||
|  | phutil_require_module('phutil', 'utils'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | phutil_require_source('HeraldDifferentialRevisionAdapter.php'); | ||||||
| @@ -444,7 +444,7 @@ class HeraldRuleController extends HeraldController { | |||||||
|     return array( |     return array( | ||||||
|       'source' => array( |       'source' => array( | ||||||
|         'email'       => '/typeahead/common/mailable/', |         'email'       => '/typeahead/common/mailable/', | ||||||
|         'user'        => '/typeahead/common/user/', |         'user'        => '/typeahead/common/users/', | ||||||
|         'repository'  => '/typeahead/common/repository/', |         'repository'  => '/typeahead/common/repository/', | ||||||
| /* | /* | ||||||
|         'tag'         => '/datasource/tag/', |         'tag'         => '/datasource/tag/', | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
|  |  | ||||||
| phutil_require_module('phabricator', 'aphront/response/redirect'); | phutil_require_module('phabricator', 'aphront/response/redirect'); | ||||||
| phutil_require_module('phabricator', 'applications/differential/storage/revision'); | phutil_require_module('phabricator', 'applications/differential/storage/revision'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/adapter/differential'); | ||||||
| phutil_require_module('phabricator', 'applications/herald/adapter/dryrun'); | phutil_require_module('phabricator', 'applications/herald/adapter/dryrun'); | ||||||
| phutil_require_module('phabricator', 'applications/herald/controller/base'); | phutil_require_module('phabricator', 'applications/herald/controller/base'); | ||||||
| phutil_require_module('phabricator', 'applications/herald/engine/engine'); | phutil_require_module('phabricator', 'applications/herald/engine/engine'); | ||||||
|   | |||||||
| @@ -0,0 +1,543 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Copyright 2011 Facebook, Inc. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class HeraldTranscriptController extends HeraldController { | ||||||
|  |  | ||||||
|  |   const FILTER_AFFECTED = 'affected'; | ||||||
|  |   const FILTER_OWNED    = 'owned'; | ||||||
|  |   const FILTER_ALL      = 'all'; | ||||||
|  |  | ||||||
|  |   private $id; | ||||||
|  |   private $filter; | ||||||
|  |   private $handles; | ||||||
|  |  | ||||||
|  |   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; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function processRequest() { | ||||||
|  |  | ||||||
|  |     $xscript = id(new HeraldTranscript())->load($this->id); | ||||||
|  |     if (!$xscript) { | ||||||
|  |       throw new Exception('Uknown transcript!'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $field_names = HeraldFieldConfig::getFieldMap(); | ||||||
|  |     $condition_names = HeraldConditionConfig::getConditionMap(); | ||||||
|  |     $action_names = HeraldActionConfig::getActionMap(); | ||||||
|  |  | ||||||
|  |     require_celerity_resource('herald-test-css'); | ||||||
|  |  | ||||||
|  |     $filter = $this->getFilterPHIDs(); | ||||||
|  |     $this->filterTranscript($xscript, $filter); | ||||||
|  |     $phids = array_merge($filter, $this->getTranscriptPHIDs($xscript)); | ||||||
|  |     $phids = array_unique($phids); | ||||||
|  |     $phids = array_filter($phids); | ||||||
|  |  | ||||||
|  |     $handles = id(new PhabricatorObjectHandleData($phids)) | ||||||
|  |       ->loadHandles(); | ||||||
|  |     $this->handles = $handles; | ||||||
|  |  | ||||||
|  |     $object_xscript = $xscript->getObjectTranscript(); | ||||||
|  |  | ||||||
|  |     $nav = $this->buildSideNav(); | ||||||
|  |  | ||||||
|  |     $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); | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $notice = null; | ||||||
|  |     if ($xscript->getDryRun()) { | ||||||
|  |       $notice = | ||||||
|  |         <tools:notice title="Dry Run"> | ||||||
|  |           This was a dry run to test Herald rules, no actions were executed. | ||||||
|  |         </tools:notice>; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (!$object_xscript) { | ||||||
|  |       $notice = | ||||||
|  |         <x:frag> | ||||||
|  |           <tools:notice title="Old Transcript"> | ||||||
|  |             Details of this transcript have been discarded. Full transcripts | ||||||
|  |             are retained for 30 days. | ||||||
|  |           </tools:notice> | ||||||
|  |           {$notice} | ||||||
|  |         </x:frag>; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     return | ||||||
|  |       <herald:standard-page title="Transcript"> | ||||||
|  |         <div style="padding: 1em;"> | ||||||
|  |           <tools:side-nav items={$this->renderNavItems()}> | ||||||
|  |             {$notice} | ||||||
|  |             {$apply_xscript_markup} | ||||||
|  |             {$rule_table} | ||||||
|  |             {$object_xscript_table} | ||||||
|  |           </tools:side-nav> | ||||||
|  |         </div> | ||||||
|  |       </herald:standard-page>; | ||||||
|  | */ | ||||||
|  |  | ||||||
|  |     return $this->buildStandardPageResponse( | ||||||
|  |       $nav, | ||||||
|  |       array( | ||||||
|  |         'title' => 'Transcript', | ||||||
|  |       )); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return | ||||||
|  |       '<span class="condition-test-value">'. | ||||||
|  |         phutil_escape_html($value). | ||||||
|  |       '</span>'; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private function buildSideNav() { | ||||||
|  |     $nav = new AphrontSideNavView(); | ||||||
|  |  | ||||||
|  |     $items = array(); | ||||||
|  |     $filters = $this->getFilterMap(); | ||||||
|  |     foreach ($filters as $key => $name) { | ||||||
|  |       $nav->addNavItem( | ||||||
|  |         phutil_render_tag( | ||||||
|  |           'a', | ||||||
|  |           array( | ||||||
|  |             'href' => '/herald/transcript/'.$this->id.'/'.$key.'/', | ||||||
|  |             'class' => | ||||||
|  |               ($key == $this->filter) | ||||||
|  |                 ? 'aphront-side-nav-selected' | ||||||
|  |                 : null, | ||||||
|  |           ), | ||||||
|  |           phutil_escape_html($name))); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $nav; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   protected function getFilterMap() { | ||||||
|  |     return array( | ||||||
|  |       self::FILTER_AFFECTED => 'Rules that Affected Me', | ||||||
|  |       self::FILTER_OWNED    => 'Rules I Own', | ||||||
|  |       self::FILTER_ALL      => 'All Rules', | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   protected function getFilterPHIDs() { | ||||||
|  |     return array($this->getRequest()->getUser()->getPHID()); | ||||||
|  |  | ||||||
|  | /* TODO | ||||||
|  |     $viewer_id = $this->getRequest()->getUser()->getPHID(); | ||||||
|  |  | ||||||
|  |     $fbids = array(); | ||||||
|  |     if ($this->filter == self::FILTER_AFFECTED) { | ||||||
|  |       $fbids[] = $viewer_id; | ||||||
|  |       require_module_lazy('intern/subscriptions'); | ||||||
|  |       $datastore = new SubscriberDatabaseStore(); | ||||||
|  |       $lists = $datastore->getUserMailmanLists($viewer_id); | ||||||
|  |       foreach ($lists as $list) { | ||||||
|  |         $fbids[] = $list; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return $fbids; | ||||||
|  | */ | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   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) { | ||||||
|  |         if (!$rule_xscripts[$rule_id]) { | ||||||
|  |           // 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; | ||||||
|  |  | ||||||
|  |     $action_names = HeraldActionConfig::getActionMap(); | ||||||
|  |  | ||||||
|  |     $rows = array(); | ||||||
|  |     foreach ($xscript->getApplyTranscripts() as $apply_xscript) { | ||||||
|  |       // TODO: Hacks, this is an approximate guess at the target type. | ||||||
|  |       $target = (array)$apply_xscript->getTarget(); | ||||||
|  |       if (!$target) { | ||||||
|  |         if ($apply_xscript->getAction() == HeraldActionConfig::ACTION_NOTHING) { | ||||||
|  |           $target = ''; | ||||||
|  |         } else { | ||||||
|  |           $target = '<empty>'; | ||||||
|  |         } | ||||||
|  |       } else { | ||||||
|  |         foreach ($target as $k => $phid) { | ||||||
|  |           $target[$k] = $handles[$phid]->getName(); | ||||||
|  |         } | ||||||
|  |         $target = implode("\n", $target); | ||||||
|  |       } | ||||||
|  |       $target = phutil_escape_html($target); | ||||||
|  |  | ||||||
|  |       if ($apply_xscript->getApplied()) { | ||||||
|  |         $outcome = '<span class="outcome-success">SUCCESS</span>'; | ||||||
|  |       } else { | ||||||
|  |         $outcome = '<span class="outcome-failure">FAILURE</span>'; | ||||||
|  |       } | ||||||
|  |       $outcome .= ' '.phutil_escape_html($apply_xscript->getAppliedReason()); | ||||||
|  |  | ||||||
|  |       $rows[] = array( | ||||||
|  |         phutil_escape_html($action_names[$apply_xscript->getAction()]), | ||||||
|  |         $target, | ||||||
|  |         '<strong>Taken because:</strong> '. | ||||||
|  |         phutil_escape_html($apply_xscript->getReason()). | ||||||
|  |         '<br />'. | ||||||
|  |         '<strong>Outcome:</strong> '.$outcome, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $table = new AphrontTableView($rows); | ||||||
|  |     $table->setNoDataString('No actions were taken.'); | ||||||
|  |     $table->setHeaders( | ||||||
|  |       array( | ||||||
|  |         'Action', | ||||||
|  |         'Target', | ||||||
|  |         'Details', | ||||||
|  |       )); | ||||||
|  |     $table->setColumnClasses( | ||||||
|  |       array( | ||||||
|  |         '', | ||||||
|  |         '', | ||||||
|  |         'wide', | ||||||
|  |       )); | ||||||
|  |  | ||||||
|  |     $panel = new AphrontPanelView(); | ||||||
|  |     $panel->setHeader('Actions Taken'); | ||||||
|  |     $panel->appendChild($table); | ||||||
|  |  | ||||||
|  |     return $panel; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private function buildActionTranscriptPanel($xscript) { | ||||||
|  |     $action_xscript = mgroup($xscript->getApplyTranscripts(), 'getRuleID'); | ||||||
|  |  | ||||||
|  |     $field_names = HeraldFieldConfig::getFieldMap(); | ||||||
|  |     $condition_names = HeraldConditionConfig::getConditionMap(); | ||||||
|  |     $action_names = HeraldActionConfig::getActionMap(); | ||||||
|  |  | ||||||
|  |     $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()) { | ||||||
|  |           $note = | ||||||
|  |             '<div class="herald-condition-note">'. | ||||||
|  |               phutil_escape_html($cond->getNote()). | ||||||
|  |             '</div>'; | ||||||
|  |         } else { | ||||||
|  |           $note = null; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if ($cond->getResult()) { | ||||||
|  |           $result = | ||||||
|  |             '<span class="herald-outcome condition-pass">'. | ||||||
|  |               "\xE2\x9C\x93". | ||||||
|  |             '</span>'; | ||||||
|  |         } else { | ||||||
|  |           $result = | ||||||
|  |             '<span class="herald-outcome condition-fail">'. | ||||||
|  |               "\xE2\x9C\x98". | ||||||
|  |             '</span>'; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         $cond_markup[] = | ||||||
|  |           '<li>'. | ||||||
|  |             $result.' Condition: '. | ||||||
|  |             phutil_escape_html($field_names[$cond->getFieldName()]). | ||||||
|  |             ' '. | ||||||
|  |             phutil_escape_html($condition_names[$cond->getCondition()]). | ||||||
|  |             ' '. | ||||||
|  |             $this->renderConditionTestValue($cond, $handles). | ||||||
|  |             $note. | ||||||
|  |           '</li>'; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if ($rule->getResult()) { | ||||||
|  |         $result = '<span class="herald-outcome rule-pass">PASS</span>'; | ||||||
|  |         $class = 'herald-rule-pass'; | ||||||
|  |       } else { | ||||||
|  |         $result = '<span class="herald-outcome rule-fail">FAIL</span>'; | ||||||
|  |         $class = 'herald-rule-fail'; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       $cond_markup[] = | ||||||
|  |         '<li>'.$result.' '.phutil_escape_html($rule->getReason()).'</li>'; | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |       if ($rule->getResult()) { | ||||||
|  |         $actions = idx($action_xscript, $rule_id, array()); | ||||||
|  |         if ($actions) { | ||||||
|  |           $cond_markup[] = <li><div class="action-header">Actions</div></li>; | ||||||
|  |           foreach ($actions as $action) { | ||||||
|  |  | ||||||
|  |             $target = $action->getTarget(); | ||||||
|  |             if ($target) { | ||||||
|  |               foreach ((array)$target as $k => $phid) { | ||||||
|  |                 $target[$k] = $handles[$phid]->getName(); | ||||||
|  |               } | ||||||
|  |               $target = <strong>: {implode(', ', $target)}</strong>; | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             $cond_markup[] = | ||||||
|  |               <li> | ||||||
|  |                 {$action_names[$action->getAction()]} | ||||||
|  |                 {$target} | ||||||
|  |               </li>; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  | */ | ||||||
|  |       $user_phid = $this->getRequest()->getUser()->getPHID(); | ||||||
|  |  | ||||||
|  |       $name = $rule->getRuleName(); | ||||||
|  |       if ($rule->getRuleOwner() == $user_phid) { | ||||||
|  | //        $name = <a href={"/herald/rule/".$rule->getRuleID()."/"}>{$name}</a>; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       $rule_markup[] = | ||||||
|  |         phutil_render_tag( | ||||||
|  |           'li', | ||||||
|  |           array( | ||||||
|  |             'class' => $class, | ||||||
|  |           ), | ||||||
|  |           '<div class="rule-name">'. | ||||||
|  |             '<strong>'.phutil_escape_html($name).'</strong> '. | ||||||
|  |             phutil_escape_html($handles[$rule->getRuleOwner()]->getName()). | ||||||
|  |           '</div>'. | ||||||
|  |           '<ul>'.implode("\n", $cond_markup).'</ul>'); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $panel = new AphrontPanelView(); | ||||||
|  |     $panel->setHeader('Rule Details'); | ||||||
|  |     $panel->appendChild( | ||||||
|  |       '<ul class="herald-explain-list">'. | ||||||
|  |         implode("\n", $rule_markup). | ||||||
|  |       '</ul>'); | ||||||
|  |  | ||||||
|  |     return $panel; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   private function buildObjectTranscriptPanel($xscript) { | ||||||
|  |  | ||||||
|  |     $field_names = HeraldFieldConfig::getFieldMap(); | ||||||
|  |  | ||||||
|  |     $object_xscript = $xscript->getObjectTranscript(); | ||||||
|  |  | ||||||
|  |     $data = array(); | ||||||
|  |     if ($object_xscript) { | ||||||
|  |       $data += array( | ||||||
|  |         'Object Name' => $object_xscript->getName(), | ||||||
|  |         'Object Type' => $object_xscript->getType(), | ||||||
|  |         'Object PHID' => $object_xscript->getPHID(), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $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) { | ||||||
|  |       if (!is_scalar($value) && !is_null($value)) { | ||||||
|  |         $value = implode("\n", $value); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (strlen($value) > 256) { | ||||||
|  |         $value = phutil_render_tag( | ||||||
|  |           'textarea', | ||||||
|  |           array( | ||||||
|  |             'class' => 'herald-field-value-transcript', | ||||||
|  |           ), | ||||||
|  |           phutil_escape_html($value)); | ||||||
|  |       } else { | ||||||
|  |         $value = phutil_escape_html($value); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       $rows[] = array( | ||||||
|  |         phutil_escape_html($name), | ||||||
|  |         $value, | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $table = new AphrontTableView($rows); | ||||||
|  |     $table->setColumnClasses( | ||||||
|  |       array( | ||||||
|  |         'header', | ||||||
|  |         'wide', | ||||||
|  |       )); | ||||||
|  |  | ||||||
|  |     $panel = new AphrontPanelView(); | ||||||
|  |     $panel->setHeader('Object Transcript'); | ||||||
|  |     $panel->appendChild($table); | ||||||
|  |  | ||||||
|  |     return $panel; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | } | ||||||
							
								
								
									
										24
									
								
								src/applications/herald/controller/transcript/__init__.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/applications/herald/controller/transcript/__init__.php
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * This file is automatically generated. Lint this module to rebuild it. | ||||||
|  |  * @generated | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/config/action'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/config/condition'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/config/field'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/controller/base'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/storage/transcript/base'); | ||||||
|  | phutil_require_module('phabricator', 'applications/phid/handle/data'); | ||||||
|  | phutil_require_module('phabricator', 'infrastructure/celerity/api'); | ||||||
|  | phutil_require_module('phabricator', 'view/control/table'); | ||||||
|  | phutil_require_module('phabricator', 'view/layout/panel'); | ||||||
|  | phutil_require_module('phabricator', 'view/layout/sidenav'); | ||||||
|  |  | ||||||
|  | phutil_require_module('phutil', 'markup'); | ||||||
|  | phutil_require_module('phutil', 'utils'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | phutil_require_source('HeraldTranscriptController.php'); | ||||||
| @@ -0,0 +1,120 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | /* | ||||||
|  |  * Copyright 2011 Facebook, Inc. | ||||||
|  |  * | ||||||
|  |  * Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
|  |  * you may not use this file except in compliance with the License. | ||||||
|  |  * You may obtain a copy of the License at | ||||||
|  |  * | ||||||
|  |  *   http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|  |  * | ||||||
|  |  * Unless required by applicable law or agreed to in writing, software | ||||||
|  |  * distributed under the License is distributed on an "AS IS" BASIS, | ||||||
|  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
|  |  * See the License for the specific language governing permissions and | ||||||
|  |  * limitations under the License. | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  | class HeraldTranscriptListController extends HeraldController { | ||||||
|  |  | ||||||
|  |   public function processRequest() { | ||||||
|  |  | ||||||
|  |     $request = $this->getRequest(); | ||||||
|  |  | ||||||
|  |     // Pull these objects manually since the serialized fields are gigantic. | ||||||
|  |     $transcript = new HeraldTranscript(); | ||||||
|  |     $data = queryfx_all( | ||||||
|  |       $transcript->establishConnection('r'), | ||||||
|  |       'SELECT id, objectPHID, time, duration, dryRun FROM %T | ||||||
|  |         ORDER BY id DESC | ||||||
|  |         LIMIT 100', | ||||||
|  |       $transcript->getTableName()); | ||||||
|  |  | ||||||
|  |     /* | ||||||
|  |  | ||||||
|  |     $conn_r = smc_get_db('cdb.herald', 'r'); | ||||||
|  |  | ||||||
|  |     $page_size = 100; | ||||||
|  |  | ||||||
|  |     $pager = new SimplePager(); | ||||||
|  |     $pager->setPageSize($page_size); | ||||||
|  |     $pager->setOffset((((int)$request->getInt('page')) - 1) * $page_size); | ||||||
|  |     $pager->order('id', array('id')); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $fbid = $request->getInt('fbid'); | ||||||
|  |     if ($fbid) { | ||||||
|  |       $filter = qsprintf( | ||||||
|  |         $conn_r, | ||||||
|  |         'WHERE objectID = %d', | ||||||
|  |         $fbid); | ||||||
|  |     } else { | ||||||
|  |       $filter = ''; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $data = $pager->select( | ||||||
|  |       $conn_r, | ||||||
|  |       'id, objectID, time, duration, dryRun FROM transcript %Q', | ||||||
|  |       $filter); | ||||||
|  | */ | ||||||
|  |  | ||||||
|  |     $handles = array(); | ||||||
|  |     if ($data) { | ||||||
|  |       $phids = ipull($data, 'objectPHID', 'objectPHID'); | ||||||
|  |       $handles = id(new PhabricatorObjectHandleData($phids)) | ||||||
|  |         ->loadHandles(); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $rows = array(); | ||||||
|  |     foreach ($data as $xscript) { | ||||||
|  |       $rows[] = array( | ||||||
|  |         date('F jS', $xscript['time']), | ||||||
|  |         date('g:i:s A', $xscript['time']), | ||||||
|  |         $handles[$xscript['objectPHID']]->renderLink(), | ||||||
|  |         $xscript['dryRun'] ? 'Yes' : '', | ||||||
|  |         number_format((int)(1000 * $xscript['duration'])).' ms', | ||||||
|  |         phutil_render_tag( | ||||||
|  |           'a', | ||||||
|  |           array( | ||||||
|  |             'href' => '/herald/transcript/'.$xscript['id'].'/', | ||||||
|  |             'class' => 'button small grey', | ||||||
|  |           ), | ||||||
|  |           'View Transcript'), | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $table = new AphrontTableView($rows); | ||||||
|  |     $table->setHeaders( | ||||||
|  |       array( | ||||||
|  |         'Date', | ||||||
|  |         'Time', | ||||||
|  |         'Object', | ||||||
|  |         'Dry Run', | ||||||
|  |         'Duration', | ||||||
|  |         'View', | ||||||
|  |       )); | ||||||
|  |     $table->setColumnClasses( | ||||||
|  |       array( | ||||||
|  |         '', | ||||||
|  |         'right', | ||||||
|  |         'wide wrap', | ||||||
|  |         '', | ||||||
|  |         '', | ||||||
|  |         'action', | ||||||
|  |       )); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     $panel = new AphrontPanelView(); | ||||||
|  |     $panel->setHeader('Herald Transcripts'); | ||||||
|  |     $panel->appendChild($table); | ||||||
|  |  | ||||||
|  |     return $this->buildStandardPageResponse( | ||||||
|  |       $panel, | ||||||
|  |       array( | ||||||
|  |         'title' => 'Herald Transcripts', | ||||||
|  |         'tab' => 'transcripts', | ||||||
|  |       )); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | <?php | ||||||
|  | /** | ||||||
|  |  * This file is automatically generated. Lint this module to rebuild it. | ||||||
|  |  * @generated | ||||||
|  |  */ | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/controller/base'); | ||||||
|  | phutil_require_module('phabricator', 'applications/herald/storage/transcript/base'); | ||||||
|  | phutil_require_module('phabricator', 'applications/phid/handle/data'); | ||||||
|  | phutil_require_module('phabricator', 'storage/queryfx'); | ||||||
|  | phutil_require_module('phabricator', 'view/control/table'); | ||||||
|  | phutil_require_module('phabricator', 'view/layout/panel'); | ||||||
|  |  | ||||||
|  | phutil_require_module('phutil', 'markup'); | ||||||
|  | phutil_require_module('phutil', 'utils'); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | phutil_require_source('HeraldTranscriptListController.php'); | ||||||
| @@ -18,7 +18,7 @@ | |||||||
|  |  | ||||||
| class HeraldEffect { | class HeraldEffect { | ||||||
|  |  | ||||||
|   protected $objectID; |   protected $objectPHID; | ||||||
|   protected $action; |   protected $action; | ||||||
|   protected $target; |   protected $target; | ||||||
|  |  | ||||||
| @@ -27,13 +27,13 @@ class HeraldEffect { | |||||||
|  |  | ||||||
|   protected $reason; |   protected $reason; | ||||||
|  |  | ||||||
|   public function setObjectID($object_id) { |   public function setObjectPHID($object_phid) { | ||||||
|     $this->objectID = $object_id; |     $this->objectPHID = $object_phid; | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function getObjectID() { |   public function getObjectPHID() { | ||||||
|     return $this->objectID; |     return $this->objectPHID; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function setAction($action) { |   public function setAction($action) { | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ class HeraldEngine { | |||||||
|   protected $fieldCache = array(); |   protected $fieldCache = array(); | ||||||
|   protected $object = null; |   protected $object = null; | ||||||
|  |  | ||||||
|   public static function loadAndApplyRules(IHeraldable $object) { |   public static function loadAndApplyRules(HeraldObjectAdapter $object) { | ||||||
|     $content_type = $object->getHeraldTypeName(); |     $content_type = $object->getHeraldTypeName(); | ||||||
|     $rules = HeraldRule::loadAllByContentTypeWithFullData($content_type); |     $rules = HeraldRule::loadAllByContentTypeWithFullData($content_type); | ||||||
|  |  | ||||||
| @@ -37,13 +37,13 @@ class HeraldEngine { | |||||||
|     return $engine->getTranscript(); |     return $engine->getTranscript(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function applyRules(array $rules, IHeraldable $object) { |   public function applyRules(array $rules, HeraldObjectAdapter $object) { | ||||||
|     $t_start = microtime(true); |     $t_start = microtime(true); | ||||||
|  |  | ||||||
|     $rules = mpull($rules, null, 'getID'); |     $rules = mpull($rules, null, 'getID'); | ||||||
|  |  | ||||||
|     $this->transcript = new HeraldTranscript(); |     $this->transcript = new HeraldTranscript(); | ||||||
|     $this->transcript->setObjectID((string)$object->getFBID()); |     $this->transcript->setObjectPHID((string)$object->getPHID()); | ||||||
|     $this->fieldCache = array(); |     $this->fieldCache = array(); | ||||||
|     $this->results = array(); |     $this->results = array(); | ||||||
|     $this->rules   = $rules; |     $this->rules   = $rules; | ||||||
| @@ -71,7 +71,7 @@ class HeraldEngine { | |||||||
|             "Don't do this! You have formed an unresolvable cycle in the ". |             "Don't do this! You have formed an unresolvable cycle in the ". | ||||||
|             "dependency graph!"); |             "dependency graph!"); | ||||||
|           $xscript->setRuleName($rules[$rule_id]->getName()); |           $xscript->setRuleName($rules[$rule_id]->getName()); | ||||||
|           $xscript->setRuleOwner($rules[$rule_id]->getOwnerID()); |           $xscript->setRuleOwner($rules[$rule_id]->getAuthorPHID()); | ||||||
|           $this->transcript->addRuleTranscript($xscript); |           $this->transcript->addRuleTranscript($xscript); | ||||||
|         } |         } | ||||||
|         $rule_matches = false; |         $rule_matches = false; | ||||||
| @@ -86,7 +86,7 @@ class HeraldEngine { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     $object_transcript = new HeraldObjectTranscript(); |     $object_transcript = new HeraldObjectTranscript(); | ||||||
|     $object_transcript->setFBID($object->getFBID()); |     $object_transcript->setPHID($object->getPHID()); | ||||||
|     $object_transcript->setName($object->getHeraldName()); |     $object_transcript->setName($object->getHeraldName()); | ||||||
|     $object_transcript->setType($object->getHeraldTypeName()); |     $object_transcript->setType($object->getHeraldTypeName()); | ||||||
|     $object_transcript->setFields($this->fieldCache); |     $object_transcript->setFields($this->fieldCache); | ||||||
| @@ -100,7 +100,7 @@ class HeraldEngine { | |||||||
|     return $effects; |     return $effects; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function applyEffects(array $effects, IHeraldable $object) { |   public function applyEffects(array $effects, HeraldObjectAdapter $object) { | ||||||
|     if ($object instanceof DryRunHeraldable) { |     if ($object instanceof DryRunHeraldable) { | ||||||
|       $this->transcript->setDryRun(true); |       $this->transcript->setDryRun(true); | ||||||
|     } else { |     } else { | ||||||
| @@ -121,7 +121,10 @@ class HeraldEngine { | |||||||
|     return $this->transcript; |     return $this->transcript; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected function doesRuleMatch(HeraldRule $rule, IHeraldable $object) { |   protected function doesRuleMatch( | ||||||
|  |     HeraldRule $rule, | ||||||
|  |     HeraldObjectAdapter $object) { | ||||||
|  |  | ||||||
|     $id = $rule->getID(); |     $id = $rule->getID(); | ||||||
|  |  | ||||||
|     if (isset($this->results[$id])) { |     if (isset($this->results[$id])) { | ||||||
| @@ -157,7 +160,7 @@ class HeraldEngine { | |||||||
|       $reason = "Rule failed automatically because it has no conditions."; |       $reason = "Rule failed automatically because it has no conditions."; | ||||||
|       $result = false; |       $result = false; | ||||||
| /* TOOD: Restore this in some form? | /* TOOD: Restore this in some form? | ||||||
|     } else if (!is_fb_employee($rule->getOwnerID())) { |     } else if (!is_fb_employee($rule->getAuthorPHID())) { | ||||||
|       $reason = "Rule failed automatically because its owner is not an ". |       $reason = "Rule failed automatically because its owner is not an ". | ||||||
|                 "active employee."; |                 "active employee."; | ||||||
|       $result = false; |       $result = false; | ||||||
| @@ -195,7 +198,7 @@ class HeraldEngine { | |||||||
|     $rule_transcript->setResult($result); |     $rule_transcript->setResult($result); | ||||||
|     $rule_transcript->setReason($reason); |     $rule_transcript->setReason($reason); | ||||||
|     $rule_transcript->setRuleName($rule->getName()); |     $rule_transcript->setRuleName($rule->getName()); | ||||||
|     $rule_transcript->setRuleOwner($rule->getOwnerID()); |     $rule_transcript->setRuleOwner($rule->getAuthorPHID()); | ||||||
|  |  | ||||||
|     $this->transcript->addRuleTranscript($rule_transcript); |     $this->transcript->addRuleTranscript($rule_transcript); | ||||||
|  |  | ||||||
| @@ -205,12 +208,12 @@ class HeraldEngine { | |||||||
|   protected function doesConditionMatch( |   protected function doesConditionMatch( | ||||||
|     HeraldRule $rule, |     HeraldRule $rule, | ||||||
|     HeraldCondition $condition, |     HeraldCondition $condition, | ||||||
|     IHeraldable $object) { |     HeraldObjectAdapter $object) { | ||||||
|  |  | ||||||
|     $object_value = $this->getConditionObjectValue($condition, $object); |     $object_value = $this->getConditionObjectValue($condition, $object); | ||||||
|     $test_value   = $condition->getValue(); |     $test_value   = $condition->getValue(); | ||||||
|  |  | ||||||
|     $cond = $condition->getCondition(); |     $cond = $condition->getFieldCondition(); | ||||||
|  |  | ||||||
|     $transcript = new HeraldConditionTranscript(); |     $transcript = new HeraldConditionTranscript(); | ||||||
|     $transcript->setRuleID($rule->getID()); |     $transcript->setRuleID($rule->getID()); | ||||||
| @@ -241,10 +244,10 @@ class HeraldEngine { | |||||||
|         $result = ($object_value != $test_value); |         $result = ($object_value != $test_value); | ||||||
|         break; |         break; | ||||||
|       case HeraldConditionConfig::CONDITION_IS_ME: |       case HeraldConditionConfig::CONDITION_IS_ME: | ||||||
|         $result = ($object_value == $rule->getOwnerID()); |         $result = ($object_value == $rule->getAuthorPHID()); | ||||||
|         break; |         break; | ||||||
|       case HeraldConditionConfig::CONDITION_IS_NOT_ME: |       case HeraldConditionConfig::CONDITION_IS_NOT_ME: | ||||||
|         $result = ($object_value != $rule->getOwnerID()); |         $result = ($object_value != $rule->getAuthorPHID()); | ||||||
|         break; |         break; | ||||||
|       case HeraldConditionConfig::CONDITION_IS_ANY: |       case HeraldConditionConfig::CONDITION_IS_ANY: | ||||||
|         $test_value = array_flip($test_value); |         $test_value = array_flip($test_value); | ||||||
| @@ -364,7 +367,7 @@ class HeraldEngine { | |||||||
|  |  | ||||||
|   protected function getConditionObjectValue( |   protected function getConditionObjectValue( | ||||||
|     HeraldCondition $condition, |     HeraldCondition $condition, | ||||||
|     IHeraldable $object) { |     HeraldObjectAdapter $object) { | ||||||
|  |  | ||||||
|     $field = $condition->getFieldName(); |     $field = $condition->getFieldName(); | ||||||
|  |  | ||||||
| @@ -391,7 +394,7 @@ class HeraldEngine { | |||||||
|       case HeraldFieldConfig::FIELD_AUTHOR: |       case HeraldFieldConfig::FIELD_AUTHOR: | ||||||
|       case HeraldFieldConfig::FIELD_REPOSITORY: |       case HeraldFieldConfig::FIELD_REPOSITORY: | ||||||
|       case HeraldFieldConfig::FIELD_MERGE_REQUESTER: |       case HeraldFieldConfig::FIELD_MERGE_REQUESTER: | ||||||
|         // TODO: Type should be fbid. |         // TODO: Type should be PHID. | ||||||
|         $result = $this->object->getHeraldField($field); |         $result = $this->object->getHeraldField($field); | ||||||
|         break; |         break; | ||||||
|       case HeraldFieldConfig::FIELD_TAGS: |       case HeraldFieldConfig::FIELD_TAGS: | ||||||
| @@ -424,11 +427,14 @@ class HeraldEngine { | |||||||
|     return $result; |     return $result; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected function getRuleEffects(HeraldRule $rule, IHeraldable $object) { |   protected function getRuleEffects( | ||||||
|  |     HeraldRule $rule, | ||||||
|  |     HeraldObjectAdapter $object) { | ||||||
|  |  | ||||||
|     $effects = array(); |     $effects = array(); | ||||||
|     foreach ($rule->getActions() as $action) { |     foreach ($rule->getActions() as $action) { | ||||||
|       $effect = new HeraldEffect(); |       $effect = new HeraldEffect(); | ||||||
|       $effect->setObjectID($object->getFBID()); |       $effect->setObjectPHID($object->getPHID()); | ||||||
|       $effect->setAction($action->getAction()); |       $effect->setAction($action->getAction()); | ||||||
|       $effect->setTarget($action->getTarget()); |       $effect->setTarget($action->getTarget()); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,7 +19,7 @@ | |||||||
| class HeraldTranscript extends HeraldDAO { | class HeraldTranscript extends HeraldDAO { | ||||||
|  |  | ||||||
|   protected $id; |   protected $id; | ||||||
|   protected $fbid; |   protected $phid; | ||||||
|  |  | ||||||
|   protected $objectTranscript; |   protected $objectTranscript; | ||||||
|   protected $ruleTranscripts = array(); |   protected $ruleTranscripts = array(); | ||||||
| @@ -28,10 +28,9 @@ class HeraldTranscript extends HeraldDAO { | |||||||
|  |  | ||||||
|   protected $time; |   protected $time; | ||||||
|   protected $host; |   protected $host; | ||||||
|   protected $path; |  | ||||||
|   protected $duration; |   protected $duration; | ||||||
|  |  | ||||||
|   protected $objectID; |   protected $objectPHID; | ||||||
|   protected $dryRun; |   protected $dryRun; | ||||||
|  |  | ||||||
|   public function getXHeraldRulesHeader() { |   public function getXHeraldRulesHeader() { | ||||||
| @@ -61,7 +60,8 @@ class HeraldTranscript extends HeraldDAO { | |||||||
|   protected function getConfiguration() { |   protected function getConfiguration() { | ||||||
|     // Ugh. Too much of a mess to deal with. |     // Ugh. Too much of a mess to deal with. | ||||||
|     return array( |     return array( | ||||||
|       self::CONFIG_AUX_FBID     => 'HERALD_TRANSCRIPT', |       self::CONFIG_AUX_PHID     => true, | ||||||
|  |       self::CONFIG_TIMESTAMPS   => false, | ||||||
|       self::CONFIG_SERIALIZATION => array( |       self::CONFIG_SERIALIZATION => array( | ||||||
|         'objectTranscript'      => self::SERIALIZATION_PHP, |         'objectTranscript'      => self::SERIALIZATION_PHP, | ||||||
|         'ruleTranscripts'       => self::SERIALIZATION_PHP, |         'ruleTranscripts'       => self::SERIALIZATION_PHP, | ||||||
| @@ -74,7 +74,6 @@ class HeraldTranscript extends HeraldDAO { | |||||||
|   public function __construct() { |   public function __construct() { | ||||||
|     $this->time = time(); |     $this->time = time(); | ||||||
|     $this->host = php_uname('n'); |     $this->host = php_uname('n'); | ||||||
|     $this->path = realpath($_SERVER['PHP_ROOT']); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function addApplyTranscript(HeraldApplyTranscript $transcript) { |   public function addApplyTranscript(HeraldApplyTranscript $transcript) { | ||||||
| @@ -131,14 +130,14 @@ class HeraldTranscript extends HeraldDAO { | |||||||
|  |  | ||||||
|   public function getMetadataMap() { |   public function getMetadataMap() { | ||||||
|     return array( |     return array( | ||||||
|       'Run At Epoch' => date('F jS, g:i A', $this->time), |       'Run At Epoch' => date('F jS, g:i:s A', $this->time), | ||||||
|       'Run On Host'  => $this->host.':'.$this->path, |       'Run On Host'  => $this->host, | ||||||
|       'Run Duration' => (int)(1000 * $this->duration).' ms', |       'Run Duration' => (int)(1000 * $this->duration).' ms', | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function getURI() { |   public function generatePHID() { | ||||||
|     return 'http://tools.facebook.com/herald/transcript/'.$this->getID().'/'; |     return PhabricatorPHID::generateNewPHID('HLXS'); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ | |||||||
|  |  | ||||||
|  |  | ||||||
| phutil_require_module('phabricator', 'applications/herald/storage/base'); | phutil_require_module('phabricator', 'applications/herald/storage/base'); | ||||||
|  | phutil_require_module('phabricator', 'applications/phid/storage/phid'); | ||||||
|  |  | ||||||
| phutil_require_module('phutil', 'utils'); | phutil_require_module('phutil', 'utils'); | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,18 +18,18 @@ | |||||||
|  |  | ||||||
| class HeraldObjectTranscript { | class HeraldObjectTranscript { | ||||||
|  |  | ||||||
|   protected $fbid; |   protected $phid; | ||||||
|   protected $type; |   protected $type; | ||||||
|   protected $name; |   protected $name; | ||||||
|   protected $fields; |   protected $fields; | ||||||
|  |  | ||||||
|   public function setFBID($fbid) { |   public function setPHID($phid) { | ||||||
|     $this->fbid = $fbid; |     $this->phid = $phid; | ||||||
|     return $this; |     return $this; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function getFBID() { |   public function getPHID() { | ||||||
|     return $this->fbid; |     return $this->phid; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function setType($type) { |   public function setType($type) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley