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