public function testRequestDataAccess() { $r = new AphrontRequest('http://example.com/', '/'); $r->setRequestData(array('str_empty' => '', 'str' => 'derp', 'str_true' => 'true', 'str_false' => 'false', 'zero' => '0', 'one' => '1', 'arr_empty' => array(), 'arr_num' => array(1, 2, 3), 'comma' => ',', 'comma_1' => 'a, b', 'comma_2' => ' ,a ,, b ,,,, ,, ', 'comma_3' => '0', 'comma_4' => 'a, a, b, a', 'comma_5' => "a\nb, c\n\nd\n\n\n,\n")); $this->assertEqual(1, $r->getInt('one')); $this->assertEqual(0, $r->getInt('zero')); $this->assertEqual(null, $r->getInt('does-not-exist')); $this->assertEqual(0, $r->getInt('str_empty')); $this->assertEqual(true, $r->getBool('one')); $this->assertEqual(false, $r->getBool('zero')); $this->assertEqual(true, $r->getBool('str_true')); $this->assertEqual(false, $r->getBool('str_false')); $this->assertEqual(true, $r->getBool('str')); $this->assertEqual(null, $r->getBool('does-not-exist')); $this->assertEqual(false, $r->getBool('str_empty')); $this->assertEqual('derp', $r->getStr('str')); $this->assertEqual('', $r->getStr('str_empty')); $this->assertEqual(null, $r->getStr('does-not-exist')); $this->assertEqual(array(), $r->getArr('arr_empty')); $this->assertEqual(array(1, 2, 3), $r->getArr('arr_num')); $this->assertEqual(null, $r->getArr('str_empty', null)); $this->assertEqual(null, $r->getArr('str_true', null)); $this->assertEqual(null, $r->getArr('does-not-exist', null)); $this->assertEqual(array(), $r->getArr('does-not-exist')); $this->assertEqual(array(), $r->getStrList('comma')); $this->assertEqual(array('a', 'b'), $r->getStrList('comma_1')); $this->assertEqual(array('a', 'b'), $r->getStrList('comma_2')); $this->assertEqual(array('0'), $r->getStrList('comma_3')); $this->assertEqual(array('a', 'a', 'b', 'a'), $r->getStrList('comma_4')); $this->assertEqual(array('a', 'b', 'c', 'd'), $r->getStrList('comma_5')); $this->assertEqual(array(), $r->getStrList('does-not-exist')); $this->assertEqual(null, $r->getStrList('does-not-exist', null)); $this->assertEqual(true, $r->getExists('str')); $this->assertEqual(false, $r->getExists('does-not-exist')); }
public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); $object_monograms = $request->getStrList('objectMonograms'); $saved->setParameter('objectMonograms', $object_monograms); $ids = $request->getStrList('ids'); foreach ($ids as $key => $id) { if (!$id || !is_numeric($id)) { unset($ids[$key]); } else { $ids[$key] = $id; } } $saved->setParameter('ids', $ids); return $saved; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $e_file = true; $errors = array(); if ($request->isDialogFormPost()) { $file_phids = $request->getStrList('filePHIDs'); if ($file_phids) { $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs($file_phids)->setRaisePolicyExceptions(true)->execute(); } else { $files = array(); } if ($files) { $results = array(); foreach ($files as $file) { $results[] = $file->getDragAndDropDictionary(); } $content = array('files' => $results); return id(new AphrontAjaxResponse())->setContent($content); } else { $e_file = pht('Required'); $errors[] = pht('You must choose a file to upload.'); } } if ($request->getURIData('single')) { $allow_multiple = false; } else { $allow_multiple = true; } $form = id(new AphrontFormView())->appendChild(id(new PHUIFormFileControl())->setName('filePHIDs')->setLabel(pht('Upload File'))->setAllowMultiple($allow_multiple)->setError($e_file)); return $this->newDialog()->setTitle(pht('File'))->setErrors($errors)->appendForm($form)->addSubmitButton(pht('Upload'))->addCancelButton('/'); }
protected function getParameterValue(AphrontRequest $request, $key) { $list = $request->getArr($key, null); if ($list === null) { $list = $request->getStrList($key); } return $list; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $commit = id(new PhabricatorRepositoryCommit())->load($id); if (!$commit) { return new Aphront404Response(); } $xactions = array(); $action = $request->getStr('action'); if ($action != PhabricatorAuditActionConstants::COMMENT) { $action_xaction = id(new PhabricatorAuditTransaction())->setAuthorPHID($viewer->getPHID())->setObjectPHID($commit->getPHID())->setTransactionType(PhabricatorAuditActionConstants::ACTION)->setNewValue($action); $auditors = $request->getStrList('auditors'); if ($action == PhabricatorAuditActionConstants::ADD_AUDITORS && $auditors) { $action_xaction->setTransactionType($action); $action_xaction->setNewValue(array_fuse($auditors)); } $ccs = $request->getStrList('ccs'); if ($action == PhabricatorAuditActionConstants::ADD_CCS && $ccs) { $action_xaction->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS); // NOTE: This doesn't get processed before use, so just provide fake // values. $action_xaction->setOldValue(array()); $action_xaction->setNewValue($ccs); } $xactions[] = $action_xaction; } $content = $request->getStr('content'); if (strlen($content)) { $xactions[] = id(new PhabricatorAuditTransaction())->setAuthorPHID($viewer->getPHID())->setObjectPHID($commit->getPHID())->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)->attachComment(id(new PhabricatorAuditTransactionComment())->setContent($content)); } $phids = array(); foreach ($xactions as $xaction) { $phids[] = $xaction->getRequiredHandlePHIDs(); } $phids = array_mergev($phids); $handles = $this->loadViewerHandles($phids); foreach ($xactions as $xaction) { $xaction->setHandles($handles); } $view = id(new PhabricatorAuditTransactionView())->setIsPreview(true)->setUser($viewer)->setObjectPHID($commit->getPHID())->setTransactions($xactions); id(new PhabricatorDraft())->setAuthorPHID($viewer->getPHID())->setDraftKey('diffusion-audit-' . $id)->setDraft($content)->replaceOrDelete(); return id(new AphrontAjaxResponse())->setContent(hsprintf('%s', $view)); }
public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); $saved->setParameter('isStable', $request->getStr('isStable')); $saved->setParameter('isUnstable', $request->getStr('isUnstable')); $saved->setParameter('isDeprecated', $request->getStr('isDeprecated')); $saved->setParameter('applicationNames', $request->getStrList('applicationNames')); $saved->setParameter('nameContains', $request->getStr('nameContains')); return $saved; }
public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); $saved->setParameter('callsigns', $request->getStrList('callsigns')); $saved->setParameter('status', $request->getStr('status')); $saved->setParameter('order', $request->getStr('order')); $saved->setParameter('hosted', $request->getStr('hosted')); $saved->setParameter('types', $request->getArr('types')); $saved->setParameter('name', $request->getStr('name')); $saved->setParameter('anyProjectPHIDs', $request->getArr('anyProjects')); return $saved; }
public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); $saved->setParameter('usernames', $request->getStrList('usernames')); $saved->setParameter('nameLike', $request->getStr('nameLike')); $saved->setParameter('isAdmin', $request->getStr('isAdmin')); $saved->setParameter('isDisabled', $request->getStr('isDisabled')); $saved->setParameter('isSystemAgent', $request->getStr('isSystemAgent')); $saved->setParameter('needsApproval', $request->getStr('needsApproval')); $saved->setParameter('createdStart', $request->getStr('createdStart')); $saved->setParameter('createdEnd', $request->getStr('createdEnd')); $this->readCustomFieldsFromRequest($request, $saved); return $saved; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); if (!$request->validateCSRF()) { return new Aphront400Response(); } $cancel_uri = $this->getApplicationURI(); $ids = $request->getStrList('h'); if ($ids) { $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withIDs($ids)->setRaisePolicyExceptions(true)->execute(); } else { $files = array(); } if (!$files) { return $this->newDialog()->setTitle(pht('Nothing Uploaded'))->appendParagraph(pht('Drag and drop .ics files to upload them and import them into ' . 'Calendar.'))->addCancelButton($cancel_uri, pht('Done')); } $engine = new PhabricatorCalendarICSFileImportEngine(); $imports = array(); foreach ($files as $file) { $import = PhabricatorCalendarImport::initializeNewCalendarImport($viewer, clone $engine); $xactions = array(); $xactions[] = id(new PhabricatorCalendarImportTransaction())->setTransactionType(PhabricatorCalendarImportICSFileTransaction::TRANSACTIONTYPE)->setNewValue($file->getPHID()); $editor = id(new PhabricatorCalendarImportEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->setContentSourceFromRequest($request); $editor->applyTransactions($import, $xactions); $imports[] = $import; } $import_phids = mpull($imports, 'getPHID'); $events = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withImportSourcePHIDs($import_phids)->execute(); if (count($events) == 1) { // The user imported exactly one event. This is consistent with dropping // a .ics file from an email; just take them to the event. $event = head($events); $next_uri = $event->getURI(); } else { if (count($imports) > 1) { // The user imported multiple different files. Take them to a summary // list of generated import activity. $source_phids = implode(',', $import_phids); $next_uri = '/calendar/import/log/?importSourcePHIDs=' . $source_phids; } else { // The user imported one file, which had zero or more than one event. // Take them to the import detail page. $import = head($imports); $next_uri = $import->getURI(); } } return id(new AphrontRedirectResponse())->setURI($next_uri); }
public function handleRequest(AphrontRequest $request) { $engine_key = $request->getURIData('engineKey'); $this->setEngineKey($engine_key); $key = $request->getURIData('key'); $viewer = $this->getViewer(); $config = id(new PhabricatorEditEngineConfigurationQuery())->setViewer($viewer)->withEngineKeys(array($engine_key))->withIdentifiers(array($key))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$config) { return id(new Aphront404Response()); } $cancel_uri = "/transactions/editengine/{$engine_key}/view/{$key}/"; $reorder_uri = "/transactions/editengine/{$engine_key}/reorder/{$key}/"; if ($request->isFormPost()) { $xactions = array(); $key_order = $request->getStrList('keyOrder'); $type_order = PhabricatorEditEngineConfigurationTransaction::TYPE_ORDER; $xactions[] = id(new PhabricatorEditEngineConfigurationTransaction())->setTransactionType($type_order)->setNewValue($key_order); $editor = id(new PhabricatorEditEngineConfigurationEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true); $editor->applyTransactions($config, $xactions); return id(new AphrontRedirectResponse())->setURI($cancel_uri); } $engine = $config->getEngine(); $fields = $engine->getFieldsForConfig($config); $list_id = celerity_generate_unique_node_id(); $input_id = celerity_generate_unique_node_id(); $list = id(new PHUIObjectItemListView())->setUser($viewer)->setID($list_id)->setFlush(true); $key_order = array(); foreach ($fields as $field) { if (!$field->getIsReorderable()) { continue; } $label = $field->getLabel(); $key = $field->getKey(); if ($label !== null) { $header = $label; } else { $header = $key; } $item = id(new PHUIObjectItemView())->setHeader($header)->setGrippable(true)->addSigil('editengine-form-field')->setMetadata(array('fieldKey' => $key)); $list->addItem($item); $key_order[] = $key; } Javelin::initBehavior('editengine-reorder-fields', array('listID' => $list_id, 'inputID' => $input_id, 'reorderURI' => $reorder_uri)); $note = id(new PHUIInfoView())->appendChild(pht('Drag and drop fields to reorder them.'))->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $input = phutil_tag('input', array('type' => 'hidden', 'name' => 'keyOrder', 'value' => implode(', ', $key_order), 'id' => $input_id)); return $this->newDialog()->setTitle(pht('Reorder Fields'))->setWidth(AphrontDialogView::WIDTH_FORM)->appendChild($note)->appendChild($list)->appendChild($input)->addSubmitButton(pht('Save Changes'))->addCancelButton($cancel_uri); }
protected function processDiffusionRequest(AphrontRequest $request) { $user = $request->getUser(); $drequest = $this->diffusionRequest; $repository = $drequest->getRepository(); $repository = id(new PhabricatorRepositoryQuery())->setViewer($user)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->withIDs(array($repository->getID()))->executeOne(); if (!$repository) { return new Aphront404Response(); } $edit_uri = $this->getRepositoryControllerURI($repository, 'edit/'); $v_sources = $repository->getSymbolSources(); $v_languages = $repository->getSymbolLanguages(); if ($v_languages) { $v_languages = implode(', ', $v_languages); } $errors = array(); if ($request->isFormPost()) { $v_sources = $request->getArr('sources'); $v_languages = $request->getStrList('languages'); $v_languages = array_map('phutil_utf8_strtolower', $v_languages); if (!$errors) { $xactions = array(); $template = id(new PhabricatorRepositoryTransaction()); $type_sources = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_SOURCES; $type_lang = PhabricatorRepositoryTransaction::TYPE_SYMBOLS_LANGUAGE; $xactions[] = id(clone $template)->setTransactionType($type_sources)->setNewValue($v_sources); $xactions[] = id(clone $template)->setTransactionType($type_lang)->setNewValue($v_languages); try { id(new PhabricatorRepositoryEditor())->setContinueOnNoEffect(true)->setContentSourceFromRequest($request)->setActor($user)->applyTransactions($repository, $xactions); return id(new AphrontRedirectResponse())->setURI($edit_uri); } catch (Exception $ex) { $errors[] = $ex->getMessage(); } } } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Edit Symbols')); $title = pht('Edit %s', $repository->getName()); $form = id(new AphrontFormView())->setUser($user)->appendRemarkupInstructions($this->getInstructions())->appendChild(id(new AphrontFormTextControl())->setName('languages')->setLabel(pht('Indexed Languages'))->setCaption(pht('File extensions, separate with commas, for example: php, py. ' . 'Leave blank for "any".'))->setValue($v_languages))->appendControl(id(new AphrontFormTokenizerControl())->setName('sources')->setLabel(pht('Uses Symbols From'))->setDatasource(new DiffusionRepositoryDatasource())->setValue($v_sources))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Save'))->addCancelButton($edit_uri)); $object_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setForm($form)->setFormErrors($errors); return $this->buildApplicationPage(array($crumbs, $object_box), array('title' => $title)); }
protected function getParameterValue(AphrontRequest $request, $key) { $value = $request->getStrList($key); if ($value) { return head($value); } // NOTE: At least for now, we'll attempt to read a direct upload if we // miss on a PHID. Currently, PHUIFormFileControl does a client-side // upload on workflow forms (which is good) but doesn't have a hook for // non-workflow forms (which isn't as good). Giving it a hook is desirable, // but complicated. Even if we do hook it, it may be reasonable to keep // this code around as a fallback if the client-side JS goes awry. $file_key = $this->getFileKey($key); if (!$request->getFileExists($file_key)) { return null; } $viewer = $this->getViewer(); $file = PhabricatorFile::newFromPHPUpload(idx($_FILES, $file_key), array('authorPHID' => $viewer->getPHID(), 'viewPolicy' => PhabricatorPolicies::POLICY_NOONE)); return $file->getPHID(); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $engine_class = $request->getURIData('engine'); $request->validateCSRF(); $base_class = 'PhabricatorApplicationSearchEngine'; if (!is_subclass_of($engine_class, $base_class)) { return new Aphront400Response(); } $engine = newv($engine_class, array()); $engine->setViewer($viewer); $queries = $engine->loadAllNamedQueries(); $queries = mpull($queries, null, 'getQueryKey'); $order = $request->getStrList('order'); $queries = array_select_keys($queries, $order) + $queries; $sequence = 1; foreach ($queries as $query) { $query->setSequence($sequence++); $query->save(); } return id(new AphrontAjaxResponse()); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $panel = id(new PhabricatorDashboardPanelQuery())->setViewer($viewer)->withIDs(array($id))->executeOne(); if (!$panel) { return new Aphront404Response(); } if ($request->isAjax()) { $parent_phids = $request->getStrList('parentPanelPHIDs', null); if ($parent_phids === null) { throw new Exception(pht('Required parameter `parentPanelPHIDs` is not present in ' . 'request.')); } } else { $parent_phids = array(); } $rendered_panel = id(new PhabricatorDashboardPanelRenderingEngine())->setViewer($viewer)->setPanel($panel)->setParentPanelPHIDs($parent_phids)->setHeaderMode($request->getStr('headerMode'))->setDashboardID($request->getInt('dashboardID'))->renderPanel(); if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent(array('panelMarkup' => hsprintf('%s', $rendered_panel))); } $crumbs = $this->buildApplicationCrumbs()->addTextCrumb(pht('Panels'), $this->getApplicationURI('panel/'))->addTextCrumb($panel->getMonogram(), '/' . $panel->getMonogram())->addTextCrumb(pht('Standalone View')); $view = id(new PHUIBoxView())->addClass('dashboard-view')->appendChild($rendered_panel); return $this->buildApplicationPage(array($crumbs, $view), array('title' => array(pht('Panel'), $panel->getName()))); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $server = new PhabricatorOAuthServer(); $client_phid = $request->getStr('client_id'); $redirect_uri = $request->getStr('redirect_uri'); $response_type = $request->getStr('response_type'); // state is an opaque value the client sent us for their own purposes // we just need to send it right back to them in the response! $state = $request->getStr('state'); if (!$client_phid) { return $this->buildErrorResponse('invalid_request', pht('Malformed Request'), pht('Required parameter %s was not present in the request.', phutil_tag('strong', array(), 'client_id'))); } // We require that users must be able to see an OAuth application // in order to authorize it. This allows an application's visibility // policy to be used to restrict authorized users. try { $client = id(new PhabricatorOAuthServerClientQuery())->setViewer($viewer)->withPHIDs(array($client_phid))->executeOne(); } catch (PhabricatorPolicyException $ex) { $ex->setContext(self::CONTEXT_AUTHORIZE); throw $ex; } $server->setUser($viewer); $is_authorized = false; $authorization = null; $uri = null; $name = null; // one giant try / catch around all the exciting database stuff so we // can return a 'server_error' response if something goes wrong! try { if (!$client) { return $this->buildErrorResponse('invalid_request', pht('Invalid Client Application'), pht('Request parameter %s does not specify a valid client application.', phutil_tag('strong', array(), 'client_id'))); } if ($client->getIsDisabled()) { return $this->buildErrorResponse('invalid_request', pht('Application Disabled'), pht('The %s OAuth application has been disabled.', phutil_tag('strong', array(), 'client_id'))); } $name = $client->getName(); $server->setClient($client); if ($redirect_uri) { $client_uri = new PhutilURI($client->getRedirectURI()); $redirect_uri = new PhutilURI($redirect_uri); if (!$server->validateSecondaryRedirectURI($redirect_uri, $client_uri)) { return $this->buildErrorResponse('invalid_request', pht('Invalid Redirect URI'), pht('Request parameter %s specifies an invalid redirect URI. ' . 'The redirect URI must be a fully-qualified domain with no ' . 'fragments, and must have the same domain and at least ' . 'the same query parameters as the redirect URI the client ' . 'registered.', phutil_tag('strong', array(), 'redirect_uri'))); } $uri = $redirect_uri; } else { $uri = new PhutilURI($client->getRedirectURI()); } if (empty($response_type)) { return $this->buildErrorResponse('invalid_request', pht('Invalid Response Type'), pht('Required request parameter %s is missing.', phutil_tag('strong', array(), 'response_type'))); } if ($response_type != 'code') { return $this->buildErrorResponse('unsupported_response_type', pht('Unsupported Response Type'), pht('Request parameter %s specifies an unsupported response type. ' . 'Valid response types are: %s.', phutil_tag('strong', array(), 'response_type'), implode(', ', array('code')))); } $requested_scope = $request->getStrList('scope'); $requested_scope = array_fuse($requested_scope); $scope = PhabricatorOAuthServerScope::filterScope($requested_scope); // NOTE: We're always requiring a confirmation dialog to redirect. // Partly this is a general defense against redirect attacks, and // partly this shakes off anchors in the URI (which are not shaken // by 302'ing). $auth_info = $server->userHasAuthorizedClient($scope); list($is_authorized, $authorization) = $auth_info; if ($request->isFormPost()) { if ($authorization) { $authorization->setScope($scope)->save(); } else { $authorization = $server->authorizeClient($scope); } $is_authorized = true; } } catch (Exception $e) { return $this->buildErrorResponse('server_error', pht('Server Error'), pht('The authorization server encountered an unexpected condition ' . 'which prevented it from fulfilling the request.')); } // When we reach this part of the controller, we can be in two states: // // 1. The user has not authorized the application yet. We want to // give them an "Authorize this application?" dialog. // 2. The user has authorized the application. We want to give them // a "Confirm Login" dialog. if ($is_authorized) { // The second case is simpler, so handle it first. The user either // authorized the application previously, or has just authorized the // application. Show them a confirm dialog with a normal link back to // the application. This shakes anchors from the URI. $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $auth_code = $server->generateAuthorizationCode($uri); unset($unguarded); $full_uri = $this->addQueryParams($uri, array('code' => $auth_code->getCode(), 'scope' => $authorization->getScopeString(), 'state' => $state)); if ($client->getIsTrusted()) { return id(new AphrontRedirectResponse())->setIsExternal(true)->setURI((string) $full_uri); } // TODO: It would be nice to give the user more options here, like // reviewing permissions, canceling the authorization, or aborting // the workflow. $dialog = id(new AphrontDialogView())->setUser($viewer)->setTitle(pht('Authenticate: %s', $name))->appendParagraph(pht('This application ("%s") is authorized to use your Phabricator ' . 'credentials. Continue to complete the authentication workflow.', phutil_tag('strong', array(), $name)))->addCancelButton((string) $full_uri, pht('Continue to Application')); return id(new AphrontDialogResponse())->setDialog($dialog); } // Here, we're confirming authorization for the application. if ($authorization) { $missing_scope = array_diff_key($scope, $authorization->getScope()); } else { $missing_scope = $scope; } $form = id(new AphrontFormView())->addHiddenInput('client_id', $client_phid)->addHiddenInput('redirect_uri', $redirect_uri)->addHiddenInput('response_type', $response_type)->addHiddenInput('state', $state)->addHiddenInput('scope', $request->getStr('scope'))->setUser($viewer); $cancel_msg = pht('The user declined to authorize this application.'); $cancel_uri = $this->addQueryParams($uri, array('error' => 'access_denied', 'error_description' => $cancel_msg)); $dialog = $this->newDialog()->setShortTitle(pht('Authorize Access'))->setTitle(pht('Authorize "%s"?', $name))->setSubmitURI($request->getRequestURI()->getPath())->setWidth(AphrontDialogView::WIDTH_FORM)->appendParagraph(pht('Do you want to authorize the external application "%s" to ' . 'access your Phabricator account data, including your primary ' . 'email address?', phutil_tag('strong', array(), $name)))->appendForm($form)->addSubmitButton(pht('Authorize Access'))->addCancelButton((string) $cancel_uri, pht('Do Not Authorize')); if ($missing_scope) { $dialog->appendParagraph(pht('This application has requested these additional permissions. ' . 'Authorizing it will grant it the permissions it requests:')); foreach ($missing_scope as $scope_key => $ignored) { // TODO: Once we introduce more scopes, explain them here. } } $unknown_scope = array_diff_key($requested_scope, $scope); if ($unknown_scope) { $dialog->appendParagraph(pht('This application also requested additional unrecognized ' . 'permissions. These permissions may have existed in an older ' . 'version of Phabricator, or may be from a future version of ' . 'Phabricator. They will not be granted.')); $unknown_form = id(new AphrontFormView())->setViewer($viewer)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Unknown Scope'))->setValue(implode(', ', array_keys($unknown_scope)))->setDisabled(true)); $dialog->appendForm($unknown_form); } return $dialog; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->requireApplicationCapability(ManiphestBulkEditCapability::CAPABILITY); $project = null; $board_id = $request->getInt('board'); if ($board_id) { $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->withIDs(array($board_id))->executeOne(); if (!$project) { return new Aphront404Response(); } } $task_ids = $request->getArr('batch'); if (!$task_ids) { $task_ids = $request->getStrList('batch'); } $tasks = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs($task_ids)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->needSubscriberPHIDs(true)->needProjectPHIDs(true)->execute(); if ($project) { $cancel_uri = '/project/sprint/board/' . $project->getID() . '/'; $redirect_uri = $cancel_uri; } else { $cancel_uri = '/maniphest/'; $redirect_uri = '/maniphest/?ids=' . implode(',', mpull($tasks, 'getID')); } $actions = $request->getStr('actions'); if ($actions) { $actions = phutil_json_decode($actions); } if ($request->isFormPost() && is_array($actions)) { foreach ($tasks as $task) { $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT); $field_list->readFieldsFromStorage($task); $xactions = $this->buildTransactions($actions, $task); if ($xactions) { // TODO: Set content source to "batch edit". $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true)->applyTransactions($task, $xactions); } } return id(new AphrontRedirectResponse())->setURI($redirect_uri); } $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); $list = new ManiphestTaskListView(); $list->setTasks($tasks); $list->setUser($viewer); $list->setHandles($handles); $template = new AphrontTokenizerTemplateView(); $template = $template->render(); $projects_source = new PhabricatorProjectDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $mailable_source->setViewer($viewer); $owner_source = new ManiphestAssigneeDatasource(); $owner_source->setViewer($viewer); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText(), 'browseURI' => $projects_source->getBrowseURI()), 'owner' => array('src' => $owner_source->getDatasourceURI(), 'placeholder' => $owner_source->getPlaceholderText(), 'browseURI' => $owner_source->getBrowseURI(), 'limit' => 1), 'cc' => array('src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText(), 'browseURI' => $mailable_source->getBrowseURI())), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap())); $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('board', $board_id)->setID('maniphest-batch-edit-form'); foreach ($tasks as $task) { $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID()))); } $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions'))); $form->appendChild(id(new PHUIFormInsetView())->setTitle(pht('Actions'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), pht('Add Another Action')))->setContent(javelin_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Update Tasks'))->addCancelButton($cancel_uri)); $title = pht('Batch Editor'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $task_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Selected Tasks'))->setObjectList($list); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Batch Editor'))->setForm($form); return $this->buildApplicationPage(array($crumbs, $task_box, $form_box), array('title' => $title)); }
public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getStrList($this->getFieldKey())); return $this; }
public function processRequest(AphrontRequest $request) { $user = $request->getUser(); $preferences = $user->loadPreferences(); $apps = id(new PhabricatorApplicationQuery())->setViewer($user)->withInstalled(true)->withUnlisted(false)->withLaunchable(true)->execute(); $pinned = $preferences->getPinnedApplications($apps, $user); $app_list = array(); foreach ($pinned as $app) { if (isset($apps[$app])) { $app_list[$app] = $apps[$app]; } } if ($request->getBool('add')) { $options = array(); foreach ($apps as $app) { $options[get_class($app)] = $app->getName(); } asort($options); unset($options['PhabricatorApplicationsApplication']); if ($request->isFormPost()) { $pin = $request->getStr('pin'); if (isset($options[$pin]) && !in_array($pin, $pinned)) { $pinned[] = $pin; $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_APP_PINNED, $pinned); $preferences->save(); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } } $options_control = id(new AphrontFormSelectControl())->setName('pin')->setLabel(pht('Application'))->setOptions($options)->setDisabledOptions(array_keys($app_list)); $form = id(new AphrontFormView())->setUser($user)->addHiddenInput('add', 'true')->appendRemarkupInstructions(pht('Choose an application to pin to your home page.'))->appendChild($options_control); $dialog = id(new AphrontDialogView())->setUser($user)->setWidth(AphrontDialogView::WIDTH_FORM)->setTitle(pht('Pin Application'))->appendChild($form->buildLayoutView())->addSubmitButton(pht('Pin Application'))->addCancelButton($this->getPanelURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } $unpin = $request->getStr('unpin'); if ($unpin) { $app = idx($apps, $unpin); if ($app) { if ($request->isFormPost()) { $pinned = array_diff($pinned, array($unpin)); $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_APP_PINNED, $pinned); $preferences->save(); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } $dialog = id(new AphrontDialogView())->setUser($user)->setTitle(pht('Unpin Application'))->appendParagraph(pht('Unpin the %s application from your home page?', phutil_tag('strong', array(), $app->getName())))->addSubmitButton(pht('Unpin Application'))->addCanceLButton($this->getPanelURI()); return id(new AphrontDialogResponse())->setDialog($dialog); } } $order = $request->getStrList('order'); if ($order && $request->validateCSRF()) { $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_APP_PINNED, $order); $preferences->save(); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } $list_id = celerity_generate_unique_node_id(); $list = id(new PHUIObjectItemListView())->setUser($user)->setID($list_id); Javelin::initBehavior('reorder-applications', array('listID' => $list_id, 'panelURI' => $this->getPanelURI())); foreach ($app_list as $key => $application) { if ($key == 'PhabricatorApplicationsApplication') { continue; } $icon = $application->getFontIcon(); if (!$icon) { $icon = 'application'; } $icon_view = javelin_tag('span', array('class' => 'phui-icon-view phui-font-fa ' . $icon, 'aural' => false), ''); $item = id(new PHUIObjectItemView())->setHeader($application->getName())->setImageIcon($icon_view)->addAttribute($application->getShortDescription())->setGrippable(true); $item->addAction(id(new PHUIListItemView())->setIcon('fa-times')->setHref($this->getPanelURI() . '?unpin=' . $key)->setWorkflow(true)); $item->addSigil('pinned-application'); $item->setMetadata(array('applicationClass' => $key)); $list->addItem($item); } $header = id(new PHUIHeaderView())->setHeader(pht('Pinned Applications'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setText(pht('Pin Application'))->setHref($this->getPanelURI() . '?add=true')->setWorkflow(true)->setIcon(id(new PHUIIconView())->setIconFont('fa-thumb-tack'))); $box = id(new PHUIObjectBoxView())->setHeader($header)->setObjectList($list); return $box; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); if ($id) { $id = $request->getURIData('id'); $is_new = false; $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->withIDs(array($id))->needSlugs(true)->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$project) { return new Aphront404Response(); } } else { $is_new = true; $this->requireApplicationCapability(ProjectCreateProjectsCapability::CAPABILITY); $project = PhabricatorProject::initializeNewProject($viewer); } $field_list = PhabricatorCustomField::getObjectFields($project, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($viewer)->readFieldsFromStorage($project); $e_name = true; $e_slugs = false; $e_edit = null; $v_name = $project->getName(); $project_slugs = $project->getSlugs(); $project_slugs = mpull($project_slugs, 'getSlug', 'getSlug'); $v_primary_slug = $project->getPrimarySlug(); unset($project_slugs[$v_primary_slug]); $v_slugs = $project_slugs; $v_color = $project->getColor(); $v_icon = $project->getIcon(); $v_locked = $project->getIsMembershipLocked(); $validation_exception = null; if ($request->isFormPost()) { $e_name = null; $e_slugs = null; $v_name = $request->getStr('name'); $v_slugs = $request->getStrList('slugs'); $v_view = $request->getStr('can_view'); $v_edit = $request->getStr('can_edit'); $v_join = $request->getStr('can_join'); $v_color = $request->getStr('color'); $v_icon = $request->getStr('icon'); $v_locked = $request->getInt('is_membership_locked', 0); $type_name = PhabricatorProjectTransaction::TYPE_NAME; $type_slugs = PhabricatorProjectTransaction::TYPE_SLUGS; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $type_icon = PhabricatorProjectTransaction::TYPE_ICON; $type_color = PhabricatorProjectTransaction::TYPE_COLOR; $type_locked = PhabricatorProjectTransaction::TYPE_LOCKED; $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType($type_name)->setNewValue($v_name); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType($type_slugs)->setNewValue($v_slugs); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)->setNewValue($v_view); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType($type_edit)->setNewValue($v_edit); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY)->setNewValue($v_join); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType($type_icon)->setNewValue($v_icon); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType($type_color)->setNewValue($v_color); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType($type_locked)->setNewValue($v_locked); $xactions = array_merge($xactions, $field_list->buildFieldTransactionsFromRequest(new PhabricatorProjectTransaction(), $request)); $editor = id(new PhabricatorProjectTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true); if ($is_new) { $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', PhabricatorProjectProjectHasMemberEdgeType::EDGECONST)->setNewValue(array('+' => array($viewer->getPHID() => $viewer->getPHID()))); } try { $editor->applyTransactions($project, $xactions); if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent(array('phid' => $project->getPHID(), 'name' => $project->getName())); } $redirect_uri = $this->getApplicationURI('profile/' . $project->getID() . '/'); return id(new AphrontRedirectResponse())->setURI($redirect_uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_name = $ex->getShortMessage($type_name); $e_slugs = $ex->getShortMessage($type_slugs); $e_edit = $ex->getShortMessage($type_edit); $project->setViewPolicy($v_view); $project->setEditPolicy($v_edit); $project->setJoinPolicy($v_join); } } if ($is_new) { $header_name = pht('Create a New Project'); $title = pht('Create Project'); } else { $header_name = pht('Edit Project'); $title = pht('Edit Project'); } $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($project)->execute(); $v_slugs = implode(', ', $v_slugs); $form = id(new AphrontFormView())->setUser($viewer)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Name'))->setName('name')->setValue($v_name)->setError($e_name)); $field_list->appendFieldsToForm($form); $shades = PhabricatorProjectIcon::getColorMap(); if ($is_new) { $icon_uri = $this->getApplicationURI('icon/'); } else { $icon_uri = $this->getApplicationURI('icon/' . $project->getID() . '/'); } $icon_display = PhabricatorProjectIcon::renderIconForChooser($v_icon); list($can_lock, $lock_message) = $this->explainApplicationCapability(ProjectCanLockProjectsCapability::CAPABILITY, pht('You can update the Lock Project setting.'), pht('You can not update the Lock Project setting.')); $form->appendChild(id(new AphrontFormChooseButtonControl())->setLabel(pht('Icon'))->setName('icon')->setDisplayValue($icon_display)->setButtonText(pht('Choose Icon...'))->setChooseURI($icon_uri)->setValue($v_icon))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Color'))->setName('color')->setValue($v_color)->setOptions($shades)); if (!$is_new) { $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Primary Hashtag'))->setCaption(pht('The primary hashtag is derived from the name.'))->setValue($v_primary_slug)); } $form->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Additional Hashtags'))->setCaption(pht('Specify a comma-separated list of additional hashtags.'))->setName('slugs')->setValue($v_slugs)->setError($e_slugs))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setName('can_view')->setPolicyObject($project)->setPolicies($policies)->setCapability(PhabricatorPolicyCapability::CAN_VIEW))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setName('can_edit')->setPolicyObject($project)->setPolicies($policies)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setError($e_edit))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setName('can_join')->setCaption(pht('Users who can edit a project can always join a project.'))->setPolicyObject($project)->setPolicies($policies)->setCapability(PhabricatorPolicyCapability::CAN_JOIN))->appendChild(id(new AphrontFormCheckboxControl())->setLabel(pht('Lock Project'))->setDisabled(!$can_lock)->addCheckbox('is_membership_locked', 1, pht('Prevent members from leaving this project.'), $v_locked)->setCaption($lock_message)); if ($request->isAjax()) { $errors = array(); if ($validation_exception) { $errors = mpull($ex->getErrors(), 'getMessage'); } $dialog = id(new AphrontDialogView())->setUser($viewer)->setWidth(AphrontDialogView::WIDTH_FULL)->setTitle($header_name)->setErrors($errors)->appendForm($form)->addSubmitButton($title)->addCancelButton('/project/'); return id(new AphrontDialogResponse())->setDialog($dialog); } $form->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($this->getApplicationURI())->setValue(pht('Save'))); $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setValidationException($validation_exception)->setForm($form); if (!$is_new) { $nav = $this->buildIconNavView($project); $nav->selectFilter("details/{$id}/"); $nav->appendChild($form_box); } else { $nav = array($form_box); } return $this->buildApplicationPage($nav, array('title' => $title)); }
/** * Read a list of items from the request, in either array format or string * format: * * list[]=item1&list[]=item2 * list=item1,item2 * * This provides flexibility when constructing URIs, especially from external * sources. * * @param AphrontRequest Request to read strings from. * @param string Key to read in the request. * @return list<string> List of values. */ protected function readListFromRequest(AphrontRequest $request, $key) { $list = $request->getArr($key, null); if ($list === null) { $list = $request->getStrList($key); } if (!$list) { return array(); } return $list; }
public function processRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $preferences = $this->getPreferences(); $pinned_key = PhabricatorPinnedApplicationsSetting::SETTINGKEY; $pinned = $preferences->getSettingValue($pinned_key); $apps = id(new PhabricatorApplicationQuery())->setViewer($viewer)->withInstalled(true)->withUnlisted(false)->withLaunchable(true)->execute(); $app_list = array(); foreach ($pinned as $app) { if (isset($apps[$app])) { $app_list[$app] = $apps[$app]; } } if ($request->getBool('reset')) { if ($request->isFormPost()) { $this->writePinnedApplications($preferences, null); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } return $this->newDialog()->setTitle(pht('Reset Applications'))->addHiddenInput('reset', 'true')->appendParagraph(pht('Reset pinned applications to their defaults?'))->addSubmitButton(pht('Reset Applications'))->addCancelButton($this->getPanelURI()); } if ($request->getBool('add')) { $options = array(); foreach ($apps as $app) { $options[get_class($app)] = $app->getName(); } asort($options); unset($options['PhabricatorApplicationsApplication']); if ($request->isFormPost()) { $pins = $request->getArr('pin'); $phid = head($pins); $app = id(new PhabricatorApplicationQuery())->setViewer($viewer)->withPHIDs(array($phid))->executeOne(); if ($app) { $pin = get_class($app); } else { // This likely means the user submitted an empty form // which will cause nothing to happen. $pin = ''; } if (isset($options[$pin]) && !in_array($pin, $pinned)) { $pinned[] = $pin; $this->writePinnedApplications($preferences, $pinned); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } } $options_control = id(new AphrontFormTokenizerControl())->setName('pin')->setLabel(pht('Application'))->setDatasource(new PhabricatorApplicationDatasource())->setLimit(1); $form = id(new AphrontFormView())->setViewer($viewer)->addHiddenInput('add', 'true')->appendRemarkupInstructions(pht('Choose an application to pin to your home page.'))->appendControl($options_control); return $this->newDialog()->setWidth(AphrontDialogView::WIDTH_FORM)->setTitle(pht('Pin Application'))->appendChild($form->buildLayoutView())->addSubmitButton(pht('Pin Application'))->addCancelButton($this->getPanelURI()); } $unpin = $request->getStr('unpin'); if ($unpin) { $app = idx($apps, $unpin); if ($app) { if ($request->isFormPost()) { $pinned = array_diff($pinned, array($unpin)); $this->writePinnedApplications($preferences, $pinned); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } return $this->newDialog()->setTitle(pht('Unpin Application'))->addHiddenInput('unpin', $unpin)->appendParagraph(pht('Unpin the %s application from your home page?', phutil_tag('strong', array(), $app->getName())))->addSubmitButton(pht('Unpin Application'))->addCancelButton($this->getPanelURI()); } } $order = $request->getStrList('order'); if ($order && $request->validateCSRF()) { $this->writePinnedApplications($preferences, $order); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI()); } $list_id = celerity_generate_unique_node_id(); $list = id(new PHUIObjectItemListView())->setViewer($viewer)->setID($list_id); Javelin::initBehavior('reorder-applications', array('listID' => $list_id, 'panelURI' => $this->getPanelURI())); foreach ($app_list as $key => $application) { if ($key == 'PhabricatorApplicationsApplication') { continue; } $icon = $application->getIcon(); if (!$icon) { $icon = 'fa-globe'; } $item = id(new PHUIObjectItemView())->setHeader($application->getName())->setImageIcon($icon)->addAttribute($application->getShortDescription())->setGrippable(true); $item->addAction(id(new PHUIListItemView())->setIcon('fa-times')->setHref($this->getPanelURI() . '?unpin=' . $key)->setWorkflow(true)); $item->addSigil('pinned-application'); $item->setMetadata(array('applicationClass' => $key)); $list->addItem($item); } $header = id(new PHUIHeaderView())->setHeader(pht('Pinned Applications'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setText(pht('Pin Application'))->setHref($this->getPanelURI() . '?add=true')->setWorkflow(true)->setIcon('fa-thumb-tack'))->addActionLink(id(new PHUIButtonView())->setTag('a')->setText(pht('Reset to Defaults'))->setHref($this->getPanelURI() . '?reset=true')->setWorkflow(true)->setIcon('fa-recycle')); $box = id(new PHUIObjectBoxView())->setHeader($header)->setObjectList($list); return $box; }
protected function getValueFromRequest(AphrontRequest $request, $key) { return $request->getStrList($key); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->requireApplicationCapability(ManiphestBulkEditCapability::CAPABILITY); $project = null; $board_id = $request->getInt('board'); if ($board_id) { $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->withIDs(array($board_id))->executeOne(); if (!$project) { return new Aphront404Response(); } } $task_ids = $request->getArr('batch'); if (!$task_ids) { $task_ids = $request->getStrList('batch'); } if (!$task_ids) { throw new Exception(pht('No tasks are selected.')); } $tasks = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs($task_ids)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->needSubscriberPHIDs(true)->needProjectPHIDs(true)->execute(); if (!$tasks) { throw new Exception(pht("You don't have permission to edit any of the selected tasks.")); } if ($project) { $cancel_uri = '/project/board/' . $project->getID() . '/'; $redirect_uri = $cancel_uri; } else { $cancel_uri = '/maniphest/'; $redirect_uri = '/maniphest/?ids=' . implode(',', mpull($tasks, 'getID')); } $actions = $request->getStr('actions'); if ($actions) { $actions = phutil_json_decode($actions); } if ($request->isFormPost() && $actions) { $job = PhabricatorWorkerBulkJob::initializeNewJob($viewer, new ManiphestTaskEditBulkJobType(), array('taskPHIDs' => mpull($tasks, 'getPHID'), 'actions' => $actions, 'cancelURI' => $cancel_uri, 'doneURI' => $redirect_uri)); $type_status = PhabricatorWorkerBulkJobTransaction::TYPE_STATUS; $xactions = array(); $xactions[] = id(new PhabricatorWorkerBulkJobTransaction())->setTransactionType($type_status)->setNewValue(PhabricatorWorkerBulkJob::STATUS_CONFIRM); $editor = id(new PhabricatorWorkerBulkJobEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnMissingFields(true)->applyTransactions($job, $xactions); return id(new AphrontRedirectResponse())->setURI($job->getMonitorURI()); } $handles = ManiphestTaskListView::loadTaskHandles($viewer, $tasks); $list = new ManiphestTaskListView(); $list->setTasks($tasks); $list->setUser($viewer); $list->setHandles($handles); $template = new AphrontTokenizerTemplateView(); $template = $template->render(); $projects_source = new PhabricatorProjectDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $mailable_source->setViewer($viewer); $owner_source = new ManiphestAssigneeDatasource(); $owner_source->setViewer($viewer); $spaces_source = id(new PhabricatorSpacesNamespaceDatasource())->setViewer($viewer); require_celerity_resource('maniphest-batch-editor'); Javelin::initBehavior('maniphest-batch-editor', array('root' => 'maniphest-batch-edit-form', 'tokenizerTemplate' => $template, 'sources' => array('project' => array('src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText(), 'browseURI' => $projects_source->getBrowseURI()), 'owner' => array('src' => $owner_source->getDatasourceURI(), 'placeholder' => $owner_source->getPlaceholderText(), 'browseURI' => $owner_source->getBrowseURI(), 'limit' => 1), 'cc' => array('src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText(), 'browseURI' => $mailable_source->getBrowseURI()), 'spaces' => array('src' => $spaces_source->getDatasourceURI(), 'placeholder' => $spaces_source->getPlaceholderText(), 'browseURI' => $spaces_source->getBrowseURI(), 'limit' => 1)), 'input' => 'batch-form-actions', 'priorityMap' => ManiphestTaskPriority::getTaskPriorityMap(), 'statusMap' => ManiphestTaskStatus::getTaskStatusMap())); $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('board', $board_id)->setID('maniphest-batch-edit-form'); foreach ($tasks as $task) { $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'batch[]', 'value' => $task->getID()))); } $form->appendChild(phutil_tag('input', array('type' => 'hidden', 'name' => 'actions', 'id' => 'batch-form-actions'))); $form->appendChild(id(new PHUIFormInsetView())->setTitle(pht('Actions'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-action', 'mustcapture' => true), pht('Add Another Action')))->setContent(javelin_tag('table', array('sigil' => 'maniphest-batch-actions', 'class' => 'maniphest-batch-actions-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Update Tasks'))->addCancelButton($cancel_uri)); $title = pht('Batch Editor'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $crumbs->setBorder(true); $header = id(new PHUIHeaderView())->setHeader(pht('Batch Editor'))->setHeaderIcon('fa-pencil-square-o'); $task_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Selected Tasks'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setObjectList($list); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Actions'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter(array($task_box, $form_box)); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $id = $request->getURIData('id'); $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); $can_create_projects = PhabricatorPolicyFilter::hasCapability($viewer, PhabricatorApplication::getByClass('PhabricatorProjectApplication'), ProjectCreateProjectsCapability::CAPABILITY); $parent_task = null; $template_id = null; if ($id) { $task = id(new ManiphestTaskQuery())->setViewer($viewer)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->withIDs(array($id))->needSubscriberPHIDs(true)->needProjectPHIDs(true)->executeOne(); if (!$task) { return new Aphront404Response(); } } else { $task = ManiphestTask::initializeNewTask($viewer); // 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($viewer)->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($viewer)->withUsernames(array($assign))->executeOne(); if (!$assign_user) { $assign_user = id(new PhabricatorPeopleQuery())->setViewer($viewer)->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 (strlen($parent_id)) { $parent_task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($parent_id))->executeOne(); if (!$parent_task) { return new Aphront404Response(); } if (!$template_id) { $template_id = $parent_id; } } } $errors = array(); $e_title = true; $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($viewer); $field_list->readFieldsFromStorage($task); $aux_fields = $field_list->getFields(); $v_space = $task->getSpacePHID(); if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); $new_status = $request->getStr('status'); $v_space = $request->getStr('spacePHID'); 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 = id(new PhabricatorUserProfileEditor())->setActor($viewer); $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->attachSubscriberPHIDs($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[PhabricatorTransactions::TYPE_SUBSCRIBERS] = array('=' => $request->getArr('cc')); if ($can_edit_projects) { $projects = $request->getArr('projects'); $changes[PhabricatorTransactions::TYPE_EDGE] = $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($viewer)->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_SPACE] = $v_space; $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 == PhabricatorTransactions::TYPE_EDGE) { $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transaction->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($viewer); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->applyTransactions($task, $transactions); $event = new PhabricatorEvent(PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array('task' => $task, 'new' => $is_new, 'transactions' => $transactions)); $event->setUser($viewer); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); } if ($parent_task) { // TODO: This should be transactional now. id(new PhabricatorEdgeEditor())->addEdge($parent_task->getPHID(), ManiphestTaskDependsOnTaskEdgeType::EDGECONST, $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($viewer)->withPHIDs(array($task->getOwnerPHID()))->executeOne(); } $project = $this->getSprintProjectforTask($viewer, $projects); $tasks = id(new SprintBoardTaskCard())->setViewer($viewer)->setProject($project)->setTask($task)->setOwner($owner)->setCanEdit(true)->getItem(); $column = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withPHIDs(array($request->getStr('columnPHID')))->executeOne(); if (!$column) { return new Aphront404Response(); } // re-load projects for accuracy as they are not re-loaded via // the editor $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs($task->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $task->attachProjectPHIDs($project_phids); $remove_from_board = false; if (!in_array($column->getProjectPHID(), $project_phids)) { $remove_from_board = true; } $positions = id(new PhabricatorProjectColumnPositionQuery())->setViewer($viewer)->withColumns(array($column))->execute(); $task_phids = mpull($positions, 'getObjectPHID'); $column_tasks = id(new ManiphestTaskQuery())->setViewer($viewer)->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 good to 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, 'removeFromBoard' => $remove_from_board); 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->attachSubscriberPHIDs(array($viewer->getPHID())); if ($template_id) { $template_task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($template_id))->needSubscriberPHIDs(true)->needProjectPHIDs(true)->executeOne(); if ($template_task) { $cc_phids = array_unique(array_merge($template_task->getSubscriberPHIDs(), array($viewer->getPHID()))); $task->attachSubscriberPHIDs($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()); $v_space = $template_task->getSpacePHID(); $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($viewer)->readFieldsFromStorage($template_task); foreach ($fields as $key => $field) { $aux_fields[$key]->setValueFromStorage($field->getValueForStorage()); } } } } } } $error_view = null; if ($errors) { $error_view = new PHUIInfoView(); $error_view->setErrors($errors); } $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($task->getOwnerPHID()) { $assigned_value = array($task->getOwnerPHID()); } else { $assigned_value = array(); } if ($task->getSubscriberPHIDs()) { $cc_value = $task->getSubscriberPHIDs(); } else { $cc_value = array(); } if ($task->getProjectPHIDs()) { $projects_value = $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($viewer)->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($viewer->renderHandle($parent_task->getPHID())))->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($viewer)->setObject($task)->execute(); if ($can_edit_assign) { $form->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Assigned To'))->setName('assigned_to')->setValue($assigned_value)->setUser($viewer)->setDatasource(new PhabricatorPeopleDatasource())->setLimit(1)); } $form->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('CC'))->setName('cc')->setValue($cc_value)->setUser($viewer)->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($viewer)->setCapability(PhabricatorPolicyCapability::CAN_VIEW)->setPolicyObject($task)->setPolicies($policies)->setSpacePHID($v_space)->setName('viewPolicy'))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setPolicyObject($task)->setPolicies($policies)->setName('editPolicy')); } if ($can_edit_projects) { $caption = null; if ($can_create_projects) { $caption = javelin_tag('a', array('href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create'), pht('Create New Project')); } $form->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setValue($projects_value)->setID($project_tokenizer_id)->setCaption($caption)->setDatasource(new PhabricatorProjectDatasource())); } $field_list->appendFieldsToForm($form); require_celerity_resource('phui-info-view-css'); Javelin::initBehavior('project-create', array('tokenizerID' => $project_tokenizer_id)); $description_control = id(new PhabricatorRemarkupControl())->setLabel(pht('Description'))->setName('description')->setID('description-textarea')->setValue($task->getDescription())->setUser($viewer); $form->appendChild($description_control); if ($request->isAjax()) { $dialog = id(new AphrontDialogView())->setUser($viewer)->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); $title = $header_name; return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->setPageObjectPHIDs($page_objects)->appendChild(array($form_box, $preview)); }
public function readFormValuesFromRequest(AphrontRequest $request) { $values = array(); foreach ($this->getPropertyKeys() as $key) { switch ($key) { case self::KEY_REALNAME_ATTRIBUTES: $values[$key] = $request->getStrList($key, array()); break; default: $values[$key] = $request->getStr($key); break; } } return $values; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $group_map = $this->getColumnMap(); $group = explode('.', $request->getStr('group')); $group = array_intersect($group, array_keys($group_map)); $group = array_fuse($group); if (empty($group['type'])) { $group['type'] = 'type'; } $now = PhabricatorTime::getNow(); $ago = $now - phutil_units('24 hours in seconds'); $table = new MultimeterEvent(); $conn = $table->establishConnection('r'); $where = array(); $where[] = qsprintf($conn, 'epoch >= %d AND epoch <= %d', $ago, $now); $with = array(); foreach ($group_map as $key => $column) { // Don't let non-admins filter by viewers, this feels a little too // invasive of privacy. if ($key == 'viewer') { if (!$viewer->getIsAdmin()) { continue; } } $with[$key] = $request->getStrList($key); if ($with[$key]) { $where[] = qsprintf($conn, '%T IN (%Ls)', $column, $with[$key]); } } $where = '(' . implode(') AND (', $where) . ')'; $data = queryfx_all($conn, 'SELECT *, count(*) AS N, SUM(sampleRate * resourceCost) AS totalCost, SUM(sampleRate * resourceCost) / SUM(sampleRate) AS averageCost FROM %T WHERE %Q GROUP BY %Q ORDER BY totalCost DESC, MAX(id) DESC LIMIT 100', $table->getTableName(), $where, implode(', ', array_select_keys($group_map, $group))); $this->loadDimensions($data); $phids = array(); foreach ($data as $row) { $viewer_name = $this->getViewerDimension($row['eventViewerID'])->getName(); $viewer_phid = $this->getEventViewerPHID($viewer_name); if ($viewer_phid) { $phids[] = $viewer_phid; } } $handles = $viewer->loadHandles($phids); $rows = array(); foreach ($data as $row) { if ($row['N'] == 1) { $events_col = $row['id']; } else { $events_col = $this->renderGroupingLink($group, 'id', pht('%s Event(s)', new PhutilNumber($row['N']))); } if (isset($group['request'])) { $request_col = $row['requestKey']; if (!$with['request']) { $request_col = $this->renderSelectionLink('request', $row['requestKey'], $request_col); } } else { $request_col = $this->renderGroupingLink($group, 'request'); } if (isset($group['viewer'])) { if ($viewer->getIsAdmin()) { $viewer_col = $this->getViewerDimension($row['eventViewerID'])->getName(); $viewer_phid = $this->getEventViewerPHID($viewer_col); if ($viewer_phid) { $viewer_col = $handles[$viewer_phid]->getName(); } if (!$with['viewer']) { $viewer_col = $this->renderSelectionLink('viewer', $row['eventViewerID'], $viewer_col); } } else { $viewer_col = phutil_tag('em', array(), pht('(Masked)')); } } else { $viewer_col = $this->renderGroupingLink($group, 'viewer'); } if (isset($group['context'])) { $context_col = $this->getContextDimension($row['eventContextID'])->getName(); if (!$with['context']) { $context_col = $this->renderSelectionLink('context', $row['eventContextID'], $context_col); } } else { $context_col = $this->renderGroupingLink($group, 'context'); } if (isset($group['host'])) { $host_col = $this->getHostDimension($row['eventHostID'])->getName(); if (!$with['host']) { $host_col = $this->renderSelectionLink('host', $row['eventHostID'], $host_col); } } else { $host_col = $this->renderGroupingLink($group, 'host'); } if (isset($group['label'])) { $label_col = $this->getLabelDimension($row['eventLabelID'])->getName(); if (!$with['label']) { $label_col = $this->renderSelectionLink('label', $row['eventLabelID'], $label_col); } } else { $label_col = $this->renderGroupingLink($group, 'label'); } if ($with['type']) { $type_col = MultimeterEvent::getEventTypeName($row['eventType']); } else { $type_col = $this->renderSelectionLink('type', $row['eventType'], MultimeterEvent::getEventTypeName($row['eventType'])); } $rows[] = array($events_col, $request_col, $viewer_col, $context_col, $host_col, $type_col, $label_col, MultimeterEvent::formatResourceCost($viewer, $row['eventType'], $row['averageCost']), MultimeterEvent::formatResourceCost($viewer, $row['eventType'], $row['totalCost']), $row['N'] == 1 ? $row['sampleRate'] : '-', phabricator_datetime($row['epoch'], $viewer)); } $table = id(new AphrontTableView($rows))->setHeaders(array(pht('ID'), pht('Request'), pht('Viewer'), pht('Context'), pht('Host'), pht('Type'), pht('Label'), pht('Avg'), pht('Cost'), pht('Rate'), pht('Epoch')))->setColumnClasses(array(null, null, null, null, null, null, 'wide', 'n', 'n', 'n', null)); $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Samples'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setTable($table); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Samples'), $this->getGroupURI(array(), true)); $crumbs->setBorder(true); $crumb_map = array('host' => pht('By Host'), 'context' => pht('By Context'), 'viewer' => pht('By Viewer'), 'request' => pht('By Request'), 'label' => pht('By Label'), 'id' => pht('By ID')); $parts = array(); foreach ($group as $item) { if ($item == 'type') { continue; } $parts[$item] = $item; $crumbs->addTextCrumb(idx($crumb_map, $item, $item), $this->getGroupURI($parts, true)); } $header = id(new PHUIHeaderView())->setHeader(pht('Samples (%s - %s)', phabricator_datetime($ago, $viewer), phabricator_datetime($now, $viewer)))->setHeaderIcon('fa-motorcycle'); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter($box); return $this->newPage()->setTitle(pht('Samples'))->setCrumbs($crumbs)->appendChild($view); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); if ($id) { $mock = id(new PholioMockQuery())->setViewer($viewer)->needImages(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->withIDs(array($id))->executeOne(); if (!$mock) { return new Aphront404Response(); } $title = pht('Edit Mock: %s', $mock->getName()); $header_icon = 'fa-pencil'; $is_new = false; $mock_images = $mock->getImages(); $files = mpull($mock_images, 'getFile'); $mock_images = mpull($mock_images, null, 'getFilePHID'); } else { $mock = PholioMock::initializeNewMock($viewer); $title = pht('Create Mock'); $header_icon = 'fa-plus-square'; $is_new = true; $files = array(); $mock_images = array(); } if ($is_new) { $v_projects = array(); } else { $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs($mock->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $v_projects = array_reverse($v_projects); } $e_name = true; $e_images = count($mock_images) ? null : true; $errors = array(); $posted_mock_images = array(); $v_name = $mock->getName(); $v_desc = $mock->getDescription(); $v_view = $mock->getViewPolicy(); $v_edit = $mock->getEditPolicy(); $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID($mock->getPHID()); $v_space = $mock->getSpacePHID(); if ($request->isFormPost()) { $xactions = array(); $type_name = PholioTransaction::TYPE_NAME; $type_desc = PholioTransaction::TYPE_DESCRIPTION; $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; $type_cc = PhabricatorTransactions::TYPE_SUBSCRIBERS; $type_space = PhabricatorTransactions::TYPE_SPACE; $v_name = $request->getStr('name'); $v_desc = $request->getStr('description'); $v_view = $request->getStr('can_view'); $v_edit = $request->getStr('can_edit'); $v_cc = $request->getArr('cc'); $v_projects = $request->getArr('projects'); $v_space = $request->getStr('spacePHID'); $mock_xactions = array(); $mock_xactions[$type_name] = $v_name; $mock_xactions[$type_desc] = $v_desc; $mock_xactions[$type_view] = $v_view; $mock_xactions[$type_edit] = $v_edit; $mock_xactions[$type_cc] = array('=' => $v_cc); $mock_xactions[$type_space] = $v_space; if (!strlen($request->getStr('name'))) { $e_name = pht('Required'); $errors[] = pht('You must give the mock a name.'); } $file_phids = $request->getArr('file_phids'); if ($file_phids) { $files = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs($file_phids)->execute(); $files = mpull($files, null, 'getPHID'); $files = array_select_keys($files, $file_phids); } else { $files = array(); } if (!$files) { $e_images = pht('Required'); $errors[] = pht('You must add at least one image to the mock.'); } else { $mock->setCoverPHID(head($files)->getPHID()); } foreach ($mock_xactions as $type => $value) { $xactions[$type] = id(new PholioTransaction())->setTransactionType($type)->setNewValue($value); } $order = $request->getStrList('imageOrder'); $sequence_map = array_flip($order); $replaces = $request->getArr('replaces'); $replaces_map = array_flip($replaces); /** * Foreach file posted, check to see whether we are replacing an image, * adding an image, or simply updating image metadata. Create * transactions for these cases as appropos. */ foreach ($files as $file_phid => $file) { $replaces_image_phid = null; if (isset($replaces_map[$file_phid])) { $old_file_phid = $replaces_map[$file_phid]; if ($old_file_phid != $file_phid) { $old_image = idx($mock_images, $old_file_phid); if ($old_image) { $replaces_image_phid = $old_image->getPHID(); } } } $existing_image = idx($mock_images, $file_phid); $title = (string) $request->getStr('title_' . $file_phid); $description = (string) $request->getStr('description_' . $file_phid); $sequence = $sequence_map[$file_phid]; if ($replaces_image_phid) { $replace_image = id(new PholioImage())->setReplacesImagePHID($replaces_image_phid)->setFilePhid($file_phid)->attachFile($file)->setName(strlen($title) ? $title : $file->getName())->setDescription($description)->setSequence($sequence); $xactions[] = id(new PholioTransaction())->setTransactionType(PholioTransaction::TYPE_IMAGE_REPLACE)->setNewValue($replace_image); $posted_mock_images[] = $replace_image; } else { if (!$existing_image) { // this is an add $add_image = id(new PholioImage())->setFilePhid($file_phid)->attachFile($file)->setName(strlen($title) ? $title : $file->getName())->setDescription($description)->setSequence($sequence); $xactions[] = id(new PholioTransaction())->setTransactionType(PholioTransaction::TYPE_IMAGE_FILE)->setNewValue(array('+' => array($add_image))); $posted_mock_images[] = $add_image; } else { $xactions[] = id(new PholioTransaction())->setTransactionType(PholioTransaction::TYPE_IMAGE_NAME)->setNewValue(array($existing_image->getPHID() => $title)); $xactions[] = id(new PholioTransaction())->setTransactionType(PholioTransaction::TYPE_IMAGE_DESCRIPTION)->setNewValue(array($existing_image->getPHID() => $description)); $xactions[] = id(new PholioTransaction())->setTransactionType(PholioTransaction::TYPE_IMAGE_SEQUENCE)->setNewValue(array($existing_image->getPHID() => $sequence)); $posted_mock_images[] = $existing_image; } } } foreach ($mock_images as $file_phid => $mock_image) { if (!isset($files[$file_phid]) && !isset($replaces[$file_phid])) { // this is an outright delete $xactions[] = id(new PholioTransaction())->setTransactionType(PholioTransaction::TYPE_IMAGE_FILE)->setNewValue(array('-' => array($mock_image))); } } if (!$errors) { $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new PholioTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $proj_edge_type)->setNewValue(array('=' => array_fuse($v_projects))); $mock->openTransaction(); $editor = id(new PholioMockEditor())->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setActor($viewer); $xactions = $editor->applyTransactions($mock, $xactions); $mock->saveTransaction(); return id(new AphrontRedirectResponse())->setURI('/M' . $mock->getID()); } } if ($id) { $submit = id(new AphrontFormSubmitControl())->addCancelButton('/M' . $id)->setValue(pht('Save')); } else { $submit = id(new AphrontFormSubmitControl())->addCancelButton($this->getApplicationURI())->setValue(pht('Create')); } $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($mock)->execute(); // NOTE: Make this show up correctly on the rendered form. $mock->setViewPolicy($v_view); $mock->setEditPolicy($v_edit); $image_elements = array(); if ($posted_mock_images) { $display_mock_images = $posted_mock_images; } else { $display_mock_images = $mock_images; } foreach ($display_mock_images as $mock_image) { $image_elements[] = id(new PholioUploadedImageView())->setUser($viewer)->setImage($mock_image)->setReplacesPHID($mock_image->getFilePHID()); } $list_id = celerity_generate_unique_node_id(); $drop_id = celerity_generate_unique_node_id(); $order_id = celerity_generate_unique_node_id(); $list_control = phutil_tag('div', array('id' => $list_id, 'class' => 'pholio-edit-list'), $image_elements); $drop_control = phutil_tag('a', array('id' => $drop_id, 'class' => 'pholio-edit-drop'), pht('Click here, or drag and drop images to add them to the mock.')); $order_control = phutil_tag('input', array('type' => 'hidden', 'name' => 'imageOrder', 'id' => $order_id)); Javelin::initBehavior('pholio-mock-edit', array('listID' => $list_id, 'dropID' => $drop_id, 'orderID' => $order_id, 'uploadURI' => '/file/dropupload/', 'renderURI' => $this->getApplicationURI('image/upload/'), 'pht' => array('uploading' => pht('Uploading Image...'), 'uploaded' => pht('Upload Complete...'), 'undo' => pht('Undo'), 'removed' => pht('This image will be removed from the mock.')))); require_celerity_resource('pholio-edit-css'); $form = id(new AphrontFormView())->setUser($viewer)->appendChild($order_control)->appendChild(id(new AphrontFormTextControl())->setName('name')->setValue($v_name)->setLabel(pht('Name'))->setError($e_name))->appendChild(id(new PhabricatorRemarkupControl())->setName('description')->setValue($v_desc)->setLabel(pht('Description'))->setUser($viewer))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Tags'))->setName('projects')->setValue($v_projects)->setDatasource(new PhabricatorProjectDatasource()))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Subscribers'))->setName('cc')->setValue($v_cc)->setUser($viewer)->setDatasource(new PhabricatorMetaMTAMailableDatasource()))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setCapability(PhabricatorPolicyCapability::CAN_VIEW)->setPolicyObject($mock)->setPolicies($policies)->setSpacePHID($v_space)->setName('can_view'))->appendChild(id(new AphrontFormPolicyControl())->setUser($viewer)->setCapability(PhabricatorPolicyCapability::CAN_EDIT)->setPolicyObject($mock)->setPolicies($policies)->setName('can_edit'))->appendChild(id(new AphrontFormMarkupControl())->setValue($list_control))->appendChild(id(new AphrontFormMarkupControl())->setValue($drop_control)->setError($e_images))->appendChild($submit); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Mock'))->setFormErrors($errors)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form); $crumbs = $this->buildApplicationCrumbs(); if (!$is_new) { $crumbs->addTextCrumb($mock->getMonogram(), '/' . $mock->getMonogram()); } $crumbs->addTextCrumb($title); $crumbs->setBorder(true); $header = id(new PHUIHeaderView())->setHeader($title)->setHeaderIcon($header_icon); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter($form_box); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->addQuicksandConfig(array('mockEditConfig' => true))->appendChild($view); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $object = $this->loadRelationshipObject(); if (!$object) { return new Aphront404Response(); } $relationship = $this->loadRelationship($object); if (!$relationship) { return new Aphront404Response(); } $src_phid = $object->getPHID(); $edge_type = $relationship->getEdgeConstant(); // If this is a normal relationship, users can remove related objects. If // it's a special relationship like a merge, we can't undo it, so we won't // prefill the current related objects. if ($relationship->canUndoRelationship()) { $dst_phids = PhabricatorEdgeQuery::loadDestinationPHIDs($src_phid, $edge_type); } else { $dst_phids = array(); } $all_phids = $dst_phids; $all_phids[] = $src_phid; $handles = $viewer->loadHandles($all_phids); $src_handle = $handles[$src_phid]; $done_uri = $src_handle->getURI(); $initial_phids = $dst_phids; $maximum = $relationship->getMaximumSelectionSize(); if ($request->isFormPost()) { $phids = explode(';', $request->getStr('phids')); $phids = array_filter($phids); $phids = array_values($phids); // The UI normally enforces this with Javascript, so this is just a // sanity check and does not need to be particularly user-friendly. if ($maximum && count($phids) > $maximum) { throw new Exception(pht('Too many relationships (%s, of type "%s").', phutil_count($phids), $relationship->getRelationshipConstant())); } $initial_phids = $request->getStrList('initialPHIDs'); // Apply the changes as adds and removes relative to the original state // of the object when the dialog was rendered so that two users adding // relationships at the same time don't race and overwrite one another. $add_phids = array_diff($phids, $initial_phids); $rem_phids = array_diff($initial_phids, $phids); $all_phids = array_merge($add_phids, $rem_phids); $capabilities = $relationship->getRequiredRelationshipCapabilities(); if ($all_phids) { $dst_objects = id(new PhabricatorObjectQuery())->setViewer($viewer)->withPHIDs($all_phids)->setRaisePolicyExceptions(true)->requireCapabilities($capabilities)->execute(); $dst_objects = mpull($dst_objects, null, 'getPHID'); } else { $dst_objects = array(); } try { foreach ($add_phids as $add_phid) { $dst_object = idx($dst_objects, $add_phid); if (!$dst_object) { throw new Exception(pht('You can not create a relationship to object "%s" because ' . 'the object does not exist or could not be loaded.', $add_phid)); } if ($add_phid == $src_phid) { throw new Exception(pht('You can not create a relationship to object "%s" because ' . 'objects can not be related to themselves.', $add_phid)); } if (!$relationship->canRelateObjects($object, $dst_object)) { throw new Exception(pht('You can not create a relationship (of type "%s") to object ' . '"%s" because it is not the right type of object for this ' . 'relationship.', $relationship->getRelationshipConstant(), $add_phid)); } } } catch (Exception $ex) { return $this->newUnrelatableObjectResponse($ex, $done_uri); } $content_source = PhabricatorContentSource::newFromRequest($request); $relationship->setContentSource($content_source); $editor = $object->getApplicationTransactionEditor()->setActor($viewer)->setContentSource($content_source)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true); $xactions = array(); $xactions[] = $object->getApplicationTransactionTemplate()->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $edge_type)->setNewValue(array('+' => array_fuse($add_phids), '-' => array_fuse($rem_phids))); $add_objects = array_select_keys($dst_objects, $add_phids); $rem_objects = array_select_keys($dst_objects, $rem_phids); if ($add_objects || $rem_objects) { $more_xactions = $relationship->willUpdateRelationships($object, $add_objects, $rem_objects); foreach ($more_xactions as $xaction) { $xactions[] = $xaction; } } try { $editor->applyTransactions($object, $xactions); if ($add_objects || $rem_objects) { $relationship->didUpdateRelationships($object, $add_objects, $rem_objects); } return id(new AphrontRedirectResponse())->setURI($done_uri); } catch (PhabricatorEdgeCycleException $ex) { return $this->newGraphCycleResponse($ex, $done_uri); } } $handles = iterator_to_array($handles); $handles = array_select_keys($handles, $dst_phids); $dialog_title = $relationship->getDialogTitleText(); $dialog_header = $relationship->getDialogHeaderText(); $dialog_button = $relationship->getDialogButtonText(); $dialog_instructions = $relationship->getDialogInstructionsText(); $source_uri = $relationship->getSourceURI($object); $source = $relationship->newSource(); $filters = $source->getFilters(); $selected_filter = $source->getSelectedFilter(); return id(new PhabricatorObjectSelectorDialog())->setUser($viewer)->setInitialPHIDs($initial_phids)->setHandles($handles)->setFilters($filters)->setSelectedFilter($selected_filter)->setExcluded($src_phid)->setCancelURI($done_uri)->setSearchURI($source_uri)->setTitle($dialog_title)->setHeader($dialog_header)->setButtonText($dialog_button)->setInstructions($dialog_instructions)->setMaximumSelectionSize($maximum)->buildDialog(); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $engine_key = $request->getURIData('engineKey'); $this->setEngineKey($engine_key); $type = $request->getURIData('type'); $is_create = $type == 'create'; $engine = id(new PhabricatorEditEngineQuery())->setViewer($viewer)->withEngineKeys(array($engine_key))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$engine) { return id(new Aphront404Response()); } $cancel_uri = "/transactions/editengine/{$engine_key}/"; $reorder_uri = "/transactions/editengine/{$engine_key}/sort/{$type}/"; $query = id(new PhabricatorEditEngineConfigurationQuery())->setViewer($viewer)->withEngineKeys(array($engine->getEngineKey())); if ($is_create) { $query->withIsDefault(true); } else { $query->withIsEdit(true); } $configs = $query->execute(); if ($is_create) { $configs = msort($configs, 'getCreateSortKey'); } else { $configs = msort($configs, 'getEditSortKey'); } if ($request->isFormPost()) { $form_order = $request->getStrList('formOrder'); // NOTE: This has a side-effect of saving any factory-default forms // to the database. We might want to warn the user better, but this // shouldn't generally be very important or confusing. $configs = mpull($configs, null, 'getIdentifier'); $configs = array_select_keys($configs, $form_order) + $configs; $order = 1; foreach ($configs as $config) { $xactions = array(); if ($is_create) { $xaction_type = PhabricatorEditEngineConfigurationTransaction::TYPE_CREATEORDER; } else { $xaction_type = PhabricatorEditEngineConfigurationTransaction::TYPE_EDITORDER; } $xactions[] = id(new PhabricatorEditEngineConfigurationTransaction())->setTransactionType($xaction_type)->setNewValue($order); $editor = id(new PhabricatorEditEngineConfigurationEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true); $editor->applyTransactions($config, $xactions); $order++; } return id(new AphrontRedirectResponse())->setURI($cancel_uri); } $list_id = celerity_generate_unique_node_id(); $input_id = celerity_generate_unique_node_id(); $list = id(new PHUIObjectItemListView())->setUser($viewer)->setID($list_id)->setFlush(true); $form_order = array(); foreach ($configs as $config) { $name = $config->getName(); $identifier = $config->getIdentifier(); $item = id(new PHUIObjectItemView())->setHeader($name)->setGrippable(true)->addSigil('editengine-form-config')->setMetadata(array('formIdentifier' => $identifier)); $list->addItem($item); $form_order[] = $identifier; } Javelin::initBehavior('editengine-reorder-configs', array('listID' => $list_id, 'inputID' => $input_id, 'reorderURI' => $reorder_uri)); if ($is_create) { $title = pht('Reorder Create Forms'); $button = pht('Save Create Order'); $note_text = pht('Drag and drop fields to change the order in which they appear in ' . 'the application "Create" menu.'); } else { $title = pht('Reorder Edit Forms'); $button = pht('Save Edit Order'); $note_text = pht('Drag and drop fields to change their priority for edits. When a ' . 'user edits an object, they will be shown the first form in this ' . 'list that they have permission to see.'); } $note = id(new PHUIInfoView())->appendChild($note_text)->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $input = phutil_tag('input', array('type' => 'hidden', 'name' => 'formOrder', 'value' => implode(', ', $form_order), 'id' => $input_id)); return $this->newDialog()->setTitle($title)->setWidth(AphrontDialogView::WIDTH_FORM)->appendChild($note)->appendChild($list)->appendChild($input)->addSubmitButton(pht('Save Changes'))->addCancelButton($cancel_uri); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $id = $request->getURIData('id'); $revision = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs(array($id))->executeOne(); if (!$revision) { return new Aphront404Response(); } $type_comment = PhabricatorTransactions::TYPE_COMMENT; $type_action = DifferentialTransaction::TYPE_ACTION; $type_edge = PhabricatorTransactions::TYPE_EDGE; $type_subscribers = PhabricatorTransactions::TYPE_SUBSCRIBERS; $xactions = array(); $action = $request->getStr('action'); switch ($action) { case DifferentialAction::ACTION_COMMENT: case DifferentialAction::ACTION_ADDREVIEWERS: case DifferentialAction::ACTION_ADDCCS: break; default: $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_action)->setNewValue($action); break; } $edge_reviewer = DifferentialRevisionHasReviewerEdgeType::EDGECONST; $reviewers = $request->getStrList('reviewers'); if (DifferentialAction::allowReviewers($action) && $reviewers) { $faux_edges = array(); foreach ($reviewers as $phid) { $faux_edges[$phid] = array('src' => $revision->getPHID(), 'type' => $edge_reviewer, 'dst' => $phid); } $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_edge)->setMetadataValue('edge:type', $edge_reviewer)->setOldValue(array())->setNewValue($faux_edges); } $ccs = $request->getStrList('ccs'); if ($ccs) { $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_subscribers)->setOldValue(array())->setNewValue(array_fuse($ccs)); } // Add a comment transaction if there's nothing, so we'll generate a // nonempty result. if (strlen($request->getStr('content')) || !$xactions) { $xactions[] = id(new DifferentialTransaction())->setTransactionType($type_comment)->attachComment(id(new ManiphestTransactionComment())->setContent($request->getStr('content'))); } foreach ($xactions as $xaction) { $xaction->setAuthorPHID($viewer->getPHID()); } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($request->getUser()); foreach ($xactions as $xaction) { if ($xaction->hasComment()) { $engine->addObject($xaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); $phids = mpull($xactions, 'getRequiredHandlePHIDs'); $phids = array_mergev($phids); $handles = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs($phids)->execute(); foreach ($xactions as $xaction) { $xaction->setHandles($handles); } $view = id(new DifferentialTransactionView())->setUser($viewer)->setTransactions($xactions)->setIsPreview(true); $metadata = array('reviewers' => $reviewers, 'ccs' => $ccs); if ($action != DifferentialAction::ACTION_COMMENT) { $metadata['action'] = $action; } $draft_key = 'differential-comment-' . $id; $draft = id(new PhabricatorDraft())->setAuthorPHID($viewer->getPHID())->setDraftKey($draft_key)->setDraft($request->getStr('content'))->setMetadata($metadata)->replaceOrDelete(); if ($draft->isDeleted()) { DifferentialDraft::deleteHasDraft($viewer->getPHID(), $revision->getPHID(), $draft_key); } else { DifferentialDraft::markHasDraft($viewer->getPHID(), $revision->getPHID(), $draft_key); } return id(new AphrontAjaxResponse())->setContent((string) phutil_implode_html('', $view->buildEvents())); }