/src/applications/maniphest/controller/transactionsave/ManiphestTransactionSaveController.php
PHP | 261 lines | 175 code | 33 blank | 53 comment | 29 complexity | db857484e43ff67e549f1bb451e4a5bb MD5 | raw file
Possible License(s): JSON, MPL-2.0-no-copyleft-exception, Apache-2.0, BSD-3-Clause, LGPL-2.0, MIT, LGPL-2.1, LGPL-3.0
- <?php
- /*
- * Copyright 2011 Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- /**
- * @group maniphest
- */
- class ManiphestTransactionSaveController extends ManiphestController {
- public function processRequest() {
- $request = $this->getRequest();
- $user = $request->getUser();
- $task = id(new ManiphestTask())->load($request->getStr('taskID'));
- if (!$task) {
- return new Aphront404Response();
- }
- $transactions = array();
- $action = $request->getStr('action');
- // If we have drag-and-dropped files, attach them first in a separate
- // transaction. These can come in on any transaction type, which is why we
- // handle them separately.
- $files = array();
- // Look for drag-and-drop uploads first.
- $file_phids = $request->getArr('files');
- if ($file_phids) {
- $files = id(new PhabricatorFile())->loadAllWhere(
- 'phid in (%Ls)',
- $file_phids);
- }
- // This means "attach a file" even though we store other types of data
- // as 'attached'.
- if ($action == ManiphestTransactionType::TYPE_ATTACH) {
- if (!empty($_FILES['file'])) {
- $err = idx($_FILES['file'], 'error');
- if ($err != UPLOAD_ERR_NO_FILE) {
- $file = PhabricatorFile::newFromPHPUpload(
- $_FILES['file'],
- array(
- 'authorPHID' => $user->getPHID(),
- ));
- $files[] = $file;
- }
- }
- }
- // If we had explicit or drag-and-drop files, create a transaction
- // for those before we deal with whatever else might have happened.
- $file_transaction = null;
- if ($files) {
- $files = mpull($files, 'getPHID', 'getPHID');
- $new = $task->getAttached();
- foreach ($files as $phid) {
- if (empty($new[PhabricatorPHIDConstants::PHID_TYPE_FILE])) {
- $new[PhabricatorPHIDConstants::PHID_TYPE_FILE] = array();
- }
- $new[PhabricatorPHIDConstants::PHID_TYPE_FILE][$phid] = array();
- }
- $transaction = new ManiphestTransaction();
- $transaction
- ->setAuthorPHID($user->getPHID())
- ->setTransactionType(ManiphestTransactionType::TYPE_ATTACH);
- $transaction->setNewValue($new);
- $transactions[] = $transaction;
- $file_transaction = $transaction;
- }
- // Compute new CCs added by @mentions. Several things can cause CCs to
- // be added as side effects: mentions, explicit CCs, users who aren't
- // CC'd interacting with the task, and ownership changes. We build up a
- // list of all the CCs and then construct a transaction for them at the
- // end if necessary.
- $added_ccs = PhabricatorMarkupEngine::extractPHIDsFromMentions(
- array(
- $request->getStr('comments'),
- ));
- $cc_transaction = new ManiphestTransaction();
- $cc_transaction
- ->setAuthorPHID($user->getPHID())
- ->setTransactionType(ManiphestTransactionType::TYPE_CCS);
- $force_cc_transaction = false;
- $transaction = new ManiphestTransaction();
- $transaction
- ->setAuthorPHID($user->getPHID())
- ->setComments($request->getStr('comments'))
- ->setTransactionType($action);
- switch ($action) {
- case ManiphestTransactionType::TYPE_STATUS:
- $transaction->setNewValue($request->getStr('resolution'));
- break;
- case ManiphestTransactionType::TYPE_OWNER:
- $assign_to = $request->getArr('assign_to');
- $assign_to = reset($assign_to);
- $transaction->setNewValue($assign_to);
- break;
- case ManiphestTransactionType::TYPE_PROJECTS:
- $projects = $request->getArr('projects');
- $projects = array_merge($projects, $task->getProjectPHIDs());
- $projects = array_filter($projects);
- $projects = array_unique($projects);
- $transaction->setNewValue($projects);
- break;
- case ManiphestTransactionType::TYPE_CCS:
- // Accumulate the new explicit CCs into the array that we'll add in
- // the CC transaction later.
- $added_ccs = array_merge($added_ccs, $request->getArr('ccs'));
- // Transfer any comments over to the CC transaction.
- $cc_transaction->setComments($transaction->getComments());
- // Make sure we include this transaction, even if the user didn't
- // actually add any CC's, because we'll discard their comment otherwise.
- $force_cc_transaction = true;
- // Throw away the primary transaction.
- $transaction = null;
- break;
- case ManiphestTransactionType::TYPE_PRIORITY:
- $transaction->setNewValue($request->getInt('priority'));
- break;
- case ManiphestTransactionType::TYPE_NONE:
- case ManiphestTransactionType::TYPE_ATTACH:
- // If we have a file transaction, just get rid of this secondary
- // transaction and put the comments on it instead.
- if ($file_transaction) {
- $file_transaction->setComments($transaction->getComments());
- $transaction = null;
- }
- break;
- default:
- throw new Exception('unknown action');
- }
- if ($transaction) {
- $transactions[] = $transaction;
- }
- // When you interact with a task, we add you to the CC list so you get
- // further updates, and possibly assign the task to you if you took an
- // ownership action (closing it) but it's currently unowned. We also move
- // previous owners to CC if ownership changes. Detect all these conditions
- // and create side-effect transactions for them.
- $implicitly_claimed = false;
- switch ($action) {
- case ManiphestTransactionType::TYPE_OWNER:
- if ($task->getOwnerPHID() == $transaction->getNewValue()) {
- // If this is actually no-op, don't generate the side effect.
- break;
- }
- // Otherwise, when a task is reassigned, move the previous owner to CC.
- $added_ccs[] = $task->getOwnerPHID();
- break;
- case ManiphestTransactionType::TYPE_STATUS:
- if (!$task->getOwnerPHID() &&
- $request->getStr('resolution') !=
- ManiphestTaskStatus::STATUS_OPEN) {
- // Closing an unassigned task. Assign the user as the owner of
- // this task.
- $assign = new ManiphestTransaction();
- $assign->setAuthorPHID($user->getPHID());
- $assign->setTransactionType(ManiphestTransactionType::TYPE_OWNER);
- $assign->setNewValue($user->getPHID());
- $transactions[] = $assign;
- $implicitly_claimed = true;
- }
- break;
- }
- $user_owns_task = false;
- if ($implicitly_claimed) {
- $user_owns_task = true;
- } else {
- if ($action == ManiphestTransactionType::TYPE_OWNER) {
- if ($transaction->getNewValue() == $user->getPHID()) {
- $user_owns_task = true;
- }
- } else if ($task->getOwnerPHID() == $user->getPHID()) {
- $user_owns_task = true;
- }
- }
- if (!$user_owns_task) {
- // If we aren't making the user the new task owner and they aren't the
- // existing task owner, add them to CC.
- $added_ccs[] = $user->getPHID();
- }
- if ($added_ccs || $force_cc_transaction) {
- // We've added CCs, so include a CC transaction. It's safe to do this even
- // if we're just "adding" CCs which already exist, because the
- // ManiphestTransactionEditor is smart enough to ignore them.
- $all_ccs = array_merge($task->getCCPHIDs(), $added_ccs);
- $cc_transaction->setNewValue($all_ccs);
- $transactions[] = $cc_transaction;
- }
- $content_source = PhabricatorContentSource::newForSource(
- PhabricatorContentSource::SOURCE_WEB,
- array(
- 'ip' => $request->getRemoteAddr(),
- ));
- foreach ($transactions as $transaction) {
- $transaction->setContentSource($content_source);
- }
- $event = new PhabricatorEvent(
- PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK,
- array(
- 'task' => $task,
- 'new' => false,
- 'transactions' => $transactions,
- ));
- $event->setUser($user);
- $event->setAphrontRequest($request);
- PhutilEventEngine::dispatchEvent($event);
- $task = $event->getValue('task');
- $transactions = $event->getValue('transactions');
- $editor = new ManiphestTransactionEditor();
- $editor->applyTransactions($task, $transactions);
- $draft = id(new PhabricatorDraft())->loadOneWhere(
- 'authorPHID = %s AND draftKey = %s',
- $user->getPHID(),
- $task->getPHID());
- if ($draft) {
- $draft->delete();
- }
- return id(new AphrontRedirectResponse())
- ->setURI('/T'.$task->getID());
- }
- }