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
			
			
This commit is contained in:
		
							
								
								
									
										5
									
								
								resources/sql/autopatches/20160206.cover.1.sql
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								resources/sql/autopatches/20160206.cover.1.sql
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| ALTER TABLE {$NAMESPACE}_maniphest.maniphest_task | ||||
|   ADD properties LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}; | ||||
|  | ||||
| UPDATE {$NAMESPACE}_maniphest.maniphest_task | ||||
|   SET properties = '{}' WHERE properties = ''; | ||||
| @@ -1815,6 +1815,7 @@ phutil_register_library_map(array( | ||||
|     'PhabricatorBinariesSetupCheck' => 'applications/config/check/PhabricatorBinariesSetupCheck.php', | ||||
|     'PhabricatorBitbucketAuthProvider' => 'applications/auth/provider/PhabricatorBitbucketAuthProvider.php', | ||||
|     'PhabricatorBoardLayoutEngine' => 'applications/project/engine/PhabricatorBoardLayoutEngine.php', | ||||
|     'PhabricatorBoardRenderingEngine' => 'applications/project/engine/PhabricatorBoardRenderingEngine.php', | ||||
|     'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', | ||||
|     'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php', | ||||
|     'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php', | ||||
| @@ -6043,6 +6044,7 @@ phutil_register_library_map(array( | ||||
|     'PhabricatorBinariesSetupCheck' => 'PhabricatorSetupCheck', | ||||
|     'PhabricatorBitbucketAuthProvider' => 'PhabricatorOAuth1AuthProvider', | ||||
|     'PhabricatorBoardLayoutEngine' => 'Phobject', | ||||
|     'PhabricatorBoardRenderingEngine' => 'Phobject', | ||||
|     'PhabricatorBot' => 'PhabricatorDaemon', | ||||
|     'PhabricatorBotChannel' => 'PhabricatorBotTarget', | ||||
|     'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler', | ||||
|   | ||||
| @@ -7,6 +7,7 @@ final class PhabricatorFileThumbnailTransform | ||||
|   const TRANSFORM_PINBOARD = 'pinboard'; | ||||
|   const TRANSFORM_THUMBGRID = 'thumbgrid'; | ||||
|   const TRANSFORM_PREVIEW = 'preview'; | ||||
|   const TRANSFORM_WORKCARD = 'workcard'; | ||||
|  | ||||
|   private $name; | ||||
|   private $key; | ||||
| @@ -73,6 +74,10 @@ final class PhabricatorFileThumbnailTransform | ||||
|         ->setName(pht('Preview (220px)')) | ||||
|         ->setKey(self::TRANSFORM_PREVIEW) | ||||
|         ->setDimensions(220, null), | ||||
|       id(new self()) | ||||
|         ->setName(pht('Workcard (526px)')) | ||||
|         ->setKey(self::TRANSFORM_WORKCARD) | ||||
|         ->setDimensions(526, null), | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -334,39 +334,27 @@ final class ManiphestEditEngine | ||||
|       'sortMap' => $sort_map, | ||||
|     ); | ||||
|  | ||||
|     // TODO: This should just use HandlePool once we get through the EditEngine | ||||
|     // transition. | ||||
|     $owner = null; | ||||
|     if ($task->getOwnerPHID()) { | ||||
|       $owner = id(new PhabricatorHandleQuery()) | ||||
|     $rendering_engine = id(new PhabricatorBoardRenderingEngine()) | ||||
|       ->setViewer($viewer) | ||||
|         ->withPHIDs(array($task->getOwnerPHID())) | ||||
|         ->executeOne(); | ||||
|     } | ||||
|       ->setObjects(array($task)) | ||||
|       ->setExcludedProjectPHIDs($board_phids); | ||||
|  | ||||
|     $handle_phids = $task->getProjectPHIDs(); | ||||
|     $handle_phids = array_fuse($handle_phids); | ||||
|     $handle_phids = array_diff_key($handle_phids, $board_phids); | ||||
|     $card = $rendering_engine->renderCard($task->getPHID()); | ||||
|  | ||||
|     $project_handles = $viewer->loadHandles($handle_phids); | ||||
|     $project_handles = iterator_to_array($project_handles); | ||||
|  | ||||
|     $tasks = id(new ProjectBoardTaskCard()) | ||||
|       ->setViewer($viewer) | ||||
|       ->setTask($task) | ||||
|       ->setOwner($owner) | ||||
|       ->setProjectHandles($project_handles) | ||||
|       ->setCanEdit(true) | ||||
|       ->getItem(); | ||||
|  | ||||
|     $tasks->addClass('phui-workcard'); | ||||
|     $item = $card->getItem(); | ||||
|     $item->addClass('phui-workcard'); | ||||
|  | ||||
|     $payload = array( | ||||
|       'tasks' => $tasks, | ||||
|       'tasks' => $item, | ||||
|       'data' => $data, | ||||
|     ); | ||||
|  | ||||
|     return id(new AphrontAjaxResponse())->setContent($payload); | ||||
|     return id(new AphrontAjaxResponse()) | ||||
|       ->setContent( | ||||
|         array( | ||||
|           'tasks' => $item, | ||||
|           'data' => $data, | ||||
|         )); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -38,6 +38,7 @@ final class ManiphestTask extends ManiphestDAO | ||||
|  | ||||
|   protected $ownerOrdering; | ||||
|   protected $spacePHID; | ||||
|   protected $properties = array(); | ||||
|  | ||||
|   private $subscriberPHIDs = self::ATTACHABLE; | ||||
|   private $groupByProjectPHID = self::ATTACHABLE; | ||||
| @@ -74,6 +75,7 @@ final class ManiphestTask extends ManiphestDAO | ||||
|         'ccPHIDs' => self::SERIALIZATION_JSON, | ||||
|         'attached' => self::SERIALIZATION_JSON, | ||||
|         'projectPHIDs' => self::SERIALIZATION_JSON, | ||||
|         'properties' => self::SERIALIZATION_JSON, | ||||
|       ), | ||||
|       self::CONFIG_COLUMN_SCHEMA => array( | ||||
|         'ownerPHID' => 'phid?', | ||||
| @@ -215,6 +217,19 @@ final class ManiphestTask extends ManiphestDAO | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   public function setProperty($key, $value) { | ||||
|     $this->properties[$key] = $value; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getProperty($key, $default = null) { | ||||
|     return idx($this->properties, $key, $default); | ||||
|   } | ||||
|  | ||||
|   public function getCoverImageThumbnailPHID() { | ||||
|     return idx($this->properties, 'cover.thumbnailPHID'); | ||||
|   } | ||||
|  | ||||
|  | ||||
| /* -(  PhabricatorSubscribableInterface  )----------------------------------- */ | ||||
|  | ||||
|   | ||||
| @@ -7,7 +7,6 @@ final class PhabricatorProjectBoardViewController | ||||
|  | ||||
|   private $id; | ||||
|   private $slug; | ||||
|   private $handles; | ||||
|   private $queryKey; | ||||
|   private $filter; | ||||
|   private $sortKey; | ||||
| @@ -226,22 +225,9 @@ final class PhabricatorProjectBoardViewController | ||||
|       'project-boards', | ||||
|       $behavior_config); | ||||
|  | ||||
|     $this->handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); | ||||
|  | ||||
|     $all_project_phids = array(); | ||||
|     foreach ($tasks as $task) { | ||||
|       foreach ($task->getProjectPHIDs() as $project_phid) { | ||||
|         $all_project_phids[$project_phid] = $project_phid; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     foreach ($select_phids as $phid) { | ||||
|       unset($all_project_phids[$phid]); | ||||
|     } | ||||
|  | ||||
|     $all_handles = $viewer->loadHandles($all_project_phids); | ||||
|     $all_handles = iterator_to_array($all_handles); | ||||
|  | ||||
|     $visible_columns = array(); | ||||
|     $column_phids = array(); | ||||
|     $visible_phids = array(); | ||||
|     foreach ($columns as $column) { | ||||
|       if (!$this->showHidden) { | ||||
|         if ($column->isHidden()) { | ||||
| @@ -268,6 +254,25 @@ final class PhabricatorProjectBoardViewController | ||||
|         $column_tasks = array_select_keys($column_tasks, array_keys($tasks)); | ||||
|       } | ||||
|  | ||||
|       $column_phid = $column->getPHID(); | ||||
|  | ||||
|       $visible_columns[$column_phid] = $column; | ||||
|       $column_phids[$column_phid] = $column_tasks; | ||||
|  | ||||
|       foreach ($column_tasks as $phid => $task) { | ||||
|         $visible_phids[$phid] = $phid; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     $rendering_engine = id(new PhabricatorBoardRenderingEngine()) | ||||
|       ->setViewer($viewer) | ||||
|       ->setObjects(array_select_keys($tasks, $visible_phids)) | ||||
|       ->setEditMap($task_can_edit_map) | ||||
|       ->setExcludedProjectPHIDs($select_phids); | ||||
|  | ||||
|     foreach ($visible_columns as $column_phid => $column) { | ||||
|       $column_tasks = $column_phids[$column_phid]; | ||||
|  | ||||
|       $panel = id(new PHUIWorkpanelView()) | ||||
|         ->setHeader($column->getDisplayName()) | ||||
|         ->setSubHeader($column->getDisplayType()) | ||||
| @@ -317,22 +322,10 @@ final class PhabricatorProjectBoardViewController | ||||
|           )); | ||||
|  | ||||
|       foreach ($column_tasks as $task) { | ||||
|         $owner = null; | ||||
|         if ($task->getOwnerPHID()) { | ||||
|           $owner = $this->handles[$task->getOwnerPHID()]; | ||||
|         $card = $rendering_engine->renderCard($task->getPHID()); | ||||
|         $cards->addItem($card->getItem()); | ||||
|       } | ||||
|         $can_edit = idx($task_can_edit_map, $task->getPHID(), false); | ||||
|  | ||||
|         $handles = array_select_keys($all_handles, $task->getProjectPHIDs()); | ||||
|  | ||||
|         $cards->addItem(id(new ProjectBoardTaskCard()) | ||||
|           ->setViewer($viewer) | ||||
|           ->setProjectHandles($handles) | ||||
|           ->setTask($task) | ||||
|           ->setOwner($owner) | ||||
|           ->setCanEdit($can_edit) | ||||
|           ->getItem()); | ||||
|       } | ||||
|       $panel->setCards($cards); | ||||
|       $board->addPanel($panel); | ||||
|     } | ||||
|   | ||||
| @@ -175,24 +175,11 @@ final class PhabricatorProjectMoveController | ||||
|  | ||||
|     $editor->applyTransactions($object, $xactions); | ||||
|  | ||||
|     $owner = null; | ||||
|     if ($object->getOwnerPHID()) { | ||||
|       $owner = id(new PhabricatorHandleQuery()) | ||||
|         ->setViewer($viewer) | ||||
|         ->withPHIDs(array($object->getOwnerPHID())) | ||||
|         ->executeOne(); | ||||
|     } | ||||
|  | ||||
|     // Reload the object so it reflects edits which have been applied. | ||||
|     $object = id(new ManiphestTaskQuery()) | ||||
|       ->setViewer($viewer) | ||||
|       ->withPHIDs(array($object_phid)) | ||||
|       ->needProjectPHIDs(true) | ||||
|       ->requireCapabilities( | ||||
|         array( | ||||
|           PhabricatorPolicyCapability::CAN_VIEW, | ||||
|           PhabricatorPolicyCapability::CAN_EDIT, | ||||
|         )) | ||||
|       ->executeOne(); | ||||
|  | ||||
|     $except_phids = array($board_phid); | ||||
| @@ -206,25 +193,21 @@ final class PhabricatorProjectMoveController | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     $except_phids = array_fuse($except_phids); | ||||
|     $handle_phids = array_fuse($object->getProjectPHIDs()); | ||||
|     $handle_phids = array_diff_key($handle_phids, $except_phids); | ||||
|  | ||||
|     $project_handles = $viewer->loadHandles($handle_phids); | ||||
|     $project_handles = iterator_to_array($project_handles); | ||||
|  | ||||
|     $card = id(new ProjectBoardTaskCard()) | ||||
|     $rendering_engine = id(new PhabricatorBoardRenderingEngine()) | ||||
|       ->setViewer($viewer) | ||||
|       ->setTask($object) | ||||
|       ->setOwner($owner) | ||||
|       ->setCanEdit(true) | ||||
|       ->setProjectHandles($project_handles) | ||||
|       ->getItem(); | ||||
|       ->setObjects(array($object)) | ||||
|       ->setExcludedProjectPHIDs($except_phids); | ||||
|  | ||||
|     $card->addClass('phui-workcard'); | ||||
|     $card = $rendering_engine->renderCard($object->getPHID()); | ||||
|  | ||||
|     return id(new AphrontAjaxResponse())->setContent( | ||||
|       array('task' => $card)); | ||||
|     $item = $card->getItem(); | ||||
|     $item->addClass('phui-workcard'); | ||||
|  | ||||
|     return id(new AphrontAjaxResponse()) | ||||
|       ->setContent( | ||||
|         array( | ||||
|           'task' => $item, | ||||
|         )); | ||||
|   } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,144 @@ | ||||
| <?php | ||||
|  | ||||
| final class PhabricatorBoardRenderingEngine extends Phobject { | ||||
|  | ||||
|   private $viewer; | ||||
|   private $objects; | ||||
|   private $excludedProjectPHIDs; | ||||
|   private $editMap; | ||||
|  | ||||
|   private $loaded; | ||||
|   private $handles; | ||||
|   private $coverFiles; | ||||
|  | ||||
|   public function setViewer(PhabricatorUser $viewer) { | ||||
|     $this->viewer = $viewer; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getViewer() { | ||||
|     return $this->viewer; | ||||
|   } | ||||
|  | ||||
|   public function setObjects(array $objects) { | ||||
|     $this->objects = mpull($objects, null, 'getPHID'); | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getObjects() { | ||||
|     return $this->objects; | ||||
|   } | ||||
|  | ||||
|   public function setExcludedProjectPHIDs(array $phids) { | ||||
|     $this->excludedProjectPHIDs = $phids; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getExcludedProjectPHIDs() { | ||||
|     return $this->excludedProjectPHIDs; | ||||
|   } | ||||
|  | ||||
|   public function setEditMap(array $edit_map) { | ||||
|     $this->editMap = $edit_map; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getEditMap() { | ||||
|     return $this->editMap; | ||||
|   } | ||||
|  | ||||
|   public function renderCard($phid) { | ||||
|     $this->willRender(); | ||||
|  | ||||
|     $viewer = $this->getViewer(); | ||||
|     $object = idx($this->getObjects(), $phid); | ||||
|  | ||||
|     $card = id(new ProjectBoardTaskCard()) | ||||
|       ->setViewer($viewer) | ||||
|       ->setTask($object) | ||||
|       ->setCanEdit($this->getCanEdit($phid)); | ||||
|  | ||||
|     $owner_phid = $object->getOwnerPHID(); | ||||
|     if ($owner_phid) { | ||||
|       $owner_handle = $this->handles[$owner_phid]; | ||||
|       $card->setOwner($owner_handle); | ||||
|     } | ||||
|  | ||||
|     $project_phids = $object->getProjectPHIDs(); | ||||
|     $project_handles = array_select_keys($this->handles, $project_phids); | ||||
|     if ($project_handles) { | ||||
|       $card->setProjectHandles($project_handles); | ||||
|     } | ||||
|  | ||||
|     $cover_phid = $object->getCoverImageThumbnailPHID(); | ||||
|     if ($cover_phid) { | ||||
|       $cover_file = idx($this->coverFiles, $cover_phid); | ||||
|       if ($cover_file) { | ||||
|         $card->setCoverImageFile($cover_file); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     return $card; | ||||
|   } | ||||
|  | ||||
|   private function willRender() { | ||||
|     if ($this->loaded) { | ||||
|       return; | ||||
|     } | ||||
|  | ||||
|     $phids = array(); | ||||
|     foreach ($this->objects as $object) { | ||||
|       $owner_phid = $object->getOwnerPHID(); | ||||
|       if ($owner_phid) { | ||||
|         $phids[$owner_phid] = $owner_phid; | ||||
|       } | ||||
|  | ||||
|       foreach ($object->getProjectPHIDs() as $phid) { | ||||
|         $phids[$phid] = $phid; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if ($this->excludedProjectPHIDs) { | ||||
|       foreach ($this->excludedProjectPHIDs as $excluded_phid) { | ||||
|         unset($phids[$excluded_phid]); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     $viewer = $this->getViewer(); | ||||
|  | ||||
|     $handles = $viewer->loadHandles($phids); | ||||
|     $handles = iterator_to_array($handles); | ||||
|     $this->handles = $handles; | ||||
|  | ||||
|     $cover_phids = array(); | ||||
|     foreach ($this->objects as $object) { | ||||
|       $cover_phid = $object->getCoverImageThumbnailPHID(); | ||||
|       if ($cover_phid) { | ||||
|         $cover_phids[$cover_phid] = $cover_phid; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     if ($cover_phids) { | ||||
|       $cover_files = id(new PhabricatorFileQuery()) | ||||
|         ->setViewer($viewer) | ||||
|         ->withPHIDs($cover_phids) | ||||
|         ->execute(); | ||||
|       $cover_files = mpull($cover_files, null, 'getPHID'); | ||||
|     } else { | ||||
|       $cover_files = array(); | ||||
|     } | ||||
|  | ||||
|     $this->coverFiles = $cover_files; | ||||
|  | ||||
|     $this->loaded = true; | ||||
|   } | ||||
|  | ||||
|   private function getCanEdit($phid) { | ||||
|     if ($this->editMap === null) { | ||||
|       return true; | ||||
|     } | ||||
|  | ||||
|     return idx($this->editMap, $phid); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -7,6 +7,7 @@ final class ProjectBoardTaskCard extends Phobject { | ||||
|   private $task; | ||||
|   private $owner; | ||||
|   private $canEdit; | ||||
|   private $coverImageFile; | ||||
|  | ||||
|   public function setViewer(PhabricatorUser $viewer) { | ||||
|     $this->viewer = $viewer; | ||||
| @@ -25,6 +26,15 @@ final class ProjectBoardTaskCard extends Phobject { | ||||
|     return $this->projectHandles; | ||||
|   } | ||||
|  | ||||
|   public function setCoverImageFile(PhabricatorFile $cover_image_file) { | ||||
|     $this->coverImageFile = $cover_image_file; | ||||
|     return $this; | ||||
|   } | ||||
|  | ||||
|   public function getCoverImageFile() { | ||||
|     return $this->coverImageFile; | ||||
|   } | ||||
|  | ||||
|   public function setTask(ManiphestTask $task) { | ||||
|     $this->task = $task; | ||||
|     return $this; | ||||
| @@ -84,6 +94,11 @@ final class ProjectBoardTaskCard extends Phobject { | ||||
|       $card->addHandleIcon($owner, $owner->getName()); | ||||
|     } | ||||
|  | ||||
|     $cover_file = $this->getCoverImageFile(); | ||||
|     if ($cover_file) { | ||||
|       $card->setCoverImage($cover_file->getBestURI()); | ||||
|     } | ||||
|  | ||||
|     if ($task->isClosed()) { | ||||
|       $icon = ManiphestTaskStatus::getStatusIcon($task->getStatus()); | ||||
|       $icon = id(new PHUIIconView()) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 epriestley
					epriestley