@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Give "FileAttachment" policy support and a query object

Summary: Ref T13682. This supports an "Attached Files" curtain UI element.

Test Plan: See next change.

Maniphest Tasks: T13682

Differential Revision: https://secure.phabricator.com/D21835

+248 -31
+7 -1
src/__phutil_library_map__.php
··· 3453 3453 'PhabricatorFileAES256StorageFormat' => 'applications/files/format/PhabricatorFileAES256StorageFormat.php', 3454 3454 'PhabricatorFileAltTextTransaction' => 'applications/files/xaction/PhabricatorFileAltTextTransaction.php', 3455 3455 'PhabricatorFileAttachment' => 'applications/files/storage/PhabricatorFileAttachment.php', 3456 + 'PhabricatorFileAttachmentQuery' => 'applications/files/query/PhabricatorFileAttachmentQuery.php', 3456 3457 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 3457 3458 'PhabricatorFileChunk' => 'applications/files/storage/PhabricatorFileChunk.php', 3458 3459 'PhabricatorFileChunkIterator' => 'applications/files/engine/PhabricatorFileChunkIterator.php', ··· 9892 9893 ), 9893 9894 'PhabricatorFileAES256StorageFormat' => 'PhabricatorFileStorageFormat', 9894 9895 'PhabricatorFileAltTextTransaction' => 'PhabricatorFileTransactionType', 9895 - 'PhabricatorFileAttachment' => 'PhabricatorFileDAO', 9896 + 'PhabricatorFileAttachment' => array( 9897 + 'PhabricatorFileDAO', 9898 + 'PhabricatorPolicyInterface', 9899 + 'PhabricatorExtendedPolicyInterface', 9900 + ), 9901 + 'PhabricatorFileAttachmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 9896 9902 'PhabricatorFileBundleLoader' => 'Phobject', 9897 9903 'PhabricatorFileChunk' => array( 9898 9904 'PhabricatorFileDAO',
+110
src/applications/files/query/PhabricatorFileAttachmentQuery.php
··· 1 + <?php 2 + 3 + final class PhabricatorFileAttachmentQuery 4 + extends PhabricatorCursorPagedPolicyAwareQuery { 5 + 6 + private $objectPHIDs; 7 + private $needFiles; 8 + 9 + public function withObjectPHIDs(array $object_phids) { 10 + $this->objectPHIDs = $object_phids; 11 + return $this; 12 + } 13 + 14 + public function needFiles($need) { 15 + $this->needFiles = $need; 16 + return $this; 17 + } 18 + 19 + public function newResultObject() { 20 + return new PhabricatorFileAttachment(); 21 + } 22 + 23 + protected function loadPage() { 24 + return $this->loadStandardPage($this->newResultObject()); 25 + } 26 + 27 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 28 + $where = parent::buildWhereClauseParts($conn); 29 + 30 + if ($this->objectPHIDs !== null) { 31 + $where[] = qsprintf( 32 + $conn, 33 + 'attachments.objectPHID IN (%Ls)', 34 + $this->objectPHIDs); 35 + } 36 + 37 + return $where; 38 + } 39 + 40 + protected function willFilterPage(array $attachments) { 41 + $viewer = $this->getViewer(); 42 + $object_phids = array(); 43 + 44 + foreach ($attachments as $attachment) { 45 + $object_phid = $attachment->getObjectPHID(); 46 + $object_phids[$object_phid] = $object_phid; 47 + } 48 + 49 + if ($object_phids) { 50 + $objects = id(new PhabricatorObjectQuery()) 51 + ->setViewer($viewer) 52 + ->setParentQuery($this) 53 + ->withPHIDs($object_phids) 54 + ->execute(); 55 + $objects = mpull($objects, null, 'getPHID'); 56 + } else { 57 + $objects = array(); 58 + } 59 + 60 + foreach ($attachments as $key => $attachment) { 61 + $object_phid = $attachment->getObjectPHID(); 62 + $object = idx($objects, $object_phid); 63 + 64 + if (!$object) { 65 + $this->didRejectResult($attachment); 66 + unset($attachments[$key]); 67 + continue; 68 + } 69 + 70 + $attachment->attachObject($object); 71 + } 72 + 73 + if ($this->needFiles) { 74 + $file_phids = array(); 75 + foreach ($attachments as $attachment) { 76 + $file_phid = $attachment->getFilePHID(); 77 + $file_phids[$file_phid] = $file_phid; 78 + } 79 + 80 + if ($file_phids) { 81 + $files = id(new PhabricatorFileQuery()) 82 + ->setViewer($viewer) 83 + ->setParentQuery($this) 84 + ->withPHIDs($file_phids) 85 + ->execute(); 86 + $files = mpull($files, null, 'getPHID'); 87 + } else { 88 + $files = array(); 89 + } 90 + 91 + foreach ($attachments as $key => $attachment) { 92 + $file_phid = $attachment->getFilePHID(); 93 + $file = idx($files, $file_phid); 94 + 95 + $attachment->attachFile($file); 96 + } 97 + } 98 + 99 + return $attachments; 100 + } 101 + 102 + protected function getPrimaryTableAlias() { 103 + return 'attachments'; 104 + } 105 + 106 + public function getQueryApplicationClass() { 107 + return 'PhabricatorFilesApplication'; 108 + } 109 + 110 + }
+12 -4
src/applications/files/query/PhabricatorFileQuery.php
··· 309 309 310 310 $attachments = queryfx_all( 311 311 $attachments_conn, 312 - 'SELECT filePHID, objectPHID FROM %R WHERE filePHID IN (%Ls)', 312 + 'SELECT filePHID, objectPHID FROM %R WHERE filePHID IN (%Ls) 313 + AND attachmentMode IN (%Ls)', 313 314 $attachments_table, 314 - $file_phids); 315 + $file_phids, 316 + array( 317 + PhabricatorFileAttachment::MODE_ATTACH, 318 + )); 315 319 316 320 $attachments_map = array_fill_keys($file_phids, array()); 317 321 foreach ($attachments as $row) { ··· 374 378 if ($this->shouldJoinAttachmentsTable()) { 375 379 $joins[] = qsprintf( 376 380 $conn, 377 - 'JOIN %R attachments ON attachments.filePHID = f.phid', 378 - new PhabricatorFileAttachment()); 381 + 'JOIN %R attachments ON attachments.filePHID = f.phid 382 + AND attachmentMode IN (%Ls)', 383 + new PhabricatorFileAttachment(), 384 + array( 385 + PhabricatorFileAttachment::MODE_ATTACH, 386 + )); 379 387 } 380 388 381 389 return $joins;
+56 -1
src/applications/files/storage/PhabricatorFileAttachment.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorFileAttachment 4 - extends PhabricatorFileDAO { 4 + extends PhabricatorFileDAO 5 + implements 6 + PhabricatorPolicyInterface, 7 + PhabricatorExtendedPolicyInterface { 5 8 6 9 protected $objectPHID; 7 10 protected $filePHID; 8 11 protected $attacherPHID; 9 12 protected $attachmentMode; 13 + 14 + private $object = self::ATTACHABLE; 15 + private $file = self::ATTACHABLE; 10 16 11 17 const MODE_ATTACH = 'attach'; 12 18 const MODE_REFERENCE = 'reference'; ··· 37 43 self::MODE_ATTACH, 38 44 self::MODE_REFERENCE, 39 45 self::MODE_DETACH, 46 + ); 47 + } 48 + 49 + public function attachObject($object) { 50 + $this->object = $object; 51 + return $this; 52 + } 53 + 54 + public function getObject() { 55 + return $this->assertAttached($this->object); 56 + } 57 + 58 + public function attachFile(PhabricatorFile $file = null) { 59 + $this->file = $file; 60 + return $this; 61 + } 62 + 63 + public function getFile() { 64 + return $this->assertAttached($this->file); 65 + } 66 + 67 + 68 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 69 + 70 + 71 + public function getCapabilities() { 72 + return array( 73 + PhabricatorPolicyCapability::CAN_VIEW, 74 + ); 75 + } 76 + 77 + public function getPolicy($capability) { 78 + switch ($capability) { 79 + case PhabricatorPolicyCapability::CAN_VIEW: 80 + return PhabricatorPolicies::getMostOpenPolicy(); 81 + } 82 + } 83 + 84 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 85 + return false; 86 + } 87 + 88 + 89 + /* -( PhabricatorExtendedPolicyInterface )--------------------------------- */ 90 + 91 + 92 + public function getExtendedPolicy($capability, PhabricatorUser $viewer) { 93 + return array( 94 + array($this->getObject(), $capability), 40 95 ); 41 96 } 42 97
+56 -5
src/applications/files/storage/__tests__/PhabricatorFileTestCase.php
··· 100 100 $xactions[] = id(new ManiphestTransaction()) 101 101 ->setTransactionType( 102 102 ManiphestTaskDescriptionTransaction::TRANSACTIONTYPE) 103 - ->setNewValue('{'.$file->getMonogram().'}'); 103 + ->setNewValue('{'.$file->getMonogram().'}') 104 + ->setMetadataValue( 105 + 'remarkup.control', 106 + array( 107 + 'attachedFilePHIDs' => array( 108 + $file->getPHID(), 109 + ), 110 + )); 104 111 105 112 id(new ManiphestTransactionEditor()) 106 113 ->setActor($author) ··· 167 174 168 175 // Create an object and test object policies. 169 176 170 - $object = ManiphestTask::initializeNewTask($author); 171 - $object->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()); 172 - $object->save(); 177 + $object = ManiphestTask::initializeNewTask($author) 178 + ->setTitle(pht('File Visibility Test Task')) 179 + ->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()) 180 + ->save(); 173 181 174 182 $this->assertTrue( 175 183 $filter->hasCapability( ··· 185 193 PhabricatorPolicyCapability::CAN_VIEW), 186 194 pht('Object Visible to Others')); 187 195 196 + // Reference the file in a comment. This should not affect the file 197 + // policy. 198 + 199 + $file_ref = '{F'.$file->getID().'}'; 200 + 201 + $xactions = array(); 202 + $xactions[] = id(new ManiphestTransaction()) 203 + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) 204 + ->attachComment( 205 + id(new ManiphestTransactionComment()) 206 + ->setContent($file_ref)); 207 + 208 + id(new ManiphestTransactionEditor()) 209 + ->setActor($author) 210 + ->setContentSource($this->newContentSource()) 211 + ->applyTransactions($object, $xactions); 212 + 213 + // Test the referenced file's visibility. 214 + $this->assertEqual( 215 + array( 216 + true, 217 + false, 218 + ), 219 + $this->canViewFile($users, $file), 220 + pht('Referenced File Visibility')); 221 + 188 222 // Attach the file to the object and test that the association opens a 189 223 // policy exception for the non-author viewer. 190 224 191 - $file->attachToObject($object->getPHID()); 225 + $xactions = array(); 226 + $xactions[] = id(new ManiphestTransaction()) 227 + ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) 228 + ->setMetadataValue( 229 + 'remarkup.control', 230 + array( 231 + 'attachedFilePHIDs' => array( 232 + $file->getPHID(), 233 + ), 234 + )) 235 + ->attachComment( 236 + id(new ManiphestTransactionComment()) 237 + ->setContent($file_ref)); 238 + 239 + id(new ManiphestTransactionEditor()) 240 + ->setActor($author) 241 + ->setContentSource($this->newContentSource()) 242 + ->applyTransactions($object, $xactions); 192 243 193 244 // Test the attached file's visibility. 194 245 $this->assertEqual(
-20
src/applications/transactions/editengine/PhabricatorEditEngine.php
··· 2080 2080 } 2081 2081 } 2082 2082 2083 - public static function newTransactionsFromRemarkupMetadata( 2084 - PhabricatorApplicationTransaction $template, 2085 - array $metadata) { 2086 - 2087 - $xactions = array(); 2088 - 2089 - $attached_phids = idx($metadata, 'attachedFilePHIDs'); 2090 - if (is_array($attached_phids) && $attached_phids) { 2091 - $attachment_map = array_fill_keys( 2092 - $attached_phids, 2093 - PhabricatorFileAttachment::MODE_ATTACH); 2094 - 2095 - $xactions[] = id(clone $template) 2096 - ->setTransactionType(PhabricatorTransactions::TYPE_FILE) 2097 - ->setNewValue($attachment_map); 2098 - } 2099 - 2100 - return $xactions; 2101 - } 2102 - 2103 2083 protected function newDraftEngine($object) { 2104 2084 $viewer = $this->getViewer(); 2105 2085
+7
src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php
··· 2266 2266 $viewer = $this->getActor(); 2267 2267 2268 2268 $old_blocks = mpull($remarkup_changes, 'getOldValue'); 2269 + foreach ($old_blocks as $key => $old_block) { 2270 + $old_blocks[$key] = phutil_string_cast($old_block); 2271 + } 2272 + 2269 2273 $new_blocks = mpull($remarkup_changes, 'getNewValue'); 2274 + foreach ($new_blocks as $key => $new_block) { 2275 + $new_blocks[$key] = phutil_string_cast($new_block); 2276 + } 2270 2277 2271 2278 $old_refs = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles( 2272 2279 $viewer,