1
0
Fork 0
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:
Bob Trahan 2013-09-05 13:11:02 -07:00
parent 4b061a766a
commit 228496cdbe
24 changed files with 585 additions and 17 deletions

View 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";

View file

@ -0,0 +1,2 @@
ALTER TABLE {$NAMESPACE}_file.file
ADD `mailKey` varchar(20) NOT NULL;

View 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;

View file

@ -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',

View file

@ -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>[^/]+)/.*'

View file

@ -1,5 +1,8 @@
<?php
/**
* @group conduit
*/
abstract class ConduitAPI_file_Method extends ConduitAPIMethod {
public function getApplication() {

View file

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

View file

@ -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);
}
}
}

View file

@ -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();

View 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;
}
}

View file

@ -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())

View 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);
}
}

View 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();
}
}

View file

@ -1,5 +1,8 @@
<?php
/**
* @group file
*/
final class PhabricatorFileQuery
extends PhabricatorCursorPagedPolicyAwareQuery {

View file

@ -1,5 +1,8 @@
<?php
/**
* @group file
*/
final class PhabricatorFileSearchEngine
extends PhabricatorApplicationSearchEngine {

View file

@ -0,0 +1,13 @@
<?php
/**
* @group file
*/
final class PhabricatorFileTransactionQuery
extends PhabricatorApplicationTransactionQuery {
public function getTemplateApplicationTransaction() {
return new PhabricatorFileTransaction();
}
}

View file

@ -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(),
);
}
}

View file

@ -1,5 +1,8 @@
<?php
/**
* @group file
*/
abstract class PhabricatorFileDAO extends PhabricatorLiskDAO {
public function getApplicationName() {

View file

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

View file

@ -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();
}
}

View file

@ -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);
}
}

View file

@ -1,5 +1,8 @@
<?php
/**
* @group file
*/
final class PhabricatorTransformedFile extends PhabricatorFileDAO {
protected $originalPHID;

View file

@ -1,5 +1,8 @@
<?php
/**
* @group file
*/
final class PhabricatorFileTestCase extends PhabricatorTestCase {
public function getPhabricatorTestCaseConfiguration() {

View file

@ -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'),
),
);
}
}