mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-10 00:42:41 +01:00
File - add transactions and editor
Summary: this ends up being a little weird since you can't actually edit files. Also, since we create files all sorts of ways, sometimes without even having a user, we don't bother logging transactions for those events. Fixes T3651. Turns out this work is important for T3612, which is a priority of mine to help get Pholio out the door. Test Plan: left a comment on a file. it worked! use bin/mail to verify mail content looked correct. Reviewers: epriestley Reviewed By: epriestley CC: Korvin, aran, wez Maniphest Tasks: T3651, T3612 Differential Revision: https://secure.phabricator.com/D6789
This commit is contained in:
parent
4b061a766a
commit
228496cdbe
24 changed files with 585 additions and 17 deletions
32
resources/sql/patches/20130820.file-mailkey-populate.php
Normal file
32
resources/sql/patches/20130820.file-mailkey-populate.php
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
|
||||
echo "Populating Phabricator files with mail keys xactions...\n";
|
||||
|
||||
$table = new PhabricatorFile();
|
||||
$table_name = $table->getTableName();
|
||||
|
||||
$conn_w = $table->establishConnection('w');
|
||||
$conn_w->openTransaction();
|
||||
|
||||
$sql = array();
|
||||
foreach (new LiskRawMigrationIterator($conn_w, 'file') as $row) {
|
||||
$sql[] = qsprintf(
|
||||
$conn_w,
|
||||
'(%d, %s)',
|
||||
$row['id'],
|
||||
Filesystem::readRandomCharacters(20));
|
||||
}
|
||||
|
||||
if ($sql) {
|
||||
foreach (PhabricatorLiskDAO::chunkSQL($sql, ', ') as $chunk) {
|
||||
queryfx(
|
||||
$conn_w,
|
||||
'INSERT INTO %T (id, mailKey) VALUES %Q '.
|
||||
'ON DUPLICATE KEY UPDATE mailKey = VALUES(mailKey)',
|
||||
$table_name,
|
||||
$chunk);
|
||||
}
|
||||
}
|
||||
|
||||
$table->saveTransaction();
|
||||
echo "Done.\n";
|
2
resources/sql/patches/20130820.filemailkey.sql
Normal file
2
resources/sql/patches/20130820.filemailkey.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_file.file
|
||||
ADD `mailKey` varchar(20) NOT NULL;
|
42
resources/sql/patches/20130820.filexactions.sql
Normal file
42
resources/sql/patches/20130820.filexactions.sql
Normal file
|
@ -0,0 +1,42 @@
|
|||
CREATE TABLE {$NAMESPACE}_file.file_transaction (
|
||||
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
objectPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
commentPHID VARCHAR(64) COLLATE utf8_bin,
|
||||
commentVersion INT UNSIGNED NOT NULL,
|
||||
transactionType VARCHAR(32) NOT NULL COLLATE utf8_bin,
|
||||
oldValue LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
newValue LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
contentSource LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
metadata LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
|
||||
UNIQUE KEY `key_phid` (phid),
|
||||
KEY `key_object` (objectPHID)
|
||||
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
||||
|
||||
CREATE TABLE {$NAMESPACE}_file.file_transaction_comment (
|
||||
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
phid VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
transactionPHID VARCHAR(64) COLLATE utf8_bin,
|
||||
authorPHID VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
viewPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
editPolicy VARCHAR(64) NOT NULL COLLATE utf8_bin,
|
||||
commentVersion INT UNSIGNED NOT NULL,
|
||||
content LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
contentSource LONGTEXT NOT NULL COLLATE utf8_bin,
|
||||
isDeleted BOOL NOT NULL,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
|
||||
UNIQUE KEY `key_phid` (phid),
|
||||
UNIQUE KEY `key_version` (transactionPHID, commentVersion),
|
||||
UNIQUE KEY `key_draft` (authorPHID, transactionPHID)
|
||||
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
||||
|
|
@ -596,7 +596,9 @@ phutil_register_library_map(array(
|
|||
'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php',
|
||||
'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php',
|
||||
'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php',
|
||||
'FilesCreateMailReceiver' => 'applications/files/mail/FilesCreateMailReceiver.php',
|
||||
'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php',
|
||||
'FileMailReceiver' => 'applications/files/mail/FileMailReceiver.php',
|
||||
'FileReplyHandler' => 'applications/files/mail/FileReplyHandler.php',
|
||||
'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php',
|
||||
'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php',
|
||||
'HarbormasterRunnerWorker' => 'applications/harbormaster/worker/HarbormasterRunnerWorker.php',
|
||||
|
@ -1161,11 +1163,13 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFeedStoryStatus' => 'applications/feed/story/PhabricatorFeedStoryStatus.php',
|
||||
'PhabricatorFeedStoryTypeConstants' => 'applications/feed/constants/PhabricatorFeedStoryTypeConstants.php',
|
||||
'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php',
|
||||
'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php',
|
||||
'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php',
|
||||
'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php',
|
||||
'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php',
|
||||
'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php',
|
||||
'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php',
|
||||
'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php',
|
||||
'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php',
|
||||
'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php',
|
||||
'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php',
|
||||
|
@ -1181,6 +1185,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorFileStorageEngineSelector.php',
|
||||
'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php',
|
||||
'PhabricatorFileTestDataGenerator' => 'applications/files/lipsum/PhabricatorFileTestDataGenerator.php',
|
||||
'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php',
|
||||
'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php',
|
||||
'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php',
|
||||
'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php',
|
||||
'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php',
|
||||
'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php',
|
||||
|
@ -2631,7 +2638,9 @@ phutil_register_library_map(array(
|
|||
'FeedPublisherHTTPWorker' => 'FeedPushWorker',
|
||||
'FeedPublisherWorker' => 'FeedPushWorker',
|
||||
'FeedPushWorker' => 'PhabricatorWorker',
|
||||
'FilesCreateMailReceiver' => 'PhabricatorMailReceiver',
|
||||
'FileCreateMailReceiver' => 'PhabricatorMailReceiver',
|
||||
'FileMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
'FileReplyHandler' => 'PhabricatorMailReplyHandler',
|
||||
'HarbormasterDAO' => 'PhabricatorLiskDAO',
|
||||
'HarbormasterObject' => 'HarbormasterDAO',
|
||||
'HarbormasterRunnerWorker' => 'PhabricatorWorker',
|
||||
|
@ -3245,13 +3254,17 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFile' =>
|
||||
array(
|
||||
0 => 'PhabricatorFileDAO',
|
||||
1 => 'PhabricatorPolicyInterface',
|
||||
1 => 'PhabricatorTokenReceiverInterface',
|
||||
2 => 'PhabricatorSubscribableInterface',
|
||||
3 => 'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorFileCommentController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileController' => 'PhabricatorController',
|
||||
'PhabricatorFileDAO' => 'PhabricatorLiskDAO',
|
||||
'PhabricatorFileDataController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDeleteController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorFileImageMacro' =>
|
||||
array(
|
||||
0 => 'PhabricatorFileDAO',
|
||||
|
@ -3275,6 +3288,9 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileStorageConfigurationException' => 'Exception',
|
||||
'PhabricatorFileTestCase' => 'PhabricatorTestCase',
|
||||
'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator',
|
||||
'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorFileTransformController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileUploadController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileUploadDialogController' => 'PhabricatorFileController',
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorApplicationFiles extends PhabricatorApplication {
|
||||
|
||||
public function getBaseURI() {
|
||||
|
@ -48,6 +51,7 @@ final class PhabricatorApplicationFiles extends PhabricatorApplication {
|
|||
'(query/(?P<key>[^/]+)/)?' => 'PhabricatorFileListController',
|
||||
'upload/' => 'PhabricatorFileUploadController',
|
||||
'dropupload/' => 'PhabricatorFileDropUploadController',
|
||||
'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorFileCommentController',
|
||||
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
|
||||
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
|
||||
'data/(?P<key>[^/]+)/(?P<phid>[^/]+)/.*'
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group conduit
|
||||
*/
|
||||
abstract class ConduitAPI_file_Method extends ConduitAPIMethod {
|
||||
|
||||
public function getApplication() {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFilesConfigOptions
|
||||
extends PhabricatorApplicationConfigOptions {
|
||||
|
||||
|
@ -158,7 +161,12 @@ final class PhabricatorFilesConfigOptions
|
|||
'metamta.files.public-create-email',
|
||||
'string',
|
||||
null)
|
||||
->setDescription(pht('Allow uploaded files via email.')),
|
||||
->setDescription(pht('Allow uploaded files via email.')),
|
||||
$this->newOption(
|
||||
'metamta.files.subject-prefix',
|
||||
'string',
|
||||
'[File]')
|
||||
->setDescription(pht('Subject prefix for paste email.')),
|
||||
$this->newOption('files.enable-imagemagick', 'bool', false)
|
||||
->setBoolOptions(
|
||||
array(
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileCommentController
|
||||
extends PhabricatorFileController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = idx($data, 'id');
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
if (!$request->isFormPost()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($this->id))
|
||||
->executeOne();
|
||||
if (!$file) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$is_preview = $request->isPreviewRequest();
|
||||
$draft = PhabricatorDraft::buildFromRequest($request);
|
||||
|
||||
$view_uri = $file->getInfoURI();
|
||||
|
||||
$xactions = array();
|
||||
$xactions[] = id(new PhabricatorFileTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
id(new PhabricatorFileTransactionComment())
|
||||
->setContent($request->getStr('comment')));
|
||||
|
||||
$editor = id(new PhabricatorFileEditor())
|
||||
->setActor($user)
|
||||
->setContinueOnNoEffect($request->isContinueRequest())
|
||||
->setContentSourceFromRequest($request)
|
||||
->setIsPreview($is_preview);
|
||||
|
||||
try {
|
||||
$xactions = $editor->applyTransactions($file, $xactions);
|
||||
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
|
||||
return id(new PhabricatorApplicationTransactionNoEffectResponse())
|
||||
->setCancelURI($view_uri)
|
||||
->setException($ex);
|
||||
}
|
||||
|
||||
if ($draft) {
|
||||
$draft->replaceOrDelete();
|
||||
}
|
||||
|
||||
if ($request->isAjax()) {
|
||||
return id(new PhabricatorApplicationTransactionResponse())
|
||||
->setViewer($user)
|
||||
->setTransactions($xactions)
|
||||
->setIsPreview($is_preview)
|
||||
->setAnchorOffset($request->getStr('anchor'));
|
||||
} else {
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($view_uri);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -21,8 +21,13 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$this->loadHandles(array($file->getAuthorPHID()));
|
||||
$phid = $file->getPHID();
|
||||
$xactions = id(new PhabricatorFileTransactionQuery())
|
||||
->setViewer($user)
|
||||
->withObjectPHIDs(array($phid))
|
||||
->execute();
|
||||
|
||||
$this->loadHandles(array($file->getAuthorPHID()));
|
||||
$header = id(new PhabricatorHeaderView())
|
||||
->setHeader($file->getName());
|
||||
|
||||
|
@ -36,7 +41,7 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
|
||||
$actions = $this->buildActionView($file);
|
||||
$properties = $this->buildPropertyView($file);
|
||||
|
||||
$timeline = $this->buildTransactionView($file, $xactions);
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->setActionList($actions);
|
||||
$crumbs->addCrumb(
|
||||
|
@ -50,13 +55,64 @@ final class PhabricatorFileInfoController extends PhabricatorFileController {
|
|||
$header,
|
||||
$actions,
|
||||
$properties,
|
||||
$timeline
|
||||
),
|
||||
array(
|
||||
'title' => $file->getName(),
|
||||
'device' => true,
|
||||
'pageObjects' => array($file->getPHID()),
|
||||
));
|
||||
}
|
||||
|
||||
private function buildTransactionView(
|
||||
PhabricatorFile $file,
|
||||
array $xactions) {
|
||||
|
||||
$user = $this->getRequest()->getUser();
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($user);
|
||||
foreach ($xactions as $xaction) {
|
||||
if ($xaction->getComment()) {
|
||||
$engine->addObject(
|
||||
$xaction->getComment(),
|
||||
PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT);
|
||||
}
|
||||
}
|
||||
$engine->process();
|
||||
|
||||
$timeline = id(new PhabricatorApplicationTransactionView())
|
||||
->setUser($user)
|
||||
->setObjectPHID($file->getPHID())
|
||||
->setTransactions($xactions)
|
||||
->setMarkupEngine($engine);
|
||||
|
||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||
|
||||
$add_comment_header = id(new PhabricatorHeaderView())
|
||||
->setHeader(
|
||||
$is_serious
|
||||
? pht('Add Comment')
|
||||
: pht('Question File Integrity'));
|
||||
|
||||
$submit_button_name = $is_serious
|
||||
? pht('Add Comment')
|
||||
: pht('Debate the Bits');
|
||||
|
||||
$draft = PhabricatorDraft::newFromUserAndKey($user, $file->getPHID());
|
||||
|
||||
$add_comment_form = id(new PhabricatorApplicationTransactionCommentView())
|
||||
->setUser($user)
|
||||
->setObjectPHID($file->getPHID())
|
||||
->setDraft($draft)
|
||||
->setAction($this->getApplicationURI('/comment/'.$file->getID().'/'))
|
||||
->setSubmitButtonName($submit_button_name);
|
||||
|
||||
return array(
|
||||
$timeline,
|
||||
$add_comment_header,
|
||||
$add_comment_form);
|
||||
}
|
||||
|
||||
private function buildActionView(PhabricatorFile $file) {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
|
89
src/applications/files/editor/PhabricatorFileEditor.php
Normal file
89
src/applications/files/editor/PhabricatorFileEditor.php
Normal file
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
}
|
||||
|
||||
protected function supportsMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function getMailSubjectPrefix() {
|
||||
return PhabricatorEnv::getEnvConfig('metamta.files.subject-prefix');
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
return array(
|
||||
$object->getAuthorPHID(),
|
||||
$this->requireActor()->getPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||
return id(new FileReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
}
|
||||
|
||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||
$id = $object->getID();
|
||||
$name = $object->getName();
|
||||
|
||||
return id(new PhabricatorMetaMTAMail())
|
||||
->setSubject("F{$id}: {$name}")
|
||||
->addHeader('Thread-Topic', "F{$id}");
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
|
||||
$body->addTextSection(
|
||||
pht('FILE DETAIL'),
|
||||
PhabricatorEnv::getProductionURI($object->getInfoURI()));
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
protected function supportsFeed() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function supportsSearch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
/**
|
||||
* @group files
|
||||
*/
|
||||
final class FilesCreateMailReceiver
|
||||
final class FileCreateMailReceiver
|
||||
extends PhabricatorMailReceiver {
|
||||
|
||||
public function isEnabled() {
|
||||
|
@ -48,6 +48,8 @@ final class FilesCreateMailReceiver
|
|||
} else {
|
||||
$subject = pht('You successfully uploaded a file.');
|
||||
}
|
||||
$subject_prefix =
|
||||
PhabricatorEnv::getEnvConfig('metamta.files.subject-prefix');
|
||||
|
||||
$file_uris = array();
|
||||
foreach ($attachment_phids as $phid) {
|
||||
|
@ -61,7 +63,8 @@ final class FilesCreateMailReceiver
|
|||
|
||||
id(new PhabricatorMetaMTAMail())
|
||||
->addTos(array($sender->getPHID()))
|
||||
->setSubject('[Files] '.$subject)
|
||||
->setSubject($subject)
|
||||
->setSubjectPrefix($subject_prefix)
|
||||
->setFrom($sender->getPHID())
|
||||
->setRelatedPHID($first_phid)
|
||||
->setBody($body->render())
|
40
src/applications/files/mail/FileMailReceiver.php
Normal file
40
src/applications/files/mail/FileMailReceiver.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class FileMailReceiver extends PhabricatorObjectMailReceiver {
|
||||
|
||||
public function isEnabled() {
|
||||
$app_class = 'PhabricatorApplicationFiles';
|
||||
return PhabricatorApplication::isClassInstalled($app_class);
|
||||
}
|
||||
|
||||
protected function getObjectPattern() {
|
||||
return 'F[1-9]\d*';
|
||||
}
|
||||
|
||||
protected function loadObject($pattern, PhabricatorUser $viewer) {
|
||||
$id = (int)trim($pattern, 'F');
|
||||
|
||||
return id(new PhabricatorPasteQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->executeOne();
|
||||
}
|
||||
|
||||
protected function processReceivedObjectMail(
|
||||
PhabricatorMetaMTAReceivedMail $mail,
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorUser $sender) {
|
||||
|
||||
$handler = id(new FileReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
|
||||
$handler->setActor($sender);
|
||||
$handler->setExcludeMailRecipientPHIDs(
|
||||
$mail->loadExcludeMailRecipientPHIDs());
|
||||
$handler->processEmail($mail);
|
||||
}
|
||||
|
||||
}
|
92
src/applications/files/mail/FileReplyHandler.php
Normal file
92
src/applications/files/mail/FileReplyHandler.php
Normal file
|
@ -0,0 +1,92 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class FileReplyHandler extends PhabricatorMailReplyHandler {
|
||||
|
||||
public function validateMailReceiver($mail_receiver) {
|
||||
if (!($mail_receiver instanceof PhabricatorFile)) {
|
||||
throw new Exception('Mail receiver is not a PhabricatorFile.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrivateReplyHandlerEmailAddress(
|
||||
PhabricatorObjectHandle $handle) {
|
||||
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'F');
|
||||
}
|
||||
|
||||
public function getPublicReplyHandlerEmailAddress() {
|
||||
return $this->getDefaultPublicReplyHandlerEmailAddress('F');
|
||||
}
|
||||
|
||||
public function getReplyHandlerInstructions() {
|
||||
if ($this->supportsReplies()) {
|
||||
return pht('Reply to comment or !unsubscribe.');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
|
||||
$actor = $this->getActor();
|
||||
$file = $this->getMailReceiver();
|
||||
|
||||
$body = $mail->getCleanTextBody();
|
||||
$body = trim($body);
|
||||
$body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments());
|
||||
|
||||
$content_source = PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_EMAIL,
|
||||
array(
|
||||
'id' => $mail->getID(),
|
||||
));
|
||||
|
||||
$lines = explode("\n", trim($body));
|
||||
$first_line = head($lines);
|
||||
|
||||
$xactions = array();
|
||||
$command = null;
|
||||
$matches = null;
|
||||
if (preg_match('/^!(\w+)/', $first_line, $matches)) {
|
||||
$lines = array_slice($lines, 1);
|
||||
$body = implode("\n", $lines);
|
||||
$body = trim($body);
|
||||
|
||||
$command = $matches[1];
|
||||
}
|
||||
|
||||
switch ($command) {
|
||||
case 'unsubscribe':
|
||||
$xaction = id(new PhabricatorFileTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)
|
||||
->setNewValue(array('-' => array($actor->getPHID())));
|
||||
$xactions[] = $xaction;
|
||||
break;
|
||||
}
|
||||
|
||||
$xactions[] = id(new PhabricatorFileTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
id(new PhabricatorFileTransactionComment())
|
||||
->setContent($body));
|
||||
|
||||
$editor = id(new PhabricatorFileEditor())
|
||||
->setActor($actor)
|
||||
->setContentSource($content_source)
|
||||
->setContinueOnNoEffect(true)
|
||||
->setIsPreview(false);
|
||||
|
||||
try {
|
||||
$xactions = $editor->applyTransactions($file, $xactions);
|
||||
} catch (PhabricatorApplicationTransactionNoEffectException $ex) {
|
||||
// just do nothing, though unclear why you're sending a blank email
|
||||
return true;
|
||||
}
|
||||
|
||||
$head_xaction = head($xactions);
|
||||
return $head_xaction->getID();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileQuery
|
||||
extends PhabricatorCursorPagedPolicyAwareQuery {
|
||||
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileSearchEngine
|
||||
extends PhabricatorApplicationSearchEngine {
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
public function getTemplateApplicationTransaction() {
|
||||
return new PhabricatorFileTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,13 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFile extends PhabricatorFileDAO
|
||||
implements PhabricatorPolicyInterface {
|
||||
implements
|
||||
PhabricatorTokenReceiverInterface,
|
||||
PhabricatorSubscribableInterface,
|
||||
PhabricatorPolicyInterface {
|
||||
|
||||
const STORAGE_FORMAT_RAW = 'raw';
|
||||
|
||||
|
@ -16,6 +22,7 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
protected $secretKey;
|
||||
protected $contentHash;
|
||||
protected $metadata = array();
|
||||
protected $mailKey;
|
||||
|
||||
protected $storageEngine;
|
||||
protected $storageFormat;
|
||||
|
@ -38,6 +45,16 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
PhabricatorFilePHIDTypeFile::TYPECONST);
|
||||
}
|
||||
|
||||
public function save() {
|
||||
if (!$this->getSecretKey()) {
|
||||
$this->setSecretKey($this->generateSecretKey());
|
||||
}
|
||||
if (!$this->getMailKey()) {
|
||||
$this->setMailKey(Filesystem::readRandomCharacters(20));
|
||||
}
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
public static function readUploadedFileData($spec) {
|
||||
if (!$spec) {
|
||||
throw new Exception("No file was uploaded!");
|
||||
|
@ -648,13 +665,6 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
return ($key == $this->getSecretKey());
|
||||
}
|
||||
|
||||
public function save() {
|
||||
if (!$this->getSecretKey()) {
|
||||
$this->setSecretKey($this->generateSecretKey());
|
||||
}
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
public function generateSecretKey() {
|
||||
return Filesystem::readRandomCharacters(20);
|
||||
}
|
||||
|
@ -820,4 +830,23 @@ final class PhabricatorFile extends PhabricatorFileDAO
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorSubscribableInterface Implementation )-------------------- */
|
||||
|
||||
|
||||
public function isAutomaticallySubscribed($phid) {
|
||||
return ($this->authorPHID == $phid);
|
||||
}
|
||||
|
||||
|
||||
/* -( PhabricatorTokenReceiverInterface )---------------------------------- */
|
||||
|
||||
|
||||
public function getUsersToNotifyOfTokenGiven() {
|
||||
return array(
|
||||
$this->getAuthorPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
abstract class PhabricatorFileDAO extends PhabricatorLiskDAO {
|
||||
|
||||
public function getApplicationName() {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
/**
|
||||
* Simple blob store DAO for @{class:PhabricatorMySQLFileStorageEngine}.
|
||||
*
|
||||
* @group filestorage
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileStorageBlob extends PhabricatorFileDAO {
|
||||
// max_allowed_packet defaults to 1 MiB, escaping can make the data twice
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'file';
|
||||
}
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return PhabricatorFilePHIDTypeFile::TYPECONST;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionCommentObject() {
|
||||
return new PhabricatorFileTransactionComment();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileTransactionComment
|
||||
extends PhabricatorApplicationTransactionComment {
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
return new PhabricatorFileTransaction();
|
||||
}
|
||||
|
||||
public function shouldUseMarkupCache($field) {
|
||||
// Only cache submitted comments.
|
||||
return ($this->getTransactionPHID() != null);
|
||||
}
|
||||
}
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorTransformedFile extends PhabricatorFileDAO {
|
||||
|
||||
protected $originalPHID;
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @group file
|
||||
*/
|
||||
final class PhabricatorFileTestCase extends PhabricatorTestCase {
|
||||
|
||||
public function getPhabricatorTestCaseConfiguration() {
|
||||
|
|
|
@ -1559,6 +1559,19 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20130826.divinernode.sql'),
|
||||
),
|
||||
'20130820.filexactions.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20130820.filexactions.sql'),
|
||||
),
|
||||
'20130820.filemailkey.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20130820.filemailkey.sql'),
|
||||
),
|
||||
'20130820.file-mailkey-populate.php' => array(
|
||||
'type' => 'php',
|
||||
'name' =>
|
||||
$this->getPatchPath('20130820.file-mailkey-populate.php'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue