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

Add storage and read logic for workboard card cover photos

Summary:
No way to set photos yet, but if you magic them in they work.

Primarily, this consolidates rendering logic so the move + edit + view controllers all run the same code to do tags / cover photos.

Test Plan: {F1095870}

Reviewers: chad

Reviewed By: chad

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

+237 -87
+5
resources/sql/autopatches/20160206.cover.1.sql
··· 1 + ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task 2 + ADD properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}; 3 + 4 + UPDATE {$NAMESPACE}_maniphest.maniphest_task 5 + SET properties = '{}' WHERE properties = '';
+2
src/__phutil_library_map__.php
··· 1815 1815 'PhabricatorBinariesSetupCheck' => 'applications/config/check/PhabricatorBinariesSetupCheck.php', 1816 1816 'PhabricatorBitbucketAuthProvider' => 'applications/auth/provider/PhabricatorBitbucketAuthProvider.php', 1817 1817 'PhabricatorBoardLayoutEngine' => 'applications/project/engine/PhabricatorBoardLayoutEngine.php', 1818 + 'PhabricatorBoardRenderingEngine' => 'applications/project/engine/PhabricatorBoardRenderingEngine.php', 1818 1819 'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', 1819 1820 'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php', 1820 1821 'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php', ··· 6043 6044 'PhabricatorBinariesSetupCheck' => 'PhabricatorSetupCheck', 6044 6045 'PhabricatorBitbucketAuthProvider' => 'PhabricatorOAuth1AuthProvider', 6045 6046 'PhabricatorBoardLayoutEngine' => 'Phobject', 6047 + 'PhabricatorBoardRenderingEngine' => 'Phobject', 6046 6048 'PhabricatorBot' => 'PhabricatorDaemon', 6047 6049 'PhabricatorBotChannel' => 'PhabricatorBotTarget', 6048 6050 'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler',
+5
src/applications/files/transform/PhabricatorFileThumbnailTransform.php
··· 7 7 const TRANSFORM_PINBOARD = 'pinboard'; 8 8 const TRANSFORM_THUMBGRID = 'thumbgrid'; 9 9 const TRANSFORM_PREVIEW = 'preview'; 10 + const TRANSFORM_WORKCARD = 'workcard'; 10 11 11 12 private $name; 12 13 private $key; ··· 73 74 ->setName(pht('Preview (220px)')) 74 75 ->setKey(self::TRANSFORM_PREVIEW) 75 76 ->setDimensions(220, null), 77 + id(new self()) 78 + ->setName(pht('Workcard (526px)')) 79 + ->setKey(self::TRANSFORM_WORKCARD) 80 + ->setDimensions(526, null), 76 81 ); 77 82 } 78 83
+14 -26
src/applications/maniphest/editor/ManiphestEditEngine.php
··· 334 334 'sortMap' => $sort_map, 335 335 ); 336 336 337 - // TODO: This should just use HandlePool once we get through the EditEngine 338 - // transition. 339 - $owner = null; 340 - if ($task->getOwnerPHID()) { 341 - $owner = id(new PhabricatorHandleQuery()) 342 - ->setViewer($viewer) 343 - ->withPHIDs(array($task->getOwnerPHID())) 344 - ->executeOne(); 345 - } 346 - 347 - $handle_phids = $task->getProjectPHIDs(); 348 - $handle_phids = array_fuse($handle_phids); 349 - $handle_phids = array_diff_key($handle_phids, $board_phids); 350 - 351 - $project_handles = $viewer->loadHandles($handle_phids); 352 - $project_handles = iterator_to_array($project_handles); 353 - 354 - $tasks = id(new ProjectBoardTaskCard()) 337 + $rendering_engine = id(new PhabricatorBoardRenderingEngine()) 355 338 ->setViewer($viewer) 356 - ->setTask($task) 357 - ->setOwner($owner) 358 - ->setProjectHandles($project_handles) 359 - ->setCanEdit(true) 360 - ->getItem(); 339 + ->setObjects(array($task)) 340 + ->setExcludedProjectPHIDs($board_phids); 361 341 362 - $tasks->addClass('phui-workcard'); 342 + $card = $rendering_engine->renderCard($task->getPHID()); 343 + 344 + $item = $card->getItem(); 345 + $item->addClass('phui-workcard'); 363 346 364 347 $payload = array( 365 - 'tasks' => $tasks, 348 + 'tasks' => $item, 366 349 'data' => $data, 367 350 ); 368 351 369 - return id(new AphrontAjaxResponse())->setContent($payload); 352 + return id(new AphrontAjaxResponse()) 353 + ->setContent( 354 + array( 355 + 'tasks' => $item, 356 + 'data' => $data, 357 + )); 370 358 } 371 359 372 360
+15
src/applications/maniphest/storage/ManiphestTask.php
··· 38 38 39 39 protected $ownerOrdering; 40 40 protected $spacePHID; 41 + protected $properties = array(); 41 42 42 43 private $subscriberPHIDs = self::ATTACHABLE; 43 44 private $groupByProjectPHID = self::ATTACHABLE; ··· 74 75 'ccPHIDs' => self::SERIALIZATION_JSON, 75 76 'attached' => self::SERIALIZATION_JSON, 76 77 'projectPHIDs' => self::SERIALIZATION_JSON, 78 + 'properties' => self::SERIALIZATION_JSON, 77 79 ), 78 80 self::CONFIG_COLUMN_SCHEMA => array( 79 81 'ownerPHID' => 'phid?', ··· 213 215 -$this->getSubpriority(), 214 216 $this->getID(), 215 217 ); 218 + } 219 + 220 + public function setProperty($key, $value) { 221 + $this->properties[$key] = $value; 222 + return $this; 223 + } 224 + 225 + public function getProperty($key, $default = null) { 226 + return idx($this->properties, $key, $default); 227 + } 228 + 229 + public function getCoverImageThumbnailPHID() { 230 + return idx($this->properties, 'cover.thumbnailPHID'); 216 231 } 217 232 218 233
+25 -32
src/applications/project/controller/PhabricatorProjectBoardViewController.php
··· 7 7 8 8 private $id; 9 9 private $slug; 10 - private $handles; 11 10 private $queryKey; 12 11 private $filter; 13 12 private $sortKey; ··· 226 225 'project-boards', 227 226 $behavior_config); 228 227 229 - $this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); 230 - 231 - $all_project_phids = array(); 232 - foreach ($tasks as $task) { 233 - foreach ($task->getProjectPHIDs() as $project_phid) { 234 - $all_project_phids[$project_phid] = $project_phid; 235 - } 236 - } 237 - 238 - foreach ($select_phids as $phid) { 239 - unset($all_project_phids[$phid]); 240 - } 241 - 242 - $all_handles = $viewer->loadHandles($all_project_phids); 243 - $all_handles = iterator_to_array($all_handles); 244 - 228 + $visible_columns = array(); 229 + $column_phids = array(); 230 + $visible_phids = array(); 245 231 foreach ($columns as $column) { 246 232 if (!$this->showHidden) { 247 233 if ($column->isHidden()) { ··· 268 254 $column_tasks = array_select_keys($column_tasks, array_keys($tasks)); 269 255 } 270 256 257 + $column_phid = $column->getPHID(); 258 + 259 + $visible_columns[$column_phid] = $column; 260 + $column_phids[$column_phid] = $column_tasks; 261 + 262 + foreach ($column_tasks as $phid => $task) { 263 + $visible_phids[$phid] = $phid; 264 + } 265 + } 266 + 267 + $rendering_engine = id(new PhabricatorBoardRenderingEngine()) 268 + ->setViewer($viewer) 269 + ->setObjects(array_select_keys($tasks, $visible_phids)) 270 + ->setEditMap($task_can_edit_map) 271 + ->setExcludedProjectPHIDs($select_phids); 272 + 273 + foreach ($visible_columns as $column_phid => $column) { 274 + $column_tasks = $column_phids[$column_phid]; 275 + 271 276 $panel = id(new PHUIWorkpanelView()) 272 277 ->setHeader($column->getDisplayName()) 273 278 ->setSubHeader($column->getDisplayType()) ··· 317 322 )); 318 323 319 324 foreach ($column_tasks as $task) { 320 - $owner = null; 321 - if ($task->getOwnerPHID()) { 322 - $owner = $this->handles[$task->getOwnerPHID()]; 323 - } 324 - $can_edit = idx($task_can_edit_map, $task->getPHID(), false); 325 - 326 - $handles = array_select_keys($all_handles, $task->getProjectPHIDs()); 327 - 328 - $cards->addItem(id(new ProjectBoardTaskCard()) 329 - ->setViewer($viewer) 330 - ->setProjectHandles($handles) 331 - ->setTask($task) 332 - ->setOwner($owner) 333 - ->setCanEdit($can_edit) 334 - ->getItem()); 325 + $card = $rendering_engine->renderCard($task->getPHID()); 326 + $cards->addItem($card->getItem()); 335 327 } 328 + 336 329 $panel->setCards($cards); 337 330 $board->addPanel($panel); 338 331 }
+12 -29
src/applications/project/controller/PhabricatorProjectMoveController.php
··· 175 175 176 176 $editor->applyTransactions($object, $xactions); 177 177 178 - $owner = null; 179 - if ($object->getOwnerPHID()) { 180 - $owner = id(new PhabricatorHandleQuery()) 181 - ->setViewer($viewer) 182 - ->withPHIDs(array($object->getOwnerPHID())) 183 - ->executeOne(); 184 - } 185 - 186 178 // Reload the object so it reflects edits which have been applied. 187 179 $object = id(new ManiphestTaskQuery()) 188 180 ->setViewer($viewer) 189 181 ->withPHIDs(array($object_phid)) 190 182 ->needProjectPHIDs(true) 191 - ->requireCapabilities( 192 - array( 193 - PhabricatorPolicyCapability::CAN_VIEW, 194 - PhabricatorPolicyCapability::CAN_EDIT, 195 - )) 196 183 ->executeOne(); 197 184 198 185 $except_phids = array($board_phid); ··· 206 193 } 207 194 } 208 195 209 - $except_phids = array_fuse($except_phids); 210 - $handle_phids = array_fuse($object->getProjectPHIDs()); 211 - $handle_phids = array_diff_key($handle_phids, $except_phids); 196 + $rendering_engine = id(new PhabricatorBoardRenderingEngine()) 197 + ->setViewer($viewer) 198 + ->setObjects(array($object)) 199 + ->setExcludedProjectPHIDs($except_phids); 212 200 213 - $project_handles = $viewer->loadHandles($handle_phids); 214 - $project_handles = iterator_to_array($project_handles); 215 - 216 - $card = id(new ProjectBoardTaskCard()) 217 - ->setViewer($viewer) 218 - ->setTask($object) 219 - ->setOwner($owner) 220 - ->setCanEdit(true) 221 - ->setProjectHandles($project_handles) 222 - ->getItem(); 201 + $card = $rendering_engine->renderCard($object->getPHID()); 223 202 224 - $card->addClass('phui-workcard'); 203 + $item = $card->getItem(); 204 + $item->addClass('phui-workcard'); 225 205 226 - return id(new AphrontAjaxResponse())->setContent( 227 - array('task' => $card)); 206 + return id(new AphrontAjaxResponse()) 207 + ->setContent( 208 + array( 209 + 'task' => $item, 210 + )); 228 211 } 229 212 230 213 }
+144
src/applications/project/engine/PhabricatorBoardRenderingEngine.php
··· 1 + <?php 2 + 3 + final class PhabricatorBoardRenderingEngine extends Phobject { 4 + 5 + private $viewer; 6 + private $objects; 7 + private $excludedProjectPHIDs; 8 + private $editMap; 9 + 10 + private $loaded; 11 + private $handles; 12 + private $coverFiles; 13 + 14 + public function setViewer(PhabricatorUser $viewer) { 15 + $this->viewer = $viewer; 16 + return $this; 17 + } 18 + 19 + public function getViewer() { 20 + return $this->viewer; 21 + } 22 + 23 + public function setObjects(array $objects) { 24 + $this->objects = mpull($objects, null, 'getPHID'); 25 + return $this; 26 + } 27 + 28 + public function getObjects() { 29 + return $this->objects; 30 + } 31 + 32 + public function setExcludedProjectPHIDs(array $phids) { 33 + $this->excludedProjectPHIDs = $phids; 34 + return $this; 35 + } 36 + 37 + public function getExcludedProjectPHIDs() { 38 + return $this->excludedProjectPHIDs; 39 + } 40 + 41 + public function setEditMap(array $edit_map) { 42 + $this->editMap = $edit_map; 43 + return $this; 44 + } 45 + 46 + public function getEditMap() { 47 + return $this->editMap; 48 + } 49 + 50 + public function renderCard($phid) { 51 + $this->willRender(); 52 + 53 + $viewer = $this->getViewer(); 54 + $object = idx($this->getObjects(), $phid); 55 + 56 + $card = id(new ProjectBoardTaskCard()) 57 + ->setViewer($viewer) 58 + ->setTask($object) 59 + ->setCanEdit($this->getCanEdit($phid)); 60 + 61 + $owner_phid = $object->getOwnerPHID(); 62 + if ($owner_phid) { 63 + $owner_handle = $this->handles[$owner_phid]; 64 + $card->setOwner($owner_handle); 65 + } 66 + 67 + $project_phids = $object->getProjectPHIDs(); 68 + $project_handles = array_select_keys($this->handles, $project_phids); 69 + if ($project_handles) { 70 + $card->setProjectHandles($project_handles); 71 + } 72 + 73 + $cover_phid = $object->getCoverImageThumbnailPHID(); 74 + if ($cover_phid) { 75 + $cover_file = idx($this->coverFiles, $cover_phid); 76 + if ($cover_file) { 77 + $card->setCoverImageFile($cover_file); 78 + } 79 + } 80 + 81 + return $card; 82 + } 83 + 84 + private function willRender() { 85 + if ($this->loaded) { 86 + return; 87 + } 88 + 89 + $phids = array(); 90 + foreach ($this->objects as $object) { 91 + $owner_phid = $object->getOwnerPHID(); 92 + if ($owner_phid) { 93 + $phids[$owner_phid] = $owner_phid; 94 + } 95 + 96 + foreach ($object->getProjectPHIDs() as $phid) { 97 + $phids[$phid] = $phid; 98 + } 99 + } 100 + 101 + if ($this->excludedProjectPHIDs) { 102 + foreach ($this->excludedProjectPHIDs as $excluded_phid) { 103 + unset($phids[$excluded_phid]); 104 + } 105 + } 106 + 107 + $viewer = $this->getViewer(); 108 + 109 + $handles = $viewer->loadHandles($phids); 110 + $handles = iterator_to_array($handles); 111 + $this->handles = $handles; 112 + 113 + $cover_phids = array(); 114 + foreach ($this->objects as $object) { 115 + $cover_phid = $object->getCoverImageThumbnailPHID(); 116 + if ($cover_phid) { 117 + $cover_phids[$cover_phid] = $cover_phid; 118 + } 119 + } 120 + 121 + if ($cover_phids) { 122 + $cover_files = id(new PhabricatorFileQuery()) 123 + ->setViewer($viewer) 124 + ->withPHIDs($cover_phids) 125 + ->execute(); 126 + $cover_files = mpull($cover_files, null, 'getPHID'); 127 + } else { 128 + $cover_files = array(); 129 + } 130 + 131 + $this->coverFiles = $cover_files; 132 + 133 + $this->loaded = true; 134 + } 135 + 136 + private function getCanEdit($phid) { 137 + if ($this->editMap === null) { 138 + return true; 139 + } 140 + 141 + return idx($this->editMap, $phid); 142 + } 143 + 144 + }
+15
src/applications/project/view/ProjectBoardTaskCard.php
··· 7 7 private $task; 8 8 private $owner; 9 9 private $canEdit; 10 + private $coverImageFile; 10 11 11 12 public function setViewer(PhabricatorUser $viewer) { 12 13 $this->viewer = $viewer; ··· 23 24 24 25 public function getProjectHandles() { 25 26 return $this->projectHandles; 27 + } 28 + 29 + public function setCoverImageFile(PhabricatorFile $cover_image_file) { 30 + $this->coverImageFile = $cover_image_file; 31 + return $this; 32 + } 33 + 34 + public function getCoverImageFile() { 35 + return $this->coverImageFile; 26 36 } 27 37 28 38 public function setTask(ManiphestTask $task) { ··· 82 92 83 93 if ($owner) { 84 94 $card->addHandleIcon($owner, $owner->getName()); 95 + } 96 + 97 + $cover_file = $this->getCoverImageFile(); 98 + if ($cover_file) { 99 + $card->setCoverImage($cover_file->getBestURI()); 85 100 } 86 101 87 102 if ($task->isClosed()) {