Give Pholio Images an authorPHID and use ExtendedPolicies to implement policy behavior

Summary:
Depends on D19912. Ref T11351. Images currently use `getMock()->getPolicy()` stuff to define policies. This causes bugs with object policies like "Subscribers", since the policy engine tries to evaluate the subscribers //for the image// when the intent is to evaluate the subscribers for the mock.

Move this to ExtendedPolicies to fix the behavior, and give Images sensible policy behavior when they aren't attached to a mock (specifically: only the user who created the image can see it).

Test Plan: Applied migrations, created and edited mocks and images without anything blowing up. Set mock visibility to "Subscribers", everything worked great.

Reviewers: amckinley

Reviewed By: amckinley

Subscribers: PHID-OPKG-gm6ozazyms6q6i22gyam

Maniphest Tasks: T11351

Differential Revision: https://secure.phabricator.com/D19913
This commit is contained in:
epriestley
2018-12-18 15:54:27 -08:00
parent c4c5d8a210
commit aa3b2ec5dc
7 changed files with 53 additions and 19 deletions

View File

@@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_pholio.pholio_image
ADD authorPHID VARBINARY(64) NOT NULL;

View File

@@ -10947,6 +10947,7 @@ phutil_register_library_map(array(
'PholioImage' => array( 'PholioImage' => array(
'PholioDAO', 'PholioDAO',
'PhabricatorPolicyInterface', 'PhabricatorPolicyInterface',
'PhabricatorExtendedPolicyInterface',
), ),
'PholioImageDescriptionTransaction' => 'PholioImageTransactionType', 'PholioImageDescriptionTransaction' => 'PholioImageTransactionType',
'PholioImageFileTransaction' => 'PholioImageTransactionType', 'PholioImageFileTransaction' => 'PholioImageTransactionType',

View File

@@ -23,6 +23,7 @@ final class PholioImageUploadController extends PholioController {
} }
$image = PholioImage::initializeNewImage() $image = PholioImage::initializeNewImage()
->setAuthorPHID($viewer->getPHID())
->attachFile($file) ->attachFile($file)
->setName($title) ->setName($title)
->setDescription($description) ->setDescription($description)

View File

@@ -141,6 +141,7 @@ final class PholioMockEditController extends PholioController {
if ($replaces_image_phid) { if ($replaces_image_phid) {
$replace_image = PholioImage::initializeNewImage() $replace_image = PholioImage::initializeNewImage()
->setAuthorPHID($viewer->getPHID())
->setReplacesImagePHID($replaces_image_phid) ->setReplacesImagePHID($replaces_image_phid)
->setFilePhid($file_phid) ->setFilePhid($file_phid)
->attachFile($file) ->attachFile($file)
@@ -154,6 +155,7 @@ final class PholioMockEditController extends PholioController {
$posted_mock_images[] = $replace_image; $posted_mock_images[] = $replace_image;
} else if (!$existing_image) { // this is an add } else if (!$existing_image) { // this is an add
$add_image = PholioImage::initializeNewImage() $add_image = PholioImage::initializeNewImage()
->setAuthorPHID($viewer->getPHID())
->setFilePhid($file_phid) ->setFilePhid($file_phid)
->attachFile($file) ->attachFile($file)
->setName(strlen($title) ? $title : $file->getName()) ->setName(strlen($title) ? $title : $file->getName())

View File

@@ -82,7 +82,7 @@ final class PholioMockViewController extends PholioController {
$add_comment = $this->buildAddCommentView($mock, $comment_form_id); $add_comment = $this->buildAddCommentView($mock, $comment_form_id);
$crumbs = $this->buildApplicationCrumbs(); $crumbs = $this->buildApplicationCrumbs();
$crumbs->addTextCrumb('M'.$mock->getID(), '/M'.$mock->getID()); $crumbs->addTextCrumb($mock->getMonogram(), $mock->getURI());
$crumbs->setBorder(true); $crumbs->setBorder(true);
$thumb_grid = id(new PholioMockThumbGridView()) $thumb_grid = id(new PholioMockThumbGridView())
@@ -92,16 +92,17 @@ final class PholioMockViewController extends PholioController {
$view = id(new PHUITwoColumnView()) $view = id(new PHUITwoColumnView())
->setHeader($header) ->setHeader($header)
->setCurtain($curtain) ->setCurtain($curtain)
->setMainColumn(array( ->setMainColumn(
$output, array(
$thumb_grid, $output,
$details, $thumb_grid,
$timeline, $details,
$add_comment, $timeline,
)); $add_comment,
));
return $this->newPage() return $this->newPage()
->setTitle('M'.$mock->getID().' '.$title) ->setTitle(pht('%s %s', $mock->getMonogram(), $title))
->setCrumbs($crumbs) ->setCrumbs($crumbs)
->setPageObjectPHIDs(array($mock->getPHID())) ->setPageObjectPHIDs(array($mock->getPHID()))
->addQuicksandConfig( ->addQuicksandConfig(

View File

@@ -42,6 +42,7 @@ final class PhabricatorPholioMockTestDataGenerator
$images = array(); $images = array();
foreach ($files as $file) { foreach ($files as $file) {
$image = PholioImage::initializeNewImage() $image = PholioImage::initializeNewImage()
->setAuthorPHID($author_phid)
->setFilePHID($file->getPHID()) ->setFilePHID($file->getPHID())
->setSequence($sequence++) ->setSequence($sequence++)
->attachMock($mock); ->attachMock($mock);

View File

@@ -2,8 +2,10 @@
final class PholioImage extends PholioDAO final class PholioImage extends PholioDAO
implements implements
PhabricatorPolicyInterface { PhabricatorPolicyInterface,
PhabricatorExtendedPolicyInterface {
protected $authorPHID;
protected $mockID; protected $mockID;
protected $filePHID; protected $filePHID;
protected $name; protected $name;
@@ -57,8 +59,7 @@ final class PholioImage extends PholioDAO
} }
public function getFile() { public function getFile() {
$this->assertAttached($this->file); return $this->assertAttached($this->file);
return $this->file;
} }
public function attachMock(PholioMock $mock) { public function attachMock(PholioMock $mock) {
@@ -67,8 +68,7 @@ final class PholioImage extends PholioDAO
} }
public function getMock() { public function getMock() {
$this->assertAttached($this->mock); return $this->assertAttached($this->mock);
return $this->mock;
} }
public function attachInlineComments(array $inline_comments) { public function attachInlineComments(array $inline_comments) {
@@ -83,20 +83,46 @@ final class PholioImage extends PholioDAO
} }
/* -( PhabricatorPolicyInterface Implementation )-------------------------- */ /* -( PhabricatorPolicyInterface )----------------------------------------- */
public function getCapabilities() { public function getCapabilities() {
return $this->getMock()->getCapabilities(); return array(
PhabricatorPolicyCapability::CAN_VIEW,
PhabricatorPolicyCapability::CAN_EDIT,
);
} }
public function getPolicy($capability) { public function getPolicy($capability) {
return $this->getMock()->getPolicy($capability); // If the image is attached to a mock, we use an extended policy to match
// the mock's permissions.
if ($this->getMockID()) {
return PhabricatorPolicies::getMostOpenPolicy();
}
// If the image is not attached to a mock, only the author can see it.
return $this->getAuthorPHID();
} }
// really the *mock* controls who can see an image
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
return $this->getMock()->hasAutomaticCapability($capability, $viewer); return false;
}
/* -( PhabricatorExtendedPolicyInterface )--------------------------------- */
public function getExtendedPolicy($capability, PhabricatorUser $viewer) {
if ($this->getMockID()) {
return array(
array(
$this->getMock(),
$capability,
),
);
}
return array();
} }
} }