diff --git a/src/applications/files/controller/PhabricatorFileInfoController.php b/src/applications/files/controller/PhabricatorFileInfoController.php index 4abf378725..2964587b5e 100644 --- a/src/applications/files/controller/PhabricatorFileInfoController.php +++ b/src/applications/files/controller/PhabricatorFileInfoController.php @@ -27,7 +27,11 @@ final class PhabricatorFileInfoController extends PhabricatorFileController { ->withObjectPHIDs(array($phid)) ->execute(); - $this->loadHandles(array($file->getAuthorPHID())); + $handle_phids = array_merge( + array($file->getAuthorPHID()), + $file->getObjectPHIDs()); + + $this->loadHandles($handle_phids); $header = id(new PHUIHeaderView()) ->setHeader($file->getName()); @@ -207,6 +211,15 @@ final class PhabricatorFileInfoController extends PhabricatorFileController { } } + $phids = $file->getObjectPHIDs(); + if ($phids) { + $view->addSectionHeader(pht('Attached')); + $view->addProperty( + pht('Attached To'), + $this->renderHandlesForPHIDs($phids)); + } + + if ($file->isViewableImage()) { $image = phutil_tag( diff --git a/src/applications/files/query/PhabricatorFileQuery.php b/src/applications/files/query/PhabricatorFileQuery.php index 12b1907c34..fd859a8fbe 100644 --- a/src/applications/files/query/PhabricatorFileQuery.php +++ b/src/applications/files/query/PhabricatorFileQuery.php @@ -104,7 +104,48 @@ final class PhabricatorFileQuery $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); - return $table->loadAllFromArray($data); + $files = $table->loadAllFromArray($data); + + if (!$files) { + return $files; + } + + // We need to load attached objects to perform policy checks for files. + // First, load the edges. + + $edge_type = PhabricatorEdgeConfig::TYPE_FILE_HAS_OBJECT; + $phids = mpull($files, 'getPHID'); + $edges = id(new PhabricatorEdgeQuery()) + ->withSourcePHIDs($phids) + ->withEdgeTypes(array($edge_type)) + ->execute(); + + $object_phids = array(); + foreach ($files as $file) { + $phids = array_keys($edges[$file->getPHID()][$edge_type]); + $file->attachObjectPHIDs($phids); + foreach ($phids as $phid) { + $object_phids[$phid] = true; + } + } + + // Now, load the objects. + + $objects = array(); + if ($object_phids) { + $objects = id(new PhabricatorObjectQuery()) + ->setViewer($this->getViewer()) + ->withPHIDs($object_phids) + ->execute(); + $objects = mpull($objects, null, 'getPHID'); + } + + foreach ($files as $file) { + $file_objects = array_select_keys($objects, $file->getObjectPHIDs()); + $file->attachObjects($file_objects); + } + + return $files; } private function buildJoinClause(AphrontDatabaseConnection $conn_r) { diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index 7ec943d58d..8d656f05ef 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -31,6 +31,9 @@ final class PhabricatorFile extends PhabricatorFileDAO protected $ttl; protected $isExplicitUpload = 1; + private $objects = self::ATTACHABLE; + private $objectPHIDs = self::ATTACHABLE; + public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, @@ -803,6 +806,9 @@ final class PhabricatorFile extends PhabricatorFileDAO ->save(); unset($unguarded); + $file->attachObjectPHIDs(array()); + $file->attachObjects(array()); + $files[$name] = $file; } @@ -821,6 +827,24 @@ final class PhabricatorFile extends PhabricatorFileDAO return idx(self::loadBuiltins($user, array($name)), $name); } + public function getObjects() { + return $this->assertAttached($this->objects); + } + + public function attachObjects(array $objects) { + $this->objects = $objects; + return $this; + } + + public function getObjectPHIDs() { + return $this->assertAttached($this->objectPHIDs); + } + + public function attachObjectPHIDs(array $object_phids) { + $this->objectPHIDs = $object_phids; + return $this; + } + /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ @@ -838,11 +862,35 @@ final class PhabricatorFile extends PhabricatorFileDAO } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { + $viewer_phid = $viewer->getPHID(); + if ($viewer_phid) { + if ($this->getAuthorPHID() == $viewer_phid) { + return true; + } + } + + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + // If you can see any object this file is attached to, you can see + // the file. + return (count($this->getObjects()) > 0); + } + return false; } public function describeAutomaticCapability($capability) { - return null; + $out = array(); + $out[] = pht('The user who uploaded a file can always view and edit it.'); + switch ($capability) { + case PhabricatorPolicyCapability::CAN_VIEW: + $out[] = pht( + 'Files attached to objects are visible to users who can view '. + 'those objects.'); + break; + } + + return $out; }