mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
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
This commit is contained in:
parent
eb06aca951
commit
6d90c7ad92
3 changed files with 86 additions and 5 deletions
|
@ -151,6 +151,12 @@ final class PhabricatorMetaMTAMailViewController
|
||||||
|
|
||||||
$properties->addTextContent($body);
|
$properties->addTextContent($body);
|
||||||
|
|
||||||
|
$file_phids = $mail->getAttachmentFilePHIDs();
|
||||||
|
if ($file_phids) {
|
||||||
|
$properties->addProperty(
|
||||||
|
pht('Attached Files'),
|
||||||
|
$viewer->loadHandles($file_phids)->renderList());
|
||||||
|
}
|
||||||
|
|
||||||
return $properties;
|
return $properties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
final class PhabricatorMetaMTAAttachment extends Phobject {
|
final class PhabricatorMetaMTAAttachment extends Phobject {
|
||||||
protected $data;
|
|
||||||
protected $filename;
|
private $data;
|
||||||
protected $mimetype;
|
private $filename;
|
||||||
|
private $mimetype;
|
||||||
|
private $file;
|
||||||
|
private $filePHID;
|
||||||
|
|
||||||
public function __construct($data, $filename, $mimetype) {
|
public function __construct($data, $filename, $mimetype) {
|
||||||
$this->setData($data);
|
$this->setData($data);
|
||||||
|
@ -39,18 +42,49 @@ final class PhabricatorMetaMTAAttachment extends Phobject {
|
||||||
}
|
}
|
||||||
|
|
||||||
public function toDictionary() {
|
public function toDictionary() {
|
||||||
|
if (!$this->file) {
|
||||||
|
$iterator = new ArrayIterator(array($this->getData()));
|
||||||
|
|
||||||
|
$source = id(new PhabricatorIteratorFileUploadSource())
|
||||||
|
->setName($this->getFilename())
|
||||||
|
->setViewPolicy(PhabricatorPolicies::POLICY_NOONE)
|
||||||
|
->setMIMEType($this->getMimeType())
|
||||||
|
->setIterator($iterator);
|
||||||
|
|
||||||
|
$this->file = $source->uploadFile();
|
||||||
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'filename' => $this->getFilename(),
|
'filename' => $this->getFilename(),
|
||||||
'mimetype' => $this->getMimeType(),
|
'mimetype' => $this->getMimeType(),
|
||||||
'data' => $this->getData(),
|
'filePHID' => $this->file->getPHID(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function newFromDictionary(array $dict) {
|
public static function newFromDictionary(array $dict) {
|
||||||
return new PhabricatorMetaMTAAttachment(
|
$file = null;
|
||||||
|
|
||||||
|
$file_phid = idx($dict, 'filePHID');
|
||||||
|
if ($file_phid) {
|
||||||
|
$file = id(new PhabricatorFileQuery())
|
||||||
|
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||||
|
->withPHIDs(array($file_phid))
|
||||||
|
->executeOne();
|
||||||
|
if ($file) {
|
||||||
|
$dict['data'] = $file->loadFileData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$attachment = new self(
|
||||||
idx($dict, 'data'),
|
idx($dict, 'data'),
|
||||||
idx($dict, 'filename'),
|
idx($dict, 'filename'),
|
||||||
idx($dict, 'mimetype'));
|
idx($dict, 'mimetype'));
|
||||||
|
|
||||||
|
if ($file) {
|
||||||
|
$attachment->file = $file;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $attachment;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -197,6 +197,35 @@ final class PhabricatorMetaMTAMail
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAttachmentFilePHIDs() {
|
||||||
|
$file_phids = array();
|
||||||
|
|
||||||
|
$dictionaries = $this->getParam('attachments');
|
||||||
|
if ($dictionaries) {
|
||||||
|
foreach ($dictionaries as $dictionary) {
|
||||||
|
$file_phid = idx($dictionary, 'filePHID');
|
||||||
|
if ($file_phid) {
|
||||||
|
$file_phids[] = $file_phid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $file_phids;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function loadAttachedFiles(PhabricatorUser $viewer) {
|
||||||
|
$file_phids = $this->getAttachmentFilePHIDs();
|
||||||
|
|
||||||
|
if (!$file_phids) {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
|
||||||
|
return id(new PhabricatorFileQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs($file_phids)
|
||||||
|
->execute();
|
||||||
|
}
|
||||||
|
|
||||||
public function setAttachments(array $attachments) {
|
public function setAttachments(array $attachments) {
|
||||||
assert_instances_of($attachments, 'PhabricatorMetaMTAAttachment');
|
assert_instances_of($attachments, 'PhabricatorMetaMTAAttachment');
|
||||||
$this->setParam('attachments', mpull($attachments, 'toDictionary'));
|
$this->setParam('attachments', mpull($attachments, 'toDictionary'));
|
||||||
|
@ -526,6 +555,12 @@ final class PhabricatorMetaMTAMail
|
||||||
mpull($cc_actors, 'getEmailAddress'));
|
mpull($cc_actors, 'getEmailAddress'));
|
||||||
break;
|
break;
|
||||||
case 'attachments':
|
case 'attachments':
|
||||||
|
$attached_viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
$files = $this->loadAttachedFiles($attached_viewer);
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$file->attachToObject($this->getPHID());
|
||||||
|
}
|
||||||
|
|
||||||
// If the mail content must be encrypted, don't add attachments.
|
// If the mail content must be encrypted, don't add attachments.
|
||||||
if ($must_encrypt) {
|
if ($must_encrypt) {
|
||||||
break;
|
break;
|
||||||
|
@ -1299,6 +1334,12 @@ final class PhabricatorMetaMTAMail
|
||||||
|
|
||||||
public function destroyObjectPermanently(
|
public function destroyObjectPermanently(
|
||||||
PhabricatorDestructionEngine $engine) {
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
|
$files = $this->loadAttachedFiles($engine->getViewer());
|
||||||
|
foreach ($files as $file) {
|
||||||
|
$engine->destroyObject($file);
|
||||||
|
}
|
||||||
|
|
||||||
$this->delete();
|
$this->delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue