@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.

Modularize file transforms and provide a "transforms" UI

Summary:
Ref T7707. Available transforms are currently relatively hard-coded and don't really have any support UI.

Modularize them so we can build some support UI.

This doesn't actually //use// any of the new stuff yet: I want to make a clean cutover once I fix the aspect ratio stuff so I can pick up a cachekey/URI change as a side effect.

Test Plan: {F400524}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: chad, epriestley

Maniphest Tasks: T7707

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

+319 -16
+8
src/__phutil_library_map__.php
··· 1860 1860 'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php', 1861 1861 'PhabricatorFileHasObjectEdgeType' => 'applications/files/edge/PhabricatorFileHasObjectEdgeType.php', 1862 1862 'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php', 1863 + 'PhabricatorFileImageTransform' => 'applications/files/transform/PhabricatorFileImageTransform.php', 1863 1864 'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php', 1864 1865 'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php', 1865 1866 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', ··· 1873 1874 'PhabricatorFileTemporaryGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileTemporaryGarbageCollector.php', 1874 1875 'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php', 1875 1876 'PhabricatorFileTestDataGenerator' => 'applications/files/lipsum/PhabricatorFileTestDataGenerator.php', 1877 + 'PhabricatorFileThumbnailTransform' => 'applications/files/transform/PhabricatorFileThumbnailTransform.php', 1876 1878 'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php', 1877 1879 'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php', 1878 1880 'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php', 1881 + 'PhabricatorFileTransform' => 'applications/files/transform/PhabricatorFileTransform.php', 1879 1882 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 1883 + 'PhabricatorFileTransformListController' => 'applications/files/controller/PhabricatorFileTransformListController.php', 1880 1884 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 1881 1885 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 1882 1886 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', ··· 5262 5266 'PhabricatorFlaggableInterface', 5263 5267 'PhabricatorPolicyInterface', 5264 5268 ), 5269 + 'PhabricatorFileImageTransform' => 'PhabricatorFileTransform', 5265 5270 'PhabricatorFileInfoController' => 'PhabricatorFileController', 5266 5271 'PhabricatorFileLinkListView' => 'AphrontView', 5267 5272 'PhabricatorFileLinkView' => 'AphrontView', ··· 5274 5279 'PhabricatorFileTemporaryGarbageCollector' => 'PhabricatorGarbageCollector', 5275 5280 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 5276 5281 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', 5282 + 'PhabricatorFileThumbnailTransform' => 'PhabricatorFileImageTransform', 5277 5283 'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction', 5278 5284 'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment', 5279 5285 'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 5286 + 'PhabricatorFileTransform' => 'Phobject', 5280 5287 'PhabricatorFileTransformController' => 'PhabricatorFileController', 5288 + 'PhabricatorFileTransformListController' => 'PhabricatorFileController', 5281 5289 'PhabricatorFileUploadController' => 'PhabricatorFileController', 5282 5290 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 5283 5291 'PhabricatorFileUploadException' => 'Exception',
+2
src/applications/files/application/PhabricatorFilesApplication.php
··· 91 91 '(?P<phid>[^/]+)/'. 92 92 '(?P<key>[^/]+)/' 93 93 => 'PhabricatorFileTransformController', 94 + 'transforms/(?P<id>[1-9]\d*)/' => 95 + 'PhabricatorFileTransformListController', 94 96 'uploaddialog/' => 'PhabricatorFileUploadDialogController', 95 97 'download/(?P<phid>[^/]+)/' => 'PhabricatorFileDialogController', 96 98 ),
+6 -1
src/applications/files/controller/PhabricatorFileInfoController.php
··· 170 170 ->setWorkflow(true) 171 171 ->setDisabled(!$can_edit)); 172 172 173 + $view->addAction( 174 + id(new PhabricatorActionView()) 175 + ->setName(pht('View Transforms')) 176 + ->setIcon('fa-crop') 177 + ->setHref($this->getApplicationURI("/transforms/{$id}/"))); 178 + 173 179 return $view; 174 180 } 175 181 ··· 266 272 pht('Attached To'), 267 273 $user->renderHandleList($phids)); 268 274 } 269 - 270 275 271 276 if ($file->isViewableImage()) { 272 277 $image = phutil_tag(
+27 -15
src/applications/files/controller/PhabricatorFileTransformController.php
··· 48 48 // protection. 49 49 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); 50 50 51 - switch ($transform) { 52 - case 'thumb-profile': 53 - $xformed_file = $this->executeThumbTransform($file, 50, 50); 54 - break; 55 - case 'thumb-280x210': 56 - $xformed_file = $this->executeThumbTransform($file, 280, 210); 57 - break; 58 - case 'preview-100': 59 - $xformed_file = $this->executePreviewTransform($file, 100); 60 - break; 61 - case 'preview-220': 62 - $xformed_file = $this->executePreviewTransform($file, 220); 63 - break; 64 - default: 65 - return new Aphront400Response(); 51 + $xformed_file = null; 52 + 53 + $xforms = PhabricatorFileTransform::getAllTransforms(); 54 + if (isset($xforms[$transform])) { 55 + $xform = $xforms[$transform]; 56 + if ($xform->canApplyTransform($file)) { 57 + $xformed_file = $xforms[$transform]->applyTransform($file); 58 + } 59 + } 60 + 61 + if (!$xformed_file) { 62 + switch ($transform) { 63 + case 'thumb-profile': 64 + $xformed_file = $this->executeThumbTransform($file, 50, 50); 65 + break; 66 + case 'thumb-280x210': 67 + $xformed_file = $this->executeThumbTransform($file, 280, 210); 68 + break; 69 + case 'preview-100': 70 + $xformed_file = $this->executePreviewTransform($file, 100); 71 + break; 72 + case 'preview-220': 73 + $xformed_file = $this->executePreviewTransform($file, 220); 74 + break; 75 + default: 76 + return new Aphront400Response(); 77 + } 66 78 } 67 79 68 80 if (!$xformed_file) {
+137
src/applications/files/controller/PhabricatorFileTransformListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorFileTransformListController 4 + extends PhabricatorFileController { 5 + 6 + public function shouldAllowPublic() { 7 + return true; 8 + } 9 + 10 + public function handleRequest(AphrontRequest $request) { 11 + $viewer = $this->getViewer(); 12 + 13 + $file = id(new PhabricatorFileQuery()) 14 + ->setViewer($viewer) 15 + ->withIDs(array($request->getURIData('id'))) 16 + ->executeOne(); 17 + if (!$file) { 18 + return new Aphront404Response(); 19 + } 20 + 21 + $monogram = $file->getMonogram(); 22 + 23 + $xdst = id(new PhabricatorTransformedFile())->loadAllWhere( 24 + 'transformedPHID = %s', 25 + $file->getPHID()); 26 + 27 + $dst_rows = array(); 28 + foreach ($xdst as $source) { 29 + $dst_rows[] = array( 30 + $source->getTransform(), 31 + $viewer->renderHandle($source->getOriginalPHID()), 32 + ); 33 + } 34 + $dst_table = id(new AphrontTableView($dst_rows)) 35 + ->setHeaders( 36 + array( 37 + pht('Key'), 38 + pht('Source'), 39 + )) 40 + ->setColumnClasses( 41 + array( 42 + '', 43 + 'wide', 44 + )) 45 + ->setNoDataString( 46 + pht( 47 + 'This file was not created by transforming another file.')); 48 + 49 + $xsrc = id(new PhabricatorTransformedFile())->loadAllWhere( 50 + 'originalPHID = %s', 51 + $file->getPHID()); 52 + $xsrc = mpull($xsrc, 'getTransformedPHID', 'getTransform'); 53 + 54 + $src_rows = array(); 55 + $xforms = PhabricatorFileTransform::getAllTransforms(); 56 + foreach ($xforms as $xform) { 57 + $dst_phid = idx($xsrc, $xform->getTransformKey()); 58 + 59 + if ($xform->canApplyTransform($file)) { 60 + $can_apply = pht('Yes'); 61 + $view_href = $file->getURIForTransform($xform); 62 + if ($dst_phid) { 63 + $view_text = pht('View Transform'); 64 + } else { 65 + $view_text = pht('Generate Transform'); 66 + } 67 + $view_link = phutil_tag( 68 + 'a', 69 + array( 70 + 'class' => 'small grey button', 71 + 'href' => $view_href, 72 + ), 73 + $view_text); 74 + } else { 75 + $can_apply = phutil_tag('em', array(), pht('No')); 76 + $view_link = phutil_tag('em', array(), pht('None')); 77 + } 78 + 79 + if ($dst_phid) { 80 + $dst_link = $viewer->renderHandle($dst_phid); 81 + } else { 82 + $dst_link = phutil_tag('em', array(), pht('None')); 83 + } 84 + 85 + $src_rows[] = array( 86 + $xform->getTransformName(), 87 + $xform->getTransformKey(), 88 + $can_apply, 89 + $dst_link, 90 + $view_link, 91 + ); 92 + } 93 + 94 + $src_table = id(new AphrontTableView($src_rows)) 95 + ->setHeaders( 96 + array( 97 + pht('Name'), 98 + pht('Key'), 99 + pht('Supported'), 100 + pht('Transform'), 101 + pht('View'), 102 + )) 103 + ->setColumnClasses( 104 + array( 105 + 'wide', 106 + '', 107 + '', 108 + '', 109 + 'action', 110 + )); 111 + 112 + $crumbs = $this->buildApplicationCrumbs(); 113 + $crumbs->addTextCrumb($monogram, '/'.$monogram); 114 + $crumbs->addTextCrumb(pht('Transforms')); 115 + 116 + $dst_box = id(new PHUIObjectBoxView()) 117 + ->setHeaderText(pht('File Sources')) 118 + ->appendChild($dst_table); 119 + 120 + $src_box = id(new PHUIObjectBoxView()) 121 + ->setHeaderText(pht('Available Transforms')) 122 + ->appendChild($src_table); 123 + 124 + return $this->buildApplicationPage( 125 + array( 126 + $crumbs, 127 + $dst_box, 128 + $src_box, 129 + ), 130 + array( 131 + 'title' => array( 132 + pht('%s %s', $monogram, $file->getName()), 133 + pht('Tranforms'), 134 + ), 135 + )); 136 + } 137 + }
+4
src/applications/files/storage/PhabricatorFile.php
··· 760 760 return (string) $uri; 761 761 } 762 762 763 + public function getURIForTransform(PhabricatorFileTransform $transform) { 764 + return $this->getTransformedURI($transform->getTransformKey()); 765 + } 766 + 763 767 private function getTransformedURI($transform) { 764 768 $parts = array(); 765 769 $parts[] = 'file';
+17
src/applications/files/transform/PhabricatorFileImageTransform.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorFileImageTransform extends PhabricatorFileTransform { 4 + 5 + public function canApplyTransform(PhabricatorFile $file) { 6 + if (!$file->isViewableImage()) { 7 + return false; 8 + } 9 + 10 + if (!$file->isTransformableImage()) { 11 + return false; 12 + } 13 + 14 + return true; 15 + } 16 + 17 + }
+74
src/applications/files/transform/PhabricatorFileThumbnailTransform.php
··· 1 + <?php 2 + 3 + final class PhabricatorFileThumbnailTransform 4 + extends PhabricatorFileImageTransform { 5 + 6 + const TRANSFORM_PROFILE = 'profile'; 7 + const TRANSFORM_PINBOARD = 'pinboard'; 8 + const TRANSFORM_THUMBGRID = 'thumbgrid'; 9 + const TRANSFORM_PREVIEW = 'preview'; 10 + 11 + private $name; 12 + private $key; 13 + private $dstX; 14 + private $dstY; 15 + 16 + public function setName($name) { 17 + $this->name = $name; 18 + return $this; 19 + } 20 + 21 + public function setKey($key) { 22 + $this->key = $key; 23 + return $this; 24 + } 25 + 26 + public function setDimensions($x, $y) { 27 + $this->dstX = $x; 28 + $this->dstY = $y; 29 + return $this; 30 + } 31 + 32 + public function getTransformName() { 33 + return $this->name; 34 + } 35 + 36 + public function getTransformKey() { 37 + return $this->key; 38 + } 39 + 40 + public function generateTransforms() { 41 + return array( 42 + id(new PhabricatorFileThumbnailTransform()) 43 + ->setName(pht("Profile (100px \xC3\x97 100px)")) 44 + ->setKey(self::TRANSFORM_PROFILE) 45 + ->setDimensions(100, 100), 46 + id(new PhabricatorFileThumbnailTransform()) 47 + ->setName(pht("Pinboard (280px \xC3\x97 210px)")) 48 + ->setKey(self::TRANSFORM_PINBOARD) 49 + ->setDimensions(280, 210), 50 + id(new PhabricatorFileThumbnailTransform()) 51 + ->setName(pht('Thumbgrid (100px)')) 52 + ->setKey(self::TRANSFORM_THUMBGRID) 53 + ->setDimensions(100, null), 54 + id(new PhabricatorFileThumbnailTransform()) 55 + ->setName(pht('Preview (220px)')) 56 + ->setKey(self::TRANSFORM_PREVIEW) 57 + ->setDimensions(220, null), 58 + ); 59 + } 60 + 61 + public function applyTransform(PhabricatorFile $file) { 62 + $x = $this->dstX; 63 + $y = $this->dstY; 64 + 65 + $xformer = new PhabricatorImageTransformer(); 66 + 67 + if ($y === null) { 68 + return $xformer->executePreviewTransform($file, $x); 69 + } else { 70 + return $xformer->executeThumbTransform($file, $x, $y); 71 + } 72 + } 73 + 74 + }
+44
src/applications/files/transform/PhabricatorFileTransform.php
··· 1 + <?php 2 + 3 + abstract class PhabricatorFileTransform extends Phobject { 4 + 5 + abstract public function getTransformName(); 6 + abstract public function getTransformKey(); 7 + abstract public function canApplyTransform(PhabricatorFile $file); 8 + abstract public function applyTransform(PhabricatorFile $file); 9 + 10 + public function generateTransforms() { 11 + return array($this); 12 + } 13 + 14 + public static function getAllTransforms() { 15 + static $map; 16 + 17 + if ($map === null) { 18 + $xforms = id(new PhutilSymbolLoader()) 19 + ->setAncestorClass(__CLASS__) 20 + ->loadObjects(); 21 + 22 + $result = array(); 23 + foreach ($xforms as $xform_template) { 24 + foreach ($xform_template->generateTransforms() as $xform) { 25 + $key = $xform->getTransformKey(); 26 + if (isset($result[$key])) { 27 + throw new Exception( 28 + pht( 29 + 'Two %s objects define the same transform key ("%s"), but '. 30 + 'each transform must have a unique key.', 31 + __CLASS__, 32 + $key)); 33 + } 34 + $result[$key] = $xform; 35 + } 36 + } 37 + 38 + $map = $result; 39 + } 40 + 41 + return $map; 42 + } 43 + 44 + }