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

Save mail attachments in Files, not on the actual objects

Summary:
Depends on D18985. Ref T13053. See PHI125. Currently, mail attachments are just encoded onto the actual objects in the `MetaMTAMail` table.

This fails if attachments can't be encoded in JSON -- e.g., they aren't UTF8. This happens most often when revisions or commits attach patches to mail and those patches contain source code changes for files that are not encoded in UTF8.

Instead, save attachments in (and load attachments from) Files.

Test Plan: Enabled patches for mail, created a revision, saw it attach a patch. Viewed mail in web UI, saw link to download patch. Followed link, saw sensible file. Checked database, saw a `filePHID`. Destroyed mail with `bin/remove destroy`, saw attached files also destroyed.

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T13053

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

+86 -5
+6
src/applications/metamta/controller/PhabricatorMetaMTAMailViewController.php
··· 151 151 152 152 $properties->addTextContent($body); 153 153 154 + $file_phids = $mail->getAttachmentFilePHIDs(); 155 + if ($file_phids) { 156 + $properties->addProperty( 157 + pht('Attached Files'), 158 + $viewer->loadHandles($file_phids)->renderList()); 159 + } 154 160 155 161 return $properties; 156 162 }
+39 -5
src/applications/metamta/storage/PhabricatorMetaMTAAttachment.php
··· 1 1 <?php 2 2 3 3 final class PhabricatorMetaMTAAttachment extends Phobject { 4 - protected $data; 5 - protected $filename; 6 - protected $mimetype; 4 + 5 + private $data; 6 + private $filename; 7 + private $mimetype; 8 + private $file; 9 + private $filePHID; 7 10 8 11 public function __construct($data, $filename, $mimetype) { 9 12 $this->setData($data); ··· 39 42 } 40 43 41 44 public function toDictionary() { 45 + if (!$this->file) { 46 + $iterator = new ArrayIterator(array($this->getData())); 47 + 48 + $source = id(new PhabricatorIteratorFileUploadSource()) 49 + ->setName($this->getFilename()) 50 + ->setViewPolicy(PhabricatorPolicies::POLICY_NOONE) 51 + ->setMIMEType($this->getMimeType()) 52 + ->setIterator($iterator); 53 + 54 + $this->file = $source->uploadFile(); 55 + } 56 + 42 57 return array( 43 58 'filename' => $this->getFilename(), 44 59 'mimetype' => $this->getMimeType(), 45 - 'data' => $this->getData(), 60 + 'filePHID' => $this->file->getPHID(), 46 61 ); 47 62 } 48 63 49 64 public static function newFromDictionary(array $dict) { 50 - return new PhabricatorMetaMTAAttachment( 65 + $file = null; 66 + 67 + $file_phid = idx($dict, 'filePHID'); 68 + if ($file_phid) { 69 + $file = id(new PhabricatorFileQuery()) 70 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 71 + ->withPHIDs(array($file_phid)) 72 + ->executeOne(); 73 + if ($file) { 74 + $dict['data'] = $file->loadFileData(); 75 + } 76 + } 77 + 78 + $attachment = new self( 51 79 idx($dict, 'data'), 52 80 idx($dict, 'filename'), 53 81 idx($dict, 'mimetype')); 82 + 83 + if ($file) { 84 + $attachment->file = $file; 85 + } 86 + 87 + return $attachment; 54 88 } 55 89 56 90 }
+41
src/applications/metamta/storage/PhabricatorMetaMTAMail.php
··· 197 197 return $result; 198 198 } 199 199 200 + public function getAttachmentFilePHIDs() { 201 + $file_phids = array(); 202 + 203 + $dictionaries = $this->getParam('attachments'); 204 + if ($dictionaries) { 205 + foreach ($dictionaries as $dictionary) { 206 + $file_phid = idx($dictionary, 'filePHID'); 207 + if ($file_phid) { 208 + $file_phids[] = $file_phid; 209 + } 210 + } 211 + } 212 + 213 + return $file_phids; 214 + } 215 + 216 + public function loadAttachedFiles(PhabricatorUser $viewer) { 217 + $file_phids = $this->getAttachmentFilePHIDs(); 218 + 219 + if (!$file_phids) { 220 + return array(); 221 + } 222 + 223 + return id(new PhabricatorFileQuery()) 224 + ->setViewer($viewer) 225 + ->withPHIDs($file_phids) 226 + ->execute(); 227 + } 228 + 200 229 public function setAttachments(array $attachments) { 201 230 assert_instances_of($attachments, 'PhabricatorMetaMTAAttachment'); 202 231 $this->setParam('attachments', mpull($attachments, 'toDictionary')); ··· 526 555 mpull($cc_actors, 'getEmailAddress')); 527 556 break; 528 557 case 'attachments': 558 + $attached_viewer = PhabricatorUser::getOmnipotentUser(); 559 + $files = $this->loadAttachedFiles($attached_viewer); 560 + foreach ($files as $file) { 561 + $file->attachToObject($this->getPHID()); 562 + } 563 + 529 564 // If the mail content must be encrypted, don't add attachments. 530 565 if ($must_encrypt) { 531 566 break; ··· 1299 1334 1300 1335 public function destroyObjectPermanently( 1301 1336 PhabricatorDestructionEngine $engine) { 1337 + 1338 + $files = $this->loadAttachedFiles($engine->getViewer()); 1339 + foreach ($files as $file) { 1340 + $engine->destroyObject($file); 1341 + } 1342 + 1302 1343 $this->delete(); 1303 1344 } 1304 1345