diff --git a/src/applications/phriction/editor/PhrictionTransactionEditor.php b/src/applications/phriction/editor/PhrictionTransactionEditor.php --- a/src/applications/phriction/editor/PhrictionTransactionEditor.php +++ b/src/applications/phriction/editor/PhrictionTransactionEditor.php @@ -3,6 +3,9 @@ final class PhrictionTransactionEditor extends PhabricatorApplicationTransactionEditor { + const VALIDATE_CREATE_ANCESTRY = 'create'; + const VALIDATE_MOVE_ANCESTRY = 'move'; + private $description; private $oldContent; private $newContent; @@ -519,6 +522,18 @@ $errors[] = $error; } } + + if ($this->getIsNewObject()) { + $ancestry_errors = $this->validateAncestry( + $object, + $type, + $xaction, + self::VALIDATE_CREATE_ANCESTRY); + if ($ancestry_errors) { + $errors = array_merge($errors, $ancestry_errors); + } + } + break; case PhrictionTransaction::TYPE_MOVE_TO: @@ -547,8 +562,15 @@ $errors[] = $error; } - // NOTE: We use the ominpotent user because we can't let users - // overwrite documents even if they can't see them. + $ancestry_errors = $this->validateAncestry( + $object, + $type, + $xaction, + self::VALIDATE_MOVE_ANCESTRY); + if ($ancestry_errors) { + $errors = array_merge($errors, $ancestry_errors); + } + $target_document = id(new PhrictionDocumentQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withSlugs(array($object->getSlug())) @@ -606,6 +628,59 @@ return $errors; } + private function validateAncestry( + PhabricatorLiskDAO $object, + $type, + PhabricatorApplicationTransaction $xaction, + $verb) { + + $errors = array(); + // NOTE: We use the ominpotent user for these checks because policy + // doesn't matter; existence does. + $other_doc_viewer = PhabricatorUser::getOmnipotentUser(); + $ancestral_slugs = PhabricatorSlug::getAncestry($object->getSlug()); + if ($ancestral_slugs) { + $ancestors = id(new PhrictionDocumentQuery()) + ->setViewer($other_doc_viewer) + ->withSlugs($ancestral_slugs) + ->execute(); + $ancestors = mpull($ancestors, null, 'getSlug'); + foreach ($ancestral_slugs as $slug) { + $ancestor_doc = idx($ancestors, $slug); + if (!$ancestor_doc) { + $create_uri = '/phriction/edit/?slug='.$slug; + $create_link = phutil_tag( + 'a', + array( + 'href' => $create_uri, + ), + $slug); + switch ($verb) { + case self::VALIDATE_MOVE_ANCESTRY: + $message = pht( + 'Can not move document because the parent document with '. + 'slug %s does not exist!', + $create_link); + break; + case self::VALIDATE_CREATE_ANCESTRY: + $message = pht( + 'Can not create document because the parent document with '. + 'slug %s does not exist!', + $create_link); + break; + } + $error = new PhabricatorApplicationTransactionValidationError( + $type, + pht('Missing Ancestor'), + $message, + $xaction); + $errors[] = $error; + } + } + } + return $errors; + } + private function validateContentVersion( PhabricatorLiskDAO $object, $type,