public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $event = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withIDs(array($request->getURIData('id')))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$event) { return new Aphront404Response(); } if (!$request->validateCSRF()) { return new Aphront400Response(); } if ($event->getIsAllDay()) { return new Aphront400Response(); } $xactions = array(); $duration = $event->getDuration(); $start = $request->getInt('start'); $start_value = id(AphrontFormDateControlValue::newFromEpoch($viewer, $start)); $end = $start + $duration; $end_value = id(AphrontFormDateControlValue::newFromEpoch($viewer, $end)); $xactions[] = id(new PhabricatorCalendarEventTransaction())->setTransactionType(PhabricatorCalendarEventStartDateTransaction::TRANSACTIONTYPE)->setNewValue($start_value); $xactions[] = id(new PhabricatorCalendarEventTransaction())->setTransactionType(PhabricatorCalendarEventEndDateTransaction::TRANSACTIONTYPE)->setNewValue($end_value); $editor = id(new PhabricatorCalendarEventEditor())->setActor($viewer)->setContinueOnMissingFields(true)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true); $xactions = $editor->applyTransactions($event, $xactions); return id(new AphrontReloadResponse()); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $id = $request->getURIData('id'); $event = id(new PhabricatorCalendarEventQuery())->setViewer($viewer)->withIDs(array($id))->executeOne(); if (!$event) { return new Aphront404Response(); } $response = $this->newImportedEventResponse($event); if ($response) { return $response; } $cancel_uri = $event->getURI(); if (!$event->getIsUserAttending($viewer->getPHID())) { return $this->newDialog()->setTitle(pht('Not Attending Event'))->appendParagraph(pht('You can not change your display availability for events you ' . 'are not attending.'))->addCancelButton($cancel_uri); } // TODO: This endpoint currently only works via AJAX. It would be vaguely // nice to provide a plain HTML version of the workflow where we return // a dialog with a vanilla <select /> in it for cases where all the JS // breaks. $request->validateCSRF(); $invitee = $event->getInviteeForPHID($viewer->getPHID()); $map = PhabricatorCalendarEventInvitee::getAvailabilityMap(); $new_availability = $request->getURIData('availability'); if (isset($map[$new_availability])) { $invitee->setAvailability($new_availability)->save(); // Invalidate the availability cache. $viewer->writeAvailabilityCache(array(), null); } return id(new AphrontRedirectResponse())->setURI($cancel_uri); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); if (!$request->validateCSRF()) { return new Aphront403Response(); } $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($request->getInt('task')))->needProjectPHIDs(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$task) { return new Aphront404Response(); } if ($request->getInt('after')) { $after_task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($request->getInt('after')))->executeOne(); if (!$after_task) { return new Aphront404Response(); } list($pri, $sub) = ManiphestTransactionEditor::getAdjacentSubpriority($after_task, $is_after = true); } else { list($pri, $sub) = ManiphestTransactionEditor::getEdgeSubpriority($request->getInt('priority'), $is_end = false); } $xactions = array(); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_PRIORITY)->setNewValue($pri); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_SUBPRIORITY)->setNewValue($sub); $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); $editor->applyTransactions($task, $xactions); return id(new AphrontAjaxResponse())->setContent(array('tasks' => $this->renderSingleTask($task))); }
public function handleRequest(AphrontRequest $request) { $action = $request->getURIData('action'); $id = $request->getURIData('requestID'); $viewer = $request->getViewer(); $request->validateCSRF(); $pull = id(new ReleephRequestQuery())->setViewer($viewer)->withIDs(array($id))->executeOne(); if (!$pull) { return new Aphront404Response(); } $branch = $pull->getBranch(); $product = $branch->getProduct(); $origin_uri = '/' . $pull->getMonogram(); $editor = id(new ReleephRequestTransactionalEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); $xactions = array(); switch ($action) { case 'want': case 'pass': static $action_map = array('want' => ReleephRequest::INTENT_WANT, 'pass' => ReleephRequest::INTENT_PASS); $intent = $action_map[$action]; $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT)->setMetadataValue('isAuthoritative', $product->isAuthoritative($viewer))->setNewValue($intent); break; case 'mark-manually-picked': case 'mark-manually-reverted': if ($pull->getRequestUserPHID() === $viewer->getPHID() || $product->isAuthoritative($viewer)) { // We're all good! } else { throw new Exception(pht("Bug! Only pushers or the requestor can manually change a " . "request's in-branch status!")); } if ($action === 'mark-manually-picked') { $in_branch = 1; $intent = ReleephRequest::INTENT_WANT; } else { $in_branch = 0; $intent = ReleephRequest::INTENT_PASS; } $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT)->setMetadataValue('isManual', true)->setMetadataValue('isAuthoritative', true)->setNewValue($intent); $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH)->setNewValue($in_branch); break; default: throw new Exception(pht('Unknown or unimplemented action %s.', $action)); } $editor->applyTransactions($pull, $xactions); if ($request->getBool('render')) { $field_list = PhabricatorCustomField::getObjectFields($pull, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($viewer)->readFieldsFromStorage($pull); // TODO: This should be more modern and general. $engine = id(new PhabricatorMarkupEngine())->setViewer($viewer); foreach ($field_list->getFields() as $field) { if ($field->shouldMarkup()) { $field->setMarkupEngine($engine); } } $engine->process(); $pull_box = id(new ReleephRequestView())->setUser($viewer)->setCustomFields($field_list)->setPullRequest($pull)->setIsListView(true); return id(new AphrontAjaxResponse())->setContent(array('markup' => hsprintf('%s', $pull_box))); } return id(new AphrontRedirectResponse())->setURI($origin_uri); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $request->validateCSRF(); $column_phid = $request->getStr('columnPHID'); $object_phid = $request->getStr('objectPHID'); $after_phid = $request->getStr('afterPHID'); $before_phid = $request->getStr('beforePHID'); $order = $request->getStr('order', PhabricatorProjectColumn::DEFAULT_ORDER); $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW))->withIDs(array($id))->executeOne(); if (!$project) { return new Aphront404Response(); } $board_phid = $project->getPHID(); $object = id(new ManiphestTaskQuery())->setViewer($viewer)->withPHIDs(array($object_phid))->needProjectPHIDs(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$object) { return new Aphront404Response(); } $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute(); $columns = mpull($columns, null, 'getPHID'); $column = idx($columns, $column_phid); if (!$column) { // User is trying to drop this object into a nonexistent column, just kick // them out. return new Aphront404Response(); } $engine = id(new PhabricatorBoardLayoutEngine())->setViewer($viewer)->setBoardPHIDs(array($board_phid))->setObjectPHIDs(array($object_phid))->executeLayout(); $columns = $engine->getObjectColumns($board_phid, $object_phid); $old_column_phids = mpull($columns, 'getPHID'); $xactions = array(); $order_params = array(); if ($order == PhabricatorProjectColumn::ORDER_NATURAL) { if ($after_phid) { $order_params['afterPHID'] = $after_phid; } else { if ($before_phid) { $order_params['beforePHID'] = $before_phid; } } } $xactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_COLUMNS)->setNewValue(array(array('columnPHID' => $column->getPHID()) + $order_params)); if ($order == PhabricatorProjectColumn::ORDER_PRIORITY) { $priority_xactions = $this->getPriorityTransactions($object, $after_phid, $before_phid); foreach ($priority_xactions as $xaction) { $xactions[] = $xaction; } } $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); $editor->applyTransactions($object, $xactions); return $this->newCardResponse($board_phid, $object_phid); }
/** * @phutil-external-symbol class PhabricatorStartup */ public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); // NOTE: Throws if valid CSRF token is not present in the request. $request->validateCSRF(); $name = $request->getStr('name'); $file_phid = $request->getStr('phid'); // If there's no explicit view policy, make it very restrictive by default. // This is the correct policy for files dropped onto objects during // creation, comment and edit flows. $view_policy = $request->getStr('viewPolicy'); if (!$view_policy) { $view_policy = $viewer->getPHID(); } $is_chunks = $request->getBool('querychunks'); if ($is_chunks) { $params = array('filePHID' => $file_phid); $result = id(new ConduitCall('file.querychunks', $params))->setUser($viewer)->execute(); return id(new AphrontAjaxResponse())->setContent($result); } $is_allocate = $request->getBool('allocate'); if ($is_allocate) { $params = array('name' => $name, 'contentLength' => $request->getInt('length'), 'viewPolicy' => $view_policy); $result = id(new ConduitCall('file.allocate', $params))->setUser($viewer)->execute(); $file_phid = $result['filePHID']; if ($file_phid) { $file = $this->loadFile($file_phid); $result += $file->getDragAndDropDictionary(); } return id(new AphrontAjaxResponse())->setContent($result); } // Read the raw request data. We're either doing a chunk upload or a // vanilla upload, so we need it. $data = PhabricatorStartup::getRawInput(); $is_chunk_upload = $request->getBool('uploadchunk'); if ($is_chunk_upload) { $params = array('filePHID' => $file_phid, 'byteStart' => $request->getInt('byteStart'), 'data' => $data); $result = id(new ConduitCall('file.uploadchunk', $params))->setUser($viewer)->execute(); $file = $this->loadFile($file_phid); if ($file->getIsPartial()) { $result = array(); } else { $result = array('complete' => true) + $file->getDragAndDropDictionary(); } return id(new AphrontAjaxResponse())->setContent($result); } $file = PhabricatorFile::newFromXHRUpload($data, array('name' => $request->getStr('name'), 'authorPHID' => $viewer->getPHID(), 'viewPolicy' => $view_policy, 'isExplicitUpload' => true)); $result = $file->getDragAndDropDictionary(); return id(new AphrontAjaxResponse())->setContent($result); }
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) { $viewer = $request->getViewer(); $story_type = 'PhabricatorNotificationTestFeedStory'; $story_data = array('title' => pht('This is a test notification, sent at %s.', phabricator_datetime(time(), $viewer))); $viewer_phid = $viewer->getPHID(); // NOTE: Because we don't currently show you your own notifications, make // sure this comes from a different PHID. $application_phid = id(new PhabricatorNotificationsApplication())->getPHID(); // TODO: When it's easier to get these buttons to render as forms, this // would be slightly nicer as a more standard isFormPost() check. if ($request->validateCSRF()) { id(new PhabricatorFeedStoryPublisher())->setStoryType($story_type)->setStoryData($story_data)->setStoryTime(time())->setStoryAuthorPHID($application_phid)->setRelatedPHIDs(array($viewer_phid))->setPrimaryObjectPHID($viewer_phid)->setSubscribedPHIDs(array($viewer_phid))->setNotifyAuthor(true)->publish(); } return id(new AphrontAjaxResponse()); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $request->validateCSRF(); $board_phid = $request->getStr('boardPHID'); $object_phid = $request->getStr('objectPHID'); $file_phid = $request->getStr('filePHID'); $object = id(new ManiphestTaskQuery())->setViewer($viewer)->withPHIDs(array($object_phid))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$object) { return new Aphront404Response(); } $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($file_phid))->executeOne(); if (!$file) { return new Aphront404Response(); } $xactions = array(); $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_COVER_IMAGE)->setNewValue($file->getPHID()); $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); $editor->applyTransactions($object, $xactions); return $this->newCardResponse($board_phid, $object_phid); }
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()); }
/** * Require high security, or prompt the user to enter high security. * * If the user's session is in high security, this method will return a * token. Otherwise, it will throw an exception which will eventually * be converted into a multi-factor authentication workflow. * * @param PhabricatorUser User whose session needs to be in high security. * @param AphrontReqeust Current request. * @param string URI to return the user to if they cancel. * @param bool True to jump partial sessions directly into high * security instead of just upgrading them to full * sessions. * @return PhabricatorAuthHighSecurityToken Security token. * @task hisec */ public function requireHighSecuritySession(PhabricatorUser $viewer, AphrontRequest $request, $cancel_uri, $jump_into_hisec = false) { if (!$viewer->hasSession()) { throw new Exception(pht('Requiring a high-security session from a user with no session!')); } $session = $viewer->getSession(); // Check if the session is already in high security mode. $token = $this->issueHighSecurityToken($session); if ($token) { return $token; } // Load the multi-factor auth sources attached to this account. $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere('userPHID = %s', $viewer->getPHID()); // If the account has no associated multi-factor auth, just issue a token // without putting the session into high security mode. This is generally // easier for users. A minor but desirable side effect is that when a user // adds an auth factor, existing sessions won't get a free pass into hisec, // since they never actually got marked as hisec. if (!$factors) { return $this->issueHighSecurityToken($session, true); } // Check for a rate limit without awarding points, so the user doesn't // get partway through the workflow only to get blocked. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorAuthTryFactorAction(), 0); $validation_results = array(); if ($request->isHTTPPost()) { $request->validateCSRF(); if ($request->getExists(AphrontRequest::TYPE_HISEC)) { // Limit factor verification rates to prevent brute force attacks. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorAuthTryFactorAction(), 1); $ok = true; foreach ($factors as $factor) { $id = $factor->getID(); $impl = $factor->requireImplementation(); $validation_results[$id] = $impl->processValidateFactorForm($factor, $viewer, $request); if (!$impl->isFactorValid($factor, $validation_results[$id])) { $ok = false; } } if ($ok) { // Give the user a credit back for a successful factor verification. PhabricatorSystemActionEngine::willTakeAction(array($viewer->getPHID()), new PhabricatorAuthTryFactorAction(), -1); if ($session->getIsPartial() && !$jump_into_hisec) { // If we have a partial session and are not jumping directly into // hisec, just issue a token without putting it in high security // mode. return $this->issueHighSecurityToken($session, true); } $until = time() + phutil_units('15 minutes in seconds'); $session->setHighSecurityUntil($until); queryfx($session->establishConnection('w'), 'UPDATE %T SET highSecurityUntil = %d WHERE id = %d', $session->getTableName(), $until, $session->getID()); $log = PhabricatorUserLog::initializeNewLog($viewer, $viewer->getPHID(), PhabricatorUserLog::ACTION_ENTER_HISEC); $log->save(); } else { $log = PhabricatorUserLog::initializeNewLog($viewer, $viewer->getPHID(), PhabricatorUserLog::ACTION_FAIL_HISEC); $log->save(); } } } $token = $this->issueHighSecurityToken($session); if ($token) { return $token; } throw id(new PhabricatorAuthHighSecurityRequiredException())->setCancelURI($cancel_uri)->setFactors($factors)->setFactorValidationResults($validation_results); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $projectid = $request->getURIData('projectID'); $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->withIDs(array($projectid))->executeOne(); if (!$project) { return new Aphront404Response(); } $this->setProject($project); $project_id = $project->getID(); $board_uri = $this->getApplicationURI("board/{$project_id}/"); $reorder_uri = $this->getApplicationURI("board/{$project_id}/reorder/"); if ($request->isFormPost()) { // User clicked "Done", make sure the page reloads to show the new // column order. return id(new AphrontRedirectResponse())->setURI($board_uri); } $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute(); $columns = msort($columns, 'getSequence'); $column_phid = $request->getStr('columnPHID'); if ($column_phid && $request->validateCSRF()) { $columns = mpull($columns, null, 'getPHID'); if (empty($columns[$column_phid])) { return new Aphront404Response(); } $target_column = $columns[$column_phid]; $new_sequence = $request->getInt('sequence'); if ($new_sequence < 0) { return new Aphront404Response(); } // TODO: For now, we're not recording any transactions here. We probably // should, but this sort of edit is extremely trivial. // Resequence the columns so that the moved column has the correct // sequence number. Move columns after it up one place in the sequence. $new_map = array(); foreach ($columns as $phid => $column) { $value = $column->getSequence(); if ($column->getPHID() == $column_phid) { $value = $new_sequence; } else { if ($column->getSequence() >= $new_sequence) { $value = $value + 1; } } $new_map[$phid] = $value; } // Sort the columns into their new ordering. asort($new_map); // Now, compact the ordering and adjust any columns that need changes. $project->openTransaction(); $sequence = 0; foreach ($new_map as $phid => $ignored) { $new_value = $sequence++; $cur_value = $columns[$phid]->getSequence(); if ($new_value != $cur_value) { $columns[$phid]->setSequence($new_value)->save(); } } $project->saveTransaction(); return id(new AphrontAjaxResponse())->setContent(array('sequenceMap' => mpull($columns, 'getSequence', 'getPHID'))); } $list_id = celerity_generate_unique_node_id(); $list = id(new PHUIObjectItemListView())->setUser($viewer)->setID($list_id)->setFlush(true); foreach ($columns as $column) { $item = id(new PHUIObjectItemView())->setHeader($column->getDisplayName())->addIcon('none', $column->getDisplayType()); if ($column->isHidden()) { $item->setDisabled(true); } $item->setGrippable(true); $item->addSigil('board-column'); $item->setMetadata(array('columnPHID' => $column->getPHID(), 'columnSequence' => $column->getSequence())); $list->addItem($item); } Javelin::initBehavior('reorder-columns', array('listID' => $list_id, 'reorderURI' => $reorder_uri)); $note = id(new PHUIInfoView())->appendChild(pht('Drag and drop columns to reorder them.'))->setSeverity(PHUIInfoView::SEVERITY_NOTICE); return $this->newDialog()->setTitle(pht('Reorder Columns'))->setWidth(AphrontDialogView::WIDTH_FORM)->appendChild($note)->appendChild($list)->addSubmitButton(pht('Done')); }
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 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; }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $request->validateCSRF(); $column_phid = $request->getStr('columnPHID'); $object_phid = $request->getStr('objectPHID'); $after_phid = $request->getStr('afterPHID'); $before_phid = $request->getStr('beforePHID'); $order = $request->getStr('order', PhabricatorProjectColumn::DEFAULT_ORDER); $project = id(new PhabricatorProjectQuery())->setViewer($viewer)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW))->withIDs(array($id))->executeOne(); if (!$project) { return new Aphront404Response(); } $board_phid = $project->getPHID(); $object = id(new ManiphestTaskQuery())->setViewer($viewer)->withPHIDs(array($object_phid))->needProjectPHIDs(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$object) { return new Aphront404Response(); } $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute(); $columns = mpull($columns, null, 'getPHID'); $column = idx($columns, $column_phid); if (!$column) { // User is trying to drop this object into a nonexistent column, just kick // them out. return new Aphront404Response(); } $engine = id(new PhabricatorBoardLayoutEngine())->setViewer($viewer)->setBoardPHIDs(array($board_phid))->setObjectPHIDs(array($object_phid))->executeLayout(); $columns = $engine->getObjectColumns($board_phid, $object_phid); $old_column_phids = mpull($columns, 'getPHID'); $xactions = array(); if ($order == PhabricatorProjectColumn::ORDER_NATURAL) { $order_params = array('afterPHID' => $after_phid, 'beforePHID' => $before_phid); } else { $order_params = array(); } $xactions[] = id(new ManiphestTransaction())->setTransactionType(ManiphestTransaction::TYPE_PROJECT_COLUMN)->setNewValue(array('columnPHIDs' => array($column->getPHID()), 'projectPHID' => $column->getProjectPHID()) + $order_params)->setOldValue(array('columnPHIDs' => $old_column_phids, 'projectPHID' => $column->getProjectPHID())); if ($order == PhabricatorProjectColumn::ORDER_PRIORITY) { $priority_xactions = $this->getPriorityTransactions($object, $after_phid, $before_phid); foreach ($priority_xactions as $xaction) { $xactions[] = $xaction; } } $proxy = $column->getProxy(); if ($proxy) { // We're moving the task into a subproject or milestone column, so add // the subproject or milestone. $add_projects = array($proxy->getPHID()); } else { if ($project->getHasSubprojects() || $project->getHasMilestones()) { // We're moving the task into the "Backlog" column on the parent project, // so add the parent explicitly. This gets rid of any subproject or // milestone tags. $add_projects = array($project->getPHID()); } else { $add_projects = array(); } } if ($add_projects) { $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $xactions[] = id(new ManiphestTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDGE)->setMetadataValue('edge:type', $project_type)->setNewValue(array('+' => array_fuse($add_projects))); } $editor = id(new ManiphestTransactionEditor())->setActor($viewer)->setContinueOnMissingFields(true)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); $editor->applyTransactions($object, $xactions); return $this->newCardResponse($board_phid, $object_phid); }