public function generateObject() { $author_phid = $this->loadPhabrictorUserPHID(); $author = id(new PhabricatorUser())->loadOneWhere('phid = %s', $author_phid); $task = ManiphestTask::initializeNewTask($author)->setSubPriority($this->generateTaskSubPriority())->setTitle($this->generateTitle()); $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_UNKNOWN, array()); $template = new ManiphestTransaction(); // Accumulate Transactions $changes = array(); $changes[ManiphestTransaction::TYPE_TITLE] = $this->generateTitle(); $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $this->generateDescription(); $changes[ManiphestTransaction::TYPE_OWNER] = $this->loadOwnerPHID(); $changes[ManiphestTransaction::TYPE_STATUS] = $this->generateTaskStatus(); $changes[ManiphestTransaction::TYPE_PRIORITY] = $this->generateTaskPriority(); $changes[PhabricatorTransactions::TYPE_SUBSCRIBERS] = array('=' => $this->getCCPHIDs()); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); $transaction->setNewValue($value); $transactions[] = $transaction; } $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)->setNewValue(array('=' => array_fuse($this->getProjectPHIDs()))); // Apply Transactions $editor = id(new ManiphestTransactionEditor())->setActor($author)->setContentSource($content_source)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->applyTransactions($task, $transactions); return $task; }
public function testFileVisibility() { $engine = new PhabricatorTestStorageEngine(); $data = Filesystem::readRandomCharacters(64); $author = $this->generateNewTestUser(); $viewer = $this->generateNewTestUser(); $users = array($author, $viewer); $params = array('name' => 'test.dat', 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, 'authorPHID' => $author->getPHID(), 'storageEngines' => array($engine)); $file = PhabricatorFile::newFromFileData($data, $params); $filter = new PhabricatorPolicyFilter(); // Test bare file policies. $this->assertEqual(array(true, false), $this->canViewFile($users, $file), pht('File Visibility')); // Create an object and test object policies. $object = ManiphestTask::initializeNewTask($author); $object->setViewPolicy(PhabricatorPolicies::getMostOpenPolicy()); $object->save(); $this->assertTrue($filter->hasCapability($author, $object, PhabricatorPolicyCapability::CAN_VIEW), pht('Object Visible to Author')); $this->assertTrue($filter->hasCapability($viewer, $object, PhabricatorPolicyCapability::CAN_VIEW), pht('Object Visible to Others')); // Attach the file to the object and test that the association opens a // policy exception for the non-author viewer. $file->attachToObject($object->getPHID()); // Test the attached file's visibility. $this->assertEqual(array(true, true), $this->canViewFile($users, $file), pht('Attached File Visibility')); // Create a "thumbnail" of the original file. $params = array('name' => 'test.thumb.dat', 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE, 'storageEngines' => array($engine)); $xform = PhabricatorFile::newFromFileData($data, $params); id(new PhabricatorTransformedFile())->setOriginalPHID($file->getPHID())->setTransform('test-thumb')->setTransformedPHID($xform->getPHID())->save(); // Test the thumbnail's visibility. $this->assertEqual(array(true, true), $this->canViewFile($users, $xform), pht('Attached Thumbnail Visibility')); // Detach the object and make sure it affects the thumbnail. $file->detachFromObject($object->getPHID()); // Test the detached thumbnail's visibility. $this->assertEqual(array(true, false), $this->canViewFile($users, $xform), pht('Detached Thumbnail Visibility')); }
protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { $task = ManiphestTask::initializeNewTask($sender); $task->setOriginalEmailSource($mail->getHeader('From')); $handler = PhabricatorEnv::newObjectFromConfig('metamta.maniphest.reply-handler'); $handler->setMailReceiver($task); $handler->setActor($sender); $handler->setExcludeMailRecipientPHIDs($mail->loadExcludeMailRecipientPHIDs()); $handler->processEmail($mail); $mail->setRelatedPHID($task->getPHID()); }
protected function processReceivedMail(PhabricatorMetaMTAReceivedMail $mail, PhabricatorUser $sender) { $task = ManiphestTask::initializeNewTask($sender); $task->setOriginalEmailSource($mail->getHeader('From')); $handler = new ManiphestReplyHandler(); $handler->setMailReceiver($task); $handler->setActor($sender); $handler->setExcludeMailRecipientPHIDs($mail->loadAllRecipientPHIDs()); if ($this->getApplicationEmail()) { $handler->setApplicationEmail($this->getApplicationEmail()); } $handler->processEmail($mail); $mail->setRelatedPHID($task->getPHID()); }
public function testCustomPolicyRuleLunarPhase() { $user_a = $this->generateNewTestUser(); $author = $this->generateNewTestUser(); $policy = id(new PhabricatorPolicy())->setRules(array(array('action' => PhabricatorPolicy::ACTION_ALLOW, 'rule' => 'PhabricatorPolicyRuleLunarPhase', 'value' => 'new')))->save(); $task = ManiphestTask::initializeNewTask($author); $task->setViewPolicy($policy->getPHID()); $task->save(); $time_a = PhabricatorTime::pushTime(934354800, 'UTC'); $can_a_view = PhabricatorPolicyFilter::hasCapability($user_a, $task, PhabricatorPolicyCapability::CAN_VIEW); $this->assertTrue($can_a_view); unset($time_a); $time_b = PhabricatorTime::pushTime(1116745200, 'UTC'); $can_a_view = PhabricatorPolicyFilter::hasCapability($user_a, $task, PhabricatorPolicyCapability::CAN_VIEW); $this->assertFalse($can_a_view); unset($time_b); }
function addTask($kan_task, $project_id) { $user = getAdmin(); $task = ManiphestTask::initializeNewTask($user); $changes = array(); $transactions = array(); $changes[ManiphestTransaction::TYPE_TITLE] = $kan_task['title']; $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $kan_task['description']; $changes[ManiphestTransaction::TYPE_STATUS] = ManiphestTaskStatus::getDefaultStatus(); $changes[PhabricatorTransactions::TYPE_COMMENT] = null; $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setNewValue(array('=' => array_fuse(array($project_id)))); $template = new ManiphestTransaction(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); $transaction->setNewValue($value); $transactions[] = $transaction; } $editor = id(new ManiphestTransactionEditor())->setActor($user)->setContentSourceFromConduitRequest(new ConduitAPIRequest(array()))->setContinueOnNoEffect(true); $editor->applyTransactions($task, $transactions); }
protected function newEditableObject() { return ManiphestTask::initializeNewTask($this->getViewer()); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $response_type = $request->getStr('responseType', 'task'); $order = $request->getStr('order', PhabricatorProjectColumn::DEFAULT_ORDER); $can_edit_assign = $this->hasApplicationCapability(ManiphestEditAssignCapability::CAPABILITY); $can_edit_policies = $this->hasApplicationCapability(ManiphestEditPoliciesCapability::CAPABILITY); $can_edit_priority = $this->hasApplicationCapability(ManiphestEditPriorityCapability::CAPABILITY); $can_edit_projects = $this->hasApplicationCapability(ManiphestEditProjectsCapability::CAPABILITY); $can_edit_status = $this->hasApplicationCapability(ManiphestEditStatusCapability::CAPABILITY); $parent_task = null; $template_id = null; if ($this->id) { $task = id(new ManiphestTaskQuery())->setViewer($user)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->withIDs(array($this->id))->executeOne(); if (!$task) { return new Aphront404Response(); } } else { $task = ManiphestTask::initializeNewTask($user); // We currently do not allow you to set the task status when creating // a new task, although now that statuses are custom it might make // sense. $can_edit_status = false; // These allow task creation with defaults. if (!$request->isFormPost()) { $task->setTitle($request->getStr('title')); if ($can_edit_projects) { $projects = $request->getStr('projects'); if ($projects) { $tokens = $request->getStrList('projects'); $type_project = PhabricatorProjectProjectPHIDType::TYPECONST; foreach ($tokens as $key => $token) { if (phid_get_type($token) == $type_project) { // If this is formatted like a PHID, leave it as-is. continue; } if (preg_match('/^#/', $token)) { // If this already has a "#", leave it as-is. continue; } // Add a "#" prefix. $tokens[$key] = '#' . $token; } $default_projects = id(new PhabricatorObjectQuery())->setViewer($user)->withNames($tokens)->execute(); $default_projects = mpull($default_projects, 'getPHID'); if ($default_projects) { $task->attachProjectPHIDs($default_projects); } } } if ($can_edit_priority) { $priority = $request->getInt('priority'); if ($priority !== null) { $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if (isset($priority_map[$priority])) { $task->setPriority($priority); } } } $task->setDescription($request->getStr('description')); if ($can_edit_assign) { $assign = $request->getStr('assign'); if (strlen($assign)) { $assign_user = id(new PhabricatorPeopleQuery())->setViewer($user)->withUsernames(array($assign))->executeOne(); if (!$assign_user) { $assign_user = id(new PhabricatorPeopleQuery())->setViewer($user)->withPHIDs(array($assign))->executeOne(); } if ($assign_user) { $task->setOwnerPHID($assign_user->getPHID()); } } } } $template_id = $request->getInt('template'); // You can only have a parent task if you're creating a new task. $parent_id = $request->getInt('parent'); if ($parent_id) { $parent_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($parent_id))->executeOne(); if (!$template_id) { $template_id = $parent_id; } } } $errors = array(); $e_title = true; $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($user); $field_list->readFieldsFromStorage($task); $aux_fields = $field_list->getFields(); if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); $new_status = $request->getStr('status'); if (!$task->getID()) { $workflow = 'create'; } else { $workflow = ''; } $changes[ManiphestTransaction::TYPE_TITLE] = $new_title; $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $new_desc; if ($can_edit_status) { $changes[ManiphestTransaction::TYPE_STATUS] = $new_status; } else { if (!$task->getID()) { // Create an initial status transaction for the burndown chart. // TODO: We can probably remove this once Facts comes online. $changes[ManiphestTransaction::TYPE_STATUS] = $task->getStatus(); } } $owner_tokenizer = $request->getArr('assigned_to'); $owner_phid = reset($owner_tokenizer); if (!strlen($new_title)) { $e_title = pht('Required'); $errors[] = pht('Title is required.'); } $old_values = array(); foreach ($aux_fields as $aux_arr_key => $aux_field) { // TODO: This should be buildFieldTransactionsFromRequest() once we // switch to ApplicationTransactions properly. $aux_old_value = $aux_field->getOldValueForApplicationTransactions(); $aux_field->readValueFromRequest($request); $aux_new_value = $aux_field->getNewValueForApplicationTransactions(); // TODO: We're faking a call to the ApplicaitonTransaction validation // logic here. We need valid objects to pass, but they aren't used // in a meaningful way. For now, build User objects. Once the Maniphest // objects exist, this will switch over automatically. This is a big // hack but shouldn't be long for this world. $placeholder_editor = new PhabricatorUserProfileEditor(); $field_errors = $aux_field->validateApplicationTransactions($placeholder_editor, PhabricatorTransactions::TYPE_CUSTOMFIELD, array(id(new ManiphestTransaction())->setOldValue($aux_old_value)->setNewValue($aux_new_value))); foreach ($field_errors as $error) { $errors[] = $error->getMessage(); } $old_values[$aux_field->getFieldKey()] = $aux_old_value; } if ($errors) { $task->setTitle($new_title); $task->setDescription($new_desc); $task->setPriority($request->getInt('priority')); $task->setOwnerPHID($owner_phid); $task->setCCPHIDs($request->getArr('cc')); $task->attachProjectPHIDs($request->getArr('projects')); } else { if ($can_edit_priority) { $changes[ManiphestTransaction::TYPE_PRIORITY] = $request->getInt('priority'); } if ($can_edit_assign) { $changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid; } $changes[ManiphestTransaction::TYPE_CCS] = $request->getArr('cc'); if ($can_edit_projects) { $projects = $request->getArr('projects'); $changes[ManiphestTransaction::TYPE_PROJECTS] = $projects; $column_phid = $request->getStr('columnPHID'); // allow for putting a task in a project column at creation -only- if (!$task->getID() && $column_phid && $projects) { $column = id(new PhabricatorProjectColumnQuery())->setViewer($user)->withProjectPHIDs($projects)->withPHIDs(array($column_phid))->executeOne(); if ($column) { $changes[ManiphestTransaction::TYPE_PROJECT_COLUMN] = array('new' => array('projectPHID' => $column->getProjectPHID(), 'columnPHIDs' => array($column_phid)), 'old' => array('projectPHID' => $column->getProjectPHID(), 'columnPHIDs' => array())); } } } if ($can_edit_policies) { $changes[PhabricatorTransactions::TYPE_VIEW_POLICY] = $request->getStr('viewPolicy'); $changes[PhabricatorTransactions::TYPE_EDIT_POLICY] = $request->getStr('editPolicy'); } $template = new ManiphestTransaction(); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); if ($type == ManiphestTransaction::TYPE_PROJECT_COLUMN) { $transaction->setNewValue($value['new']); $transaction->setOldValue($value['old']); } else { if ($type == ManiphestTransaction::TYPE_PROJECTS) { // TODO: Gross. $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transaction->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setNewValue(array('=' => array_fuse($value))); } else { $transaction->setNewValue($value); } } $transactions[] = $transaction; } if ($aux_fields) { foreach ($aux_fields as $aux_field) { $transaction = clone $template; $transaction->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD); $aux_key = $aux_field->getFieldKey(); $transaction->setMetadataValue('customfield:key', $aux_key); $old = idx($old_values, $aux_key); $new = $aux_field->getNewValueForApplicationTransactions(); $transaction->setOldValue($old); $transaction->setNewValue($new); $transactions[] = $transaction; } } if ($transactions) { $is_new = !$task->getID(); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $editor = id(new ManiphestTransactionEditor())->setActor($user)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->applyTransactions($task, $transactions); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); } if ($parent_task) { // TODO: This should be transactional now. id(new PhabricatorEdgeEditor())->addEdge($parent_task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK, $task->getPHID())->save(); $workflow = $parent_task->getID(); } if ($request->isAjax()) { switch ($response_type) { case 'card': $owner = null; if ($task->getOwnerPHID()) { $owner = id(new PhabricatorHandleQuery())->setViewer($user)->withPHIDs(array($task->getOwnerPHID()))->executeOne(); } $tasks = id(new ProjectBoardTaskCard())->setViewer($user)->setTask($task)->setOwner($owner)->setCanEdit(true)->getItem(); $column = id(new PhabricatorProjectColumnQuery())->setViewer($user)->withPHIDs(array($request->getStr('columnPHID')))->executeOne(); if (!$column) { return new Aphront404Response(); } $positions = id(new PhabricatorProjectColumnPositionQuery())->setViewer($user)->withColumns(array($column))->execute(); $task_phids = mpull($positions, 'getObjectPHID'); $column_tasks = id(new ManiphestTaskQuery())->setViewer($user)->withPHIDs($task_phids)->execute(); if ($order == PhabricatorProjectColumn::ORDER_NATURAL) { // TODO: This is a little bit awkward, because PHP and JS use // slightly different sort order parameters to achieve the same // effect. It would be unify this a bit at some point. $sort_map = array(); foreach ($positions as $position) { $sort_map[$position->getObjectPHID()] = array(-$position->getSequence(), $position->getID()); } } else { $sort_map = mpull($column_tasks, 'getPrioritySortVector', 'getPHID'); } $data = array('sortMap' => $sort_map); break; case 'task': default: $tasks = $this->renderSingleTask($task); $data = array(); break; } return id(new AphrontAjaxResponse())->setContent(array('tasks' => $tasks, 'data' => $data)); } $redirect_uri = '/T' . $task->getID(); if ($workflow) { $redirect_uri .= '?workflow=' . $workflow; } return id(new AphrontRedirectResponse())->setURI($redirect_uri); } } else { if (!$task->getID()) { $task->setCCPHIDs(array($user->getPHID())); if ($template_id) { $template_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($template_id))->executeOne(); if ($template_task) { $cc_phids = array_unique(array_merge($template_task->getCCPHIDs(), array($user->getPHID()))); $task->setCCPHIDs($cc_phids); $task->attachProjectPHIDs($template_task->getProjectPHIDs()); $task->setOwnerPHID($template_task->getOwnerPHID()); $task->setPriority($template_task->getPriority()); $task->setViewPolicy($template_task->getViewPolicy()); $task->setEditPolicy($template_task->getEditPolicy()); $template_fields = PhabricatorCustomField::getObjectFields($template_task, PhabricatorCustomField::ROLE_EDIT); $fields = $template_fields->getFields(); foreach ($fields as $key => $field) { if (!$field->shouldCopyWhenCreatingSimilarTask()) { unset($fields[$key]); } if (empty($aux_fields[$key])) { unset($fields[$key]); } } if ($fields) { id(new PhabricatorCustomFieldList($fields))->setViewer($user)->readFieldsFromStorage($template_task); foreach ($fields as $key => $field) { $aux_fields[$key]->setValueFromStorage($field->getValueForStorage()); } } } } } } $phids = array_merge(array($task->getOwnerPHID()), $task->getCCPHIDs(), $task->getProjectPHIDs()); if ($parent_task) { $phids[] = $parent_task->getPHID(); } $phids = array_filter($phids); $phids = array_unique($phids); $handles = $this->loadViewerHandles($phids); $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); } $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($task->getOwnerPHID()) { $assigned_value = array($handles[$task->getOwnerPHID()]); } else { $assigned_value = array(); } if ($task->getCCPHIDs()) { $cc_value = array_select_keys($handles, $task->getCCPHIDs()); } else { $cc_value = array(); } if ($task->getProjectPHIDs()) { $projects_value = array_select_keys($handles, $task->getProjectPHIDs()); } else { $projects_value = array(); } $cancel_id = nonempty($task->getID(), $template_id); if ($cancel_id) { $cancel_uri = '/T' . $cancel_id; } else { $cancel_uri = '/maniphest/'; } if ($task->getID()) { $button_name = pht('Save Task'); $header_name = pht('Edit Task'); } else { if ($parent_task) { $cancel_uri = '/T' . $parent_task->getID(); $button_name = pht('Create Task'); $header_name = pht('Create New Subtask'); } else { $button_name = pht('Create Task'); $header_name = pht('Create New Task'); } } require_celerity_resource('maniphest-task-edit-css'); $project_tokenizer_id = celerity_generate_unique_node_id(); $form = new AphrontFormView(); $form->setUser($user)->addHiddenInput('template', $template_id)->addHiddenInput('responseType', $response_type)->addHiddenInput('order', $order)->addHiddenInput('ungrippable', $request->getStr('ungrippable'))->addHiddenInput('columnPHID', $request->getStr('columnPHID')); if ($parent_task) { $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Parent Task'))->setValue($handles[$parent_task->getPHID()]->getFullName()))->addHiddenInput('parent', $parent_task->getID()); } $form->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Title'))->setName('title')->setError($e_title)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)->setValue($task->getTitle())); if ($can_edit_status) { // See T4819. $status_map = ManiphestTaskStatus::getTaskStatusMap(); $dup_status = ManiphestTaskStatus::getDuplicateStatus(); if ($task->getStatus() != $dup_status) { unset($status_map[$dup_status]); } $form->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('status')->setValue($task->getStatus())->setOptions($status_map)); } $policies = id(new PhabricatorPolicyQuery())->setViewer($user)->setObject($task)->execute(); if ($can_edit_assign) { $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('Assigned To'))->setName('assigned_to')->setValue($assigned_value)->setUser($user)->setDatasource(new PhabricatorPeopleDatasource())->setLimit(1)); } $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('CC'))->setName('cc')->setValue($cc_value)->setUser($user)->setDatasource(new PhabricatorMetaMTAMailableDatasource())); if ($can_edit_priority) { $form->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Priority'))->setName('priority')->setOptions($priority_map)->setValue($task->getPriority())); } if ($can_edit_policies) { $form->appendChild(id(new AphrontFormPolicyControl())->setUser($user)->setCapability(PhabricatorPolicyCapability::CAN_VIEW)->setPolicyObject($task)->setPolicies($policies)->setName('viewPolicy'))->appendChild(id(new AphrontFormPolicyControl())->setUser($user)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setPolicyObject($task)->setPolicies($policies)->setName('editPolicy')); } if ($can_edit_projects) { $form->appendChild(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setValue($projects_value)->setID($project_tokenizer_id)->setCaption(javelin_tag('a', array('href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create'), pht('Create New Project')))->setDatasource(new PhabricatorProjectDatasource())); } $field_list->appendFieldsToForm($form); require_celerity_resource('aphront-error-view-css'); Javelin::initBehavior('project-create', array('tokenizerID' => $project_tokenizer_id)); $description_control = new PhabricatorRemarkupControl(); // "Upsell" creating tasks via email in create flows if the instance is // configured for this awesomeness. $email_create = PhabricatorEnv::getEnvConfig('metamta.maniphest.public-create-email'); if (!$task->getID() && $email_create) { $email_hint = pht('You can also create tasks by sending an email to: %s', phutil_tag('tt', array(), $email_create)); $description_control->setCaption($email_hint); } $description_control->setLabel(pht('Description'))->setName('description')->setID('description-textarea')->setValue($task->getDescription())->setUser($user); $form->appendChild($description_control); if ($request->isAjax()) { $dialog = id(new AphrontDialogView())->setUser($user)->setWidth(AphrontDialogView::WIDTH_FULL)->setTitle($header_name)->appendChild(array($error_view, $form->buildLayoutView()))->addCancelButton($cancel_uri)->addSubmitButton($button_name); return id(new AphrontDialogResponse())->setDialog($dialog); } $form->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($button_name)); $form_box = id(new PHUIObjectBoxView())->setHeaderText($header_name)->setFormErrors($errors)->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel())->setHeader(pht('Description Preview'))->setControlID('description-textarea')->setPreviewURI($this->getApplicationURI('task/descriptionpreview/')); if ($task->getID()) { $page_objects = array($task->getPHID()); } else { $page_objects = array(); } $crumbs = $this->buildApplicationCrumbs(); if ($task->getID()) { $crumbs->addTextCrumb('T' . $task->getID(), '/T' . $task->getID()); } $crumbs->addTextCrumb($header_name); return $this->buildApplicationPage(array($crumbs, $form_box, $preview), array('title' => $header_name, 'pageObjects' => $page_objects)); }
public function testObjectPolicyRuleSubscribers() { $author = $this->generateNewTestUser(); $rule = new PhabricatorSubscriptionsSubscribersPolicyRule(); $task = ManiphestTask::initializeNewTask($author); $task->setViewPolicy($rule->getObjectPolicyFullKey()); $task->save(); $this->assertFalse(PhabricatorPolicyFilter::hasCapability($author, $task, PhabricatorPolicyCapability::CAN_VIEW)); id(new PhabricatorSubscriptionsEditor())->setActor($author)->setObject($task)->subscribeExplicit(array($author->getPHID()))->save(); $this->assertTrue(PhabricatorPolicyFilter::hasCapability($author, $task, PhabricatorPolicyCapability::CAN_VIEW)); }
private function newTask(PhabricatorUser $viewer, array $projects, $name = null) { $task = ManiphestTask::initializeNewTask($viewer); if (!strlen($name)) { $name = pht('Test Task'); } $xactions = array(); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_TITLE)->setNewValue($name); if ($projects) { $xactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)->setNewValue(array('=' => array_fuse(mpull($projects, 'getPHID')))); } $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContentSource(PhabricatorContentSource::newConsoleSource())->setContinueOnNoEffect(true)->applyTransactions($task, $xactions); return $task; }
private function syncItem(NuanceItem $item, NuanceItemCommand $command) { $xobj_phid = $item->getItemProperty('doorkeeper.xobj.phid'); if (!$xobj_phid) { throw new Exception(pht('Unable to sync: no external object PHID.')); } // TODO: Write some kind of marker to prevent double-synchronization. $viewer = $this->getViewer(); $xobj = id(new DoorkeeperExternalObjectQuery())->setViewer($viewer)->withPHIDs(array($xobj_phid))->executeOne(); if (!$xobj) { throw new Exception(pht('Unable to sync: failed to load object "%s".', $xobj_phid)); } $acting_as_phid = $this->getActingAsPHID($item); $xactions = array(); $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withBridgedObjectPHIDs(array($xobj_phid))->executeOne(); if (!$task) { $task = ManiphestTask::initializeNewTask($viewer)->setAuthorPHID($acting_as_phid)->setBridgedObjectPHID($xobj_phid); $title = $xobj->getProperty('task.title'); if (!strlen($title)) { $title = pht('Nuance Item %d Task', $item->getID()); } $description = $xobj->getProperty('task.description'); $created = $xobj->getProperty('task.created'); $state = $xobj->getProperty('task.state'); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_TITLE)->setNewValue($title)->setDateCreated($created); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_DESCRIPTION)->setNewValue($description)->setDateCreated($created); $task->setDateCreated($created); // TODO: Synchronize state. } $event = $this->newRawEvent($item); $comment = $event->getComment(); if (strlen($comment)) { $xactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment(id(new ManiphestTransactionComment())->setContent($comment)); } $agent_phid = $command->getAuthorPHID(); $source = $this->newContentSource($item, $agent_phid); $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setActingAsPHID($acting_as_phid)->setContentSource($source)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true); $xactions = $editor->applyTransactions($task, $xactions); return array('objectPHID' => $task->getPHID(), 'xactionPHIDs' => mpull($xactions, 'getPHID')); }
private function newTask(PhabricatorUser $viewer, $title) { $task = ManiphestTask::initializeNewTask($viewer); $xactions = array(); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_TITLE)->setNewValue($title); $this->applyTaskTransactions($viewer, $task, $xactions); return $task; }
protected function execute(ConduitAPIRequest $request) { $task = ManiphestTask::initializeNewTask($request->getUser()); $task = $this->applyRequest($task, $request, $is_new = true); return $this->buildTaskInfoDictionary($task); }
protected function receiveEmail(PhabricatorMetaMTAReceivedMail $mail) { // NOTE: We'll drop in here on both the "reply to a task" and "create a // new task" workflows! Make sure you test both if you make changes! $task = $this->getMailReceiver(); $is_new_task = !$task->getID(); $user = $this->getActor(); $body_data = $mail->parseBody(); $body = $body_data['body']; $body = $this->enhanceBodyWithAttachments($body, $mail->getAttachments()); $xactions = array(); $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_EMAIL, array('id' => $mail->getID())); $template = new ManiphestTransaction(); $is_unsub = false; if ($is_new_task) { $task = ManiphestTask::initializeNewTask($user); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_STATUS)->setNewValue(ManiphestTaskStatus::getDefaultStatus()); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_TITLE)->setNewValue(nonempty($mail->getSubject(), pht('Untitled Task'))); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_DESCRIPTION)->setNewValue($body); } else { $command = $body_data['command']; $command_value = $body_data['command_value']; $ttype = PhabricatorTransactions::TYPE_COMMENT; $new_value = null; switch ($command) { case 'close': $ttype = ManiphestTransaction::TYPE_STATUS; $new_value = ManiphestTaskStatus::getDefaultClosedStatus(); break; case 'claim': $ttype = ManiphestTransaction::TYPE_OWNER; $new_value = $user->getPHID(); break; case 'assign': $ttype = ManiphestTransaction::TYPE_OWNER; if ($command_value) { $assign_users = id(new PhabricatorPeopleQuery())->setViewer($user)->withUsernames(array($command_value))->execute(); if ($assign_users) { $assign_user = head($assign_users); $new_value = $assign_user->getPHID(); } } // assign to the user by default if (!$new_value) { $new_value = $user->getPHID(); } break; case 'unsubscribe': $is_unsub = true; $ttype = ManiphestTransaction::TYPE_CCS; $ccs = $task->getCCPHIDs(); foreach ($ccs as $k => $phid) { if ($phid == $user->getPHID()) { unset($ccs[$k]); } } $new_value = array_values($ccs); break; } if ($ttype != PhabricatorTransactions::TYPE_COMMENT) { $xaction = clone $template; $xaction->setTransactionType($ttype); $xaction->setNewValue($new_value); $xactions[] = $xaction; } if (strlen($body)) { $xaction = clone $template; $xaction->setTransactionType(PhabricatorTransactions::TYPE_COMMENT); $xaction->attachComment(id(new ManiphestTransactionComment())->setContent($body)); $xactions[] = $xaction; } } $ccs = $mail->loadCCPHIDs(); $old_ccs = $task->getCCPHIDs(); $new_ccs = array_merge($old_ccs, $ccs); if (!$is_unsub) { $new_ccs[] = $user->getPHID(); } $new_ccs = array_unique($new_ccs); if (array_diff($new_ccs, $old_ccs)) { $cc_xaction = clone $template; $cc_xaction->setTransactionType(ManiphestTransaction::TYPE_CCS); $cc_xaction->setNewValue($new_ccs); $xactions[] = $cc_xaction; } $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array('task' => $task, 'mail' => $mail, 'new' => $is_new_task, 'transactions' => $xactions)); $event->setUser($user); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $xactions = $event->getValue('transactions'); $editor = id(new ManiphestTransactionEditor())->setActor($user)->setParentMessageID($mail->getMessageID())->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs())->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->setContentSource($content_source)->applyTransactions($task, $xactions); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new_task, 'transactions' => $xactions)); $event->setUser($user); PhutilEventEngine::dispatchEvent($event); }
public function generateTask($project, $start, $end) { // Decide when the task was created switch (mt_rand(0, 10)) { case 0: // A few are created during sprint $date_created = mt_rand($start, $end); break; default: // Most are created sometime in the 3 days before the sprint $date_created = mt_rand($start - 3 * 24 * 60 * 60, $start); break; } $author = $this->loadPhabrictorUser(); $task = ManiphestTask::initializeNewTask($author); $task->setDateCreated($date_created); $content_source = PhabricatorContentSource::newForSource(PhabricatorContentSource::SOURCE_UNKNOWN, array()); $template = new ManiphestTransaction(); // Accumulate Transactions $changes = array(); $changes[ManiphestTransaction::TYPE_TITLE] = $this->generateTitle(); $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $this->generateDescription(); $changes[ManiphestTransaction::TYPE_OWNER] = $this->loadOwnerPHID(); $changes[ManiphestTransaction::TYPE_STATUS] = ManiphestTaskStatus::STATUS_OPEN; $changes[ManiphestTransaction::TYPE_PRIORITY] = $this->generateTaskPriority(); $changes[ManiphestTransaction::TYPE_CCS] = $this->getCCPHIDs(); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); $transaction->setDateCreated($date_created); $transaction->setNewValue($value); $transactions[] = $transaction; } // For most tasks, project will be added when created // But for a few, let's add it later $project_added = mt_rand(0, 10) == 0 ? mt_rand($date_created, $end) : $date_created; $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setDateCreated($project_added)->setMetadataValue('edge:type', PhabricatorProjectObjectHasProjectEdgeType::EDGECONST)->setNewValue(array('=' => array($project->getPHID() => $project->getPHID()))); // Set points when created $points = mt_rand(0, 10); $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)->setMetadataValue('customfield:key', 'isdc:sprint:storypoints')->setDateCreated($date_created)->setOldValue(null)->setNewValue($points); $editor = id(new ManiphestTransactionEditor())->setActor($author)->setContentSource($content_source)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true); // Apply and clear transactions $editor->applyTransactions($task, $transactions); $transactions = array(); // For some tasks, change points part way through sprint if (mt_rand(0, 10) == 0) { $transactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_CUSTOMFIELD)->setMetadataValue('customfield:key', 'isdc:sprint:storypoints')->setDateCreated(mt_rand($date_created, $end))->setOldValue($points)->setNewValue(mt_rand(0, 10)); } // Close some amount of the tasks in the sprint $total_days = floor(($end - $start) / 24 * 60 * 60); $elapsed_days = floor((time() - $start) / 24 * 60 * 60); if (mt_rand(0, $total_days) <= $elapsed_days) { $transactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_STATUS)->setDateCreated(mt_rand(max($date_created, $start), $end))->setNewValue(ManiphestTaskStatus::STATUS_CLOSED_RESOLVED); } // Apply any "during sprint" transactions if ($transactions) { $editor->applyTransactions($task, $transactions); } return $task; }