Migrate Project image to modular transactions
Summary: I'm not sure you can actually remove a project's image (maybe via the API?), but I kept the code for rendering the relevant title/feed anyway. Test Plan: Unit tests + adding/changing project pictures. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: Korvin, epriestley Differential Revision: https://secure.phabricator.com/D17954
This commit is contained in:
		| @@ -3621,6 +3621,7 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorProjectHovercardEngineExtension' => 'applications/project/engineextension/PhabricatorProjectHovercardEngineExtension.php', |     'PhabricatorProjectHovercardEngineExtension' => 'applications/project/engineextension/PhabricatorProjectHovercardEngineExtension.php', | ||||||
|     'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', |     'PhabricatorProjectIconSet' => 'applications/project/icon/PhabricatorProjectIconSet.php', | ||||||
|     'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php', |     'PhabricatorProjectIconsConfigOptionType' => 'applications/project/config/PhabricatorProjectIconsConfigOptionType.php', | ||||||
|  |     'PhabricatorProjectImageTransaction' => 'applications/project/xaction/PhabricatorProjectImageTransaction.php', | ||||||
|     'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', |     'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', | ||||||
|     'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', |     'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', | ||||||
|     'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php', |     'PhabricatorProjectListView' => 'applications/project/view/PhabricatorProjectListView.php', | ||||||
| @@ -9035,6 +9036,7 @@ phutil_register_library_map(array( | |||||||
|     'PhabricatorProjectHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', |     'PhabricatorProjectHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension', | ||||||
|     'PhabricatorProjectIconSet' => 'PhabricatorIconSet', |     'PhabricatorProjectIconSet' => 'PhabricatorIconSet', | ||||||
|     'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType', |     'PhabricatorProjectIconsConfigOptionType' => 'PhabricatorConfigJSONOptionType', | ||||||
|  |     'PhabricatorProjectImageTransaction' => 'PhabricatorProjectTransactionType', | ||||||
|     'PhabricatorProjectListController' => 'PhabricatorProjectController', |     'PhabricatorProjectListController' => 'PhabricatorProjectController', | ||||||
|     'PhabricatorProjectListView' => 'AphrontView', |     'PhabricatorProjectListView' => 'AphrontView', | ||||||
|     'PhabricatorProjectLockController' => 'PhabricatorProjectController', |     'PhabricatorProjectLockController' => 'PhabricatorProjectController', | ||||||
|   | |||||||
| @@ -48,7 +48,8 @@ final class PhabricatorFileComposeController | |||||||
|  |  | ||||||
|         $xactions = array(); |         $xactions = array(); | ||||||
|         $xactions[] = id(new PhabricatorProjectTransaction()) |         $xactions[] = id(new PhabricatorProjectTransaction()) | ||||||
|           ->setTransactionType(PhabricatorProjectTransaction::TYPE_IMAGE) |           ->setTransactionType( | ||||||
|  |               PhabricatorProjectImageTransaction::TRANSACTIONTYPE) | ||||||
|           ->setNewValue($file->getPHID()); |           ->setNewValue($file->getPHID()); | ||||||
|  |  | ||||||
|         $editor = id(new PhabricatorProjectTransactionEditor()) |         $editor = id(new PhabricatorProjectTransactionEditor()) | ||||||
|   | |||||||
| @@ -78,7 +78,8 @@ final class PhabricatorProjectEditPictureController | |||||||
|  |  | ||||||
|         $xactions = array(); |         $xactions = array(); | ||||||
|         $xactions[] = id(new PhabricatorProjectTransaction()) |         $xactions[] = id(new PhabricatorProjectTransaction()) | ||||||
|           ->setTransactionType(PhabricatorProjectTransaction::TYPE_IMAGE) |           ->setTransactionType( | ||||||
|  |               PhabricatorProjectImageTransaction::TRANSACTIONTYPE) | ||||||
|           ->setNewValue($new_value); |           ->setNewValue($new_value); | ||||||
|  |  | ||||||
|         $editor = id(new PhabricatorProjectTransactionEditor()) |         $editor = id(new PhabricatorProjectTransactionEditor()) | ||||||
|   | |||||||
| @@ -30,7 +30,6 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; |     $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; | ||||||
|     $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; |     $types[] = PhabricatorTransactions::TYPE_JOIN_POLICY; | ||||||
|  |  | ||||||
|     $types[] = PhabricatorProjectTransaction::TYPE_IMAGE; |  | ||||||
|     $types[] = PhabricatorProjectTransaction::TYPE_ICON; |     $types[] = PhabricatorProjectTransaction::TYPE_ICON; | ||||||
|     $types[] = PhabricatorProjectTransaction::TYPE_COLOR; |     $types[] = PhabricatorProjectTransaction::TYPE_COLOR; | ||||||
|     $types[] = PhabricatorProjectTransaction::TYPE_LOCKED; |     $types[] = PhabricatorProjectTransaction::TYPE_LOCKED; | ||||||
| @@ -49,8 +48,6 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     PhabricatorApplicationTransaction $xaction) { |     PhabricatorApplicationTransaction $xaction) { | ||||||
|  |  | ||||||
|     switch ($xaction->getTransactionType()) { |     switch ($xaction->getTransactionType()) { | ||||||
|       case PhabricatorProjectTransaction::TYPE_IMAGE: |  | ||||||
|         return $object->getProfileImagePHID(); |  | ||||||
|       case PhabricatorProjectTransaction::TYPE_ICON: |       case PhabricatorProjectTransaction::TYPE_ICON: | ||||||
|         return $object->getIcon(); |         return $object->getIcon(); | ||||||
|       case PhabricatorProjectTransaction::TYPE_COLOR: |       case PhabricatorProjectTransaction::TYPE_COLOR: | ||||||
| @@ -78,7 +75,6 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     PhabricatorApplicationTransaction $xaction) { |     PhabricatorApplicationTransaction $xaction) { | ||||||
|  |  | ||||||
|     switch ($xaction->getTransactionType()) { |     switch ($xaction->getTransactionType()) { | ||||||
|       case PhabricatorProjectTransaction::TYPE_IMAGE: |  | ||||||
|       case PhabricatorProjectTransaction::TYPE_ICON: |       case PhabricatorProjectTransaction::TYPE_ICON: | ||||||
|       case PhabricatorProjectTransaction::TYPE_COLOR: |       case PhabricatorProjectTransaction::TYPE_COLOR: | ||||||
|       case PhabricatorProjectTransaction::TYPE_LOCKED: |       case PhabricatorProjectTransaction::TYPE_LOCKED: | ||||||
| @@ -105,9 +101,6 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     PhabricatorApplicationTransaction $xaction) { |     PhabricatorApplicationTransaction $xaction) { | ||||||
|  |  | ||||||
|     switch ($xaction->getTransactionType()) { |     switch ($xaction->getTransactionType()) { | ||||||
|       case PhabricatorProjectTransaction::TYPE_IMAGE: |  | ||||||
|         $object->setProfileImagePHID($xaction->getNewValue()); |  | ||||||
|         return; |  | ||||||
|       case PhabricatorProjectTransaction::TYPE_ICON: |       case PhabricatorProjectTransaction::TYPE_ICON: | ||||||
|         $object->setIcon($xaction->getNewValue()); |         $object->setIcon($xaction->getNewValue()); | ||||||
|         return; |         return; | ||||||
| @@ -150,7 +143,6 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     $new = $xaction->getNewValue(); |     $new = $xaction->getNewValue(); | ||||||
|  |  | ||||||
|     switch ($xaction->getTransactionType()) { |     switch ($xaction->getTransactionType()) { | ||||||
|       case PhabricatorProjectTransaction::TYPE_IMAGE: |  | ||||||
|       case PhabricatorProjectTransaction::TYPE_ICON: |       case PhabricatorProjectTransaction::TYPE_ICON: | ||||||
|       case PhabricatorProjectTransaction::TYPE_COLOR: |       case PhabricatorProjectTransaction::TYPE_COLOR: | ||||||
|       case PhabricatorProjectTransaction::TYPE_LOCKED: |       case PhabricatorProjectTransaction::TYPE_LOCKED: | ||||||
| @@ -336,7 +328,7 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     switch ($xaction->getTransactionType()) { |     switch ($xaction->getTransactionType()) { | ||||||
|       case PhabricatorProjectNameTransaction::TRANSACTIONTYPE: |       case PhabricatorProjectNameTransaction::TRANSACTIONTYPE: | ||||||
|       case PhabricatorProjectStatusTransaction::TRANSACTIONTYPE: |       case PhabricatorProjectStatusTransaction::TRANSACTIONTYPE: | ||||||
|       case PhabricatorProjectTransaction::TYPE_IMAGE: |       case PhabricatorProjectImageTransaction::TRANSACTIONTYPE: | ||||||
|       case PhabricatorProjectTransaction::TYPE_ICON: |       case PhabricatorProjectTransaction::TYPE_ICON: | ||||||
|       case PhabricatorProjectTransaction::TYPE_COLOR: |       case PhabricatorProjectTransaction::TYPE_COLOR: | ||||||
|         PhabricatorPolicyFilter::requireCapability( |         PhabricatorPolicyFilter::requireCapability( | ||||||
| @@ -475,22 +467,6 @@ final class PhabricatorProjectTransactionEditor | |||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   protected function extractFilePHIDsFromCustomTransaction( |  | ||||||
|     PhabricatorLiskDAO $object, |  | ||||||
|     PhabricatorApplicationTransaction $xaction) { |  | ||||||
|  |  | ||||||
|     switch ($xaction->getTransactionType()) { |  | ||||||
|       case PhabricatorProjectTransaction::TYPE_IMAGE: |  | ||||||
|         $new = $xaction->getNewValue(); |  | ||||||
|         if ($new) { |  | ||||||
|           return array($new); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return parent::extractFilePHIDsFromCustomTransaction($object, $xaction); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   protected function applyFinalEffects( |   protected function applyFinalEffects( | ||||||
|     PhabricatorLiskDAO $object, |     PhabricatorLiskDAO $object, | ||||||
|     array $xactions) { |     array $xactions) { | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ | |||||||
| final class PhabricatorProjectTransaction | final class PhabricatorProjectTransaction | ||||||
|   extends PhabricatorModularTransaction { |   extends PhabricatorModularTransaction { | ||||||
|  |  | ||||||
|   const TYPE_IMAGE      = 'project:image'; |  | ||||||
|   const TYPE_ICON       = 'project:icon'; |   const TYPE_ICON       = 'project:icon'; | ||||||
|   const TYPE_COLOR      = 'project:color'; |   const TYPE_COLOR      = 'project:color'; | ||||||
|   const TYPE_LOCKED     = 'project:locked'; |   const TYPE_LOCKED     = 'project:locked'; | ||||||
| @@ -45,10 +44,6 @@ final class PhabricatorProjectTransaction | |||||||
|         $rem = array_diff($old, $new); |         $rem = array_diff($old, $new); | ||||||
|         $req_phids = array_merge($add, $rem); |         $req_phids = array_merge($add, $rem); | ||||||
|         break; |         break; | ||||||
|       case self::TYPE_IMAGE: |  | ||||||
|         $req_phids[] = $old; |  | ||||||
|         $req_phids[] = $new; |  | ||||||
|         break; |  | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return array_merge($req_phids, parent::getRequiredHandlePHIDs()); |     return array_merge($req_phids, parent::getRequiredHandlePHIDs()); | ||||||
| @@ -106,8 +101,6 @@ final class PhabricatorProjectTransaction | |||||||
|         } |         } | ||||||
|       case self::TYPE_ICON: |       case self::TYPE_ICON: | ||||||
|         return PhabricatorProjectIconSet::getIconIcon($new); |         return PhabricatorProjectIconSet::getIconIcon($new); | ||||||
|       case self::TYPE_IMAGE: |  | ||||||
|         return 'fa-photo'; |  | ||||||
|       case self::TYPE_MEMBERS: |       case self::TYPE_MEMBERS: | ||||||
|         return 'fa-user'; |         return 'fa-user'; | ||||||
|     } |     } | ||||||
| @@ -126,26 +119,6 @@ final class PhabricatorProjectTransaction | |||||||
|           '%s created this project.', |           '%s created this project.', | ||||||
|           $this->renderHandleLink($author_phid)); |           $this->renderHandleLink($author_phid)); | ||||||
|  |  | ||||||
|       case self::TYPE_IMAGE: |  | ||||||
|         // TODO: Some day, it would be nice to show the images. |  | ||||||
|         if (!$old) { |  | ||||||
|           return pht( |  | ||||||
|             "%s set this project's image to %s.", |  | ||||||
|             $author_handle, |  | ||||||
|             $this->renderHandleLink($new)); |  | ||||||
|         } else if (!$new) { |  | ||||||
|           return pht( |  | ||||||
|             "%s removed this project's image.", |  | ||||||
|             $author_handle); |  | ||||||
|         } else { |  | ||||||
|           return pht( |  | ||||||
|             "%s updated this project's image from %s to %s.", |  | ||||||
|             $author_handle, |  | ||||||
|             $this->renderHandleLink($old), |  | ||||||
|             $this->renderHandleLink($new)); |  | ||||||
|         } |  | ||||||
|         break; |  | ||||||
|  |  | ||||||
|       case self::TYPE_ICON: |       case self::TYPE_ICON: | ||||||
|         $set = new PhabricatorProjectIconSet(); |         $set = new PhabricatorProjectIconSet(); | ||||||
|  |  | ||||||
| @@ -253,27 +226,6 @@ final class PhabricatorProjectTransaction | |||||||
|     $new = $this->getNewValue(); |     $new = $this->getNewValue(); | ||||||
|  |  | ||||||
|     switch ($this->getTransactionType()) { |     switch ($this->getTransactionType()) { | ||||||
|       case self::TYPE_IMAGE: |  | ||||||
|         // TODO: Some day, it would be nice to show the images. |  | ||||||
|         if (!$old) { |  | ||||||
|           return pht( |  | ||||||
|             '%s set the image for %s to %s.', |  | ||||||
|             $author_handle, |  | ||||||
|             $object_handle, |  | ||||||
|             $this->renderHandleLink($new)); |  | ||||||
|         } else if (!$new) { |  | ||||||
|           return pht( |  | ||||||
|             '%s removed the image for %s.', |  | ||||||
|             $author_handle, |  | ||||||
|             $object_handle); |  | ||||||
|         } else { |  | ||||||
|           return pht( |  | ||||||
|             '%s updated the image for %s from %s to %s.', |  | ||||||
|             $author_handle, |  | ||||||
|             $object_handle, |  | ||||||
|             $this->renderHandleLink($old), |  | ||||||
|             $this->renderHandleLink($new)); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|       case self::TYPE_ICON: |       case self::TYPE_ICON: | ||||||
|         $set = new PhabricatorProjectIconSet(); |         $set = new PhabricatorProjectIconSet(); | ||||||
| @@ -313,7 +265,7 @@ final class PhabricatorProjectTransaction | |||||||
|     switch ($this->getTransactionType()) { |     switch ($this->getTransactionType()) { | ||||||
|       case PhabricatorProjectNameTransaction::TRANSACTIONTYPE: |       case PhabricatorProjectNameTransaction::TRANSACTIONTYPE: | ||||||
|       case PhabricatorProjectSlugsTransaction::TRANSACTIONTYPE: |       case PhabricatorProjectSlugsTransaction::TRANSACTIONTYPE: | ||||||
|       case self::TYPE_IMAGE: |       case PhabricatorProjectImageTransaction::TRANSACTIONTYPE: | ||||||
|       case self::TYPE_ICON: |       case self::TYPE_ICON: | ||||||
|       case self::TYPE_COLOR: |       case self::TYPE_COLOR: | ||||||
|         $tags[] = self::MAILTAG_METADATA; |         $tags[] = self::MAILTAG_METADATA; | ||||||
|   | |||||||
| @@ -0,0 +1,136 @@ | |||||||
|  | <?php | ||||||
|  |  | ||||||
|  | final class PhabricatorProjectImageTransaction | ||||||
|  |   extends PhabricatorProjectTransactionType { | ||||||
|  |  | ||||||
|  |   const TRANSACTIONTYPE = 'project:image'; | ||||||
|  |  | ||||||
|  |   public function generateOldValue($object) { | ||||||
|  |     return $object->getProfileImagePHID(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function applyInternalEffects($object, $value) { | ||||||
|  |     $object->setProfileImagePHID($value); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function applyExternalEffects($object, $value) { | ||||||
|  |     $old = $this->getOldValue(); | ||||||
|  |     $new = $value; | ||||||
|  |     $all = array(); | ||||||
|  |     if ($old) { | ||||||
|  |       $all[] = $old; | ||||||
|  |     } | ||||||
|  |     if ($new) { | ||||||
|  |       $all[] = $new; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $files = id(new PhabricatorFileQuery()) | ||||||
|  |       ->setViewer($this->getActor()) | ||||||
|  |       ->withPHIDs($all) | ||||||
|  |       ->execute(); | ||||||
|  |     $files = mpull($files, null, 'getPHID'); | ||||||
|  |  | ||||||
|  |     $old_file = idx($files, $old); | ||||||
|  |     if ($old_file) { | ||||||
|  |       $old_file->detachFromObject($object->getPHID()); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     $new_file = idx($files, $new); | ||||||
|  |     if ($new_file) { | ||||||
|  |       $new_file->attachToObject($object->getPHID()); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getTitle() { | ||||||
|  |     $old = $this->getOldValue(); | ||||||
|  |     $new = $this->getNewValue(); | ||||||
|  |  | ||||||
|  |     // TODO: Some day, it would be nice to show the images. | ||||||
|  |     if (!$old) { | ||||||
|  |       return pht( | ||||||
|  |         "%s set this project's image to %s.", | ||||||
|  |         $this->renderAuthor(), | ||||||
|  |         $this->renderNewHandle()); | ||||||
|  |     } else if (!$new) { | ||||||
|  |       return pht( | ||||||
|  |         "%s removed this project's image.", | ||||||
|  |         $this->renderAuthor()); | ||||||
|  |     } else { | ||||||
|  |       return pht( | ||||||
|  |         "%s updated this project's image from %s to %s.", | ||||||
|  |         $this->renderAuthor(), | ||||||
|  |         $this->renderOldHandle(), | ||||||
|  |         $this->renderNewHandle()); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getTitleForFeed() { | ||||||
|  |     $old = $this->getOldValue(); | ||||||
|  |     $new = $this->getNewValue(); | ||||||
|  |  | ||||||
|  |     // TODO: Some day, it would be nice to show the images. | ||||||
|  |     if (!$old) { | ||||||
|  |       return pht( | ||||||
|  |         '%s set the image for %s to %s.', | ||||||
|  |         $this->renderAuthor(), | ||||||
|  |         $this->renderObject(), | ||||||
|  |         $this->renderNewHandle()); | ||||||
|  |     } else if (!$new) { | ||||||
|  |       return pht( | ||||||
|  |         '%s removed the image for %s.', | ||||||
|  |         $this->renderAuthor(), | ||||||
|  |         $this->renderObject()); | ||||||
|  |     } else { | ||||||
|  |       return pht( | ||||||
|  |         '%s updated the image for %s from %s to %s.', | ||||||
|  |         $this->renderAuthor(), | ||||||
|  |         $this->renderObject(), | ||||||
|  |         $this->renderOldHandle(), | ||||||
|  |         $this->renderNewHandle()); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function getIcon() { | ||||||
|  |     return 'fa-photo'; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function extractFilePHIDs($object, $value) { | ||||||
|  |     if ($value) { | ||||||
|  |       return array($value); | ||||||
|  |     } | ||||||
|  |     return array(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   public function validateTransactions($object, array $xactions) { | ||||||
|  |     $errors = array(); | ||||||
|  |     $viewer = $this->getActor(); | ||||||
|  |  | ||||||
|  |     foreach ($xactions as $xaction) { | ||||||
|  |       $file_phid = $xaction->getNewValue(); | ||||||
|  |  | ||||||
|  |       // Only validate if file was uploaded | ||||||
|  |       if ($file_phid) { | ||||||
|  |         $file = id(new PhabricatorFileQuery()) | ||||||
|  |           ->setViewer($viewer) | ||||||
|  |           ->withPHIDs(array($file_phid)) | ||||||
|  |           ->executeOne(); | ||||||
|  |  | ||||||
|  |         if (!$file) { | ||||||
|  |           $errors[] = $this->newInvalidError( | ||||||
|  |             pht('"%s" is not a valid file PHID.', | ||||||
|  |             $file_phid)); | ||||||
|  |         } else { | ||||||
|  |           if (!$file->isViewableImage()) { | ||||||
|  |             $mime_type = $file->getMimeType(); | ||||||
|  |             $errors[] = $this->newInvalidError( | ||||||
|  |               pht('File mime type of "%s" is not a valid viewable image.', | ||||||
|  |               $mime_type)); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return $errors; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
| @@ -61,7 +61,6 @@ final class PhabricatorProjectSlugsTransaction | |||||||
|           count($rem), |           count($rem), | ||||||
|           $this->renderSlugList($rem)); |           $this->renderSlugList($rem)); | ||||||
|     } |     } | ||||||
|     break; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   public function getTitleForFeed() { |   public function getTitleForFeed() { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Austin McKinley
					Austin McKinley