mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-22 14:52:41 +01:00
Modernize Macro application
Summary: Adds feed, email, notifications, comments, partial editing, subscriptions, enable/disable, flags and crumbs to Macro. Test Plan: {F26839} {F26840} {F26841} {F26842} {F26843} {F26844} {F26845} Reviewers: vrana, btrahan, chad Reviewed By: vrana CC: aran Maniphest Tasks: T2157, T175, T2104 Differential Revision: https://secure.phabricator.com/D4141
This commit is contained in:
parent
4081579e79
commit
ba7723d905
33 changed files with 1233 additions and 117 deletions
|
@ -383,13 +383,20 @@ return array(
|
|||
// distinguish between testing and development installs, for example.
|
||||
'metamta.maniphest.subject-prefix' => '[Maniphest]',
|
||||
|
||||
// See 'metamta.pholio.reply-handler-domain'. This does the same thing, but
|
||||
// See 'metamta.maniphest.reply-handler-domain'. This does the same thing, but
|
||||
// affects Pholio.
|
||||
'metamta.pholio.reply-handler-domain' => null,
|
||||
|
||||
// Prefix prepended to mail sent by Pholio.
|
||||
'metamta.pholio.subject-prefix' => '[Pholio]',
|
||||
|
||||
// See 'metamta.maniphest.reply-handler-domain'. This does the same thing, but
|
||||
// affects Macro.
|
||||
'metamta.macro.reply-handler-domain' => null,
|
||||
|
||||
// Prefix prepended to mail sent by Macro.
|
||||
'metamta.macro.subject-prefix' => '[Macro]',
|
||||
|
||||
// See 'metamta.maniphest.reply-handler-domain'. This does the same thing,
|
||||
// but allows email replies via Differential.
|
||||
'metamta.differential.reply-handler-domain' => null,
|
||||
|
|
54
resources/sql/patches/20121209.xmacroadd.sql
Normal file
54
resources/sql/patches/20121209.xmacroadd.sql
Normal file
|
@ -0,0 +1,54 @@
|
|||
CREATE TABLE {$NAMESPACE}_file.macro_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,
|
||||
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.macro_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)
|
||||
|
||||
) ENGINE=InnoDB, COLLATE utf8_general_ci;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||
ADD dateCreated INT UNSIGNED NOT NULL;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||
ADD dateModified INT UNSIGNED NOT NULL;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||
ADD phid VARCHAR(64) NOT NULL COLLATE utf8_bin AFTER id;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||
ADD isDisabled BOOL NOT NULL;
|
||||
|
||||
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||
ADD KEY `key_disabled` (isDisabled);
|
18
resources/sql/patches/20121209.xmacromigrate.php
Normal file
18
resources/sql/patches/20121209.xmacromigrate.php
Normal file
|
@ -0,0 +1,18 @@
|
|||
<?php
|
||||
|
||||
echo "Giving image macros PHIDs";
|
||||
foreach (new LiskMigrationIterator(new PhabricatorFileImageMacro()) as $macro) {
|
||||
if ($macro->getPHID()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
echo ".";
|
||||
|
||||
queryfx(
|
||||
$macro->establishConnection('r'),
|
||||
'UPDATE %T SET phid = %s WHERE id = %d',
|
||||
$macro->getTableName(),
|
||||
$macro->generatePHID(),
|
||||
$macro->getID());
|
||||
}
|
||||
echo "\nDone.\n";
|
2
resources/sql/patches/20121209.xmacromigratekey.sql
Normal file
2
resources/sql/patches/20121209.xmacromigratekey.sql
Normal file
|
@ -0,0 +1,2 @@
|
|||
ALTER TABLE {$NAMESPACE}_file.file_imagemacro
|
||||
ADD UNIQUE KEY `key_phid` (phid);
|
|
@ -604,6 +604,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php',
|
||||
'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php',
|
||||
'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php',
|
||||
'PhabricatorApplicationTransactionView' => 'applications/transactions/view/PhabricatorApplicationTransactionView.php',
|
||||
'PhabricatorApplicationTransactions' => 'applications/transactions/application/PhabricatorApplicationTransactions.php',
|
||||
'PhabricatorApplicationUIExamples' => 'applications/uiexample/application/PhabricatorApplicationUIExamples.php',
|
||||
'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php',
|
||||
|
@ -829,10 +830,18 @@ phutil_register_library_map(array(
|
|||
'PhabricatorLoginController' => 'applications/auth/controller/PhabricatorLoginController.php',
|
||||
'PhabricatorLoginValidateController' => 'applications/auth/controller/PhabricatorLoginValidateController.php',
|
||||
'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php',
|
||||
'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php',
|
||||
'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php',
|
||||
'PhabricatorMacroDeleteController' => 'applications/macro/controller/PhabricatorMacroDeleteController.php',
|
||||
'PhabricatorMacroDisableController' => 'applications/macro/controller/PhabricatorMacroDisableController.php',
|
||||
'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php',
|
||||
'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php',
|
||||
'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php',
|
||||
'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php',
|
||||
'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php',
|
||||
'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php',
|
||||
'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php',
|
||||
'PhabricatorMacroTransactionType' => 'applications/macro/constants/PhabricatorMacroTransactionType.php',
|
||||
'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php',
|
||||
'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php',
|
||||
'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php',
|
||||
|
@ -1869,6 +1878,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor',
|
||||
'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory',
|
||||
'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
|
||||
'PhabricatorApplicationTransactionView' => 'AphrontView',
|
||||
'PhabricatorApplicationTransactions' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationUIExamples' => 'PhabricatorApplication',
|
||||
'PhabricatorApplicationsListController' => 'PhabricatorController',
|
||||
|
@ -2024,7 +2034,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileDataController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDeleteController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileImageMacro' => 'PhabricatorFileDAO',
|
||||
'PhabricatorFileImageMacro' =>
|
||||
array(
|
||||
0 => 'PhabricatorFileDAO',
|
||||
1 => 'PhabricatorSubscribableInterface',
|
||||
),
|
||||
'PhabricatorFileInfoController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileLinkListView' => 'AphrontView',
|
||||
'PhabricatorFileLinkView' => 'AphrontView',
|
||||
|
@ -2080,10 +2094,17 @@ phutil_register_library_map(array(
|
|||
'PhabricatorLoginController' => 'PhabricatorAuthController',
|
||||
'PhabricatorLoginValidateController' => 'PhabricatorAuthController',
|
||||
'PhabricatorLogoutController' => 'PhabricatorAuthController',
|
||||
'PhabricatorMacroCommentController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMacroController' => 'PhabricatorController',
|
||||
'PhabricatorMacroDeleteController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMacroDisableController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMacroEditController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorMacroListController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMacroReplyHandler' => 'PhabricatorMailReplyHandler',
|
||||
'PhabricatorMacroTransaction' => 'PhabricatorApplicationTransaction',
|
||||
'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment',
|
||||
'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
|
||||
'PhabricatorMacroViewController' => 'PhabricatorMacroController',
|
||||
'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter',
|
||||
'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||
'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter',
|
||||
|
|
|
@ -161,6 +161,11 @@ final class AphrontRequest {
|
|||
return array_key_exists($name, $this->requestData);
|
||||
}
|
||||
|
||||
final public function getFileExists($name) {
|
||||
return isset($_FILES[$name]) &&
|
||||
(idx($_FILES[$name], 'error') !== UPLOAD_ERR_NO_FILE);
|
||||
}
|
||||
|
||||
final public function isHTTPPost() {
|
||||
return ($_SERVER['REQUEST_METHOD'] == 'POST');
|
||||
}
|
||||
|
|
|
@ -26,8 +26,11 @@ final class PhabricatorApplicationMacro extends PhabricatorApplication {
|
|||
return array(
|
||||
'/macro/' => array(
|
||||
'' => 'PhabricatorMacroListController',
|
||||
'edit/(?:(?P<id>[1-9]\d*)/)?' => 'PhabricatorMacroEditController',
|
||||
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroDeleteController',
|
||||
'create/' => 'PhabricatorMacroEditController',
|
||||
'view/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroViewController',
|
||||
'comment/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroCommentController',
|
||||
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroEditController',
|
||||
'disable/(?P<id>[1-9]\d*)/' => 'PhabricatorMacroDisableController',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroTransactionType {
|
||||
|
||||
const TYPE_NAME = 'macro:name';
|
||||
const TYPE_DISABLED = 'macro:disabled';
|
||||
const TYPE_FILE = 'macro:file';
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroCommentController
|
||||
extends PhabricatorMacroController {
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
$macro = id(new PhabricatorFileImageMacro())->load($this->id);
|
||||
if (!$macro) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/');
|
||||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(new PhabricatorMacroTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
id(new PhabricatorMacroTransactionComment())
|
||||
->setContent($request->getStr('comment')));
|
||||
|
||||
$editor = id(new PhabricatorMacroEditor())
|
||||
->setActor($user)
|
||||
->setContentSource(
|
||||
PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_WEB,
|
||||
array(
|
||||
'ip' => $request->getRemoteAddr(),
|
||||
)))
|
||||
->applyTransactions($macro, $xactions);
|
||||
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($view_uri);
|
||||
}
|
||||
|
||||
}
|
|
@ -3,19 +3,39 @@
|
|||
abstract class PhabricatorMacroController
|
||||
extends PhabricatorController {
|
||||
|
||||
protected function buildSideNavView(PhabricatorFileImageMacro $macro = null) {
|
||||
protected function buildSideNavView($for_app = false, $has_search = false) {
|
||||
$nav = new AphrontSideNavFilterView();
|
||||
$nav->setBaseURI(new PhutilURI($this->getApplicationURI()));
|
||||
|
||||
$nav->addLabel('Create');
|
||||
$nav->addFilter('edit', 'Create Macro');
|
||||
|
||||
$nav->addSpacer();
|
||||
if ($for_app) {
|
||||
$nav->addLabel('Create');
|
||||
$nav->addFilter('', 'Create Macro', $this->getApplicationURI('/create/'));
|
||||
}
|
||||
|
||||
$nav->addLabel('Macros');
|
||||
$nav->addFilter('', 'All Macros');
|
||||
$nav->addFilter('/', 'All Macros');
|
||||
if ($has_search) {
|
||||
$nav->addFilter('search', 'Search', $this->getRequest()->getRequestURI());
|
||||
}
|
||||
|
||||
|
||||
return $nav;
|
||||
}
|
||||
|
||||
public function buildApplicationMenu() {
|
||||
return $this->buildSideNavView($for_app = true)->getMenu();
|
||||
}
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
|
||||
$crumbs->addAction(
|
||||
id(new PhabricatorMenuItemView())
|
||||
->setName(pht('Create Macro'))
|
||||
->setHref($this->getApplicationURI('/create/'))
|
||||
->setIcon('create'));
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroDeleteController
|
||||
extends PhabricatorMacroController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
|
||||
$macro = id(new PhabricatorFileImageMacro())->load($this->id);
|
||||
if (!$macro) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$request = $this->getRequest();
|
||||
|
||||
if ($request->isDialogFormPost()) {
|
||||
$macro->delete();
|
||||
return id(new AphrontRedirectResponse())->setURI(
|
||||
$this->getApplicationURI());
|
||||
}
|
||||
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog
|
||||
->setUser($request->getUser())
|
||||
->setTitle('Really delete macro?')
|
||||
->appendChild(
|
||||
'<p>Really delete the much-beloved image macro "'.
|
||||
phutil_escape_html($macro->getName()).'"? It will be sorely missed.'.
|
||||
'</p>')
|
||||
->setSubmitURI($this->getApplicationURI('/delete/'.$this->id.'/'))
|
||||
->addSubmitButton('Delete')
|
||||
->addCancelButton($this->getApplicationURI());
|
||||
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroDisableController
|
||||
extends PhabricatorMacroController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$macro = id(new PhabricatorFileImageMacro())->load($this->id);
|
||||
if (!$macro) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$view_uri = $this->getApplicationURI('/view/'.$this->id.'/');
|
||||
|
||||
if ($request->isDialogFormPost() || $macro->getIsDisabled()) {
|
||||
$xaction = id(new PhabricatorMacroTransaction())
|
||||
->setTransactionType(PhabricatorMacroTransactionType::TYPE_DISABLED)
|
||||
->setNewValue($macro->getIsDisabled() ? 0 : 1);
|
||||
|
||||
$editor = id(new PhabricatorMacroEditor())
|
||||
->setActor($user)
|
||||
->setContentSource(
|
||||
PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_WEB,
|
||||
array(
|
||||
'ip' => $request->getRemoteAddr(),
|
||||
)))
|
||||
->applyTransactions($macro, array($xaction));
|
||||
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
}
|
||||
|
||||
$dialog = new AphrontDialogView();
|
||||
$dialog
|
||||
->setUser($request->getUser())
|
||||
->setTitle('Really disable macro?')
|
||||
->appendChild(
|
||||
'<p>Really disable the much-beloved image macro "'.
|
||||
phutil_escape_html($macro->getName()).'"? It will be sorely missed.'.
|
||||
'</p>')
|
||||
->setSubmitURI($this->getApplicationURI('/disable/'.$this->id.'/'))
|
||||
->addSubmitButton('Disable')
|
||||
->addCancelButton($view_uri);
|
||||
|
||||
return id(new AphrontDialogResponse())->setDialog($dialog);
|
||||
}
|
||||
}
|
|
@ -22,56 +22,96 @@ final class PhabricatorMacroEditController
|
|||
|
||||
$errors = array();
|
||||
$e_name = true;
|
||||
$e_file = true;
|
||||
$file = null;
|
||||
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
if ($request->isFormPost()) {
|
||||
$original = clone $macro;
|
||||
|
||||
$macro->setName($request->getStr('name'));
|
||||
$new_name = null;
|
||||
if ($request->getBool('name_form') || !$macro->getID()) {
|
||||
$new_name = $request->getStr('name');
|
||||
|
||||
if (!strlen($macro->getName())) {
|
||||
$errors[] = 'Macro name is required.';
|
||||
$e_name = 'Required';
|
||||
} else if (!preg_match('/^[a-z0-9_-]{3,}$/', $macro->getName())) {
|
||||
$errors[] = 'Macro must be at least three characters long and contain '.
|
||||
'only lowercase letters, digits, hyphen and underscore.';
|
||||
$e_name = 'Invalid';
|
||||
} else {
|
||||
$e_name = null;
|
||||
$macro->setName($new_name);
|
||||
|
||||
if (!strlen($macro->getName())) {
|
||||
$errors[] = 'Macro name is required.';
|
||||
$e_name = 'Required';
|
||||
} else if (!preg_match('/^[a-z0-9_-]{3,}$/', $macro->getName())) {
|
||||
$errors[] = 'Macro must be at least three characters long and '.
|
||||
'contain only lowercase letters, digits, hyphen and '.
|
||||
'underscore.';
|
||||
$e_name = 'Invalid';
|
||||
} else {
|
||||
$e_name = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
|
||||
$file = null;
|
||||
if ($request->getFileExists('file')) {
|
||||
$file = PhabricatorFile::newFromPHPUpload(
|
||||
idx($_FILES, 'file'),
|
||||
$_FILES['file'],
|
||||
array(
|
||||
'name' => $request->getStr('name'),
|
||||
'authorPHID' => $user->getPHID(),
|
||||
));
|
||||
$macro->setFilePHID($file->getPHID());
|
||||
} else if ($request->getStr('phid')) {
|
||||
$file = id(new PhabricatorFile())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$request->getStr('phid'));
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
if (!$file->isViewableInBrowser()) {
|
||||
$errors[] = pht('You must upload an image.');
|
||||
$e_file = pht('Invalid');
|
||||
} else {
|
||||
$macro->setFilePHID($file->getPHID());
|
||||
$e_file = null;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$macro->getID() && !$file) {
|
||||
$errors[] = 'You must upload an image to create a macro.';
|
||||
$e_file = pht('Required');
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
try {
|
||||
$macro->save();
|
||||
return id(new AphrontRedirectResponse())->setURI(
|
||||
$this->getApplicationURI());
|
||||
$xactions = array();
|
||||
|
||||
if ($new_name !== null) {
|
||||
$xactions[] = id(new PhabricatorMacroTransaction())
|
||||
->setTransactionType(PhabricatorMacroTransactionType::TYPE_NAME)
|
||||
->setNewValue($new_name);
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
$xactions[] = id(new PhabricatorMacroTransaction())
|
||||
->setTransactionType(PhabricatorMacroTransactionType::TYPE_FILE)
|
||||
->setNewValue($file->getPHID());
|
||||
}
|
||||
|
||||
$editor = id(new PhabricatorMacroEditor())
|
||||
->setActor($user)
|
||||
->setContentSource(
|
||||
PhabricatorContentSource::newForSource(
|
||||
PhabricatorContentSource::SOURCE_WEB,
|
||||
array(
|
||||
'ip' => $request->getRemoteAddr(),
|
||||
)))
|
||||
->applyTransactions($original, $xactions);
|
||||
|
||||
$view_uri = $this->getApplicationURI('/view/'.$original->getID().'/');
|
||||
return id(new AphrontRedirectResponse())->setURI($view_uri);
|
||||
} catch (AphrontQueryDuplicateKeyException $ex) {
|
||||
throw $ex;
|
||||
$errors[] = 'Macro name is not unique!';
|
||||
$e_name = 'Duplicate';
|
||||
}
|
||||
}
|
||||
} else if ($this->id) {
|
||||
$file = id(new PhabricatorFile())
|
||||
->loadOneWhere('phid = %s', $macro->getFilePHID());
|
||||
}
|
||||
|
||||
$caption = null;
|
||||
if ($file) {
|
||||
$caption = phutil_render_tag(
|
||||
'img',
|
||||
array(
|
||||
'src' => $file->getViewURI(),
|
||||
));
|
||||
}
|
||||
|
||||
if ($errors) {
|
||||
|
@ -82,7 +122,17 @@ final class PhabricatorMacroEditController
|
|||
$error_view = null;
|
||||
}
|
||||
|
||||
|
||||
$current_file = null;
|
||||
if ($macro->getFilePHID()) {
|
||||
$current_file = id(new PhabricatorFile())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$macro->getFilePHID());
|
||||
}
|
||||
|
||||
$form = new AphrontFormView();
|
||||
$form->setFlexible(true);
|
||||
$form->addHiddenInput('name_form', 1);
|
||||
$form->setUser($request->getUser());
|
||||
|
||||
$form
|
||||
|
@ -93,35 +143,101 @@ final class PhabricatorMacroEditController
|
|||
->setName('name')
|
||||
->setValue($macro->getName())
|
||||
->setCaption('This word or phrase will be replaced with the image.')
|
||||
->setError($e_name))
|
||||
->appendChild(
|
||||
->setError($e_name));
|
||||
|
||||
if (!$macro->getID()) {
|
||||
if ($current_file) {
|
||||
$current_file_view = id(new PhabricatorFileLinkView())
|
||||
->setFilePHID($current_file->getPHID())
|
||||
->setFileName($current_file->getName())
|
||||
->setFileViewable(true)
|
||||
->setFileViewURI($current_file->getBestURI())
|
||||
->render();
|
||||
$form->addHiddenInput('phid', $current_file->getPHID());
|
||||
$form->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setLabel('Selected File')
|
||||
->setValue($current_file_view));
|
||||
|
||||
$other_label = pht('Change File');
|
||||
} else {
|
||||
$other_label = pht('File');
|
||||
}
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormFileControl())
|
||||
->setLabel('File')
|
||||
->setLabel($other_label)
|
||||
->setName('file')
|
||||
->setCaption($caption)
|
||||
->setError(true))
|
||||
->setError($e_file));
|
||||
}
|
||||
|
||||
|
||||
$view_uri = $this->getApplicationURI('/view/'.$macro->getID().'/');
|
||||
|
||||
if ($macro->getID()) {
|
||||
$cancel_uri = $view_uri;
|
||||
} else {
|
||||
$cancel_uri = $this->getApplicationURI();
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Save Image Macro')
|
||||
->addCancelButton($this->getApplicationURI()));
|
||||
->setValue(pht('Save Image Macro'))
|
||||
->addCancelButton($cancel_uri));
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
|
||||
$panel = new AphrontPanelView();
|
||||
if ($macro->getID()) {
|
||||
$title = 'Edit Image Macro';
|
||||
} else {
|
||||
$title = 'Create Image Macro';
|
||||
}
|
||||
$panel->setHeader($title);
|
||||
$panel->appendChild($form);
|
||||
$panel->setWidth(AphrontPanelView::WIDTH_FULL);
|
||||
$title = pht('Edit Image Macro');
|
||||
$crumb = pht('Edit');
|
||||
|
||||
$nav = $this->buildSideNavView($macro);
|
||||
$nav->selectFilter('#', 'edit');
|
||||
$nav->appendChild($error_view);
|
||||
$nav->appendChild($panel);
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setHref($view_uri)
|
||||
->setName(pht('Macro "%s"', $macro->getName())));
|
||||
} else {
|
||||
$title = pht('Create Image Macro');
|
||||
$crumb = pht('Create');
|
||||
}
|
||||
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setHref($request->getRequestURI())
|
||||
->setName($crumb));
|
||||
|
||||
$header = id(new PhabricatorHeaderView())
|
||||
->setHeader($title);
|
||||
|
||||
|
||||
$upload = null;
|
||||
if ($macro->getID()) {
|
||||
$upload_header = id(new PhabricatorHeaderView())
|
||||
->setHeader(pht('Upload New File'));
|
||||
|
||||
$upload_form = id(new AphrontFormView())
|
||||
->setFlexible(true)
|
||||
->setEncType('multipart/form-data')
|
||||
->setUser($request->getUser())
|
||||
->appendChild(
|
||||
id(new AphrontFormFileControl())
|
||||
->setLabel('File')
|
||||
->setName('file'))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue('Upload File'));
|
||||
|
||||
$upload = array($upload_header, $upload_form);
|
||||
}
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
$crumbs,
|
||||
$header,
|
||||
$error_view,
|
||||
$form,
|
||||
$upload,
|
||||
),
|
||||
array(
|
||||
'title' => $title,
|
||||
));
|
||||
|
|
|
@ -70,8 +70,11 @@ final class PhabricatorMacroListController
|
|||
$filter_view = new AphrontListFilterView();
|
||||
$filter_view->appendChild($filter_form);
|
||||
|
||||
$nav = $this->buildSideNavView();
|
||||
$nav->selectFilter('/');
|
||||
$has_search = strlen($filter);
|
||||
$nav = $this->buildSideNavView(
|
||||
$for_app = false,
|
||||
$has_search);
|
||||
$nav->selectFilter($has_search ? 'search' : '/');
|
||||
|
||||
$nav->appendChild($filter_view);
|
||||
|
||||
|
@ -97,7 +100,7 @@ final class PhabricatorMacroListController
|
|||
array(),
|
||||
'Created on '.$datetime));
|
||||
}
|
||||
$item->setURI($this->getApplicationURI('/edit/'.$macro->getID().'/'));
|
||||
$item->setURI($this->getApplicationURI('/view/'.$macro->getID().'/'));
|
||||
$item->setHeader($macro->getName());
|
||||
|
||||
$pinboard->addItem($item);
|
||||
|
@ -109,11 +112,20 @@ final class PhabricatorMacroListController
|
|||
$nav->appendChild($list);
|
||||
}
|
||||
|
||||
|
||||
if ($filter === null) {
|
||||
if (!strlen($filter)) {
|
||||
$nav->appendChild($pager);
|
||||
$name = pht('All Macros');
|
||||
} else {
|
||||
$name = pht('Search');
|
||||
}
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setName($name)
|
||||
->setHref($request->getRequestURI()));
|
||||
$nav->setCrumbs($crumbs);
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
$nav,
|
||||
array(
|
||||
|
|
|
@ -0,0 +1,193 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroViewController
|
||||
extends PhabricatorMacroController {
|
||||
|
||||
private $id;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->id = $data['id'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
|
||||
$macro = id(new PhabricatorFileImageMacro())->load($this->id);
|
||||
if (!$macro) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$file = id(new PhabricatorFile())->loadOneWhere(
|
||||
'phid = %s',
|
||||
$macro->getFilePHID());
|
||||
|
||||
$title_short = pht('Macro "%s"', $macro->getName());
|
||||
$title_long = pht('Image Macro "%s"', $macro->getName());
|
||||
|
||||
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$macro->getPHID());
|
||||
|
||||
$this->loadHandles($subscribers);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
$crumbs->addCrumb(
|
||||
id(new PhabricatorCrumbView())
|
||||
->setHref($this->getApplicationURI('/view/'.$macro->getID().'/'))
|
||||
->setName($title_short));
|
||||
|
||||
$actions = $this->buildActionView($macro);
|
||||
$properties = $this->buildPropertyView($macro, $file, $subscribers);
|
||||
|
||||
$xactions = id(new PhabricatorMacroTransactionQuery())
|
||||
->setViewer($request->getUser())
|
||||
->withObjectPHIDs(array($macro->getPHID()))
|
||||
->execute();
|
||||
|
||||
$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())
|
||||
->setViewer($user)
|
||||
->setTransactions($xactions)
|
||||
->setMarkupEngine($engine);
|
||||
|
||||
$header = id(new PhabricatorHeaderView())
|
||||
->setHeader($title_long);
|
||||
|
||||
if ($macro->getIsDisabled()) {
|
||||
$header->addTag(
|
||||
id(new PhabricatorTagView())
|
||||
->setType(PhabricatorTagView::TYPE_STATE)
|
||||
->setName(pht('Macro Disabled'))
|
||||
->setBackgroundColor(PhabricatorTagView::COLOR_RED));
|
||||
}
|
||||
|
||||
$is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business');
|
||||
|
||||
$add_comment_header = id(new PhabricatorHeaderView())
|
||||
->setHeader(
|
||||
$is_serious
|
||||
? pht('Add Comment')
|
||||
: pht('Grovel in Awe'));
|
||||
|
||||
$add_comment_form = id(new AphrontFormView())
|
||||
->setWorkflow(true)
|
||||
->setFlexible(true)
|
||||
->setAction($this->getApplicationURI('/comment/'.$macro->getID().'/'))
|
||||
->setUser($user)
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setUser($user)
|
||||
->setLabel('Comment')
|
||||
->setName('comment'))
|
||||
->appendChild(
|
||||
id(new AphrontFormSubmitControl())
|
||||
->setValue(
|
||||
$is_serious
|
||||
? pht('Add Comment')
|
||||
: pht('Lavish Praise')));
|
||||
|
||||
return $this->buildApplicationPage(
|
||||
array(
|
||||
$crumbs,
|
||||
$header,
|
||||
$actions,
|
||||
$properties,
|
||||
$timeline,
|
||||
$add_comment_header,
|
||||
$add_comment_form,
|
||||
),
|
||||
array(
|
||||
'title' => $title_short,
|
||||
));
|
||||
}
|
||||
|
||||
private function buildActionView(PhabricatorFileImageMacro $macro) {
|
||||
$view = new PhabricatorActionListView();
|
||||
$view->setUser($this->getRequest()->getUser());
|
||||
$view->setObject($macro);
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName('Edit Macro')
|
||||
->setHref($this->getApplicationURI('/edit/'.$macro->getID().'/'))
|
||||
->setIcon('edit'));
|
||||
|
||||
if ($macro->getIsDisabled()) {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName('Restore Macro')
|
||||
->setHref($this->getApplicationURI('/disable/'.$macro->getID().'/'))
|
||||
->setWorkflow(true)
|
||||
->setIcon('undo'));
|
||||
} else {
|
||||
$view->addAction(
|
||||
id(new PhabricatorActionView())
|
||||
->setName('Disable Macro')
|
||||
->setHref($this->getApplicationURI('/disable/'.$macro->getID().'/'))
|
||||
->setWorkflow(true)
|
||||
->setIcon('delete'));
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
private function buildPropertyView(
|
||||
PhabricatorFileImageMacro $macro,
|
||||
PhabricatorFile $file = null,
|
||||
array $subscribers) {
|
||||
|
||||
$view = new PhabricatorPropertyListView();
|
||||
|
||||
$view->addProperty(
|
||||
pht('Name'),
|
||||
phutil_escape_html($macro->getName()));
|
||||
|
||||
$view->addProperty(
|
||||
pht('Status'),
|
||||
$macro->getIsDisabled()
|
||||
? pht('Disabled')
|
||||
: pht('Enabled'));
|
||||
|
||||
$view->addProperty(
|
||||
pht('Created'),
|
||||
phabricator_date(
|
||||
$macro->getDateCreated(),
|
||||
$this->getRequest()->getUser()));
|
||||
|
||||
if ($subscribers) {
|
||||
$sub_view = array();
|
||||
foreach ($subscribers as $subscriber) {
|
||||
$sub_view[] = $this->getHandle($subscriber)->renderLink();
|
||||
}
|
||||
$sub_view = implode(', ', $sub_view);
|
||||
} else {
|
||||
$sub_view = '<em>'.pht('None').'</em>';
|
||||
}
|
||||
|
||||
$view->addProperty(
|
||||
pht('Subscribers'),
|
||||
$sub_view);
|
||||
|
||||
if ($file) {
|
||||
$view->addTextContent(
|
||||
phutil_render_tag(
|
||||
'img',
|
||||
array(
|
||||
'src' => $file->getViewURI(),
|
||||
'class' => 'phabricator-image-macro-hero',
|
||||
)));
|
||||
}
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
}
|
123
src/applications/macro/editor/PhabricatorMacroEditor.php
Normal file
123
src/applications/macro/editor/PhabricatorMacroEditor.php
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroEditor
|
||||
extends PhabricatorApplicationTransactionEditor {
|
||||
|
||||
public function getTransactionTypes() {
|
||||
$types = parent::getTransactionTypes();
|
||||
|
||||
$types[] = PhabricatorMacroTransactionType::TYPE_NAME;
|
||||
$types[] = PhabricatorMacroTransactionType::TYPE_DISABLED;
|
||||
$types[] = PhabricatorMacroTransactionType::TYPE_FILE;
|
||||
|
||||
return $types;
|
||||
}
|
||||
|
||||
protected function getCustomTransactionOldValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
return $object->getName();
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
return $object->getIsDisabled();
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
return $object->getFilePHID();
|
||||
}
|
||||
}
|
||||
|
||||
protected function getCustomTransactionNewValue(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
return $xaction->getNewValue();
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomInternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
$object->setName($xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
$object->setIsDisabled($xaction->getNewValue());
|
||||
break;
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
$object->setFilePHID($xaction->getNewValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function applyCustomExternalTransaction(
|
||||
PhabricatorLiskDAO $object,
|
||||
PhabricatorApplicationTransaction $xaction) {
|
||||
return;
|
||||
}
|
||||
|
||||
protected function mergeTransactions(
|
||||
PhabricatorApplicationTransaction $u,
|
||||
PhabricatorApplicationTransaction $v) {
|
||||
|
||||
$type = $u->getTransactionType();
|
||||
switch ($type) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
return $v;
|
||||
}
|
||||
|
||||
return parent::mergeTransactions($u, $v);
|
||||
}
|
||||
|
||||
protected function supportsMail() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
||||
return id(new PhabricatorMacroReplyHandler())
|
||||
->setMailReceiver($object);
|
||||
}
|
||||
|
||||
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
||||
$name = $object->getName();
|
||||
$name = 'Image Macro "'.$name.'"';
|
||||
|
||||
return id(new PhabricatorMetaMTAMail())
|
||||
->setSubject($name)
|
||||
->addHeader('Thread-Topic', $name);
|
||||
}
|
||||
|
||||
protected function getMailTo(PhabricatorLiskDAO $object) {
|
||||
return array(
|
||||
$this->requireActor()->getPHID(),
|
||||
);
|
||||
}
|
||||
|
||||
protected function buildMailBody(
|
||||
PhabricatorLiskDAO $object,
|
||||
array $xactions) {
|
||||
|
||||
$body = parent::buildMailBody($object, $xactions);
|
||||
$body->addTextSection(
|
||||
pht('MACRO DETAIL'),
|
||||
PhabricatorEnv::getProductionURI('/macro/view/'.$object->getID().'/'));
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
protected function getMailSubjectPrefix() {
|
||||
return PhabricatorEnv::getEnvConfig('metamta.macro.subject-prefix');
|
||||
}
|
||||
|
||||
protected function supportsFeed() {
|
||||
return true;
|
||||
}
|
||||
}
|
40
src/applications/macro/mail/PhabricatorMacroReplyHandler.php
Normal file
40
src/applications/macro/mail/PhabricatorMacroReplyHandler.php
Normal file
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroReplyHandler extends PhabricatorMailReplyHandler {
|
||||
|
||||
public function validateMailReceiver($mail_receiver) {
|
||||
if (!($mail_receiver instanceof PhabricatorFileImageMacro)) {
|
||||
throw new Exception("Mail receiver is not a PhabricatorFileImageMacro!");
|
||||
}
|
||||
}
|
||||
|
||||
public function getPrivateReplyHandlerEmailAddress(
|
||||
PhabricatorObjectHandle $handle) {
|
||||
return $this->getDefaultPrivateReplyHandlerEmailAddress($handle, 'MCRO');
|
||||
}
|
||||
|
||||
public function getPublicReplyHandlerEmailAddress() {
|
||||
return $this->getDefaultPublicReplyHandlerEmailAddress('MCRO');
|
||||
}
|
||||
|
||||
public function getReplyHandlerDomain() {
|
||||
return PhabricatorEnv::getEnvConfig(
|
||||
'metamta.macro.reply-handler-domain');
|
||||
}
|
||||
|
||||
public function getReplyHandlerInstructions() {
|
||||
if ($this->supportsReplies()) {
|
||||
// TODO: Implement.
|
||||
return null;
|
||||
return "Reply to comment.";
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) {
|
||||
// TODO: Implement this.
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroTransactionQuery
|
||||
extends PhabricatorApplicationTransactionQuery {
|
||||
|
||||
protected function getTemplateApplicationTransaction() {
|
||||
return new PhabricatorMacroTransaction();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,16 +1,24 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFileImageMacro extends PhabricatorFileDAO {
|
||||
final class PhabricatorFileImageMacro extends PhabricatorFileDAO
|
||||
implements PhabricatorSubscribableInterface {
|
||||
|
||||
protected $filePHID;
|
||||
protected $phid;
|
||||
protected $name;
|
||||
protected $isDisabled = 0;
|
||||
|
||||
public function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_TIMESTAMPS => false,
|
||||
self::CONFIG_AUX_PHID => true,
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function generatePHID() {
|
||||
return PhabricatorPHID::generateNewPHID(
|
||||
PhabricatorPHIDConstants::PHID_TYPE_MCRO);
|
||||
}
|
||||
|
||||
static public function newFromImageURI($uri, $file_name, $image_macro_name) {
|
||||
$file = PhabricatorFile::newFromFileDownload($uri, $file_name);
|
||||
|
||||
|
@ -25,5 +33,10 @@ final class PhabricatorFileImageMacro extends PhabricatorFileDAO {
|
|||
|
||||
return $image_macro;
|
||||
}
|
||||
|
||||
public function isAutomaticallySubscribed($phid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
231
src/applications/macro/storage/PhabricatorMacroTransaction.php
Normal file
231
src/applications/macro/storage/PhabricatorMacroTransaction.php
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroTransaction
|
||||
extends PhabricatorApplicationTransaction {
|
||||
|
||||
public function getApplicationName() {
|
||||
return 'file';
|
||||
}
|
||||
|
||||
public function getTableName() {
|
||||
return 'macro_transaction';
|
||||
}
|
||||
|
||||
public function getApplicationTransactionType() {
|
||||
return PhabricatorPHIDConstants::PHID_TYPE_MCRO;
|
||||
}
|
||||
|
||||
public function getApplicationTransactionCommentObject() {
|
||||
return new PhabricatorMacroTransactionComment();
|
||||
}
|
||||
|
||||
public function getApplicationObjectTypeName() {
|
||||
return pht('macro');
|
||||
}
|
||||
|
||||
public function getRequiredHandlePHIDs() {
|
||||
$phids = parent::getRequiredHandlePHIDs();
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
if ($old !== null) {
|
||||
$phids[] = $old;
|
||||
}
|
||||
$phids[] = $new;
|
||||
break;
|
||||
}
|
||||
|
||||
return $phids;
|
||||
}
|
||||
|
||||
public function shouldHide() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
return ($old === null);
|
||||
}
|
||||
|
||||
return parent::shouldHide();
|
||||
}
|
||||
|
||||
public function getTitle() {
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
return pht(
|
||||
'%s renamed this macro from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
phutil_escape_html($old),
|
||||
phutil_escape_html($new));
|
||||
break;
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
if ($new) {
|
||||
return pht(
|
||||
'%s disabled this macro.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s restored this macro.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
}
|
||||
break;
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s created this macro.',
|
||||
$this->renderHandleLink($author_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s changed the image for this macro from %s to %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($old),
|
||||
$this->renderHandleLink($new));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return parent::getTitle();
|
||||
}
|
||||
|
||||
public function getTitleForFeed() {
|
||||
$author_phid = $this->getAuthorPHID();
|
||||
$object_phid = $this->getObjectPHID();
|
||||
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
return pht(
|
||||
'%s renamed %s from "%s" to "%s".',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid),
|
||||
phutil_escape_html($old),
|
||||
phutil_escape_html($new));
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
if ($new) {
|
||||
return pht(
|
||||
'%s disabled %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s restored %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
}
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
if ($old === null) {
|
||||
return pht(
|
||||
'%s created %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
} else {
|
||||
return pht(
|
||||
'%s updated the image for %s.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
$this->renderHandleLink($object_phid));
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getTitleForFeed();
|
||||
}
|
||||
|
||||
public function getActionName() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
if ($old === null) {
|
||||
return pht('Created');
|
||||
} else {
|
||||
return pht('Renamed');
|
||||
}
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
if ($new) {
|
||||
return pht('Disabled');
|
||||
} else {
|
||||
return pht('Restored');
|
||||
}
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
if ($old === null) {
|
||||
return pht('Created');
|
||||
} else {
|
||||
return pht('Edited Image');
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getActionName();
|
||||
}
|
||||
|
||||
public function getActionStrength() {
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
return 2.0;
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
return 1.5;
|
||||
}
|
||||
return parent::getActionStrength();
|
||||
}
|
||||
|
||||
public function getIcon() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
return 'edit';
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
if ($old === null) {
|
||||
return 'create';
|
||||
} else {
|
||||
return 'edit';
|
||||
}
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
if ($new) {
|
||||
return 'delete';
|
||||
} else {
|
||||
return 'undo';
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getIcon();
|
||||
}
|
||||
|
||||
public function getColor() {
|
||||
$old = $this->getOldValue();
|
||||
$new = $this->getNewValue();
|
||||
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorMacroTransactionType::TYPE_NAME:
|
||||
return PhabricatorTransactions::COLOR_BLUE;
|
||||
case PhabricatorMacroTransactionType::TYPE_FILE:
|
||||
if ($old === null) {
|
||||
return PhabricatorTransactions::COLOR_GREEN;
|
||||
} else {
|
||||
return PhabricatorTransactions::COLOR_BLUE;
|
||||
}
|
||||
case PhabricatorMacroTransactionType::TYPE_DISABLED:
|
||||
if ($new) {
|
||||
return PhabricatorTransactions::COLOR_BLACK;
|
||||
} else {
|
||||
return PhabricatorTransactions::COLOR_SKY;
|
||||
}
|
||||
}
|
||||
|
||||
return parent::getColor();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorMacroTransactionComment
|
||||
extends PhabricatorApplicationTransactionComment {
|
||||
|
||||
public function getApplicationTransactionObject() {
|
||||
return new PhabricatorMacroTransaction();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -29,6 +29,7 @@ final class PhabricatorPHIDConstants {
|
|||
const PHID_TYPE_QUES = 'QUES';
|
||||
const PHID_TYPE_ANSW = 'ANSW';
|
||||
const PHID_TYPE_MOCK = 'MOCK';
|
||||
const PHID_TYPE_MCRO = 'MCRO';
|
||||
|
||||
const PHID_TYPE_XACT = 'XACT';
|
||||
const PHID_TYPE_XCMT = 'XCMT';
|
||||
|
|
|
@ -120,12 +120,25 @@ final class PhabricatorObjectHandleData {
|
|||
->execute();
|
||||
$xactions += mpull($results, null, 'getPHID');
|
||||
break;
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_MCRO:
|
||||
$results = id(new PhabricatorMacroTransactionQuery())
|
||||
->setViewer($this->viewer)
|
||||
->withPHIDs($subtype_phids)
|
||||
->execute();
|
||||
$xactions += mpull($results, null, 'getPHID');
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach ($xactions as $xaction) {
|
||||
$objects[$xaction->getPHID()] = $xaction;
|
||||
}
|
||||
break;
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_MCRO:
|
||||
$macros = id(new PhabricatorFileImageMacro())->loadAllWhere(
|
||||
'phid IN (%Ls)',
|
||||
$phids);
|
||||
$objects += mpull($macros, null, 'getPHID');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -601,6 +614,27 @@ final class PhabricatorObjectHandleData {
|
|||
$handles[$phid] = $handle;
|
||||
}
|
||||
break;
|
||||
case PhabricatorPHIDConstants::PHID_TYPE_MCRO:
|
||||
$macros = id(new PhabricatorFileImageMacro())->loadAllWhere(
|
||||
'phid IN (%Ls)',
|
||||
$phids);
|
||||
$macros = mpull($macros, null, 'getPHID');
|
||||
foreach ($phids as $phid) {
|
||||
$handle = new PhabricatorObjectHandle();
|
||||
$handle->setPHID($phid);
|
||||
$handle->setType($type);
|
||||
if (empty($macros[$phid])) {
|
||||
$handle->setName('Unknown Macro');
|
||||
} else {
|
||||
$macro = $macros[$phid];
|
||||
$handle->setName($macro->getName());
|
||||
$handle->setFullName('Image Macro "'.$macro->getName().'"');
|
||||
$handle->setURI('/macro/view/'.$macro->getID().'/');
|
||||
$handle->setComplete(true);
|
||||
}
|
||||
$handles[$phid] = $handle;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
$loader = null;
|
||||
if (isset($external_loaders[$type])) {
|
||||
|
|
|
@ -771,8 +771,6 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$story_type = $this->getFeedStoryType();
|
||||
$story_data = $this->getFeedStoryData($object, $xactions);
|
||||
|
||||
phlog($subscribed_phids);
|
||||
|
||||
id(new PhabricatorFeedStoryPublisher())
|
||||
->setStoryType($story_type)
|
||||
->setStoryData($story_data)
|
||||
|
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
abstract class PhabricatorApplicationTransaction
|
||||
extends PhabricatorLiskDAO
|
||||
implements PhabricatorPolicyInterface{
|
||||
|
||||
const MARKUP_FIELD_COMMENT = 'markup:comment';
|
||||
implements PhabricatorPolicyInterface {
|
||||
|
||||
const TARGET_TEXT = 'text';
|
||||
const TARGET_HTML = 'html';
|
||||
|
@ -17,7 +15,6 @@ abstract class PhabricatorApplicationTransaction
|
|||
|
||||
protected $commentPHID;
|
||||
protected $commentVersion = 0;
|
||||
|
||||
protected $transactionType;
|
||||
protected $oldValue;
|
||||
protected $newValue;
|
||||
|
@ -60,6 +57,10 @@ abstract class PhabricatorApplicationTransaction
|
|||
return PhabricatorContentSource::newFromSerialized($this->contentSource);
|
||||
}
|
||||
|
||||
public function hasComment() {
|
||||
return $this->getComment() && strlen($this->getComment()->getContent());
|
||||
}
|
||||
|
||||
public function getComment() {
|
||||
if ($this->commentNotLoaded) {
|
||||
throw new Exception("Comment for this transaction was not loaded.");
|
||||
|
@ -137,6 +138,16 @@ abstract class PhabricatorApplicationTransaction
|
|||
}
|
||||
|
||||
public function getIcon() {
|
||||
switch ($this->getTransactionType()) {
|
||||
case PhabricatorTransactions::TYPE_COMMENT:
|
||||
return 'comment';
|
||||
case PhabricatorTransactions::TYPE_SUBSCRIBERS:
|
||||
return 'message';
|
||||
case PhabricatorTransactions::TYPE_VIEW_POLICY:
|
||||
case PhabricatorTransactions::TYPE_EDIT_POLICY:
|
||||
return 'lock';
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ abstract class PhabricatorApplicationTransactionComment
|
|||
extends PhabricatorLiskDAO
|
||||
implements PhabricatorMarkupInterface, PhabricatorPolicyInterface {
|
||||
|
||||
const MARKUP_FIELD_COMMENT = 'markup:comment';
|
||||
|
||||
protected $transactionPHID;
|
||||
protected $commentVersion;
|
||||
protected $authorPHID;
|
||||
|
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* @concrete-extensible
|
||||
*/
|
||||
class PhabricatorApplicationTransactionView extends AphrontView {
|
||||
|
||||
private $viewer;
|
||||
private $transactions;
|
||||
private $engine;
|
||||
private $anchorOffset = 0;
|
||||
|
||||
public function setAnchorOffset($anchor_offset) {
|
||||
$this->anchorOffset = $anchor_offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setMarkupEngine(PhabricatorMarkupEngine $engine) {
|
||||
$this->engine = $engine;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setTransactions(array $transactions) {
|
||||
assert_instances_of($transactions, 'PhabricatorApplicationTransaction');
|
||||
$this->transactions = $transactions;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setViewer(PhabricatorUser $viewer) {
|
||||
$this->viewer = $viewer;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
$field = PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT;
|
||||
|
||||
if (!$this->engine) {
|
||||
$engine = id(new PhabricatorMarkupEngine())
|
||||
->setViewer($this->viewer);
|
||||
foreach ($this->transactions as $xaction) {
|
||||
if (!$xaction->hasComment()) {
|
||||
continue;
|
||||
}
|
||||
$engine->addObject($xaction->getComment(), $field);
|
||||
}
|
||||
$engine->process();
|
||||
|
||||
$this->engine = $engine;
|
||||
}
|
||||
|
||||
$view = new PhabricatorTimelineView();
|
||||
|
||||
$anchor = $this->anchorOffset;
|
||||
foreach ($this->transactions as $xaction) {
|
||||
if ($xaction->shouldHide()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$anchor++;
|
||||
$event = id(new PhabricatorTimelineEventView())
|
||||
->setViewer($this->viewer)
|
||||
->setUserHandle($xaction->getHandle($xaction->getAuthorPHID()))
|
||||
->setIcon($xaction->getIcon())
|
||||
->setColor($xaction->getColor())
|
||||
->setTitle($xaction->getTitle())
|
||||
->setDateCreated($xaction->getDateCreated())
|
||||
->setContentSource($xaction->getContentSource())
|
||||
->setAnchor($anchor);
|
||||
|
||||
if ($xaction->hasComment()) {
|
||||
$event->appendChild(
|
||||
$this->engine->getOutput($xaction->getComment(), $field));
|
||||
}
|
||||
|
||||
$view->addEvent($event);
|
||||
}
|
||||
|
||||
return $view->render();
|
||||
}
|
||||
}
|
||||
|
|
@ -108,6 +108,7 @@ final class PhabricatorEdgeConfig extends PhabricatorEdgeConstants {
|
|||
PhabricatorPHIDConstants::PHID_TYPE_QUES => 'PonderQuestion',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_ANSW => 'PonderAnswer',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_MOCK => 'PholioMock',
|
||||
PhabricatorPHIDConstants::PHID_TYPE_MCRO => 'PhabricatorFileImageMacro',
|
||||
|
||||
);
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@ final class PhabricatorRemarkupRuleImageMacro
|
|||
public function markupImageMacro($matches) {
|
||||
if ($this->images === null) {
|
||||
$this->images = array();
|
||||
$rows = id(new PhabricatorFileImageMacro())->loadAll();
|
||||
$rows = id(new PhabricatorFileImageMacro())->loadAllWhere(
|
||||
'isDisabled = 0');
|
||||
foreach ($rows as $row) {
|
||||
$this->images[$row->getName()] = $row->getFilePHID();
|
||||
}
|
||||
|
|
|
@ -1048,6 +1048,18 @@ final class PhabricatorBuiltinPatchList extends PhabricatorSQLPatchList {
|
|||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20121209.pholioxactions.sql'),
|
||||
),
|
||||
'20121209.xmacroadd.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20121209.xmacroadd.sql'),
|
||||
),
|
||||
'20121209.xmacromigrate.php' => array(
|
||||
'type' => 'php',
|
||||
'name' => $this->getPatchPath('20121209.xmacromigrate.php'),
|
||||
),
|
||||
'20121209.xmacromigratekey.sql' => array(
|
||||
'type' => 'sql',
|
||||
'name' => $this->getPatchPath('20121209.xmacromigratekey.sql'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ final class PhabricatorHeaderView extends AphrontView {
|
|||
|
||||
private $objectName;
|
||||
private $header;
|
||||
private $tags = array();
|
||||
|
||||
public function setHeader($header) {
|
||||
$this->header = $header;
|
||||
|
@ -15,6 +16,11 @@ final class PhabricatorHeaderView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function addTag(PhabricatorTagView $tag) {
|
||||
$this->tags[] = $tag;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
require_celerity_resource('phabricator-header-view-css');
|
||||
|
||||
|
@ -29,6 +35,15 @@ final class PhabricatorHeaderView extends AphrontView {
|
|||
phutil_escape_html($this->objectName)).' '.$header;
|
||||
}
|
||||
|
||||
if ($this->tags) {
|
||||
$header .= phutil_render_tag(
|
||||
'div',
|
||||
array(
|
||||
'class' => 'phabricator-header-tags',
|
||||
),
|
||||
self::renderSingleView($this->tags));
|
||||
}
|
||||
|
||||
return phutil_render_tag(
|
||||
'h1',
|
||||
array(
|
||||
|
|
|
@ -312,3 +312,8 @@
|
|||
.remarkup-assist-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.phabricator-image-macro-hero {
|
||||
margin: 2em auto;
|
||||
max-width: 90%;
|
||||
}
|
||||
|
|
|
@ -11,3 +11,8 @@
|
|||
.device-desktop .phabricator-header-view {
|
||||
width: 66%;
|
||||
}
|
||||
|
||||
.phabricator-header-tags {
|
||||
font-size: 13px;
|
||||
float: right;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue