public function renderChangeDetails(PhabricatorUser $viewer) { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: $old = $this->getOldValue(); $new = $this->getNewValue(); return $this->renderTextCorpusChangeDetails($viewer, $old, $new); case self::TYPE_PATHS: $old = $this->getOldValue(); $new = $this->getNewValue(); $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); list($rem, $add) = $diffs; $rows = array(); foreach ($rem as $ref) { $rows[] = array('class' => 'diff-removed', 'change' => '-') + $ref; } foreach ($add as $ref) { $rows[] = array('class' => 'diff-added', 'change' => '+') + $ref; } $rowc = array(); foreach ($rows as $key => $row) { $rowc[] = $row['class']; $rows[$key] = array($row['change'], $row['excluded'] ? pht('Exclude') : pht('Include'), $viewer->renderHandle($row['repositoryPHID']), $row['path']); } $table = id(new AphrontTableView($rows))->setRowClasses($rowc)->setHeaders(array(null, pht('Type'), pht('Repository'), pht('Path')))->setColumnClasses(array(null, null, null, 'wide')); return $table; } return parent::renderChangeDetails($viewer); }
protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions) { $errors = parent::validateTransaction($object, $type, $xactions); switch ($type) { case PhabricatorOwnersPackageTransaction::TYPE_NAME: $missing = $this->validateIsEmptyTextField($object->getName(), $xactions); if ($missing) { $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Package name is required.'), nonempty(last($xactions), null)); $error->setIsMissingFieldError(true); $errors[] = $error; } break; case PhabricatorOwnersPackageTransaction::TYPE_PATHS: if (!$xactions) { continue; } $old = mpull($object->getPaths(), 'getRef'); foreach ($xactions as $xaction) { $new = $xaction->getNewValue(); // Check that we have a list of paths. if (!is_array($new)) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Path specification must be a list of paths.'), $xaction); continue; } // Check that each item in the list is formatted properly. $type_exception = null; foreach ($new as $key => $value) { try { PhutilTypeSpec::checkMap($value, array('repositoryPHID' => 'string', 'path' => 'string', 'excluded' => 'optional wild')); } catch (PhutilTypeCheckException $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Path specification list contains invalid value ' . 'in key "%s": %s.', $key, $ex->getMessage()), $xaction); $type_exception = $ex; } } if ($type_exception) { continue; } // Check that any new paths reference legitimate repositories which // the viewer has permission to see. list($rem, $add) = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); if ($add) { $repository_phids = ipull($add, 'repositoryPHID'); $repositories = id(new PhabricatorRepositoryQuery())->setViewer($this->getActor())->withPHIDs($repository_phids)->execute(); $repositories = mpull($repositories, null, 'getPHID'); foreach ($add as $ref) { $repository_phid = $ref['repositoryPHID']; if (isset($repositories[$repository_phid])) { continue; } $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Path specification list references repository PHID "%s", ' . 'but that is not a valid, visible repository.', $repository_phid)); } } } break; } return $errors; }
protected function applyCustomExternalTransaction(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorOwnersPackageTransaction::TYPE_NAME: case PhabricatorOwnersPackageTransaction::TYPE_PRIMARY: case PhabricatorOwnersPackageTransaction::TYPE_DESCRIPTION: case PhabricatorOwnersPackageTransaction::TYPE_AUDITING: return; case PhabricatorOwnersPackageTransaction::TYPE_OWNERS: $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); // TODO: needOwners this $owners = $object->loadOwners(); $owners = mpull($owners, null, 'getUserPHID'); $rem = array_diff($old, $new); foreach ($rem as $phid) { if (isset($owners[$phid])) { $owners[$phid]->delete(); unset($owners[$phid]); } } $add = array_diff($new, $old); foreach ($add as $phid) { $owners[$phid] = id(new PhabricatorOwnersOwner())->setPackageID($object->getID())->setUserPHID($phid)->save(); } // TODO: Attach owners here return; case PhabricatorOwnersPackageTransaction::TYPE_PATHS: $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); // TODO: needPaths this $paths = $object->loadPaths(); $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); list($rem, $add) = $diffs; $set = PhabricatorOwnersPath::getSetFromTransactionValue($rem); foreach ($paths as $path) { $ref = $path->getRef(); if (PhabricatorOwnersPath::isRefInSet($ref, $set)) { $path->delete(); } } foreach ($add as $ref) { $path = PhabricatorOwnersPath::newFromRef($ref)->setPackageID($object->getID())->save(); } return; } return parent::applyCustomExternalTransaction($object, $xaction); }
public function newChangeDetailView() { $old = $this->getOldValue(); $new = $this->getNewValue(); $diffs = PhabricatorOwnersPath::getTransactionValueChanges($old, $new); list($rem, $add) = $diffs; $rows = array(); foreach ($rem as $ref) { $rows[] = array('class' => 'diff-removed', 'change' => '-') + $ref; } foreach ($add as $ref) { $rows[] = array('class' => 'diff-added', 'change' => '+') + $ref; } $rowc = array(); foreach ($rows as $key => $row) { $rowc[] = $row['class']; $rows[$key] = array($row['change'], $row['excluded'] ? pht('Exclude') : pht('Include'), $this->renderHandle($row['repositoryPHID']), $row['path']); } $table = id(new AphrontTableView($rows))->setViewer($this->getViewer())->setRowClasses($rowc)->setHeaders(array(null, pht('Type'), pht('Repository'), pht('Path')))->setColumnClasses(array(null, null, null, 'wide')); return $table; }