protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhortuneAccountTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Account name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhabricatorTransactions::TYPE_EDGE:
             foreach ($xactions as $xaction) {
                 switch ($xaction->getMetadataValue('edge:type')) {
                     case PhortuneAccountHasMemberEdgeType::EDGECONST:
                         // TODO: This is a bit cumbersome, but validation happens before
                         // transaction normalization. Maybe provide a cleaner attack on
                         // this eventually? There's no way to generate "+" or "-"
                         // transactions right now.
                         $new = $xaction->getNewValue();
                         $set = idx($new, '=', array());
                         if (empty($set[$this->requireActor()->getPHID()])) {
                             $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not remove yourself as an account member.'), $xaction);
                             $errors[] = $error;
                         }
                         break;
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case AlmanacBindingTransaction::TYPE_INTERFACE:
             $missing = $this->validateIsEmptyTextField($object->getInterfacePHID(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Bindings must specify an interface.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 if ($xactions) {
                     foreach ($xactions as $xaction) {
                         $interfaces = id(new AlmanacInterfaceQuery())->setViewer($this->requireActor())->withPHIDs(array($xaction->getNewValue()))->execute();
                         if (!$interfaces) {
                             $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not bind a service to an invalid or restricted ' . 'interface.'), $xaction);
                             $errors[] = $error;
                         }
                     }
                     $final_value = last($xactions)->getNewValue();
                     $binding = id(new AlmanacBindingQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withServicePHIDs(array($object->getServicePHID()))->withInterfacePHIDs(array($final_value))->executeOne();
                     if ($binding && $binding->getID() != $object->getID()) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Already Bound'), pht('You can not bind a service to the same interface multiple ' . 'times.'), last($xactions));
                         $errors[] = $error;
                     }
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorOAuthServerTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('OAuth applications must have a name.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhabricatorOAuthServerTransaction::TYPE_REDIRECT_URI:
             $missing = $this->validateIsEmptyTextField($object->getRedirectURI(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('OAuth applications must have a valid redirect URI.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 foreach ($xactions as $xaction) {
                     $redirect_uri = $xaction->getNewValue();
                     try {
                         $server = new PhabricatorOAuthServer();
                         $server->assertValidRedirectURI($redirect_uri);
                     } catch (Exception $ex) {
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction);
                     }
                 }
             }
             break;
     }
     return $errors;
 }
 public function validateApplicationTransactions(PhabricatorApplicationTransactionEditor $editor, $type, array $xactions)
 {
     $this->setFieldError(null);
     $errors = parent::validateApplicationTransactions($editor, $type, $xactions);
     $transaction = null;
     foreach ($xactions as $xaction) {
         $value = $xaction->getNewValue();
         if ($this->isCoreFieldRequired()) {
             if ($this->isCoreFieldValueEmpty($value)) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), $this->getCoreFieldRequiredErrorString(), $xaction);
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
                 $this->setFieldError(pht('Required'));
                 continue;
             }
         }
         if (is_string($value)) {
             $parser = $this->getFieldParser();
             $result = $parser->parseCorpus($value);
             unset($result['__title__']);
             unset($result['__summary__']);
             if ($result) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The value you have entered in "%s" can not be parsed ' . 'unambiguously when rendered in a commit message. Edit the ' . 'message so that keywords like "Summary:" and "Test Plan:" do ' . 'not appear at the beginning of lines. Parsed keys: %s.', $this->getFieldName(), implode(', ', array_keys($result))), $xaction);
                 $errors[] = $error;
                 $this->setFieldError(pht('Invalid'));
                 continue;
             }
         }
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorMetaMTAApplicationEmailTransaction::TYPE_ADDRESS:
             foreach ($xactions as $xaction) {
                 $email = $xaction->getNewValue();
                 if (!strlen($email)) {
                     // We'll deal with this below.
                     continue;
                 }
                 if (!PhabricatorUserEmail::isValidAddress($email)) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Email address is not formatted properly.'));
                 }
             }
             $missing = $this->validateIsEmptyTextField($object->getAddress(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('You must provide an email address.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorPasteTransaction::TYPE_CONTENT:
             if (!$object->getFilePHID() && !$xactions) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('You must provide content to create a paste.'), null);
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case HarbormasterBuildPlanTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('You must choose a name for your build plan.'), last($xactions));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case FundInitiativeTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Initiative name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorPhurlURLTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('URL name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhabricatorPhurlURLTransaction::TYPE_URL:
             $missing = $this->validateIsEmptyTextField($object->getLongURL(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('URL path is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             foreach ($xactions as $xaction) {
                 if ($xaction->getOldValue() != $xaction->getNewValue()) {
                     $protocols = PhabricatorEnv::getEnvConfig('uri.allowed-protocols');
                     $uri = new PhutilURI($xaction->getNewValue());
                     if (!isset($protocols[$uri->getProtocol()])) {
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid URL'), pht('The protocol of the URL is invalid.'), null);
                     }
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhamePostTransaction::TYPE_TITLE:
             $missing = $this->validateIsEmptyTextField($object->getTitle(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Title is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhamePostTransaction::TYPE_PHAME_TITLE:
             $missing = $this->validateIsEmptyTextField($object->getPhameTitle(), $xactions);
             $phame_title = last($xactions)->getNewValue();
             if ($missing || $phame_title == '/') {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Phame title is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             $duplicate_post = id(new PhamePostQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withPhameTitles(array($phame_title))->executeOne();
             if ($duplicate_post && $duplicate_post->getID() != $object->getID()) {
                 $error_text = pht('Phame title must be unique; another post already has this phame ' . 'title.');
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Not Unique'), $error_text, nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case DrydockBlueprintTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getBlueprintName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('You must choose a name for this blueprint.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
                 continue;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case AlmanacNamespaceTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Namespace name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 foreach ($xactions as $xaction) {
                     $name = $xaction->getNewValue();
                     $message = null;
                     try {
                         AlmanacNames::validateName($name);
                     } catch (Exception $ex) {
                         $message = $ex->getMessage();
                     }
                     if ($message !== null) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $message, $xaction);
                         $errors[] = $error;
                         continue;
                     }
                     $other = id(new AlmanacNamespaceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withNames(array($name))->executeOne();
                     if ($other && $other->getID() != $object->getID()) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Not Unique'), pht('The namespace name "%s" is already in use by another ' . 'namespace. Each namespace must have a unique name.', $name), $xaction);
                         $errors[] = $error;
                         continue;
                     }
                     if ($name === $object->getName()) {
                         continue;
                     }
                     $namespace = AlmanacNamespace::loadRestrictedNamespace($this->getActor(), $name);
                     if ($namespace) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Restricted'), pht('You do not have permission to create Almanac namespaces ' . 'within the "%s" namespace.', $namespace->getName()), $xaction);
                         $errors[] = $error;
                         continue;
                     }
                 }
             }
             break;
     }
     return $errors;
 }
 public function validateApplicationTransactions(PhabricatorApplicationTransactionEditor $editor, $type, array $xactions)
 {
     $this->setFieldError(null);
     $errors = parent::validateApplicationTransactions($editor, $type, $xactions);
     $transaction = null;
     foreach ($xactions as $xaction) {
         $value = $xaction->getNewValue();
         if ($this->isCoreFieldRequired()) {
             if ($this->isCoreFieldValueEmpty($value)) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), $this->getCoreFieldRequiredErrorString(), $xaction);
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
                 $this->setFieldError(pht('Required'));
             }
         }
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhameBlogTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhameBlogTransaction::TYPE_DOMAIN:
             if (!$xactions) {
                 continue;
             }
             $custom_domain = last($xactions)->getNewValue();
             if (empty($custom_domain)) {
                 continue;
             }
             list($error_label, $error_text) = $object->validateCustomDomain($custom_domain);
             if ($error_label) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, $error_label, $error_text, nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             if ($object->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) {
                 $error_text = pht('For custom domains to work, the blog must have a view policy of ' . 'public.');
                 $error = new PhabricatorApplicationTransactionValidationError(PhabricatorTransactions::TYPE_VIEW_POLICY, pht('Invalid Policy'), $error_text, nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             $duplicate_blog = id(new PhameBlogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withDomain($custom_domain)->executeOne();
             if ($duplicate_blog && $duplicate_blog->getID() != $object->getID()) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Not Unique'), pht('Domain must be unique; another blog already has this domain.'), nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case NuanceSourceTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Source name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case NuanceSourceTransaction::TYPE_DEFAULT_QUEUE:
             foreach ($xactions as $xaction) {
                 if (!$xaction->getNewValue()) {
                     $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Sources must have a default queue.'), $xaction);
                     $error->setIsMissingFieldError(true);
                     $errors[] = $error;
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case AlmanacServiceTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Service name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 foreach ($xactions as $xaction) {
                     $message = null;
                     $name = $xaction->getNewValue();
                     try {
                         AlmanacNames::validateServiceOrDeviceName($name);
                     } catch (Exception $ex) {
                         $message = $ex->getMessage();
                     }
                     if ($message !== null) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $message, $xaction);
                         $errors[] = $error;
                     }
                 }
             }
             if ($xactions) {
                 $duplicate = id(new AlmanacServiceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withNames(array(last($xactions)->getNewValue()))->executeOne();
                 if ($duplicate && $duplicate->getID() != $object->getID()) {
                     $error = new PhabricatorApplicationTransactionValidationError($type, pht('Not Unique'), pht('Almanac services must have unique names.'), last($xactions));
                     $errors[] = $error;
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case ConpherenceTransaction::TYPE_TITLE:
             if (empty($xactions)) {
                 break;
             }
             $missing = $this->validateIsEmptyTextField($object->getTitle(), $xactions);
             if ($missing) {
                 $detail = pht('Room title is required.');
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), $detail, last($xactions));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case ConpherenceTransaction::TYPE_PICTURE:
             foreach ($xactions as $xaction) {
                 $file = $xaction->getNewValue();
                 if (!$file->isTransformableImage()) {
                     $detail = pht('This server only supports these image formats: %s.', implode(', ', PhabricatorFile::getTransformableImageFormats()));
                     $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $detail, last($xactions));
                     $errors[] = $error;
                 }
             }
             break;
         case ConpherenceTransaction::TYPE_PARTICIPANTS:
             foreach ($xactions as $xaction) {
                 $new_phids = $this->getPHIDTransactionNewValue($xaction, array());
                 $old_phids = nonempty($object->getParticipantPHIDs(), array());
                 $phids = array_diff($new_phids, $old_phids);
                 if (!$phids) {
                     continue;
                 }
                 $users = id(new PhabricatorPeopleQuery())->setViewer($this->requireActor())->withPHIDs($phids)->execute();
                 $users = mpull($users, null, 'getPHID');
                 foreach ($phids as $phid) {
                     if (isset($users[$phid])) {
                         continue;
                     }
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('New room participant "%s" is not a valid user.', $phid), $xaction);
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PassphraseCredentialTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Credential name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PassphraseCredentialTransaction::TYPE_USERNAME:
             $credential_type = $object->getImplementation();
             if (!$credential_type->shouldRequireUsername()) {
                 break;
             }
             $missing = $this->validateIsEmptyTextField($object->getUsername(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Username is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorProjectTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Project name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             if (!$xactions) {
                 break;
             }
             $name = last($xactions)->getNewValue();
             $name_used_already = id(new PhabricatorProjectQuery())->setViewer($this->getActor())->withNames(array($name))->executeOne();
             if ($name_used_already && $name_used_already->getPHID() != $object->getPHID()) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Duplicate'), pht('Project name is already used.'), nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             $slug = PhabricatorSlug::normalizeProjectSlug($name);
             $slug_used_already = id(new PhabricatorProjectSlug())->loadOneWhere('slug = %s', $slug);
             if ($slug_used_already && $slug_used_already->getProjectPHID() != $object->getPHID()) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Duplicate'), pht('Project name can not be used due to hashtag collision.'), nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             break;
         case PhabricatorProjectTransaction::TYPE_SLUGS:
             if (!$xactions) {
                 break;
             }
             $slug_xaction = last($xactions);
             $new = $slug_xaction->getNewValue();
             if ($new) {
                 $slugs_used_already = id(new PhabricatorProjectSlug())->loadAllWhere('slug IN (%Ls)', $new);
             } else {
                 // The project doesn't have any extra slugs.
                 $slugs_used_already = array();
             }
             $slugs_used_already = mgroup($slugs_used_already, 'getProjectPHID');
             foreach ($slugs_used_already as $project_phid => $used_slugs) {
                 $used_slug_strs = mpull($used_slugs, 'getSlug');
                 if ($project_phid == $object->getPHID()) {
                     if (in_array($object->getPrimarySlug(), $used_slug_strs)) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Project hashtag %s is already the primary hashtag.', $object->getPrimarySlug()), $slug_xaction);
                         $errors[] = $error;
                     }
                     continue;
                 }
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('%d project hashtag(s) are already used: %s.', count($used_slug_strs), implode(', ', $used_slug_strs)), $slug_xaction);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 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_PRIMARY:
             $missing = $this->validateIsEmptyTextField($object->getPrimaryOwnerPHID(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Packages must have a primary owner.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case AlmanacDeviceTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Device name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 foreach ($xactions as $xaction) {
                     $message = null;
                     $name = $xaction->getNewValue();
                     try {
                         AlmanacNames::validateServiceOrDeviceName($name);
                     } catch (Exception $ex) {
                         $message = $ex->getMessage();
                     }
                     if ($message !== null) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $message, $xaction);
                         $errors[] = $error;
                     }
                 }
             }
             if ($xactions) {
                 $duplicate = id(new AlmanacDeviceQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withNames(array(last($xactions)->getNewValue()))->executeOne();
                 if ($duplicate && $duplicate->getID() != $object->getID()) {
                     $error = new PhabricatorApplicationTransactionValidationError($type, pht('Not Unique'), pht('Almanac devices must have unique names.'), last($xactions));
                     $errors[] = $error;
                 }
             }
             break;
         case AlmanacDeviceTransaction::TYPE_INTERFACE:
             // We want to make sure that all the affected networks are visible to
             // the actor, any edited interfaces exist, and that the actual address
             // components are valid.
             $network_phids = array();
             foreach ($xactions as $xaction) {
                 $old = $xaction->getOldValue();
                 $new = $xaction->getNewValue();
                 if ($old) {
                     $network_phids[] = $old['networkPHID'];
                 }
                 if ($new) {
                     $network_phids[] = $new['networkPHID'];
                     $address = $new['address'];
                     if (!strlen($address)) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Interfaces must have an address.'), $xaction);
                         $errors[] = $error;
                     } else {
                         // TODO: Validate addresses, but IPv6 addresses are not trival
                         // to validate.
                     }
                     $port = $new['port'];
                     if (!strlen($port)) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Interfaces must have a port.'), $xaction);
                         $errors[] = $error;
                     } else {
                         if ((int) $port < 1 || (int) $port > 65535) {
                             $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Port numbers must be between 1 and 65535, inclusive.'), $xaction);
                             $errors[] = $error;
                         }
                     }
                     $phid = idx($new, 'phid');
                     if ($phid) {
                         $interface_phid_type = AlmanacInterfacePHIDType::TYPECONST;
                         if (phid_get_type($phid) !== $interface_phid_type) {
                             $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Precomputed interface PHIDs must be of type ' . 'AlmanacInterfacePHIDType.'), $xaction);
                             $errors[] = $error;
                         }
                     }
                 }
             }
             if ($network_phids) {
                 $networks = id(new AlmanacNetworkQuery())->setViewer($this->requireActor())->withPHIDs($network_phids)->execute();
                 $networks = mpull($networks, null, 'getPHID');
             } else {
                 $networks = array();
             }
             $addresses = array();
             foreach ($xactions as $xaction) {
                 $old = $xaction->getOldValue();
                 if ($old) {
                     $network = idx($networks, $old['networkPHID']);
                     if (!$network) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not edit an interface which belongs to a ' . 'nonexistent or restricted network.'), $xaction);
                         $errors[] = $error;
                     }
                     $addresses[] = $old['id'];
                 }
                 $new = $xaction->getNewValue();
                 if ($new) {
                     $network = idx($networks, $new['networkPHID']);
                     if (!$network) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not add an interface on a nonexistent or ' . 'restricted network.'), $xaction);
                         $errors[] = $error;
                     }
                 }
             }
             if ($addresses) {
                 $interfaces = id(new AlmanacInterfaceQuery())->setViewer($this->requireActor())->withDevicePHIDs(array($object->getPHID()))->withIDs($addresses)->execute();
                 $interfaces = mpull($interfaces, null, 'getID');
             } else {
                 $interfaces = array();
             }
             foreach ($xactions as $xaction) {
                 $old = $xaction->getOldValue();
                 if ($old) {
                     $interface = idx($interfaces, $old['id']);
                     if (!$interface) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not edit an invalid or restricted interface.'), $xaction);
                         $errors[] = $error;
                     }
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorCountdownTransaction::TYPE_TITLE:
             $missing = $this->validateIsEmptyTextField($object->getTitle(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('You must give the countdown a name.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhabricatorCountdownTransaction::TYPE_EPOCH:
             $date_value = AphrontFormDateControlValue::newFromEpoch($this->requireActor(), $object->getEpoch());
             if (!$date_value->isValid()) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You must give the countdown a valid end date.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhameBlogTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             foreach ($xactions as $xaction) {
                 $new = $xaction->getNewValue();
                 if (phutil_utf8_strlen($new) > 64) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The selected blog title is too long. The maximum length ' . 'of a blog title is 64 characters.'), $xaction);
                 }
             }
             break;
         case PhameBlogTransaction::TYPE_SUBTITLE:
             foreach ($xactions as $xaction) {
                 $new = $xaction->getNewValue();
                 if (phutil_utf8_strlen($new) > 64) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The selected blog subtitle is too long. The maximum length ' . 'of a blog subtitle is 64 characters.'), $xaction);
                 }
             }
             break;
         case PhameBlogTransaction::TYPE_PARENTDOMAIN:
             if (!$xactions) {
                 continue;
             }
             $parent_domain = last($xactions)->getNewValue();
             if (empty($parent_domain)) {
                 continue;
             }
             try {
                 PhabricatorEnv::requireValidRemoteURIForLink($parent_domain);
             } catch (Exception $ex) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid URI'), pht('Parent Domain must be set to a valid Remote URI.'), nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             break;
         case PhameBlogTransaction::TYPE_FULLDOMAIN:
             if (!$xactions) {
                 continue;
             }
             $custom_domain = last($xactions)->getNewValue();
             if (empty($custom_domain)) {
                 continue;
             }
             list($error_label, $error_text) = $object->validateCustomDomain($custom_domain);
             if ($error_label) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, $error_label, $error_text, nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             if ($object->getViewPolicy() != PhabricatorPolicies::POLICY_PUBLIC) {
                 $error_text = pht('For custom domains to work, the blog must have a view policy of ' . 'public.');
                 $error = new PhabricatorApplicationTransactionValidationError(PhabricatorTransactions::TYPE_VIEW_POLICY, pht('Invalid Policy'), $error_text, nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             $domain = new PhutilURI($custom_domain);
             $domain = $domain->getDomain();
             $duplicate_blog = id(new PhameBlogQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withDomain($domain)->executeOne();
             if ($duplicate_blog && $duplicate_blog->getID() != $object->getID()) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Not Unique'), pht('Domain must be unique; another blog already has this domain.'), nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case ManiphestTransaction::TYPE_TITLE:
             $missing = $this->validateIsEmptyTextField($object->getTitle(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Task title is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case ManiphestTransaction::TYPE_PARENT:
             $with_effect = array();
             foreach ($xactions as $xaction) {
                 $task_phid = $xaction->getNewValue();
                 if (!$task_phid) {
                     continue;
                 }
                 $with_effect[] = $xaction;
                 $task = id(new ManiphestTaskQuery())->setViewer($this->getActor())->withPHIDs(array($task_phid))->executeOne();
                 if (!$task) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Parent task identifier "%s" does not identify a visible ' . 'task.', $task_phid), $xaction);
                 }
             }
             if ($with_effect && !$this->getIsNewObject()) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can only select a parent task when creating a ' . 'transaction for the first time.'), last($with_effect));
             }
             break;
         case ManiphestTransaction::TYPE_COLUMN:
             $with_effect = array();
             foreach ($xactions as $xaction) {
                 $column_phid = $xaction->getNewValue();
                 if (!$column_phid) {
                     continue;
                 }
                 $with_effect[] = $xaction;
                 $column = $this->loadProjectColumn($column_phid);
                 if (!$column) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Column PHID "%s" does not identify a visible column.', $column_phid), $xaction);
                 }
             }
             if ($with_effect && !$this->getIsNewObject()) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can only put a task into an initial column during task ' . 'creation.'), last($with_effect));
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorProjectTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Project name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             if (!$xactions) {
                 break;
             }
             if ($this->getIsMilestone()) {
                 break;
             }
             $name = last($xactions)->getNewValue();
             if (!PhabricatorSlug::isValidProjectSlug($name)) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Project names must contain at least one letter or number.'), last($xactions));
                 break;
             }
             $slug = PhabricatorSlug::normalizeProjectSlug($name);
             $slug_used_already = id(new PhabricatorProjectSlug())->loadOneWhere('slug = %s', $slug);
             if ($slug_used_already && $slug_used_already->getProjectPHID() != $object->getPHID()) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Duplicate'), pht('Project name generates the same hashtag ("%s") as another ' . 'existing project. Choose a unique name.', '#' . $slug), nonempty(last($xactions), null));
                 $errors[] = $error;
             }
             break;
         case PhabricatorProjectTransaction::TYPE_SLUGS:
             if (!$xactions) {
                 break;
             }
             $slug_xaction = last($xactions);
             $new = $slug_xaction->getNewValue();
             $invalid = array();
             foreach ($new as $slug) {
                 if (!PhabricatorSlug::isValidProjectSlug($slug)) {
                     $invalid[] = $slug;
                 }
             }
             if ($invalid) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Hashtags must contain at least one letter or number. %s ' . 'project hashtag(s) are invalid: %s.', phutil_count($invalid), implode(', ', $invalid)), $slug_xaction);
                 break;
             }
             $new = $this->normalizeSlugs($new);
             if ($new) {
                 $slugs_used_already = id(new PhabricatorProjectSlug())->loadAllWhere('slug IN (%Ls)', $new);
             } else {
                 // The project doesn't have any extra slugs.
                 $slugs_used_already = array();
             }
             $slugs_used_already = mgroup($slugs_used_already, 'getProjectPHID');
             foreach ($slugs_used_already as $project_phid => $used_slugs) {
                 if ($project_phid == $object->getPHID()) {
                     continue;
                 }
                 $used_slug_strs = mpull($used_slugs, 'getSlug');
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('%s project hashtag(s) are already used by other projects: %s.', phutil_count($used_slug_strs), implode(', ', $used_slug_strs)), $slug_xaction);
                 $errors[] = $error;
             }
             break;
         case PhabricatorProjectTransaction::TYPE_PARENT:
         case PhabricatorProjectTransaction::TYPE_MILESTONE:
             if (!$xactions) {
                 break;
             }
             $xaction = last($xactions);
             $parent_phid = $xaction->getNewValue();
             if (!$parent_phid) {
                 continue;
             }
             if (!$this->getIsNewObject()) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can only set a parent or milestone project when creating a ' . 'project for the first time.'), $xaction);
                 break;
             }
             $projects = id(new PhabricatorProjectQuery())->setViewer($this->requireActor())->withPHIDs(array($parent_phid))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
             if (!$projects) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Parent or milestone project PHID ("%s") must be the PHID of a ' . 'valid, visible project which you have permission to edit.', $parent_phid), $xaction);
                 break;
             }
             $project = head($projects);
             if ($project->isMilestone()) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Parent or milestone project PHID ("%s") must not be a ' . 'milestone. Milestones may not have subprojects or milestones.', $parent_phid), $xaction);
                 break;
             }
             $limit = PhabricatorProject::getProjectDepthLimit();
             if ($project->getProjectDepth() >= $limit - 1) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can not create a subproject or mielstone under this parent ' . 'because it would nest projects too deeply. The maximum ' . 'nesting depth of projects is %s.', new PhutilNumber($limit)), $xaction);
                 break;
             }
             $object->attachParentProject($project);
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhamePostTransaction::TYPE_TITLE:
             $missing = $this->validateIsEmptyTextField($object->getTitle(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Title is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhamePostTransaction::TYPE_BLOG:
             if ($this->getIsNewObject()) {
                 if (!$xactions) {
                     $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('When creating a post, you must specify which blog it ' . 'should belong to.'), null);
                     $error->setIsMissingFieldError(true);
                     $errors[] = $error;
                     break;
                 }
             }
             foreach ($xactions as $xaction) {
                 $new_phid = $xaction->getNewValue();
                 $blog = id(new PhameBlogQuery())->setViewer($this->getActor())->withPHIDs(array($new_phid))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
                 if ($blog) {
                     continue;
                 }
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('The specified blog PHID ("%s") is not valid. You can only ' . 'create a post on (or move a post into) a blog which you ' . 'have permission to see and edit.', $new_phid), $xaction);
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorPhurlURLTransaction::TYPE_ALIAS:
             $overdrawn = $this->validateIsTextFieldTooLong($object->getName(), $xactions, 64);
             if ($overdrawn) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Alias Too Long'), pht('The alias can be no longer than 64 characters.'), nonempty(last($xactions), null));
             }
             foreach ($xactions as $xaction) {
                 if ($xaction->getOldValue() != $xaction->getNewValue()) {
                     $new_alias = $xaction->getNewValue();
                     $debug_alias = new PHUIInvisibleCharacterView($new_alias);
                     if (!preg_match('/[a-zA-Z]/', $new_alias)) {
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid Alias'), pht('The alias you provided (%s) must contain at least one ' . 'letter.', $debug_alias), $xaction);
                     }
                     if (preg_match('/[^a-z0-9]/i', $new_alias)) {
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid Alias'), pht('The alias you provided (%s) may only contain letters and ' . 'numbers.', $debug_alias), $xaction);
                     }
                 }
             }
             break;
         case PhabricatorPhurlURLTransaction::TYPE_URL:
             $missing = $this->validateIsEmptyTextField($object->getLongURL(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('URL path is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             foreach ($xactions as $xaction) {
                 if ($xaction->getOldValue() != $xaction->getNewValue()) {
                     $protocols = PhabricatorEnv::getEnvConfig('uri.allowed-protocols');
                     $uri = new PhutilURI($xaction->getNewValue());
                     if (!isset($protocols[$uri->getProtocol()])) {
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid URL'), pht('The protocol of the URL is invalid.'), null);
                     }
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case ManiphestTransaction::TYPE_TITLE:
             $missing = $this->validateIsEmptyTextField($object->getTitle(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Task title is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case ManiphestTransaction::TYPE_PARENT:
             $with_effect = array();
             foreach ($xactions as $xaction) {
                 $task_phid = $xaction->getNewValue();
                 if (!$task_phid) {
                     continue;
                 }
                 $with_effect[] = $xaction;
                 $task = id(new ManiphestTaskQuery())->setViewer($this->getActor())->withPHIDs(array($task_phid))->executeOne();
                 if (!$task) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Parent task identifier "%s" does not identify a visible ' . 'task.', $task_phid), $xaction);
                 }
             }
             if ($with_effect && !$this->getIsNewObject()) {
                 $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You can only select a parent task when creating a ' . 'transaction for the first time.'), last($with_effect));
             }
             break;
         case ManiphestTransaction::TYPE_OWNER:
             foreach ($xactions as $xaction) {
                 $old = $xaction->getOldValue();
                 $new = $xaction->getNewValue();
                 if (!strlen($new)) {
                     continue;
                 }
                 if ($new === $old) {
                     continue;
                 }
                 $assignee_list = id(new PhabricatorPeopleQuery())->setViewer($this->getActor())->withPHIDs(array($new))->execute();
                 if (!$assignee_list) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('User "%s" is not a valid user.', $new), $xaction);
                 }
             }
             break;
         case ManiphestTransaction::TYPE_COVER_IMAGE:
             foreach ($xactions as $xaction) {
                 $old = $xaction->getOldValue();
                 $new = $xaction->getNewValue();
                 if (!$new) {
                     continue;
                 }
                 if ($new === $old) {
                     continue;
                 }
                 $file = id(new PhabricatorFileQuery())->setViewer($this->getActor())->withPHIDs(array($new))->executeOne();
                 if (!$file) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('File "%s" is not valid.', $new), $xaction);
                     continue;
                 }
                 if (!$file->isTransformableImage()) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('File "%s" is not a valid image file.', $new), $xaction);
                     continue;
                 }
             }
             break;
         case ManiphestTransaction::TYPE_POINTS:
             foreach ($xactions as $xaction) {
                 $new = $xaction->getNewValue();
                 if (strlen($new) && !is_numeric($new)) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Points value must be numeric or empty.'), $xaction);
                     continue;
                 }
                 if ((double) $new < 0) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('Points value must be nonnegative.'), $xaction);
                     continue;
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case PhabricatorAuthSSHKeyTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('SSH key name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case PhabricatorAuthSSHKeyTransaction::TYPE_KEY:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('SSH key material is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 foreach ($xactions as $xaction) {
                     $new = $xaction->getNewValue();
                     try {
                         $public_key = PhabricatorAuthSSHPublicKey::newFromRawKey($new);
                     } catch (Exception $ex) {
                         $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), $ex->getMessage(), $xaction);
                     }
                 }
             }
             break;
         case PhabricatorAuthSSHKeyTransaction::TYPE_DEACTIVATE:
             foreach ($xactions as $xaction) {
                 if (!$xaction->getNewValue()) {
                     $errors[] = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('SSH keys can not be reactivated.'), $xaction);
                 }
             }
             break;
     }
     return $errors;
 }
 protected function validateTransaction(PhabricatorLiskDAO $object, $type, array $xactions)
 {
     $errors = parent::validateTransaction($object, $type, $xactions);
     switch ($type) {
         case FundInitiativeTransaction::TYPE_NAME:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Initiative name is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             }
             break;
         case FundInitiativeTransaction::TYPE_MERCHANT:
             $missing = $this->validateIsEmptyTextField($object->getName(), $xactions);
             if ($missing) {
                 $error = new PhabricatorApplicationTransactionValidationError($type, pht('Required'), pht('Payable merchant is required.'), nonempty(last($xactions), null));
                 $error->setIsMissingFieldError(true);
                 $errors[] = $error;
             } else {
                 if ($xactions) {
                     $merchant_phid = last($xactions)->getNewValue();
                     // Make sure the actor has permission to edit the merchant they're
                     // selecting. You aren't allowed to send payments to an account you
                     // do not control.
                     $merchants = id(new PhortuneMerchantQuery())->setViewer($this->requireActor())->withPHIDs(array($merchant_phid))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute();
                     if (!$merchants) {
                         $error = new PhabricatorApplicationTransactionValidationError($type, pht('Invalid'), pht('You must specify a merchant account you control as the ' . 'recipient of funds from this initiative.'), last($xactions));
                         $errors[] = $error;
                     }
                 }
             }
             break;
     }
     return $errors;
 }