diff --git a/resources/sql/patches/maniphestxcache.sql b/resources/sql/patches/maniphestxcache.sql new file mode 100644 index 0000000000..131bb52bc1 --- /dev/null +++ b/resources/sql/patches/maniphestxcache.sql @@ -0,0 +1,2 @@ +ALTER TABLE `{$NAMESPACE}_maniphest`.`maniphest_transaction` + DROP `cache`; diff --git a/scripts/util/purge_cache.php b/scripts/util/purge_cache.php index 45c91040c1..0a273a72a2 100755 --- a/scripts/util/purge_cache.php +++ b/scripts/util/purge_cache.php @@ -1,163 +1,143 @@ #!/usr/bin/env php establishConnection('w'), 'DELETE FROM %T WHERE id IN (%Ld)', DifferentialChangeset::TABLE_CACHE, $changesets); } else { echo "Purging changeset cache...\n"; queryfx( $table->establishConnection('w'), 'TRUNCATE TABLE %T', DifferentialChangeset::TABLE_CACHE); } echo "Done.\n"; } if ($purge_differential) { echo "Purging Differential comment cache...\n"; $table = new DifferentialComment(); queryfx( $table->establishConnection('w'), 'UPDATE %T SET cache = NULL', $table->getTableName()); echo "Purging Differential inline comment cache...\n"; $table = new DifferentialInlineComment(); queryfx( $table->establishConnection('w'), 'UPDATE %T SET cache = NULL', $table->getTableName()); echo "Done.\n"; } -if ($purge_maniphest) { - echo "Purging Maniphest comment cache...\n"; - $table = new ManiphestTransaction(); - queryfx( - $table->establishConnection('w'), - 'UPDATE %T SET cache = NULL', - $table->getTableName()); - echo "Done.\n"; -} - echo "Ok, caches purged.\n"; function usage($message) { echo "Usage Error: {$message}"; echo "\n\n"; echo "Run 'purge_cache.php --help' for detailed help.\n"; exit(1); } function help() { $help = <<getRequest(); $description = $request->getStr('description'); - $engine = PhabricatorMarkupEngine::newManiphestMarkupEngine(); + $task = new ManiphestTask(); + $task->setDescription($description); + + $output = PhabricatorMarkupEngine::renderOneObject( + $task, + ManiphestTask::MARKUP_FIELD_DESCRIPTION); $content = '
'. - $engine->markupText($description). + $output. '
'; return id(new AphrontAjaxResponse()) ->setContent($content); } } diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 6353a0f19f..311e537f13 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -1,530 +1,537 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTask())->load($workflow); } $transactions = id(new ManiphestTransaction())->loadAllWhere( 'taskID = %d ORDER BY id ASC', $task->getID()); $commit_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT); $phids = array_fill_keys($commit_phids, true); foreach ($transactions as $transaction) { foreach ($transaction->extractPHIDs() as $phid) { $phids[$phid] = true; } } foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); - $engine = PhabricatorMarkupEngine::newManiphestMarkupEngine(); - $dict = array(); $dict['Status'] = ''. ManiphestTaskStatus::getTaskStatusFullName($task->getStatus()). ''; $dict['Assigned To'] = $task->getOwnerPHID() ? $handles[$task->getOwnerPHID()]->renderLink() : 'None'; $dict['Priority'] = ManiphestTaskPriority::getTaskPriorityName( $task->getPriority()); $cc = $task->getCCPHIDs(); if ($cc) { $cc_links = array(); foreach ($cc as $phid) { $cc_links[] = $handles[$phid]->renderLink(); } $dict['CC'] = implode(', ', $cc_links); } else { $dict['CC'] = 'None'; } $dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink(); $source = $task->getOriginalEmailSource(); if ($source) { $subject = '[T'.$task->getID().'] '.$task->getTitle(); $dict['From Email'] = phutil_render_tag( 'a', array( 'href' => 'mailto:'.$source.'?subject='.$subject ), phutil_escape_html($source)); } $projects = $task->getProjectPHIDs(); if ($projects) { $project_links = array(); foreach ($projects as $phid) { $project_links[] = $handles[$phid]->renderLink(); } $dict['Projects'] = implode(', ', $project_links); } else { $dict['Projects'] = 'None'; } $extensions = ManiphestTaskExtensions::newExtensions(); $aux_fields = $extensions->getAuxiliaryFieldSpecifications(); if ($aux_fields) { $task->loadAndAttachAuxiliaryAttributes(); foreach ($aux_fields as $aux_field) { $aux_key = $aux_field->getAuxiliaryKey(); $aux_field->setValue($task->getAuxiliaryAttribute($aux_key)); $value = $aux_field->renderForDetailView(); if (strlen($value)) { $dict[$aux_field->getLabel()] = $value; } } } $dtasks = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_TASK); if ($dtasks) { $dtask_links = array(); foreach ($dtasks as $dtask => $info) { $dtask_links[] = $handles[$dtask]->renderLink(); } $dtask_links = implode('
', $dtask_links); $dict['Depends On'] = $dtask_links; } $revs = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_DREV); if ($revs) { $rev_links = array(); foreach ($revs as $rev => $info) { $rev_links[] = $handles[$rev]->renderLink(); } $rev_links = implode('
', $rev_links); $dict['Revisions'] = $rev_links; } if ($commit_phids) { $commit_links = array(); foreach ($commit_phids as $phid) { $commit_links[] = $handles[$phid]->renderLink(); } $commit_links = implode('
', $commit_links); $dict['Commits'] = $commit_links; } $file_infos = idx($attached, PhabricatorPHIDConstants::PHID_TYPE_FILE); if ($file_infos) { $file_phids = array_keys($file_infos); $files = id(new PhabricatorFile())->loadAllWhere( 'phid IN (%Ls)', $file_phids); $views = array(); foreach ($files as $file) { $view = new AphrontFilePreviewView(); $view->setFile($file); $views[] = $view->render(); } $dict['Files'] = implode('', $views); } $context_bar = null; if ($parent_task) { $context_bar = new AphrontContextBarView(); $context_bar->addButton( phutil_render_tag( 'a', array( 'href' => '/maniphest/task/create/?parent='.$parent_task->getID(), 'class' => 'green button', ), 'Create Another Subtask')); $context_bar->appendChild( 'Created a subtask of '. $handles[$parent_task->getPHID()]->renderLink(). ''); } else if ($workflow == 'create') { $context_bar = new AphrontContextBarView(); $context_bar->addButton(''); $context_bar->addButton( phutil_render_tag( 'a', array( 'href' => '/maniphest/task/create/?template='.$task->getID(), 'class' => 'green button', ), 'Similar Task')); $context_bar->addButton( phutil_render_tag( 'a', array( 'href' => '/maniphest/task/create/', 'class' => 'green button', ), 'Empty Task')); $context_bar->appendChild('New task created.'); } $actions = array(); $action = new AphrontHeadsupActionView(); $action->setName('Edit Task'); $action->setURI('/maniphest/task/edit/'.$task->getID().'/'); $action->setClass('action-edit'); $actions[] = $action; require_celerity_resource('phabricator-flag-css'); $flag = PhabricatorFlagQuery::loadUserFlag($user, $task->getPHID()); if ($flag) { $class = PhabricatorFlagColor::getCSSClass($flag->getColor()); $color = PhabricatorFlagColor::getColorName($flag->getColor()); $action = new AphrontHeadsupActionView(); $action->setClass('flag-clear '.$class); $action->setURI('/flag/delete/'.$flag->getID().'/'); $action->setName('Remove '.$color.' Flag'); $action->setWorkflow(true); $actions[] = $action; } else { $action = new AphrontHeadsupActionView(); $action->setClass('phabricator-flag-ghost'); $action->setURI('/flag/edit/'.$task->getPHID().'/'); $action->setName('Flag Task'); $action->setWorkflow(true); $actions[] = $action; } require_celerity_resource('phabricator-object-selector-css'); require_celerity_resource('javelin-behavior-phabricator-object-selector'); $action = new AphrontHeadsupActionView(); $action->setName('Merge Duplicates'); $action->setURI('/search/attach/'.$task->getPHID().'/TASK/merge/'); $action->setWorkflow(true); $action->setClass('action-merge'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Create Subtask'); $action->setURI('/maniphest/task/create/?parent='.$task->getID()); $action->setClass('action-branch'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Dependencies'); $action->setURI('/search/attach/'.$task->getPHID().'/TASK/dependencies/'); $action->setWorkflow(true); $action->setClass('action-dependencies'); $actions[] = $action; $action = new AphrontHeadsupActionView(); $action->setName('Edit Differential Revisions'); $action->setURI('/search/attach/'.$task->getPHID().'/DREV/'); $action->setWorkflow(true); $action->setClass('action-attach'); $actions[] = $action; $action_list = new AphrontHeadsupActionListView(); $action_list->setActions($actions); $headsup_panel = new AphrontHeadsupView(); $headsup_panel->setObjectName('T'.$task->getID()); $headsup_panel->setHeader($task->getTitle()); $headsup_panel->setActionList($action_list); $headsup_panel->setProperties($dict); + $engine = new PhabricatorMarkupEngine(); + $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); + foreach ($transactions as $xaction) { + if ($xaction->hasComments()) { + $engine->addObject($xaction, ManiphestTransaction::MARKUP_FIELD_BODY); + } + } + $engine->process(); + $headsup_panel->appendChild( '
'. - $engine->markupText($task->getDescription()). + $engine->getOutput($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION). '
'); $transaction_types = ManiphestTransactionType::getTransactionTypeMap(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); if ($task->getStatus() == ManiphestTaskStatus::STATUS_OPEN) { $resolution_types = array_select_keys( $resolution_types, array( ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, ManiphestTaskStatus::STATUS_CLOSED_INVALID, ManiphestTaskStatus::STATUS_CLOSED_SPITE, )); } else { $resolution_types = array( ManiphestTaskStatus::STATUS_OPEN => 'Reopened', ); $transaction_types[ManiphestTransactionType::TYPE_STATUS] = 'Reopen Task'; unset($transaction_types[ManiphestTransactionType::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransactionType::TYPE_OWNER]); } $default_claim = array( $user->getPHID() => $user->getUsername().' ('.$user->getRealName().')', ); $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $panel_id = celerity_generate_unique_node_id(); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { // Prevent tasks from being closed "out of spite" in serious business // installs. unset($resolution_types[ManiphestTaskStatus::STATUS_CLOSED_SPITE]); } $remarkup_href = PhabricatorEnv::getDoclink( 'article/Remarkup_Reference.html'); $comment_form = new AphrontFormView(); $comment_form ->setUser($user) ->setAction('/maniphest/transaction/save/') ->setEncType('multipart/form-data') ->addHiddenInput('taskID', $task->getID()) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Action') ->setName('action') ->setOptions($transaction_types) ->setID('transaction-action')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Resolution') ->setName('resolution') ->setControlID('resolution') ->setControlStyle('display: none') ->setOptions($resolution_types)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Assign To') ->setName('assign_to') ->setControlID('assign_to') ->setControlStyle('display: none') ->setID('assign-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('CCs') ->setName('ccs') ->setControlID('ccs') ->setControlStyle('display: none') ->setID('cc-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Priority') ->setName('priority') ->setOptions($priority_map) ->setControlID('priority') ->setControlStyle('display: none') ->setValue($task->getPriority())) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Projects') ->setName('projects') ->setControlID('projects') ->setControlStyle('display: none') ->setID('projects-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormFileControl()) ->setLabel('File') ->setName('file') ->setControlID('file') ->setControlStyle('display: none')) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Comments') ->setName('comments') ->setValue($draft_text) ->setCaption( phutil_render_tag( 'a', array( 'href' => $remarkup_href, 'tabindex' => '-1', 'target' => '_blank', ), 'Formatting Reference')) ->setID('transaction-comments')) ->appendChild( id(new AphrontFormDragAndDropUploadControl()) ->setLabel('Attached Files') ->setName('files') ->setDragAndDropTarget($panel_id) ->setActivatedClass('aphront-panel-view-drag-and-drop')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue($is_serious ? 'Submit' : 'Avast!')); $control_map = array( ManiphestTransactionType::TYPE_STATUS => 'resolution', ManiphestTransactionType::TYPE_OWNER => 'assign_to', ManiphestTransactionType::TYPE_CCS => 'ccs', ManiphestTransactionType::TYPE_PRIORITY => 'priority', ManiphestTransactionType::TYPE_PROJECTS => 'projects', ManiphestTransactionType::TYPE_ATTACH => 'file', ); $tokenizer_map = array( ManiphestTransactionType::TYPE_PROJECTS => array( 'id' => 'projects-tokenizer', 'src' => '/typeahead/common/projects/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a project name...', ), ManiphestTransactionType::TYPE_OWNER => array( 'id' => 'assign-tokenizer', 'src' => '/typeahead/common/users/', 'value' => $default_claim, 'limit' => 1, 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user name...', ), ManiphestTransactionType::TYPE_CCS => array( 'id' => 'cc-tokenizer', 'src' => '/typeahead/common/mailable/', 'ondemand' => PhabricatorEnv::getEnvConfig('tokenizer.ondemand'), 'placeholder' => 'Type a user or mailing list...', ), ); Javelin::initBehavior('maniphest-transaction-controls', array( 'select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map, )); Javelin::initBehavior('maniphest-transaction-preview', array( 'uri' => '/maniphest/transaction/preview/'.$task->getID().'/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map, )); $comment_panel = new AphrontPanelView(); $comment_panel->appendChild($comment_form); $comment_panel->setID($panel_id); $comment_panel->addClass('aphront-panel-accent'); $comment_panel->setHeader($is_serious ? 'Add Comment' : 'Weigh In'); $preview_panel = '
Loading preview...
'; $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setAuxiliaryFields($aux_fields); $transaction_view->setMarkupEngine($engine); PhabricatorFeedStoryNotification::updateObjectNotificationViews( $user, $task->getPHID()); return $this->buildStandardPageResponse( array( $context_bar, $headsup_panel, $transaction_view, $comment_panel, $preview_panel, ), array( 'title' => 'T'.$task->getID().' '.$task->getTitle(), 'pageObjects' => array($task->getPHID()), )); } } diff --git a/src/applications/maniphest/controller/ManiphestTransactionPreviewController.php b/src/applications/maniphest/controller/ManiphestTransactionPreviewController.php index cb9e3fcfed..94e6c49b0d 100644 --- a/src/applications/maniphest/controller/ManiphestTransactionPreviewController.php +++ b/src/applications/maniphest/controller/ManiphestTransactionPreviewController.php @@ -1,135 +1,137 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $comments = $request->getStr('comments'); $task = id(new ManiphestTask())->load($this->id); if (!$task) { return new Aphront404Response(); } $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if (!$draft) { $draft = new PhabricatorDraft(); $draft->setAuthorPHID($user->getPHID()); $draft->setDraftKey($task->getPHID()); } $draft->setDraft($comments); $draft->save(); $action = $request->getStr('action'); $transaction = new ManiphestTransaction(); $transaction->setAuthorPHID($user->getPHID()); $transaction->setComments($comments); $transaction->setTransactionType($action); $value = $request->getStr('value'); // grab phids for handles and set transaction values based on action and // value (empty or control-specific format) coming in from the wire switch ($action) { case ManiphestTransactionType::TYPE_PRIORITY: $transaction->setOldValue($task->getPriority()); $transaction->setNewValue($value); break; case ManiphestTransactionType::TYPE_OWNER: if ($value) { $value = current(json_decode($value)); $phids = array($value); } else { $phids = array(); } $transaction->setNewValue($value); break; case ManiphestTransactionType::TYPE_CCS: if ($value) { $value = json_decode($value); $phids = $value; foreach ($task->getCCPHIDs() as $cc_phid) { $phids[] = $cc_phid; $value[] = $cc_phid; } $transaction->setNewValue($value); } else { $phids = array(); $transaction->setNewValue(array()); } $transaction->setOldValue($task->getCCPHIDs()); break; case ManiphestTransactionType::TYPE_PROJECTS: if ($value) { $value = json_decode($value); $phids = $value; foreach ($task->getProjectPHIDs() as $project_phid) { $phids[] = $project_phid; $value[] = $project_phid; } $transaction->setNewValue($value); } else { $phids = array(); $transaction->setNewValue(array()); } $transaction->setOldValue($task->getProjectPHIDs()); break; default: $phids = array(); $transaction->setNewValue($value); break; } $phids[] = $user->getPHID(); $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $transactions = array(); $transactions[] = $transaction; - $engine = PhabricatorMarkupEngine::newManiphestMarkupEngine(); + $engine = new PhabricatorMarkupEngine(); + $engine->addObject($transaction, ManiphestTransaction::MARKUP_FIELD_BODY); + $engine->process(); $transaction_view = new ManiphestTransactionListView(); $transaction_view->setTransactions($transactions); $transaction_view->setHandles($handles); $transaction_view->setUser($user); $transaction_view->setMarkupEngine($engine); $transaction_view->setPreview(true); return id(new AphrontAjaxResponse()) ->setContent($transaction_view->render()); } } diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index cf0d88d77e..97a269d4f7 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -1,217 +1,268 @@ true, self::CONFIG_SERIALIZATION => array( 'ccPHIDs' => self::SERIALIZATION_JSON, 'attached' => self::SERIALIZATION_JSON, 'projectPHIDs' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function getAttachedPHIDs($type) { return array_keys(idx($this->attached, $type, array())); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_TASK); } public function getCCPHIDs() { return array_values(nonempty($this->ccPHIDs, array())); } public function setProjectPHIDs(array $phids) { $this->projectPHIDs = array_values($phids); $this->projectsNeedUpdate = true; return $this; } public function getProjectPHIDs() { return array_values(nonempty($this->projectPHIDs, array())); } public function setCCPHIDs(array $phids) { $this->ccPHIDs = array_values($phids); $this->subscribersNeedUpdate = true; return $this; } public function setOwnerPHID($phid) { $this->ownerPHID = $phid; $this->subscribersNeedUpdate = true; return $this; } public function getAuxiliaryAttribute($key, $default = null) { if ($this->auxiliaryAttributes === null) { throw new Exception("Attach auxiliary attributes before getting them!"); } return idx($this->auxiliaryAttributes, $key, $default); } public function setAuxiliaryAttribute($key, $val) { if ($this->auxiliaryAttributes === null) { throw new Exception("Attach auxiliary attributes before setting them!"); } $this->auxiliaryAttributes[$key] = $val; $this->auxiliaryDirty[$key] = true; return $this; } public function setTitle($title) { $this->title = $title; if (!$this->getID()) { $this->originalTitle = $title; } return $this; } public function attachAuxiliaryAttributes(array $attrs) { if ($this->auxiliaryDirty) { throw new Exception( "This object has dirty attributes, you can not attach new attributes ". "without writing or discarding the dirty attributes."); } $this->auxiliaryAttributes = $attrs; return $this; } public function loadAndAttachAuxiliaryAttributes() { if (!$this->getPHID()) { $this->auxiliaryAttributes = array(); return $this; } $storage = id(new ManiphestTaskAuxiliaryStorage())->loadAllWhere( 'taskPHID = %s', $this->getPHID()); $this->auxiliaryAttributes = mpull($storage, 'getValue', 'getName'); return $this; } public function save() { if (!$this->mailKey) { $this->mailKey = Filesystem::readRandomCharacters(20); } $result = parent::save(); if ($this->projectsNeedUpdate) { // If we've changed the project PHIDs for this task, update the link // table. ManiphestTaskProject::updateTaskProjects($this); $this->projectsNeedUpdate = false; } if ($this->subscribersNeedUpdate) { // If we've changed the subscriber PHIDs for this task, update the link // table. ManiphestTaskSubscriber::updateTaskSubscribers($this); $this->subscribersNeedUpdate = false; } if ($this->auxiliaryDirty) { $this->writeAuxiliaryUpdates(); $this->auxiliaryDirty = array(); } return $result; } private function writeAuxiliaryUpdates() { $table = new ManiphestTaskAuxiliaryStorage(); $conn_w = $table->establishConnection('w'); $update = array(); $remove = array(); foreach ($this->auxiliaryDirty as $key => $dirty) { $value = $this->getAuxiliaryAttribute($key); if ($value === null) { $remove[$key] = true; } else { $update[$key] = $value; } } if ($remove) { queryfx( $conn_w, 'DELETE FROM %T WHERE taskPHID = %s AND name IN (%Ls)', $table->getTableName(), $this->getPHID(), array_keys($remove)); } if ($update) { $sql = array(); foreach ($update as $key => $val) { $sql[] = qsprintf( $conn_w, '(%s, %s, %s)', $this->getPHID(), $key, $val); } queryfx( $conn_w, 'INSERT INTO %T (taskPHID, name, value) VALUES %Q ON DUPLICATE KEY UPDATE value = VALUES(value)', $table->getTableName(), implode(', ', $sql)); } } + +/* -( Markup Interface )--------------------------------------------------- */ + + + /** + * @task markup + */ + public function getMarkupFieldKey($field) { + $hash = PhabricatorHash::digest($this->getMarkupText($field)); + $id = $this->getID(); + return "maniphest:T{$id}:{$field}:{$hash}"; + } + + + /** + * @task markup + */ + public function getMarkupText($field) { + return $this->getDescription(); + } + + + /** + * @task markup + */ + public function newMarkupEngine($field) { + return PhabricatorMarkupEngine::newManiphestMarkupEngine(); + } + + + /** + * @task markup + */ + public function didMarkupText( + $field, + $output, + PhutilMarkupEngine $engine) { + return $output; + } + + + /** + * @task markup + */ + public function shouldUseMarkupCache($field) { + return (bool)$this->getID(); + } + } diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php index bbdd2c2756..c106e37904 100644 --- a/src/applications/maniphest/storage/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/ManiphestTransaction.php @@ -1,146 +1,200 @@ array( 'oldValue' => self::SERIALIZATION_JSON, 'newValue' => self::SERIALIZATION_JSON, 'metadata' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function extractPHIDs() { $phids = array(); switch ($this->getTransactionType()) { case ManiphestTransactionType::TYPE_CCS: case ManiphestTransactionType::TYPE_PROJECTS: foreach ($this->getOldValue() as $phid) { $phids[] = $phid; } foreach ($this->getNewValue() as $phid) { $phids[] = $phid; } break; case ManiphestTransactionType::TYPE_OWNER: $phids[] = $this->getOldValue(); $phids[] = $this->getNewValue(); break; case ManiphestTransactionType::TYPE_EDGE: $phids = array_merge( $phids, array_keys($this->getOldValue() + $this->getNewValue())); break; case ManiphestTransactionType::TYPE_ATTACH: $old = $this->getOldValue(); $new = $this->getNewValue(); if (!is_array($old)) { $old = array(); } if (!is_array($new)) { $new = array(); } $val = array_merge(array_values($old), array_values($new)); foreach ($val as $stuff) { foreach ($stuff as $phid => $ignored) { $phids[] = $phid; } } break; } $phids[] = $this->getAuthorPHID(); return $phids; } public function getMetadataValue($key, $default = null) { if (!is_array($this->metadata)) { return $default; } return idx($this->metadata, $key, $default); } public function setMetadataValue($key, $value) { if (!is_array($this->metadata)) { $this->metadata = array(); } $this->metadata[$key] = $value; return $this; } public function canGroupWith($target) { if ($target->getAuthorPHID() != $this->getAuthorPHID()) { return false; } if ($target->hasComments() && $this->hasComments()) { return false; } $ttime = $target->getDateCreated(); $stime = $this->getDateCreated(); if (abs($stime - $ttime) > 60) { return false; } if ($target->getTransactionType() == $this->getTransactionType()) { $aux_type = ManiphestTransactionType::TYPE_AUXILIARY; if ($this->getTransactionType() == $aux_type) { $that_key = $target->getMetadataValue('aux:key'); $this_key = $this->getMetadataValue('aux:key'); if ($that_key == $this_key) { return false; } } else { return false; } } return true; } public function hasComments() { return (bool)strlen(trim($this->getComments())); } public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source->serialize(); return $this; } public function getContentSource() { return PhabricatorContentSource::newFromSerialized($this->contentSource); } + +/* -( Markup Interface )--------------------------------------------------- */ + + + /** + * @task markup + */ + public function getMarkupFieldKey($field) { + if ($this->shouldUseMarkupCache($field)) { + $id = $this->getID(); + } else { + $id = PhabricatorHash::digest($this->getMarkupText($field)); + } + return "maniphest:x:{$field}:{$id}"; + } + + + /** + * @task markup + */ + public function getMarkupText($field) { + return $this->getComments(); + } + + + /** + * @task markup + */ + public function newMarkupEngine($field) { + return PhabricatorMarkupEngine::newManiphestMarkupEngine(); + } + + + /** + * @task markup + */ + public function didMarkupText( + $field, + $output, + PhutilMarkupEngine $engine) { + return $output; + } + + + /** + * @task markup + */ + public function shouldUseMarkupCache($field) { + return (bool)$this->getID(); + } + } diff --git a/src/applications/maniphest/view/ManiphestTransactionDetailView.php b/src/applications/maniphest/view/ManiphestTransactionDetailView.php index 8f8662e9e7..ccb4c7444f 100644 --- a/src/applications/maniphest/view/ManiphestTransactionDetailView.php +++ b/src/applications/maniphest/view/ManiphestTransactionDetailView.php @@ -1,776 +1,766 @@ auxiliaryFields = mpull($fields, null, 'getAuxiliaryKey'); return $this; } public function getAuxiliaryField($key) { return idx($this->auxiliaryFields, $key); } public function setTransactionGroup(array $transactions) { assert_instances_of($transactions, 'ManiphestTransaction'); $this->transactions = $transactions; return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } - public function setMarkupEngine(PhutilMarkupEngine $engine) { + public function setMarkupEngine(PhabricatorMarkupEngine $engine) { $this->markupEngine = $engine; return $this; } public function setPreview($preview) { $this->preview = $preview; return $this; } public function setRenderSummaryOnly($render_summary_only) { $this->renderSummaryOnly = $render_summary_only; return $this; } public function getRenderSummaryOnly() { return $this->renderSummaryOnly; } public function setRenderFullSummary($render_full_summary) { $this->renderFullSummary = $render_full_summary; return $this; } public function getRenderFullSummary() { return $this->renderFullSummary; } public function setCommentNumber($comment_number) { $this->commentNumber = $comment_number; return $this; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } public function setRangeSpecification($range) { $this->rangeSpecification = $range; return $this; } public function getRangeSpecification() { return $this->rangeSpecification; } public function renderForEmail($with_date) { $this->forEmail = true; $transaction = reset($this->transactions); $author = $this->renderHandles(array($transaction->getAuthorPHID())); $action = null; $descs = array(); $comments = null; foreach ($this->transactions as $transaction) { list($verb, $desc, $classes) = $this->describeAction($transaction); if ($desc === null) { continue; } if ($action === null) { $action = $verb; } $desc = $author.' '.$desc.'.'; if ($with_date) { // NOTE: This is going into a (potentially multi-recipient) email so // we can't use a single user's timezone preferences. Use the server's // instead, but make the timezone explicit. $datetime = date('M jS \a\t g:i A T', $transaction->getDateCreated()); $desc = "On {$datetime}, {$desc}"; } $descs[] = $desc; if ($transaction->hasComments()) { $comments = $transaction->getComments(); } } $descs = implode("\n", $descs); if ($comments) { $descs .= "\n".$comments; } foreach ($this->transactions as $transaction) { $supplemental = $this->renderSupplementalInfoForEmail($transaction); if ($supplemental) { $descs .= "\n\n".$supplemental; } } $this->forEmail = false; return array($action, $descs); } public function render() { if (!$this->user) { throw new Exception("Call setUser() before render()!"); } $handles = $this->handles; $transactions = $this->transactions; require_celerity_resource('maniphest-transaction-detail-css'); $comment_transaction = null; foreach ($this->transactions as $transaction) { if ($transaction->hasComments()) { $comment_transaction = $transaction; break; } } $any_transaction = reset($transactions); $author = $this->handles[$any_transaction->getAuthorPHID()]; $more_classes = array(); $descs = array(); foreach ($transactions as $transaction) { list($verb, $desc, $classes) = $this->describeAction($transaction); if ($desc === null) { continue; } $more_classes = array_merge($more_classes, $classes); $full_summary = null; if ($this->getRenderFullSummary()) { $full_summary = $this->renderFullSummary($transaction); } $descs[] = javelin_render_tag( 'div', array( 'sigil' => 'maniphest-transaction-description', ), $author->renderLink().' '.$desc.'.'.$full_summary); } if ($this->getRenderSummaryOnly()) { return implode("\n", $descs); } if ($comment_transaction && $comment_transaction->hasComments()) { - $comments = $comment_transaction->getCache(); - if (!strlen($comments)) { - $comments = $comment_transaction->getComments(); - if (strlen($comments)) { - $comments = $this->markupEngine->markupText($comments); - $comment_transaction->setCache($comments); - if ($comment_transaction->getID() && !$this->preview) { - $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); - $comment_transaction->save(); - unset($unguarded); - } - } - } + $comment_block = $this->markupEngine->getOutput( + $comment_transaction, + ManiphestTransaction::MARKUP_FIELD_BODY); $comment_block = '
'. - $comments. + $comment_block. '
'; } else { $comment_block = null; } $source_transaction = nonempty($comment_transaction, $any_transaction); $xaction_view = id(new PhabricatorTransactionView()) ->setUser($this->user) ->setImageURI($author->getImageURI()) ->setContentSource($source_transaction->getContentSource()) ->setActions($descs); foreach ($more_classes as $class) { $xaction_view->addClass($class); } if ($this->preview) { $xaction_view->setIsPreview($this->preview); } else { $xaction_view->setEpoch($any_transaction->getDateCreated()); if ($this->commentNumber) { $anchor_name = 'comment-'.$this->commentNumber; $anchor_text = 'T'.$any_transaction->getTaskID().'#'.$anchor_name; $xaction_view->setAnchor($anchor_name, $anchor_text); } } $xaction_view->appendChild($comment_block); return $xaction_view->render(); } private function renderSupplementalInfoForEmail($transaction) { $handles = $this->handles; $type = $transaction->getTransactionType(); $new = $transaction->getNewValue(); $old = $transaction->getOldValue(); switch ($type) { case ManiphestTransactionType::TYPE_DESCRIPTION: return "NEW DESCRIPTION\n ".trim($new)."\n\n". "PREVIOUS DESCRIPTION\n ".trim($old); case ManiphestTransactionType::TYPE_ATTACH: $old_raw = nonempty($old, array()); $new_raw = nonempty($new, array()); $attach_types = array( PhabricatorPHIDConstants::PHID_TYPE_DREV, PhabricatorPHIDConstants::PHID_TYPE_FILE, ); foreach ($attach_types as $attach_type) { $old = array_keys(idx($old_raw, $attach_type, array())); $new = array_keys(idx($new_raw, $attach_type, array())); if ($old != $new) { break; } } $added = array_diff($new, $old); if (!$added) { break; } $links = array(); foreach (array_select_keys($handles, $added) as $handle) { $links[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI()); } $links = implode("\n", $links); switch ($attach_type) { case PhabricatorPHIDConstants::PHID_TYPE_DREV: $title = 'ATTACHED REVISIONS'; break; case PhabricatorPHIDConstants::PHID_TYPE_FILE: $title = 'ATTACHED FILES'; break; } return $title."\n".$links; case ManiphestTransactionType::TYPE_EDGE: $add = array_diff_key($new, $old); if (!$add) { break; } $links = array(); foreach ($add as $phid => $ignored) { $handle = $handles[$phid]; $links[] = ' '.PhabricatorEnv::getProductionURI($handle->getURI()); } $links = implode("\n", $links); $edge_type = $transaction->getMetadataValue('edge:type'); $title = $this->getEdgeEmailTitle($edge_type, $add); return $title."\n".$links; default: break; } return null; } private function describeAction($transaction) { $verb = null; $desc = null; $classes = array(); $handles = $this->handles; $type = $transaction->getTransactionType(); $author_phid = $transaction->getAuthorPHID(); $new = $transaction->getNewValue(); $old = $transaction->getOldValue(); switch ($type) { case ManiphestTransactionType::TYPE_TITLE: $verb = 'Retitled'; $desc = 'changed the title from '.$this->renderString($old). ' to '.$this->renderString($new); break; case ManiphestTransactionType::TYPE_DESCRIPTION: $verb = 'Edited'; if ($this->forEmail || $this->getRenderFullSummary()) { $desc = 'updated the task description'; } else { $desc = 'updated the task description; '. $this->renderExpandLink($transaction); } break; case ManiphestTransactionType::TYPE_NONE: $verb = 'Commented On'; $desc = 'added a comment'; break; case ManiphestTransactionType::TYPE_OWNER: if ($transaction->getAuthorPHID() == $new) { $verb = 'Claimed'; $desc = 'claimed this task'; $classes[] = 'claimed'; } else if (!$new) { $verb = 'Up For Grabs'; $desc = 'placed this task up for grabs'; $classes[] = 'upforgrab'; } else if (!$old) { $verb = 'Assigned'; $desc = 'assigned this task to '.$this->renderHandles(array($new)); $classes[] = 'assigned'; } else { $verb = 'Reassigned'; $desc = 'reassigned this task from '. $this->renderHandles(array($old)). ' to '. $this->renderHandles(array($new)); $classes[] = 'reassigned'; } break; case ManiphestTransactionType::TYPE_CCS: $added = array_diff($new, $old); $removed = array_diff($old, $new); // can only add in preview so just show placeholder if nothing to add if ($this->preview && empty($added)) { $verb = 'Changed CC'; $desc = 'changed CCs..'; break; } if ($added && !$removed) { $verb = 'Added CC'; if (count($added) == 1) { $desc = 'added '.$this->renderHandles($added).' to CC'; } else { $desc = 'added CCs: '.$this->renderHandles($added); } } else if ($removed && !$added) { $verb = 'Removed CC'; if (count($removed) == 1) { $desc = 'removed '.$this->renderHandles($removed).' from CC'; } else { $desc = 'removed CCs: '.$this->renderHandles($removed); } } else { $verb = 'Changed CC'; $desc = 'changed CCs, added: '.$this->renderHandles($added).'; '. 'removed: '.$this->renderHandles($removed); } break; case ManiphestTransactionType::TYPE_EDGE: $edge_type = $transaction->getMetadataValue('edge:type'); $add = array_diff_key($new, $old); $rem = array_diff_key($old, $new); if ($add && !$rem) { $verb = $this->getEdgeAddVerb($edge_type); $desc = $this->getEdgeAddList($edge_type, $add); } else if ($rem && !$add) { $verb = $this->getEdgeRemVerb($edge_type); $desc = $this->getEdgeRemList($edge_type, $rem); } else { $verb = $this->getEdgeEditVerb($edge_type); $desc = $this->getEdgeEditList($edge_type, $add, $rem); } break; case ManiphestTransactionType::TYPE_PROJECTS: $added = array_diff($new, $old); $removed = array_diff($old, $new); // can only add in preview so just show placeholder if nothing to add if ($this->preview && empty($added)) { $verb = 'Changed Projects'; $desc = 'changed projects..'; break; } if ($added && !$removed) { $verb = 'Added Project'; if (count($added) == 1) { $desc = 'added project '.$this->renderHandles($added); } else { $desc = 'added projects: '.$this->renderHandles($added); } } else if ($removed && !$added) { $verb = 'Removed Project'; if (count($removed) == 1) { $desc = 'removed project '.$this->renderHandles($removed); } else { $desc = 'removed projects: '.$this->renderHandles($removed); } } else { $verb = 'Changed Projects'; $desc = 'changed projects, added: '.$this->renderHandles($added).'; '. 'removed: '.$this->renderHandles($removed); } break; case ManiphestTransactionType::TYPE_STATUS: if ($new == ManiphestTaskStatus::STATUS_OPEN) { if ($old) { $verb = 'Reopened'; $desc = 'reopened this task'; $classes[] = 'reopened'; } else { $verb = 'Created'; $desc = 'created this task'; $classes[] = 'created'; } } else if ($new == ManiphestTaskStatus::STATUS_CLOSED_SPITE) { $verb = 'Spited'; $desc = 'closed this task out of spite'; $classes[] = 'spited'; } else if ($new == ManiphestTaskStatus::STATUS_CLOSED_DUPLICATE) { $verb = 'Merged'; $desc = 'closed this task as a duplicate'; $classes[] = 'duplicate'; } else { $verb = 'Closed'; $full = idx(ManiphestTaskStatus::getTaskStatusMap(), $new, '???'); $desc = 'closed this task as "'.$full.'"'; $classes[] = 'closed'; } break; case ManiphestTransactionType::TYPE_PRIORITY: $old_name = ManiphestTaskPriority::getTaskPriorityName($old); $new_name = ManiphestTaskPriority::getTaskPriorityName($new); if ($old == ManiphestTaskPriority::PRIORITY_TRIAGE) { $verb = 'Triaged'; $desc = 'triaged this task as "'.$new_name.'" priority'; } else if ($old > $new) { $verb = 'Lowered Priority'; $desc = 'lowered the priority of this task from "'.$old_name.'" to '. '"'.$new_name.'"'; } else { $verb = 'Raised Priority'; $desc = 'raised the priority of this task from "'.$old_name.'" to '. '"'.$new_name.'"'; } if ($new == ManiphestTaskPriority::PRIORITY_UNBREAK_NOW) { $classes[] = 'unbreaknow'; } break; case ManiphestTransactionType::TYPE_ATTACH: if ($this->preview) { $verb = 'Changed Attached'; $desc = 'changed attachments..'; break; } $old_raw = nonempty($old, array()); $new_raw = nonempty($new, array()); foreach (array( PhabricatorPHIDConstants::PHID_TYPE_DREV, PhabricatorPHIDConstants::PHID_TYPE_TASK, PhabricatorPHIDConstants::PHID_TYPE_FILE) as $attach_type) { $old = array_keys(idx($old_raw, $attach_type, array())); $new = array_keys(idx($new_raw, $attach_type, array())); if ($old != $new) { break; } } $added = array_diff($new, $old); $removed = array_diff($old, $new); $add_desc = $this->renderHandles($added); $rem_desc = $this->renderHandles($removed); if ($added && !$removed) { $verb = 'Attached'; $desc = 'attached '. $this->getAttachName($attach_type, count($added)).': '. $add_desc; } else if ($removed && !$added) { $verb = 'Detached'; $desc = 'detached '. $this->getAttachName($attach_type, count($removed)).': '. $rem_desc; } else { $verb = 'Changed Attached'; $desc = 'changed attached '. $this->getAttachName($attach_type, count($added) + count($removed)). ', added: '.$add_desc.'; '. 'removed: '.$rem_desc; } break; case ManiphestTransactionType::TYPE_AUXILIARY: $aux_key = $transaction->getMetadataValue('aux:key'); $aux_field = $this->getAuxiliaryField($aux_key); $verb = null; if ($aux_field) { $verb = $aux_field->renderTransactionEmailVerb($transaction); } if ($verb === null) { if ($old === null) { $verb = "Set Field"; } else if ($new === null) { $verb = "Removed Field"; } else { $verb = "Updated Field"; } } $desc = null; if ($aux_field) { $use_field = $aux_field; } else { $use_field = id(new ManiphestAuxiliaryFieldDefaultSpecification()) ->setFieldType( ManiphestAuxiliaryFieldDefaultSpecification::TYPE_STRING); } $desc = $use_field->renderTransactionDescription( $transaction, $this->forEmail ? ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_TEXT : ManiphestAuxiliaryFieldSpecification::RENDER_TARGET_HTML); break; default: return array($type, ' brazenly '.$type."'d", $classes); } return array($verb, $desc, $classes); } private function renderFullSummary($transaction) { switch ($transaction->getTransactionType()) { case ManiphestTransactionType::TYPE_DESCRIPTION: $id = $transaction->getID(); $old_text = wordwrap($transaction->getOldValue(), 80); $new_text = wordwrap($transaction->getNewValue(), 80); $engine = new PhabricatorDifferenceEngine(); $changeset = $engine->generateChangesetFromFileContent($old_text, $new_text); $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL; $parser = new DifferentialChangesetParser(); $parser->setChangeset($changeset); $parser->setRenderingReference($id); $parser->setWhitespaceMode($whitespace_mode); $spec = $this->getRangeSpecification(); list($range_s, $range_e, $mask) = DifferentialChangesetParser::parseRangeSpecification($spec); $output = $parser->render($range_s, $range_e, $mask); return $output; } return null; } private function renderExpandLink($transaction) { $id = $transaction->getID(); Javelin::initBehavior('maniphest-transaction-expand'); return javelin_render_tag( 'a', array( 'href' => '/maniphest/task/descriptionchange/'.$id.'/', 'sigil' => 'maniphest-expand-transaction', 'mustcapture' => true, ), 'show details'); } private function renderHandles($phids) { $links = array(); foreach ($phids as $phid) { if ($this->forEmail) { $links[] = $this->handles[$phid]->getName(); } else { $links[] = $this->handles[$phid]->renderLink(); } } return implode(', ', $links); } private function renderString($string) { if ($this->forEmail) { return '"'.$string.'"'; } else { return '"'.phutil_escape_html($string).'"'; } } /* -( Strings )------------------------------------------------------------ */ /** * @task strings */ private function getAttachName($attach_type, $count) { switch ($attach_type) { case PhabricatorPHIDConstants::PHID_TYPE_DREV: return pht('Differential Revision(s)', $count); case PhabricatorPHIDConstants::PHID_TYPE_FILE: return pht('file(s)', $count); case PhabricatorPHIDConstants::PHID_TYPE_TASK: return pht('Maniphest Task(s)', $count); } } private function getEdgeEmailTitle($type, $count) { switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht('ATTACHED %d COMMIT(S)', $count); default: return pht('ATTACHED %d OBJECT(S)', $count); } } /** * @task strings */ private function getEdgeAddVerb($type) { switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht('Added Commit'); default: return pht('Added Object'); } } /** * @task strings */ private function getEdgeRemVerb($type) { switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht('Removed Commit'); default: return pht('Removed Object'); } } /** * @task strings */ private function getEdgeEditVerb($type) { switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht('Changed Commits'); default: return pht('Changed Objects'); } } /** * @task strings */ private function getEdgeAddList($type, array $add) { $list = $this->renderHandles(array_keys($add)); switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht('added %d commit(s): %s', $add, $list); default: return pht('added %d object(s): %s', $add, $list); } } /** * @task strings */ private function getEdgeRemList($type, array $rem) { $list = $this->renderHandles(array_keys($rem)); switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht('removed %d commit(s): %s', $rem, $list); default: return pht('removed %d object(s): %s', $rem, $list); } } /** * @task strings */ private function getEdgeEditList($type, array $add, array $rem) { $add_list = $this->renderHandles(array_keys($add)); $rem_list = $this->renderHandles(array_keys($rem)); switch ($type) { case PhabricatorEdgeConfig::TYPE_TASK_HAS_COMMIT: return pht( 'changed %d commit(s), added %d: %s; removed %d: %s', count($add) + count($rem), $add, $add_list, $rem, $rem_list); default: return pht( 'changed %d object(s), added %d: %s; removed %d: %s', count($add) + count($rem), $add, $add_list, $rem, $rem_list); } } } diff --git a/src/applications/maniphest/view/ManiphestTransactionListView.php b/src/applications/maniphest/view/ManiphestTransactionListView.php index 3ecda00487..001eee94c5 100644 --- a/src/applications/maniphest/view/ManiphestTransactionListView.php +++ b/src/applications/maniphest/view/ManiphestTransactionListView.php @@ -1,133 +1,133 @@ transactions = $transactions; return $this; } public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function setUser(PhabricatorUser $user) { $this->user = $user; return $this; } - public function setMarkupEngine(PhutilMarkupEngine $engine) { + public function setMarkupEngine(PhabricatorMarkupEngine $engine) { $this->markupEngine = $engine; return $this; } public function setPreview($preview) { $this->preview = $preview; return $this; } public function setAuxiliaryFields(array $fields) { assert_instances_of($fields, 'ManiphestAuxiliaryFieldSpecification'); $this->auxiliaryFields = $fields; return $this; } private function getAuxiliaryFields() { if (empty($this->auxiliaryFields)) { return array(); } return $this->auxiliaryFields; } public function render() { $views = array(); $last = null; $group = array(); $groups = array(); $has_description_transaction = false; foreach ($this->transactions as $transaction) { if ($transaction->getTransactionType() == ManiphestTransactionType::TYPE_DESCRIPTION) { $has_description_transaction = true; } if ($last === null) { $last = $transaction; $group[] = $transaction; continue; } else if ($last->canGroupWith($transaction)) { $group[] = $transaction; if ($transaction->hasComments()) { $last = $transaction; } } else { $groups[] = $group; $last = $transaction; $group = array($transaction); } } if ($group) { $groups[] = $group; } if ($has_description_transaction) { require_celerity_resource('differential-changeset-view-css'); require_celerity_resource('syntax-highlighting-css'); $whitespace_mode = DifferentialChangesetParser::WHITESPACE_SHOW_ALL; Javelin::initBehavior('differential-show-more', array( 'uri' => '/maniphest/task/descriptionchange/', 'whitespace' => $whitespace_mode, )); } $sequence = 1; foreach ($groups as $group) { $view = new ManiphestTransactionDetailView(); $view->setUser($this->user); $view->setAuxiliaryFields($this->getAuxiliaryFields()); $view->setTransactionGroup($group); $view->setHandles($this->handles); $view->setMarkupEngine($this->markupEngine); $view->setPreview($this->preview); $view->setCommentNumber($sequence++); $views[] = $view->render(); } return '
'. implode("\n", $views). '
'; } } diff --git a/src/infrastructure/markup/rule/PhabricatorRemarkupRuleImageMacro.php b/src/infrastructure/markup/rule/PhabricatorRemarkupRuleImageMacro.php index 96248b38a1..714c539152 100644 --- a/src/infrastructure/markup/rule/PhabricatorRemarkupRuleImageMacro.php +++ b/src/infrastructure/markup/rule/PhabricatorRemarkupRuleImageMacro.php @@ -1,65 +1,66 @@ loadAll(); - foreach ($rows as $row) { - $this->images[$row->getName()] = $row->getFilePHID(); - } - } - public function apply($text) { return preg_replace_callback( '@^([a-zA-Z0-9_\-]+)$@m', array($this, 'markupImageMacro'), $text); } public function markupImageMacro($matches) { + if ($this->images === null) { + $this->images = array(); + $rows = id(new PhabricatorFileImageMacro())->loadAll(); + foreach ($rows as $row) { + $this->images[$row->getName()] = $row->getFilePHID(); + } + } + if (array_key_exists($matches[1], $this->images)) { $phid = $this->images[$matches[1]]; $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $phid); if ($file) { $src_uri = $file->getBestURI(); } else { $src_uri = null; } $img = phutil_render_tag( 'img', array( 'src' => $src_uri, 'alt' => $matches[1], 'title' => $matches[1]), null); return $this->getEngine()->storeText($img); } else { return $matches[1]; } } } diff --git a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php index b67804920d..e4138845b8 100644 --- a/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php +++ b/src/infrastructure/storage/patch/PhabricatorBuiltinPatchList.php @@ -1,917 +1,921 @@ array( 'type' => 'db', 'name' => 'audit', 'after' => array( /* First Patch */ ), ), 'db.calendar' => array( 'type' => 'db', 'name' => 'calendar', ), 'db.chatlog' => array( 'type' => 'db', 'name' => 'chatlog', ), 'db.conduit' => array( 'type' => 'db', 'name' => 'conduit', ), 'db.countdown' => array( 'type' => 'db', 'name' => 'countdown', ), 'db.daemon' => array( 'type' => 'db', 'name' => 'daemon', ), 'db.differential' => array( 'type' => 'db', 'name' => 'differential', ), 'db.draft' => array( 'type' => 'db', 'name' => 'draft', ), 'db.drydock' => array( 'type' => 'db', 'name' => 'drydock', ), 'db.feed' => array( 'type' => 'db', 'name' => 'feed', ), 'db.file' => array( 'type' => 'db', 'name' => 'file', ), 'db.flag' => array( 'type' => 'db', 'name' => 'flag', ), 'db.harbormaster' => array( 'type' => 'db', 'name' => 'harbormaster', ), 'db.herald' => array( 'type' => 'db', 'name' => 'herald', ), 'db.maniphest' => array( 'type' => 'db', 'name' => 'maniphest', ), 'db.meta_data' => array( 'type' => 'db', 'name' => 'meta_data', ), 'db.metamta' => array( 'type' => 'db', 'name' => 'metamta', ), 'db.oauth_server' => array( 'type' => 'db', 'name' => 'oauth_server', ), 'db.owners' => array( 'type' => 'db', 'name' => 'owners', ), 'db.pastebin' => array( 'type' => 'db', 'name' => 'pastebin', ), 'db.phame' => array( 'type' => 'db', 'name' => 'phame', ), 'db.phriction' => array( 'type' => 'db', 'name' => 'phriction', ), 'db.project' => array( 'type' => 'db', 'name' => 'project', ), 'db.repository' => array( 'type' => 'db', 'name' => 'repository', ), 'db.search' => array( 'type' => 'db', 'name' => 'search', ), 'db.slowvote' => array( 'type' => 'db', 'name' => 'slowvote', ), 'db.timeline' => array( 'type' => 'db', 'name' => 'timeline', ), 'db.user' => array( 'type' => 'db', 'name' => 'user', ), 'db.worker' => array( 'type' => 'db', 'name' => 'worker', ), 'db.xhpastview' => array( 'type' => 'db', 'name' => 'xhpastview', ), 'db.cache' => array( 'type' => 'db', 'name' => 'cache', ), '0000.legacy.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('0000.legacy.sql'), 'legacy' => 0, ), '000.project.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('000.project.sql'), 'legacy' => 0, ), '001.maniphest_projects.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('001.maniphest_projects.sql'), 'legacy' => 1, ), '002.oauth.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('002.oauth.sql'), 'legacy' => 2, ), '003.more_oauth.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('003.more_oauth.sql'), 'legacy' => 3, ), '004.daemonrepos.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('004.daemonrepos.sql'), 'legacy' => 4, ), '005.workers.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('005.workers.sql'), 'legacy' => 5, ), '006.repository.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('006.repository.sql'), 'legacy' => 6, ), '007.daemonlog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('007.daemonlog.sql'), 'legacy' => 7, ), '008.repoopt.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('008.repoopt.sql'), 'legacy' => 8, ), '009.repo_summary.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('009.repo_summary.sql'), 'legacy' => 9, ), '010.herald.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('010.herald.sql'), 'legacy' => 10, ), '011.badcommit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('011.badcommit.sql'), 'legacy' => 11, ), '012.dropphidtype.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('012.dropphidtype.sql'), 'legacy' => 12, ), '013.commitdetail.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('013.commitdetail.sql'), 'legacy' => 13, ), '014.shortcuts.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('014.shortcuts.sql'), 'legacy' => 14, ), '015.preferences.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('015.preferences.sql'), 'legacy' => 15, ), '016.userrealnameindex.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('016.userrealnameindex.sql'), 'legacy' => 16, ), '017.sessionkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('017.sessionkeys.sql'), 'legacy' => 17, ), '018.owners.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('018.owners.sql'), 'legacy' => 18, ), '019.arcprojects.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('019.arcprojects.sql'), 'legacy' => 19, ), '020.pathcapital.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('020.pathcapital.sql'), 'legacy' => 20, ), '021.xhpastview.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('021.xhpastview.sql'), 'legacy' => 21, ), '022.differentialcommit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('022.differentialcommit.sql'), 'legacy' => 22, ), '023.dxkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('023.dxkeys.sql'), 'legacy' => 23, ), '024.mlistkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('024.mlistkeys.sql'), 'legacy' => 24, ), '025.commentopt.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('025.commentopt.sql'), 'legacy' => 25, ), '026.diffpropkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('026.diffpropkey.sql'), 'legacy' => 26, ), '027.metamtakeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('027.metamtakeys.sql'), 'legacy' => 27, ), '028.systemagent.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('028.systemagent.sql'), 'legacy' => 28, ), '029.cursors.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('029.cursors.sql'), 'legacy' => 29, ), '030.imagemacro.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('030.imagemacro.sql'), 'legacy' => 30, ), '031.workerrace.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('031.workerrace.sql'), 'legacy' => 31, ), '032.viewtime.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('032.viewtime.sql'), 'legacy' => 32, ), '033.privtest.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('033.privtest.sql'), 'legacy' => 33, ), '034.savedheader.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('034.savedheader.sql'), 'legacy' => 34, ), '035.proxyimage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('035.proxyimage.sql'), 'legacy' => 35, ), '036.mailkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('036.mailkey.sql'), 'legacy' => 36, ), '037.setuptest.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('037.setuptest.sql'), 'legacy' => 37, ), '038.admin.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('038.admin.sql'), 'legacy' => 38, ), '039.userlog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('039.userlog.sql'), 'legacy' => 39, ), '040.transform.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('040.transform.sql'), 'legacy' => 40, ), '041.heraldrepetition.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('041.heraldrepetition.sql'), 'legacy' => 41, ), '042.commentmetadata.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('042.commentmetadata.sql'), 'legacy' => 42, ), '043.pastebin.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('043.pastebin.sql'), 'legacy' => 43, ), '044.countdown.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('044.countdown.sql'), 'legacy' => 44, ), '045.timezone.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('045.timezone.sql'), 'legacy' => 45, ), '046.conduittoken.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('046.conduittoken.sql'), 'legacy' => 46, ), '047.projectstatus.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('047.projectstatus.sql'), 'legacy' => 47, ), '048.relationshipkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('048.relationshipkeys.sql'), 'legacy' => 48, ), '049.projectowner.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('049.projectowner.sql'), 'legacy' => 49, ), '050.taskdenormal.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('050.taskdenormal.sql'), 'legacy' => 50, ), '051.projectfilter.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('051.projectfilter.sql'), 'legacy' => 51, ), '052.pastelanguage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('052.pastelanguage.sql'), 'legacy' => 52, ), '053.feed.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('053.feed.sql'), 'legacy' => 53, ), '054.subscribers.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('054.subscribers.sql'), 'legacy' => 54, ), '055.add_author_to_files.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('055.add_author_to_files.sql'), 'legacy' => 55, ), '056.slowvote.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('056.slowvote.sql'), 'legacy' => 56, ), '057.parsecache.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('057.parsecache.sql'), 'legacy' => 57, ), '058.missingkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('058.missingkeys.sql'), 'legacy' => 58, ), '059.engines.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('059.engines.php'), 'legacy' => 59, ), '060.phriction.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('060.phriction.sql'), 'legacy' => 60, ), '061.phrictioncontent.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('061.phrictioncontent.sql'), 'legacy' => 61, ), '062.phrictionmenu.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('062.phrictionmenu.sql'), 'legacy' => 62, ), '063.pasteforks.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('063.pasteforks.sql'), 'legacy' => 63, ), '064.subprojects.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('064.subprojects.sql'), 'legacy' => 64, ), '065.sshkeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('065.sshkeys.sql'), 'legacy' => 65, ), '066.phrictioncontent.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('066.phrictioncontent.sql'), 'legacy' => 66, ), '067.preferences.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('067.preferences.sql'), 'legacy' => 67, ), '068.maniphestauxiliarystorage.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('068.maniphestauxiliarystorage.sql'), 'legacy' => 68, ), '069.heraldxscript.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('069.heraldxscript.sql'), 'legacy' => 69, ), '070.differentialaux.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('070.differentialaux.sql'), 'legacy' => 70, ), '071.contentsource.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('071.contentsource.sql'), 'legacy' => 71, ), '072.blamerevert.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('072.blamerevert.sql'), 'legacy' => 72, ), '073.reposymbols.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('073.reposymbols.sql'), 'legacy' => 73, ), '074.affectedpath.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('074.affectedpath.sql'), 'legacy' => 74, ), '075.revisionhash.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('075.revisionhash.sql'), 'legacy' => 75, ), '076.indexedlanguages.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('076.indexedlanguages.sql'), 'legacy' => 76, ), '077.originalemail.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('077.originalemail.sql'), 'legacy' => 77, ), '078.nametoken.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('078.nametoken.sql'), 'legacy' => 78, ), '079.nametokenindex.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('079.nametokenindex.php'), 'legacy' => 79, ), '080.filekeys.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('080.filekeys.sql'), 'legacy' => 80, ), '081.filekeys.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('081.filekeys.php'), 'legacy' => 81, ), '082.xactionkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('082.xactionkey.sql'), 'legacy' => 82, ), '083.dxviewtime.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('083.dxviewtime.sql'), 'legacy' => 83, ), '084.pasteauthorkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('084.pasteauthorkey.sql'), 'legacy' => 84, ), '085.packagecommitrelationship.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('085.packagecommitrelationship.sql'), 'legacy' => 85, ), '086.formeraffil.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('086.formeraffil.sql'), 'legacy' => 86, ), '087.phrictiondelete.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('087.phrictiondelete.sql'), 'legacy' => 87, ), '088.audit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('088.audit.sql'), 'legacy' => 88, ), '089.projectwiki.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('089.projectwiki.sql'), 'legacy' => 89, ), '090.forceuniqueprojectnames.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('090.forceuniqueprojectnames.php'), 'legacy' => 90, ), '091.uniqueslugkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('091.uniqueslugkey.sql'), 'legacy' => 91, ), '092.dropgithubnotification.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('092.dropgithubnotification.sql'), 'legacy' => 92, ), '093.gitremotes.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('093.gitremotes.php'), 'legacy' => 93, ), '094.phrictioncolumn.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('094.phrictioncolumn.sql'), 'legacy' => 94, ), '095.directory.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('095.directory.sql'), 'legacy' => 95, ), '096.filename.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('096.filename.sql'), 'legacy' => 96, ), '097.heraldruletypes.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('097.heraldruletypes.sql'), 'legacy' => 97, ), '098.heraldruletypemigration.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('098.heraldruletypemigration.php'), 'legacy' => 98, ), '099.drydock.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('099.drydock.sql'), 'legacy' => 99, ), '100.projectxaction.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('100.projectxaction.sql'), 'legacy' => 100, ), '101.heraldruleapplied.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('101.heraldruleapplied.sql'), 'legacy' => 101, ), '102.heraldcleanup.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('102.heraldcleanup.php'), 'legacy' => 102, ), '103.heraldedithistory.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('103.heraldedithistory.sql'), 'legacy' => 103, ), '104.searchkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('104.searchkey.sql'), 'legacy' => 104, ), '105.mimetype.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('105.mimetype.sql'), 'legacy' => 105, ), '106.chatlog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('106.chatlog.sql'), 'legacy' => 106, ), '107.oauthserver.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('107.oauthserver.sql'), 'legacy' => 107, ), '108.oauthscope.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('108.oauthscope.sql'), 'legacy' => 108, ), '109.oauthclientphidkey.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('109.oauthclientphidkey.sql'), 'legacy' => 109, ), '110.commitaudit.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('110.commitaudit.sql'), 'legacy' => 110, ), '111.commitauditmigration.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('111.commitauditmigration.php'), 'legacy' => 111, ), '112.oauthaccesscoderedirecturi.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('112.oauthaccesscoderedirecturi.sql'), 'legacy' => 112, ), '113.lastreviewer.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('113.lastreviewer.sql'), 'legacy' => 113, ), '114.auditrequest.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('114.auditrequest.sql'), 'legacy' => 114, ), '115.prepareutf8.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('115.prepareutf8.sql'), 'legacy' => 115, ), '116.utf8-backup-first-expect-wait.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('116.utf8-backup-first-expect-wait.sql'), 'legacy' => 116, ), '117.repositorydescription.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('117.repositorydescription.php'), 'legacy' => 117, ), '118.auditinline.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('118.auditinline.sql'), 'legacy' => 118, ), '119.filehash.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('119.filehash.sql'), 'legacy' => 119, ), '120.noop.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('120.noop.sql'), 'legacy' => 120, ), '121.drydocklog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('121.drydocklog.sql'), 'legacy' => 121, ), '122.flag.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('122.flag.sql'), 'legacy' => 122, ), '123.heraldrulelog.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('123.heraldrulelog.sql'), 'legacy' => 123, ), '124.subpriority.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('124.subpriority.sql'), 'legacy' => 124, ), '125.ipv6.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('125.ipv6.sql'), 'legacy' => 125, ), '126.edges.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('126.edges.sql'), 'legacy' => 126, ), '127.userkeybody.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('127.userkeybody.sql'), 'legacy' => 127, ), '128.phabricatorcom.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('128.phabricatorcom.sql'), 'legacy' => 128, ), '129.savedquery.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('129.savedquery.sql'), 'legacy' => 129, ), '130.denormalrevisionquery.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('130.denormalrevisionquery.sql'), 'legacy' => 130, ), '131.migraterevisionquery.php' => array( 'type' => 'php', 'name' => $this->getPatchPath('131.migraterevisionquery.php'), 'legacy' => 131, ), '132.phame.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('132.phame.sql'), 'legacy' => 132, ), '133.imagemacro.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('133.imagemacro.sql'), 'legacy' => 133, ), '134.emptysearch.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('134.emptysearch.sql'), 'legacy' => 134, ), '135.datecommitted.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('135.datecommitted.sql'), 'legacy' => 135, ), '136.sex.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('136.sex.sql'), 'legacy' => 136, ), '137.auditmetadata.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('137.auditmetadata.sql'), 'legacy' => 137, ), '138.notification.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('138.notification.sql'), ), 'holidays.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('holidays.sql'), ), 'userstatus.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('userstatus.sql'), ), 'emailtable.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('emailtable.sql'), ), 'emailtableport.sql' => array( 'type' => 'php', 'name' => $this->getPatchPath('emailtableport.php'), ), 'emailtableremove.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('emailtableremove.sql'), ), 'phiddrop.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('phiddrop.sql'), ), 'testdatabase.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('testdatabase.sql'), ), 'ldapinfo.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('ldapinfo.sql'), ), 'threadtopic.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('threadtopic.sql'), ), 'usertranslation.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('usertranslation.sql'), ), 'differentialbookmarks.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('differentialbookmarks.sql'), ), 'harbormasterobject.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('harbormasterobject.sql'), ), 'markupcache.sql' => array( 'type' => 'sql', 'name' => $this->getPatchPath('markupcache.sql'), ), + 'maniphestxcache.sql' => array( + 'type' => 'sql', + 'name' => $this->getPatchPath('maniphestxcache.sql'), + ), ); } }