public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $task = id(new PhabricatorWorkerActiveTask())->load($id); if (!$task) { $tasks = id(new PhabricatorWorkerArchiveTaskQuery())->withIDs(array($id))->execute(); $task = reset($tasks); } $header = new PHUIHeaderView(); if (!$task) { $title = pht('Task Does Not Exist'); $header->setHeader(pht('Task %d Missing', $id)); $error_view = new PHUIInfoView(); $error_view->setTitle(pht('No Such Task')); $error_view->appendChild(phutil_tag('p', array(), pht('This task may have recently been garbage collected.'))); $error_view->setSeverity(PHUIInfoView::SEVERITY_NODATA); $content = $error_view; } else { $title = pht('Task %d', $task->getID()); $header->setHeader(pht('Task %d: %s', $task->getID(), $task->getTaskClass())); $properties = $this->buildPropertyListView($task); $object_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->addPropertyList($properties); $retry_head = id(new PHUIHeaderView())->setHeader(pht('Retries')); $retry_info = $this->buildRetryListView($task); $retry_box = id(new PHUIObjectBoxView())->setHeader($retry_head)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->addPropertyList($retry_info); $content = array($object_box, $retry_box); } $header->setHeaderIcon('fa-sort'); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); $crumbs->setBorder(true); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter($content); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild($view); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $task = id(new PhabricatorWorkerActiveTask())->load($this->id); if (!$task) { $tasks = id(new PhabricatorWorkerArchiveTaskQuery())->withIDs(array($this->id))->execute(); $task = reset($tasks); } if (!$task) { $title = pht('Task Does Not Exist'); $error_view = new PHUIInfoView(); $error_view->setTitle(pht('No Such Task')); $error_view->appendChild(phutil_tag('p', array(), pht('This task may have recently been garbage collected.'))); $error_view->setSeverity(PHUIInfoView::SEVERITY_NODATA); $content = $error_view; } else { $title = pht('Task %d', $task->getID()); $header = id(new PHUIHeaderView())->setHeader(pht('Task %d (%s)', $task->getID(), $task->getTaskClass())); $properties = $this->buildPropertyListView($task); $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); $retry_head = id(new PHUIHeaderView())->setHeader(pht('Retries')); $retry_info = $this->buildRetryListView($task); $retry_box = id(new PHUIObjectBoxView())->setHeader($retry_head)->addPropertyList($retry_info); $content = array($object_box, $retry_box); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($title); return $this->buildApplicationPage(array($crumbs, $content), array('title' => $title)); }
protected function buildErrorView($error_message) { $error = new PHUIInfoView(); $error->setSeverity(PHUIInfoView::SEVERITY_ERROR); $error->setTitle($error_message); return $error; }
protected function renderErrorPage($title, array $messages) { $view = new PHUIInfoView(); $view->setTitle($title); $view->setErrors($messages); return $this->buildApplicationPage($view, array('title' => $title)); }
protected function renderErrorPage($title, array $messages) { $view = new PHUIInfoView(); $view->setTitle($title); $view->setErrors($messages); return $this->newPage()->setTitle($title)->appendChild($view); }
private function processImportRequest($request) { $admin = $request->getUser(); $usernames = $request->getArr('usernames'); $emails = $request->getArr('email'); $names = $request->getArr('name'); $notice_view = new PHUIInfoView(); $notice_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice_view->setTitle(pht('Import Successful')); $notice_view->setErrors(array(pht('Successfully imported users from LDAP'))); $list = new PHUIObjectItemListView(); $list->setNoDataString(pht('No users imported?')); foreach ($usernames as $username) { $user = new PhabricatorUser(); $user->setUsername($username); $user->setRealname($names[$username]); $email_obj = id(new PhabricatorUserEmail())->setAddress($emails[$username])->setIsVerified(1); try { id(new PhabricatorUserEditor())->setActor($admin)->createNewUser($user, $email_obj); id(new PhabricatorExternalAccount())->setUserPHID($user->getPHID())->setAccountType('ldap')->setAccountDomain('self')->setAccountID($username)->save(); $header = pht('Successfully added %s', $username); $attribute = null; $color = 'fa-check green'; } catch (Exception $ex) { $header = pht('Failed to add %s', $username); $attribute = $ex->getMessage(); $color = 'fa-times red'; } $item = id(new PHUIObjectItemView())->setHeader($header)->addAttribute($attribute)->setStatusIcon($color); $list->addItem($item); } return array($notice_view, $list); }
public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $xscript = id(new HeraldTranscriptQuery())->setViewer($viewer)->withIDs(array($this->id))->executeOne(); if (!$xscript) { return new Aphront404Response(); } require_celerity_resource('herald-test-css'); $nav = $this->buildSideNav(); $object_xscript = $xscript->getObjectTranscript(); if (!$object_xscript) { $notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->setTitle(pht('Old Transcript'))->appendChild(phutil_tag('p', array(), pht('Details of this transcript have been garbage collected.'))); $nav->appendChild($notice); } else { $map = HeraldAdapter::getEnabledAdapterMap($viewer); $object_type = $object_xscript->getType(); if (empty($map[$object_type])) { // TODO: We should filter these out in the Query, but we have to load // the objectTranscript right now, which is potentially enormous. We // should denormalize the object type, or move the data into a separate // table, and then filter this earlier (and thus raise a better error). // For now, just block access so we don't violate policies. throw new Exception(pht('This transcript has an invalid or inaccessible adapter.')); } $this->adapter = HeraldAdapter::getAdapterForContentType($object_type); $filter = $this->getFilterPHIDs(); $this->filterTranscript($xscript, $filter); $phids = array_merge($filter, $this->getTranscriptPHIDs($xscript)); $phids = array_unique($phids); $phids = array_filter($phids); $handles = $this->loadViewerHandles($phids); $this->handles = $handles; if ($xscript->getDryRun()) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Dry Run')); $notice->appendChild(pht('This was a dry run to test Herald rules, ' . 'no actions were executed.')); $nav->appendChild($notice); } $warning_panel = $this->buildWarningPanel($xscript); $nav->appendChild($warning_panel); $apply_xscript_panel = $this->buildApplyTranscriptPanel($xscript); $nav->appendChild($apply_xscript_panel); $action_xscript_panel = $this->buildActionTranscriptPanel($xscript); $nav->appendChild($action_xscript_panel); $object_xscript_panel = $this->buildObjectTranscriptPanel($xscript); $nav->appendChild($object_xscript_panel); } $crumbs = id($this->buildApplicationCrumbs())->addTextCrumb(pht('Transcripts'), $this->getApplicationURI('/transcript/'))->addTextCrumb($xscript->getID()); $nav->setCrumbs($crumbs); return $this->buildApplicationPage($nav, array('title' => pht('Transcript'))); }
public function processRequest() { try { $status = PhabricatorNotificationClient::getServerStatus(); $status = $this->renderServerStatus($status); } catch (Exception $ex) { $status = new PHUIInfoView(); $status->setTitle(pht('Notification Server Issue')); $status->appendChild(hsprintf('%s<br /><br />' . '<strong>%s</strong> %s', pht('Unable to determine server status. This probably means the server ' . 'is not in great shape. The specific issue encountered was:'), get_class($ex), phutil_escape_html_newlines($ex->getMessage()))); } $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Status')); return $this->buildApplicationPage(array($crumbs, $status), array('title' => pht('Notification Server Status'), 'device' => false)); }
public function render() { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $commit = $drequest->getCommit(); if ($commit) { $commit = $repository->formatCommitName($commit); } else { $commit = 'HEAD'; } $reason = $this->browseResultSet->getReasonForEmptyResultSet(); switch ($reason) { case DiffusionBrowseResultSet::REASON_IS_NONEXISTENT: $title = pht('Path Does Not Exist'); // TODO: Under git, this error message should be more specific. It // may exist on some other branch. $body = pht('This path does not exist anywhere.'); $severity = PHUIInfoView::SEVERITY_ERROR; break; case DiffusionBrowseResultSet::REASON_IS_EMPTY: $title = pht('Empty Directory'); $body = pht('This path was an empty directory at %s.', $commit); $severity = PHUIInfoView::SEVERITY_NOTICE; break; case DiffusionBrowseResultSet::REASON_IS_DELETED: $deleted = $this->browseResultSet->getDeletedAtCommit(); $existed = $this->browseResultSet->getExistedAtCommit(); $existed_text = $repository->formatCommitName($existed); $existed_href = $drequest->generateURI(array('action' => 'browse', 'path' => $drequest->getPath(), 'commit' => $existed, 'params' => array('view' => $this->view))); $existed_link = phutil_tag('a', array('href' => $existed_href), $existed_text); $title = pht('Path Was Deleted'); $body = pht('This path does not exist at %s. It was deleted in %s and last ' . 'existed at %s.', $commit, self::linkCommit($drequest->getRepository(), $deleted), $existed_link); $severity = PHUIInfoView::SEVERITY_WARNING; break; case DiffusionBrowseResultSet::REASON_IS_UNTRACKED_PARENT: $subdir = $drequest->getRepository()->getDetail('svn-subpath'); $title = pht('Directory Not Tracked'); $body = pht("This repository is configured to track only one subdirectory " . "of the entire repository ('%s'), but you aren't looking at " . "something in that subdirectory, so no information is available.", $subdir); $severity = PHUIInfoView::SEVERITY_WARNING; break; default: throw new Exception(pht('Unknown failure reason: %s', $reason)); } $error_view = new PHUIInfoView(); $error_view->setSeverity($severity); $error_view->setTitle($title); $error_view->appendChild(phutil_tag('p', array(), $body)); return $error_view->render(); }
public function processRequest(AphrontRequest $request) { $user = $this->getUser(); $viewer = $request->getUser(); id(new PhabricatorAuthSessionEngine())->requireHighSecuritySession($viewer, $request, '/settings/'); if ($request->isFormPost()) { if (!$request->isDialogFormPost()) { $dialog = new AphrontDialogView(); $dialog->setUser($viewer); $dialog->setTitle(pht('Really regenerate session?')); $dialog->setSubmitURI($this->getPanelURI()); $dialog->addSubmitButton(pht('Regenerate')); $dialog->addCancelbutton($this->getPanelURI()); $dialog->appendChild(phutil_tag('p', array(), pht('Really destroy the old certificate? Any established ' . 'sessions will be terminated.'))); return id(new AphrontDialogResponse())->setDialog($dialog); } $sessions = id(new PhabricatorAuthSessionQuery())->setViewer($user)->withIdentityPHIDs(array($user->getPHID()))->withSessionTypes(array(PhabricatorAuthSession::TYPE_CONDUIT))->execute(); foreach ($sessions as $session) { $session->delete(); } // This implicitly regenerates the certificate. $user->setConduitCertificate(null); $user->save(); return id(new AphrontRedirectResponse())->setURI($this->getPanelURI('?regenerated=true')); } if ($request->getStr('regenerated')) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Certificate Regenerated')); $notice->appendChild(phutil_tag('p', array(), pht('Your old certificate has been destroyed and you have been issued ' . 'a new certificate. Sessions established under the old certificate ' . 'are no longer valid.'))); $notice = $notice->render(); } else { $notice = null; } Javelin::initBehavior('select-on-click'); $cert_form = new AphrontFormView(); $cert_form->setUser($viewer)->appendChild(phutil_tag('p', array('class' => 'aphront-form-instructions'), pht('This certificate allows you to authenticate over Conduit, ' . 'the Phabricator API. Normally, you just run %s to install it.', phutil_tag('tt', array(), 'arc install-certificate'))))->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Certificate'))->setHeight(AphrontFormTextAreaControl::HEIGHT_SHORT)->setReadonly(true)->setSigil('select-on-click')->setValue($user->getConduitCertificate())); $cert_form = id(new PHUIObjectBoxView())->setHeaderText(pht('Arcanist Certificate'))->setForm($cert_form); $regen_instruction = pht('You can regenerate this certificate, which ' . 'will invalidate the old certificate and create a new one.'); $regen_form = new AphrontFormView(); $regen_form->setUser($viewer)->setAction($this->getPanelURI())->setWorkflow(true)->appendChild(phutil_tag('p', array('class' => 'aphront-form-instructions'), $regen_instruction))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Regenerate Certificate'))); $regen_form = id(new PHUIObjectBoxView())->setHeaderText(pht('Regenerate Certificate'))->setForm($regen_form); return array($notice, $cert_form, $regen_form); }
public function renderExample() { $request = $this->getRequest(); $user = $request->getUser(); $sevs = array(PHUIInfoView::SEVERITY_ERROR => pht('Error'), PHUIInfoView::SEVERITY_WARNING => pht('Warning'), PHUIInfoView::SEVERITY_NODATA => pht('No Data'), PHUIInfoView::SEVERITY_NOTICE => pht('Notice'), PHUIInfoView::SEVERITY_SUCCESS => pht('Success')); $button = id(new PHUIButtonView())->setTag('a')->setText(pht('Resolve Issue'))->setHref('#'); $views = array(); // Only Title foreach ($sevs as $sev => $title) { $view = new PHUIInfoView(); $view->setSeverity($sev); $view->setTitle($title); $views[] = $view; } $views[] = phutil_tag('br', array(), null); // Only Body foreach ($sevs as $sev => $title) { $view = new PHUIInfoView(); $view->setSeverity($sev); $view->appendChild(pht('Several issues were encountered.')); $view->addButton($button); $views[] = $view; } $views[] = phutil_tag('br', array(), null); // Only Errors foreach ($sevs as $sev => $title) { $view = new PHUIInfoView(); $view->setSeverity($sev); $view->setErrors(array(pht('Overcooked.'), pht('Too much salt.'), pht('Full of sand.'))); $views[] = $view; } $views[] = phutil_tag('br', array(), null); // All foreach ($sevs as $sev => $title) { $view = new PHUIInfoView(); $view->setSeverity($sev); $view->setTitle($title); $view->appendChild(pht('Several issues were encountered.')); $view->setErrors(array(pht('Overcooked.'), pht('Too much salt.'), pht('Full of sand.'))); $views[] = $view; } return $views; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $email = $viewer->loadPrimaryEmail(); if ($viewer->getIsEmailVerified()) { return id(new AphrontRedirectResponse())->setURI('/'); } $email_address = $email->getAddress(); $sent = null; if ($request->isFormPost()) { $email->sendVerificationEmail($viewer); $sent = new PHUIInfoView(); $sent->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $sent->setTitle(pht('Email Sent')); $sent->appendChild(pht('Another verification email was sent to %s.', phutil_tag('strong', array(), $email_address))); } $must_verify = pht('You must verify your email address to login. You should have a ' . 'new email message from Phabricator with verification instructions ' . 'in your inbox (%s).', phutil_tag('strong', array(), $email_address)); $send_again = pht('If you did not receive an email, you can click the button below ' . 'to try sending another one.'); $dialog = id(new AphrontDialogView())->setUser($viewer)->setTitle(pht('Check Your Email'))->appendParagraph($must_verify)->appendParagraph($send_again)->addSubmitButton(pht('Send Another Email')); return $this->buildApplicationPage(array($sent, $dialog), array('title' => pht('Must Verify Email'))); }
private function renderMiniPanel($title, $body) { $panel = new PHUIInfoView(); $panel->setSeverity(PHUIInfoView::SEVERITY_NODATA); $panel->appendChild(phutil_tag('p', array(), array(phutil_tag('strong', array(), $title . ': '), $body))); $this->minipanels[] = $panel; }
public function handleRequest(AphrontRequest $request) { if (!PhabricatorPasswordAuthProvider::getPasswordProvider()) { return new Aphront400Response(); } $e_email = true; $e_captcha = true; $errors = array(); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($request->isFormPost()) { $e_email = null; $e_captcha = pht('Again'); $captcha_ok = AphrontFormRecaptchaControl::processCaptcha($request); if (!$captcha_ok) { $errors[] = pht('Captcha response is incorrect, try again.'); $e_captcha = pht('Invalid'); } $email = $request->getStr('email'); if (!strlen($email)) { $errors[] = pht('You must provide an email address.'); $e_email = pht('Required'); } if (!$errors) { // NOTE: Don't validate the email unless the captcha is good; this makes // it expensive to fish for valid email addresses while giving the user // a better error if they goof their email. $target_email = id(new PhabricatorUserEmail())->loadOneWhere('address = %s', $email); $target_user = null; if ($target_email) { $target_user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $target_email->getUserPHID()); } if (!$target_user) { $errors[] = pht('There is no account associated with that email address.'); $e_email = pht('Invalid'); } // If this address is unverified, only send a reset link to it if // the account has no verified addresses. This prevents an opportunistic // attacker from compromising an account if a user adds an email // address but mistypes it and doesn't notice. // (For a newly created account, all the addresses may be unverified, // which is why we'll send to an unverified address in that case.) if ($target_email && !$target_email->getIsVerified()) { $verified_addresses = id(new PhabricatorUserEmail())->loadAllWhere('userPHID = %s AND isVerified = 1', $target_email->getUserPHID()); if ($verified_addresses) { $errors[] = pht('That email address is not verified. You can only send ' . 'password reset links to a verified address.'); $e_email = pht('Unverified'); } } if (!$errors) { $engine = new PhabricatorAuthSessionEngine(); $uri = $engine->getOneTimeLoginURI($target_user, null, PhabricatorAuthSessionEngine::ONETIME_RESET); if ($is_serious) { $body = pht("You can use this link to reset your Phabricator password:"******"\n\n %s\n", $uri); } else { $body = pht("Condolences on forgetting your password. You can use this " . "link to reset it:\n\n" . " %s\n\n" . "After you set a new password, consider writing it down on a " . "sticky note and attaching it to your monitor so you don't " . "forget again! Choosing a very short, easy-to-remember password " . "like \"cat\" or \"1234\" might also help.\n\n" . "Best Wishes,\nPhabricator\n", $uri); } $mail = id(new PhabricatorMetaMTAMail())->setSubject(pht('[Phabricator] Password Reset'))->setForceDelivery(true)->addRawTos(array($target_email->getAddress()))->setBody($body)->saveAndSend(); return $this->newDialog()->setTitle(pht('Check Your Email'))->setShortTitle(pht('Email Sent'))->appendParagraph(pht('An email has been sent with a link you can use to login.'))->addCancelButton('/', pht('Done')); } } } $error_view = null; if ($errors) { $error_view = new PHUIInfoView(); $error_view->setErrors($errors); } $email_auth = new PHUIFormLayoutView(); $email_auth->appendChild($error_view); $email_auth->setUser($request->getUser())->setFullWidth(true)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Email'))->setName('email')->setValue($request->getStr('email'))->setError($e_email))->appendChild(id(new AphrontFormRecaptchaControl())->setLabel(pht('Captcha'))->setError($e_captcha)); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb(pht('Reset Password')); $dialog = new AphrontDialogView(); $dialog->setUser($request->getUser()); $dialog->setTitle(pht('Forgot Password / Email Login')); $dialog->appendChild($email_auth); $dialog->addSubmitButton(pht('Send Email')); $dialog->setSubmitURI('/login/email/'); return $this->buildApplicationPage(array($crumbs, $dialog), array('title' => pht('Forgot Password'))); }
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)); }
private function buildMergesTable(PhabricatorRepositoryCommit $commit) { $viewer = $this->getViewer(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $merges = $this->getCommitMerges(); if (!$merges) { return null; } $limit = $this->getMergeDisplayLimit(); $caption = null; if (count($merges) > $limit) { $merges = array_slice($merges, 0, $limit); $caption = new PHUIInfoView(); $caption->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $caption->appendChild(pht('This commit merges a very large number of changes. ' . 'Only the first %s are shown.', new PhutilNumber($limit))); } $history_table = id(new DiffusionHistoryTableView())->setUser($viewer)->setDiffusionRequest($drequest)->setHistory($merges); $history_table->loadRevisions(); $panel = new PHUIObjectBoxView(); $panel->setHeaderText(pht('Merged Changes')); $panel->setTable($history_table); if ($caption) { $panel->setInfoView($caption); } return $panel; }
private function browseFile() { $viewer = $this->getViewer(); $request = $this->getRequest(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $before = $request->getStr('before'); if ($before) { return $this->buildBeforeResponse($before); } $path = $drequest->getPath(); $preferences = $viewer->loadPreferences(); $show_blame = $request->getBool('blame', $preferences->getPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME, false)); $show_color = $request->getBool('color', $preferences->getPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR, true)); $view = $request->getStr('view'); if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) { $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_BLAME, $show_blame); $preferences->setPreference(PhabricatorUserPreferences::PREFERENCE_DIFFUSION_COLOR, $show_color); $preferences->save(); $uri = $request->getRequestURI()->alter('blame', null)->alter('color', null); return id(new AphrontRedirectResponse())->setURI($uri); } // We need the blame information if blame is on and we're building plain // text, or blame is on and this is an Ajax request. If blame is on and // this is a colorized request, we don't show blame at first (we ajax it // in afterward) so we don't need to query for it. $needs_blame = $show_blame && !$show_color || $show_blame && $request->isAjax(); $params = array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath()); $byte_limit = null; if ($view !== 'raw') { $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold(); $time_limit = 10; $params += array('timeout' => $time_limit, 'byteLimit' => $byte_limit); } $response = $this->callConduitWithDiffusionRequest('diffusion.filecontentquery', $params); $hit_byte_limit = $response['tooHuge']; $hit_time_limit = $response['tooSlow']; $file_phid = $response['filePHID']; if ($hit_byte_limit) { $corpus = $this->buildErrorCorpus(pht('This file is larger than %s byte(s), and too large to display ' . 'in the web UI.', phutil_format_bytes($byte_limit))); } else { if ($hit_time_limit) { $corpus = $this->buildErrorCorpus(pht('This file took too long to load from the repository (more than ' . '%s second(s)).', new PhutilNumber($time_limit))); } else { $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($file_phid))->executeOne(); if (!$file) { throw new Exception(pht('Failed to load content file!')); } if ($view === 'raw') { return $file->getRedirectResponse(); } $data = $file->loadFileData(); if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) { $file_uri = $file->getBestURI(); if ($file->isViewableImage()) { $corpus = $this->buildImageCorpus($file_uri); } else { $corpus = $this->buildBinaryCorpus($file_uri, $data); } } else { $this->loadLintMessages(); $this->coverage = $drequest->loadCoverage(); // Build the content of the file. $corpus = $this->buildCorpus($show_blame, $show_color, $data, $needs_blame, $drequest, $path, $data); } } } if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent($corpus); } require_celerity_resource('diffusion-source-css'); // Render the page. $view = $this->buildActionView($drequest); $action_list = $this->enrichActionView($view, $drequest, $show_blame, $show_color); $properties = $this->buildPropertyView($drequest, $action_list); $object_box = id(new PHUIObjectBoxView())->setHeader($this->buildHeaderView($drequest))->addPropertyList($properties); $content = array(); $content[] = $object_box; $follow = $request->getStr('follow'); if ($follow) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING); $notice->setTitle(pht('Unable to Continue')); switch ($follow) { case 'first': $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit is the first commit in the repository.')); break; case 'created': $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit created the file.')); break; } $content[] = $notice; } $renamed = $request->getStr('renamed'); if ($renamed) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('File Renamed')); $notice->appendChild(pht('File history passes through a rename from "%s" to "%s".', $drequest->getPath(), $renamed)); $content[] = $notice; } $content[] = $corpus; $content[] = $this->buildOpenRevisions(); $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'browse')); $basename = basename($this->getDiffusionRequest()->getPath()); return $this->newPage()->setTitle(array($basename, $repository->getDisplayName()))->setCrumbs($crumbs)->appendChild($content); }
private function browseFile() { $viewer = $this->getViewer(); $request = $this->getRequest(); $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $before = $request->getStr('before'); if ($before) { return $this->buildBeforeResponse($before); } $path = $drequest->getPath(); $blame_key = PhabricatorDiffusionBlameSetting::SETTINGKEY; $color_key = PhabricatorDiffusionColorSetting::SETTINGKEY; $show_blame = $request->getBool('blame', $viewer->getUserSetting($blame_key)); $show_color = $request->getBool('color', $viewer->getUserSetting($color_key)); $view = $request->getStr('view'); if ($request->isFormPost() && $view != 'raw' && $viewer->isLoggedIn()) { $preferences = PhabricatorUserPreferences::loadUserPreferences($viewer); $editor = id(new PhabricatorUserPreferencesEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setContinueOnMissingFields(true); $xactions = array(); $xactions[] = $preferences->newTransaction($blame_key, $show_blame); $xactions[] = $preferences->newTransaction($color_key, $show_color); $editor->applyTransactions($preferences, $xactions); $uri = $request->getRequestURI()->alter('blame', null)->alter('color', null); return id(new AphrontRedirectResponse())->setURI($uri); } // We need the blame information if blame is on and we're building plain // text, or blame is on and this is an Ajax request. If blame is on and // this is a colorized request, we don't show blame at first (we ajax it // in afterward) so we don't need to query for it. $needs_blame = $show_blame && !$show_color || $show_blame && $request->isAjax(); $params = array('commit' => $drequest->getCommit(), 'path' => $drequest->getPath()); $byte_limit = null; if ($view !== 'raw') { $byte_limit = PhabricatorFileStorageEngine::getChunkThreshold(); $time_limit = 10; $params += array('timeout' => $time_limit, 'byteLimit' => $byte_limit); } $response = $this->callConduitWithDiffusionRequest('diffusion.filecontentquery', $params); $hit_byte_limit = $response['tooHuge']; $hit_time_limit = $response['tooSlow']; $file_phid = $response['filePHID']; if ($hit_byte_limit) { $corpus = $this->buildErrorCorpus(pht('This file is larger than %s byte(s), and too large to display ' . 'in the web UI.', phutil_format_bytes($byte_limit))); } else { if ($hit_time_limit) { $corpus = $this->buildErrorCorpus(pht('This file took too long to load from the repository (more than ' . '%s second(s)).', new PhutilNumber($time_limit))); } else { $file = id(new PhabricatorFileQuery())->setViewer($viewer)->withPHIDs(array($file_phid))->executeOne(); if (!$file) { throw new Exception(pht('Failed to load content file!')); } if ($view === 'raw') { return $file->getRedirectResponse(); } $data = $file->loadFileData(); $ref = $this->getGitLFSRef($repository, $data); if ($ref) { if ($view == 'git-lfs') { $file = $this->loadGitLFSFile($ref); // Rename the file locally so we generate a better vanity URI for // it. In storage, it just has a name like "lfs-13f9a94c0923...", // since we don't get any hints about possible human-readable names // at upload time. $basename = basename($drequest->getPath()); $file->makeEphemeral(); $file->setName($basename); return $file->getRedirectResponse(); } else { $corpus = $this->buildGitLFSCorpus($ref); } } else { if (ArcanistDiffUtils::isHeuristicBinaryFile($data)) { $file_uri = $file->getBestURI(); if ($file->isViewableImage()) { $corpus = $this->buildImageCorpus($file_uri); } else { $corpus = $this->buildBinaryCorpus($file_uri, $data); } } else { $this->loadLintMessages(); $this->coverage = $drequest->loadCoverage(); // Build the content of the file. $corpus = $this->buildCorpus($show_blame, $show_color, $data, $needs_blame, $drequest, $path, $data); } } } } if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent($corpus); } require_celerity_resource('diffusion-source-css'); // Render the page. $view = $this->buildCurtain($drequest); $curtain = $this->enrichCurtain($view, $drequest, $show_blame, $show_color); $properties = $this->buildPropertyView($drequest); $header = $this->buildHeaderView($drequest); $header->setHeaderIcon('fa-file-code-o'); $content = array(); $follow = $request->getStr('follow'); if ($follow) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING); $notice->setTitle(pht('Unable to Continue')); switch ($follow) { case 'first': $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit is the first commit in the repository.')); break; case 'created': $notice->appendChild(pht('Unable to continue tracing the history of this file because ' . 'this commit created the file.')); break; } $content[] = $notice; } $renamed = $request->getStr('renamed'); if ($renamed) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('File Renamed')); $notice->appendChild(pht('File history passes through a rename from "%s" to "%s".', $drequest->getPath(), $renamed)); $content[] = $notice; } $content[] = $corpus; $content[] = $this->buildOpenRevisions(); $crumbs = $this->buildCrumbs(array('branch' => true, 'path' => true, 'view' => 'browse')); $crumbs->setBorder(true); $basename = basename($this->getDiffusionRequest()->getPath()); $view = id(new PHUITwoColumnView())->setHeader($header)->setCurtain($curtain)->setMainColumn(array($content)); if ($properties) { $view->addPropertySection(pht('Details'), $properties); } $title = array($basename, $repository->getDisplayName()); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->appendChild(array($view)); }
public function handleException(Exception $ex) { $request = $this->getRequest(); // For Conduit requests, return a Conduit response. if ($request->isConduit()) { $response = new ConduitAPIResponse(); $response->setErrorCode(get_class($ex)); $response->setErrorInfo($ex->getMessage()); return id(new AphrontJSONResponse())->setAddJSONShield(false)->setContent($response->toDictionary()); } // For non-workflow requests, return a Ajax response. if ($request->isAjax() && !$request->isWorkflow()) { // Log these; they don't get shown on the client and can be difficult // to debug. phlog($ex); $response = new AphrontAjaxResponse(); $response->setError(array('code' => get_class($ex), 'info' => $ex->getMessage())); return $response; } $user = $request->getUser(); if (!$user) { // If we hit an exception very early, we won't have a user. $user = new PhabricatorUser(); } if ($ex instanceof PhabricatorSystemActionRateLimitException) { $dialog = id(new AphrontDialogView())->setTitle(pht('Slow Down!'))->setUser($user)->setErrors(array(pht('You are being rate limited.')))->appendParagraph($ex->getMessage())->appendParagraph($ex->getRateExplanation())->addCancelButton('/', pht('Okaaaaaaaaaaaaaay...')); $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } if ($ex instanceof PhabricatorAuthHighSecurityRequiredException) { $form = id(new PhabricatorAuthSessionEngine())->renderHighSecurityForm($ex->getFactors(), $ex->getFactorValidationResults(), $user, $request); $dialog = id(new AphrontDialogView())->setUser($user)->setTitle(pht('Entering High Security'))->setShortTitle(pht('Security Checkpoint'))->setWidth(AphrontDialogView::WIDTH_FORM)->addHiddenInput(AphrontRequest::TYPE_HISEC, true)->setErrors(array(pht('You are taking an action which requires you to enter ' . 'high security.')))->appendParagraph(pht('High security mode helps protect your account from security ' . 'threats, like session theft or someone messing with your stuff ' . 'while you\'re grabbing a coffee. To enter high security mode, ' . 'confirm your credentials.'))->appendChild($form->buildLayoutView())->appendParagraph(pht('Your account will remain in high security mode for a short ' . 'period of time. When you are finished taking sensitive ' . 'actions, you should leave high security.'))->setSubmitURI($request->getPath())->addCancelButton($ex->getCancelURI())->addSubmitButton(pht('Enter High Security')); $request_parameters = $request->getPassthroughRequestParameters($respect_quicksand = true); foreach ($request_parameters as $key => $value) { $dialog->addHiddenInput($key, $value); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } if ($ex instanceof PhabricatorPolicyException) { if (!$user->isLoggedIn()) { // If the user isn't logged in, just give them a login form. This is // probably a generally more useful response than a policy dialog that // they have to click through to get a login form. // // Possibly we should add a header here like "you need to login to see // the thing you are trying to look at". $login_controller = new PhabricatorAuthStartController(); $login_controller->setRequest($request); $auth_app_class = 'PhabricatorAuthApplication'; $auth_app = PhabricatorApplication::getByClass($auth_app_class); $login_controller->setCurrentApplication($auth_app); return $login_controller->handleRequest($request); } $content = array(phutil_tag('div', array('class' => 'aphront-policy-rejection'), $ex->getRejection())); $list = null; if ($ex->getCapabilityName()) { $list = $ex->getMoreInfo(); foreach ($list as $key => $item) { $list[$key] = $item; } $content[] = phutil_tag('div', array('class' => 'aphront-capability-details'), pht('Users with the "%s" capability:', $ex->getCapabilityName())); } $dialog = id(new AphrontDialogView())->setTitle($ex->getTitle())->setClass('aphront-access-dialog')->setUser($user)->appendChild($content); if ($list) { $dialog->appendList($list); } if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', pht('Close')); } else { $dialog->addCancelButton('/', pht('OK')); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); return $response; } if ($ex instanceof AphrontUsageException) { $error = new PHUIInfoView(); $error->setTitle($ex->getTitle()); $error->appendChild($ex->getMessage()); $view = new PhabricatorStandardPageView(); $view->setRequest($this->getRequest()); $view->appendChild($error); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); $response->setHTTPResponseCode(500); return $response; } // Always log the unhandled exception. phlog($ex); $class = get_class($ex); $message = $ex->getMessage(); if ($ex instanceof AphrontSchemaQueryException) { $message .= "\n\n" . pht("NOTE: This usually indicates that the MySQL schema has not been " . "properly upgraded. Run '%s' to ensure your schema is up to date.", 'bin/storage upgrade'); } if (PhabricatorEnv::getEnvConfig('phabricator.developer-mode')) { $trace = id(new AphrontStackTraceView())->setUser($user)->setTrace($ex->getTrace()); } else { $trace = null; } $content = phutil_tag('div', array('class' => 'aphront-unhandled-exception'), array(phutil_tag('div', array('class' => 'exception-message'), $message), $trace)); $dialog = new AphrontDialogView(); $dialog->setTitle(pht('Unhandled Exception ("%s")', $class))->setClass('aphront-exception-dialog')->setUser($user)->appendChild($content); if ($this->getRequest()->isAjax()) { $dialog->addCancelButton('/', pht('Close')); } $response = new AphrontDialogResponse(); $response->setDialog($dialog); $response->setHTTPResponseCode(500); return $response; }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($this->id))->needSubscriberPHIDs(true)->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery())->setViewer($user)->withIDs(array($workflow))->executeOne(); } $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($user)->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST; $e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = ManiphestTaskHasMockEdgeType::EDGECONST; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock)); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), true); if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = $user->loadHandles($phids); $info_view = null; if ($parent_task) { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?parent=' . $parent_task->getID())->setText(pht('Create Another Subtask'))); $info_view->appendChild(hsprintf('Created a subtask of <strong>%s</strong>.', $handles->renderHandle($parent_task->getPHID()))); } else { if ($workflow == 'create') { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?template=' . $task->getID())->setText(pht('Similar Task'))); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/')->setText(pht('Empty Task'))); $info_view->appendChild(pht('New task created. Create another?')); } } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->setContextObject($task); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery(), $engine); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); $transaction_types = array(PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), PhabricatorTransactions::TYPE_SUBSCRIBERS => pht('Add CCs'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), PhabricatorTransactions::TYPE_EDGE => pht('Associate Projects')); // Remove actions the user doesn't have permission to take. $requires = array(ManiphestTransaction::TYPE_OWNER => ManiphestEditAssignCapability::CAPABILITY, ManiphestTransaction::TYPE_PRIORITY => ManiphestEditPriorityCapability::CAPABILITY, PhabricatorTransactions::TYPE_EDGE => ManiphestEditProjectsCapability::CAPABILITY, ManiphestTransaction::TYPE_STATUS => ManiphestEditStatusCapability::CAPABILITY); foreach ($transaction_types as $type => $name) { if (isset($requires[$type])) { if (!$this->hasApplicationCapability($requires[$type])) { unset($transaction_types[$type]); } } } // Don't show an option to change to the current status, or to change to // the duplicate status explicitly. unset($resolution_types[$task->getStatus()]); unset($resolution_types[ManiphestTaskStatus::getDuplicateStatus()]); // Don't show owner/priority changes for closed tasks, as they don't make // much sense. if ($task->isClosed()) { unset($transaction_types[ManiphestTransaction::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransaction::TYPE_OWNER]); } $default_claim = array($user->getPHID() => $user->getUsername() . ' (' . $user->getRealName() . ')'); $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $projects_source = new PhabricatorProjectDatasource(); $users_source = new PhabricatorPeopleDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $comment_form = new AphrontFormView(); $comment_form->setUser($user)->setWorkflow(true)->setAction('/maniphest/transaction/save/')->setEncType('multipart/form-data')->addHiddenInput('taskID', $task->getID())->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Action'))->setName('action')->setOptions($transaction_types)->setID('transaction-action'))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Status'))->setName('resolution')->setControlID('resolution')->setControlStyle('display: none')->setOptions($resolution_types))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Assign To'))->setName('assign_to')->setControlID('assign_to')->setControlStyle('display: none')->setID('assign-tokenizer')->setDisableBehavior(true)->setDatasource($users_source))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('CCs'))->setName('ccs')->setControlID('ccs')->setControlStyle('display: none')->setID('cc-tokenizer')->setDisableBehavior(true)->setDatasource($mailable_source))->appendChild(id(new AphrontFormSelectControl())->setLabel(pht('Priority'))->setName('priority')->setOptions($priority_map)->setControlID('priority')->setControlStyle('display: none')->setValue($task->getPriority()))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Projects'))->setName('projects')->setControlID('projects')->setControlStyle('display: none')->setID('projects-tokenizer')->setDisableBehavior(true)->setDatasource($projects_source))->appendChild(id(new AphrontFormFileControl())->setLabel(pht('File'))->setName('file')->setControlID('file')->setControlStyle('display: none'))->appendChild(id(new PhabricatorRemarkupControl())->setUser($user)->setLabel(pht('Comments'))->setName('comments')->setValue($draft_text)->setID('transaction-comments')->setUser($user))->appendChild(id(new AphrontFormSubmitControl())->setValue(pht('Submit'))); $control_map = array(ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_OWNER => 'assign_to', PhabricatorTransactions::TYPE_SUBSCRIBERS => 'ccs', ManiphestTransaction::TYPE_PRIORITY => 'priority', PhabricatorTransactions::TYPE_EDGE => 'projects'); $tokenizer_map = array(PhabricatorTransactions::TYPE_EDGE => array('id' => 'projects-tokenizer', 'src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText()), ManiphestTransaction::TYPE_OWNER => array('id' => 'assign-tokenizer', 'src' => $users_source->getDatasourceURI(), 'value' => $default_claim, 'limit' => 1, 'placeholder' => $users_source->getPlaceholderText()), PhabricatorTransactions::TYPE_SUBSCRIBERS => array('id' => 'cc-tokenizer', 'src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText())); // TODO: Initializing these behaviors for logged out users fatals things. if ($user->isLoggedIn()) { Javelin::initBehavior('maniphest-transaction-controls', array('select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map)); Javelin::initBehavior('maniphest-transaction-preview', array('uri' => '/maniphest/transaction/preview/' . $task->getID() . '/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map)); } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $comment_header = $is_serious ? pht('Add Comment') : pht('Weigh In'); $preview_panel = phutil_tag_div('aphront-panel-preview', phutil_tag('div', array('id' => 'transaction-preview'), phutil_tag_div('aphront-panel-preview-loading-text', pht('Loading preview...')))); $object_name = 'T' . $task->getID(); $actions = $this->buildActionView($task); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($object_name, '/' . $object_name); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView($task, $field_list, $edges, $actions, $handles); $description = $this->buildDescriptionView($task, $engine); if (!$user->isLoggedIn()) { // TODO: Eventually, everything should run through this. For now, we're // only using it to get a consistent "Login to Comment" button. $comment_box = id(new PhabricatorApplicationTransactionCommentView())->setUser($user)->setRequestURI($request->getRequestURI()); $preview_panel = null; } else { $comment_box = id(new PHUIObjectBoxView())->setFlush(true)->setHeaderText($comment_header)->appendChild($comment_form); $timeline->setQuoteTargetID('transaction-comments'); $timeline->setQuoteRef($object_name); } $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); if ($info_view) { $object_box->setInfoView($info_view); } if ($description) { $object_box->addPropertyList($description); } return $this->buildApplicationPage(array($crumbs, $object_box, $timeline, $comment_box, $preview_panel), array('title' => 'T' . $task->getID() . ' ' . $task->getTitle(), 'pageObjects' => array($task->getPHID()))); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $id = $request->getURIData('id'); $current_version = null; if ($id) { $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($id))->needContent(true)->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$document) { return new Aphront404Response(); } $current_version = $document->getContent()->getVersion(); $revert = $request->getInt('revert'); if ($revert) { $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $revert); if (!$content) { return new Aphront404Response(); } } else { $content = $document->getContent(); } } else { $slug = $request->getStr('slug'); $slug = PhabricatorSlug::normalize($slug); if (!$slug) { return new Aphront404Response(); } $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withSlugs(array($slug))->needContent(true)->executeOne(); if ($document) { $content = $document->getContent(); $current_version = $content->getVersion(); } else { $document = PhrictionDocument::initializeNewDocument($viewer, $slug); $content = $document->getContent(); } } if ($request->getBool('nodraft')) { $draft = null; $draft_key = null; } else { if ($document->getPHID()) { $draft_key = $document->getPHID() . ':' . $content->getVersion(); } else { $draft_key = 'phriction:' . $content->getSlug(); } $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $viewer->getPHID(), $draft_key); } if ($draft && strlen($draft->getDraft()) && $draft->getDraft() != $content->getContent()) { $content_text = $draft->getDraft(); $discard = phutil_tag('a', array('href' => $request->getRequestURI()->alter('nodraft', true)), pht('discard this draft')); $draft_note = new PHUIInfoView(); $draft_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $draft_note->setTitle(pht('Recovered Draft')); $draft_note->appendChild(hsprintf('<p>%s</p>', pht('Showing a saved draft of your edits, you can %s.', $discard))); } else { $content_text = $content->getContent(); $draft_note = null; } require_celerity_resource('phriction-document-css'); $e_title = true; $e_content = true; $validation_exception = null; $notes = null; $title = $content->getTitle(); $overwrite = false; $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID($document->getPHID()); if ($request->isFormPost()) { $title = $request->getStr('title'); $content_text = $request->getStr('content'); $notes = $request->getStr('description'); $current_version = $request->getInt('contentVersion'); $v_view = $request->getStr('viewPolicy'); $v_edit = $request->getStr('editPolicy'); $v_cc = $request->getArr('cc'); $xactions = array(); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_TITLE)->setNewValue($title); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhrictionTransaction::TYPE_CONTENT)->setNewValue($content_text); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)->setNewValue($v_view); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)->setNewValue($v_edit); $xactions[] = id(new PhrictionTransaction())->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS)->setNewValue(array('=' => $v_cc)); $editor = id(new PhrictionTransactionEditor())->setActor($viewer)->setContentSourceFromRequest($request)->setContinueOnNoEffect(true)->setDescription($notes)->setProcessContentVersionError(!$request->getBool('overwrite'))->setContentVersion($current_version); try { $editor->applyTransactions($document, $xactions); if ($draft) { $draft->delete(); } $uri = PhrictionDocument::getSlugURI($document->getSlug()); return id(new AphrontRedirectResponse())->setURI($uri); } catch (PhabricatorApplicationTransactionValidationException $ex) { $validation_exception = $ex; $e_title = nonempty($ex->getShortMessage(PhrictionTransaction::TYPE_TITLE), true); $e_content = nonempty($ex->getShortMessage(PhrictionTransaction::TYPE_CONTENT), true); // if we're not supposed to process the content version error, then // overwrite that content...! if (!$editor->getProcessContentVersionError()) { $overwrite = true; } $document->setViewPolicy($v_view); $document->setEditPolicy($v_edit); } } if ($document->getID()) { $panel_header = pht('Edit Document: %s', $content->getTitle()); $page_title = pht('Edit Document'); $header_icon = 'fa-pencil'; if ($overwrite) { $submit_button = pht('Overwrite Changes'); } else { $submit_button = pht('Save Changes'); } } else { $panel_header = pht('Create New Phriction Document'); $submit_button = pht('Create Document'); $page_title = pht('Create Document'); $header_icon = 'fa-plus-square'; } $uri = $document->getSlug(); $uri = PhrictionDocument::getSlugURI($uri); $uri = PhabricatorEnv::getProductionURI($uri); $cancel_uri = PhrictionDocument::getSlugURI($document->getSlug()); $policies = id(new PhabricatorPolicyQuery())->setViewer($viewer)->setObject($document)->execute(); $view_capability = PhabricatorPolicyCapability::CAN_VIEW; $edit_capability = PhabricatorPolicyCapability::CAN_EDIT; $form = id(new AphrontFormView())->setUser($viewer)->addHiddenInput('slug', $document->getSlug())->addHiddenInput('nodraft', $request->getBool('nodraft'))->addHiddenInput('contentVersion', $current_version)->addHiddenInput('overwrite', $overwrite)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Title'))->setValue($title)->setError($e_title)->setName('title'))->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('URI'))->setValue($uri))->appendChild(id(new PhabricatorRemarkupControl())->setLabel(pht('Content'))->setValue($content_text)->setError($e_content)->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_TALL)->setName('content')->setID('document-textarea')->setUser($viewer))->appendControl(id(new AphrontFormTokenizerControl())->setLabel(pht('Subscribers'))->setName('cc')->setValue($v_cc)->setUser($viewer)->setDatasource(new PhabricatorMetaMTAMailableDatasource()))->appendChild(id(new AphrontFormPolicyControl())->setName('viewPolicy')->setPolicyObject($document)->setCapability($view_capability)->setPolicies($policies)->setCaption($document->describeAutomaticCapability($view_capability)))->appendChild(id(new AphrontFormPolicyControl())->setName('editPolicy')->setPolicyObject($document)->setCapability($edit_capability)->setPolicies($policies)->setCaption($document->describeAutomaticCapability($edit_capability)))->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Edit Notes'))->setValue($notes)->setError(null)->setName('description'))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue($submit_button)); $form_box = id(new PHUIObjectBoxView())->setHeaderText(pht('Document'))->setValidationException($validation_exception)->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel())->setHeader($content->getTitle())->setPreviewURI('/phriction/preview/' . $document->getSlug())->setControlID('document-textarea')->setPreviewType(PHUIRemarkupPreviewPanel::DOCUMENT); $crumbs = $this->buildApplicationCrumbs(); if ($document->getID()) { $crumbs->addTextCrumb($content->getTitle(), PhrictionDocument::getSlugURI($document->getSlug())); $crumbs->addTextCrumb(pht('Edit')); } else { $crumbs->addTextCrumb(pht('Create')); } $crumbs->setBorder(true); $header = id(new PHUIHeaderView())->setHeader($panel_header)->setHeaderIcon($header_icon); $view = id(new PHUITwoColumnView())->setHeader($header)->setFooter(array($draft_note, $form_box, $preview)); return $this->newPage()->setTitle($page_title)->setCrumbs($crumbs)->appendChild($view); }
public function handleRequest(AphrontRequest $request) { $viewer = $request->getViewer(); $this->slug = $request->getURIData('slug'); $slug = PhabricatorSlug::normalize($this->slug); if ($slug != $this->slug) { $uri = PhrictionDocument::getSlugURI($slug); // Canonicalize pages to their one true URI. return id(new AphrontRedirectResponse())->setURI($uri); } require_celerity_resource('phriction-document-css'); $document = id(new PhrictionDocumentQuery())->setViewer($viewer)->withSlugs(array($slug))->executeOne(); $version_note = null; $core_content = ''; $move_notice = ''; $properties = null; $content = null; if (!$document) { $document = PhrictionDocument::initializeNewDocument($viewer, $slug); $create_uri = '/phriction/edit/?slug=' . $slug; $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_WARNING); $notice->setTitle(pht('No content here!')); $notice->appendChild(pht('No document found at %s. You can <strong>' . '<a href="%s">create a new document here</a></strong>.', phutil_tag('tt', array(), $slug), $create_uri)); $core_content = $notice; $page_title = pht('Page Not Found'); } else { $version = $request->getInt('v'); if ($version) { $content = id(new PhrictionContent())->loadOneWhere('documentID = %d AND version = %d', $document->getID(), $version); if (!$content) { return new Aphront404Response(); } if ($content->getID() != $document->getContentID()) { $vdate = phabricator_datetime($content->getDateCreated(), $viewer); $version_note = new PHUIInfoView(); $version_note->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $version_note->appendChild(pht('You are viewing an older version of this document, as it ' . 'appeared on %s.', $vdate)); } } else { $content = id(new PhrictionContent())->load($document->getContentID()); } $page_title = $content->getTitle(); $properties = $this->buildPropertyListView($document, $content, $slug); $doc_status = $document->getStatus(); $current_status = $content->getChangeType(); if ($current_status == PhrictionChangeType::CHANGE_EDIT || $current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $core_content = $content->renderContent($viewer); } else { if ($current_status == PhrictionChangeType::CHANGE_DELETE) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Document Deleted')); $notice->appendChild(pht('This document has been deleted. You can edit it to put new ' . 'content here, or use history to revert to an earlier version.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_STUB) { $notice = new PHUIInfoView(); $notice->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $notice->setTitle(pht('Empty Document')); $notice->appendChild(pht('This document is empty. You can edit it to put some proper ' . 'content here.')); $core_content = $notice->render(); } else { if ($current_status == PhrictionChangeType::CHANGE_MOVE_AWAY) { $new_doc_id = $content->getChangeRef(); $slug_uri = null; // If the new document exists and the viewer can see it, provide a link // to it. Otherwise, render a generic message. $new_docs = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($new_doc_id))->execute(); if ($new_docs) { $new_doc = head($new_docs); $slug_uri = PhrictionDocument::getSlugURI($new_doc->getSlug()); } $notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved to %s. You can edit it to put ' . 'new content here, or use history to revert to an earlier ' . 'version.', phutil_tag('a', array('href' => $slug_uri), $slug_uri)))); } else { $notice->appendChild(phutil_tag('p', array(), pht('This document has been moved. You can edit it to put new ' . 'contne here, or use history to revert to an earlier ' . 'version.'))); } $core_content = $notice->render(); } else { throw new Exception(pht("Unknown document status '%s'!", $doc_status)); } } } } $move_notice = null; if ($current_status == PhrictionChangeType::CHANGE_MOVE_HERE) { $from_doc_id = $content->getChangeRef(); $slug_uri = null; // If the old document exists and is visible, provide a link to it. $from_docs = id(new PhrictionDocumentQuery())->setViewer($viewer)->withIDs(array($from_doc_id))->execute(); if ($from_docs) { $from_doc = head($from_docs); $slug_uri = PhrictionDocument::getSlugURI($from_doc->getSlug()); } $move_notice = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE); if ($slug_uri) { $move_notice->appendChild(pht('This document was moved from %s.', phutil_tag('a', array('href' => $slug_uri), $slug_uri))); } else { // Render this for consistency, even though it's a bit silly. $move_notice->appendChild(pht('This document was moved from elsewhere.')); } } } $children = $this->renderDocumentChildren($slug); $actions = $this->buildActionView($viewer, $document); $crumbs = $this->buildApplicationCrumbs(); $crumbs->setBorder(true); $crumb_views = $this->renderBreadcrumbs($slug); foreach ($crumb_views as $view) { $crumbs->addCrumb($view); } $action_button = id(new PHUIButtonView())->setTag('a')->setText(pht('Actions'))->setHref('#')->setIconFont('fa-bars')->addClass('phui-mobile-menu')->setDropdownMenu($actions); $header = id(new PHUIHeaderView())->setUser($viewer)->setPolicyObject($document)->setHeader($page_title)->addActionLink($action_button); if ($content) { $header->setEpoch($content->getDateCreated()); } $prop_list = null; if ($properties) { $prop_list = new PHUIPropertyGroupView(); $prop_list->addPropertyList($properties); } $page_content = id(new PHUIDocumentView())->setHeader($header)->appendChild(array($prop_list, $version_note, $move_notice, $core_content)); return $this->buildApplicationPage(array($crumbs->render(), $page_content, $children), array('pageObjects' => array($document->getPHID()), 'title' => $page_title)); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $viewer_is_anonymous = !$user->isLoggedIn(); $revision = id(new DifferentialRevisionQuery())->withIDs(array($this->revisionID))->setViewer($request->getUser())->needRelationships(true)->needReviewerStatus(true)->needReviewerAuthority(true)->executeOne(); if (!$revision) { return new Aphront404Response(); } $diffs = id(new DifferentialDiffQuery())->setViewer($request->getUser())->withRevisionIDs(array($this->revisionID))->execute(); $diffs = array_reverse($diffs, $preserve_keys = true); if (!$diffs) { throw new Exception(pht('This revision has no diffs. Something has gone quite wrong.')); } $revision->attachActiveDiff(last($diffs)); $diff_vs = $request->getInt('vs'); $target_id = $request->getInt('id'); $target = idx($diffs, $target_id, end($diffs)); $target_manual = $target; if (!$target_id) { foreach ($diffs as $diff) { if ($diff->getCreationMethod() != 'commit') { $target_manual = $diff; } } } if (empty($diffs[$diff_vs])) { $diff_vs = null; } $repository = null; $repository_phid = $target->getRepositoryPHID(); if ($repository_phid) { if ($repository_phid == $revision->getRepositoryPHID()) { $repository = $revision->getRepository(); } else { $repository = id(new PhabricatorRepositoryQuery())->setViewer($user)->withPHIDs(array($repository_phid))->executeOne(); } } list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository); if ($request->getExists('download')) { return $this->buildRawDiffResponse($revision, $changesets, $vs_changesets, $vs_map, $repository); } $map = $vs_map; if (!$map) { $map = array_fill_keys(array_keys($changesets), 0); } $old_ids = array(); $new_ids = array(); foreach ($map as $id => $vs) { if ($vs <= 0) { $old_ids[] = $id; $new_ids[] = $id; } else { $new_ids[] = $id; $new_ids[] = $vs; } } $props = id(new DifferentialDiffProperty())->loadAllWhere('diffID = %d', $target_manual->getID()); $props = mpull($props, 'getData', 'getName'); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $user->getPHID())); foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $field_list = PhabricatorCustomField::getObjectFields($revision, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($user); $field_list->readFieldsFromStorage($revision); $warning_handle_map = array(); foreach ($field_list->getFields() as $key => $field) { $req = $field->getRequiredHandlePHIDsForRevisionHeaderWarnings(); foreach ($req as $phid) { $warning_handle_map[$key][] = $phid; $object_phids[] = $phid; } } $handles = $this->loadViewerHandles($object_phids); $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = count($changesets); $warning = new PHUIInfoView(); $warning->setTitle(pht('Very Large Diff')); $warning->setSeverity(PHUIInfoView::SEVERITY_WARNING); $warning->appendChild(hsprintf('%s <strong>%s</strong>', pht('This diff is very large and affects %s files. ' . 'You may load each file individually or ', new PhutilNumber($count)), phutil_tag('a', array('class' => 'button grey', 'href' => $request_uri->alter('large', 'true')->setFragment('toc')), pht('Show All Files Inline')))); $warning = $warning->render(); $old = array_select_keys($changesets, $old_ids); $new = array_select_keys($changesets, $new_ids); $query = id(new DifferentialInlineCommentQuery())->setViewer($user)->needHidden(true)->withRevisionPHIDs(array($revision->getPHID())); $inlines = $query->execute(); $inlines = $query->adjustInlinesForChangesets($inlines, $old, $new, $revision); $visible_changesets = array(); foreach ($inlines as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { $visible_changesets[$changeset_id] = $changesets[$changeset_id]; } } } else { $warning = null; $visible_changesets = $changesets; } $commit_hashes = mpull($diffs, 'getSourceControlBaseRevision'); $local_commits = idx($props, 'local:commits', array()); foreach ($local_commits as $local_commit) { $commit_hashes[] = idx($local_commit, 'tree'); $commit_hashes[] = idx($local_commit, 'local'); } $commit_hashes = array_unique(array_filter($commit_hashes)); if ($commit_hashes) { $commits_for_links = id(new DiffusionCommitQuery())->setViewer($user)->withIdentifiers($commit_hashes)->execute(); $commits_for_links = mpull($commits_for_links, null, 'getCommitIdentifier'); } else { $commits_for_links = array(); } $revision_detail = id(new DifferentialRevisionDetailView())->setUser($user)->setRevision($revision)->setDiff(end($diffs))->setCustomFields($field_list)->setURI($request->getRequestURI()); $actions = $this->getRevisionActions($revision); $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_MOST); $repository = $revision->getRepository(); if ($repository) { $symbol_indexes = $this->buildSymbolIndexes($repository, $visible_changesets); } else { $symbol_indexes = array(); } $revision_detail->setActions($actions); $revision_detail->setUser($user); $revision_detail_box = $revision_detail->render(); $revision_warnings = $this->buildRevisionWarnings($revision, $field_list, $warning_handle_map, $handles); if ($revision_warnings) { $revision_warnings = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($revision_warnings); $revision_detail_box->setInfoView($revision_warnings); } $detail_diffs = array_select_keys($diffs, array($diff_vs, $target->getID())); $detail_diffs = mpull($detail_diffs, null, 'getPHID'); $buildables = id(new HarbormasterBuildableQuery())->setViewer($user)->withBuildablePHIDs(array_keys($detail_diffs))->withManualBuildables(false)->needBuilds(true)->needTargets(true)->execute(); $buildables = mpull($buildables, null, 'getBuildablePHID'); foreach ($detail_diffs as $diff_phid => $detail_diff) { $detail_diff->attachBuildable(idx($buildables, $diff_phid)); } $diff_detail_box = $this->buildDiffDetailView($detail_diffs, $revision, $field_list); $comment_view = $this->buildTransactions($revision, $diff_vs ? $diffs[$diff_vs] : $target, $target, $old_ids, $new_ids); if (!$viewer_is_anonymous) { $comment_view->setQuoteRef('D' . $revision->getID()); $comment_view->setQuoteTargetID('comment-content'); } $wrap_id = celerity_generate_unique_node_id(); $comment_view = phutil_tag('div', array('id' => $wrap_id), $comment_view); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($changesets); $changeset_view->setVisibleChangesets($visible_changesets); if (!$viewer_is_anonymous) { $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/'); } $changeset_view->setStandaloneURI('/differential/changeset/'); $changeset_view->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new'); $changeset_view->setUser($user); $changeset_view->setDiff($target); $changeset_view->setRenderingReferences($rendering_references); $changeset_view->setVsMap($vs_map); $changeset_view->setWhitespace($whitespace); if ($repository) { $changeset_view->setRepository($repository); } $changeset_view->setSymbolIndexes($symbol_indexes); $changeset_view->setTitle(pht('Diff %s', $target->getID())); $diff_history = id(new DifferentialRevisionUpdateHistoryView())->setUser($user)->setDiffs($diffs)->setSelectedVersusDiffID($diff_vs)->setSelectedDiffID($target->getID())->setSelectedWhitespace($whitespace)->setCommitsForLinks($commits_for_links); $local_view = id(new DifferentialLocalCommitsView())->setUser($user)->setLocalCommits(idx($props, 'local:commits'))->setCommitsForLinks($commits_for_links); if ($repository) { $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository); } else { $other_revisions = array(); } $other_view = null; if ($other_revisions) { $other_view = $this->renderOtherRevisions($other_revisions); } $toc_view = $this->buildTableOfContents($changesets, $visible_changesets, $target->loadCoverageMap($user)); $comment_form = null; if (!$viewer_is_anonymous) { $draft = id(new PhabricatorDraft())->loadOneWhere('authorPHID = %s AND draftKey = %s', $user->getPHID(), 'differential-comment-' . $revision->getID()); $reviewers = array(); $ccs = array(); if ($draft) { $reviewers = idx($draft->getMetadata(), 'reviewers', array()); $ccs = idx($draft->getMetadata(), 'ccs', array()); if ($reviewers || $ccs) { $handles = $this->loadViewerHandles(array_merge($reviewers, $ccs)); $reviewers = array_select_keys($handles, $reviewers); $ccs = array_select_keys($handles, $ccs); } } $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $review_warnings = array(); foreach ($field_list->getFields() as $field) { $review_warnings[] = $field->getWarningsForDetailView(); } $review_warnings = array_mergev($review_warnings); if ($review_warnings) { $review_warnings_panel = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($review_warnings); $comment_form->setInfoView($review_warnings_panel); } $comment_form->setActions($this->getRevisionCommentActions($revision)); $action_uri = $this->getApplicationURI('comment/save/' . $revision->getID() . '/'); $comment_form->setActionURI($action_uri); $comment_form->setUser($user); $comment_form->setDraft($draft); $comment_form->setReviewers(mpull($reviewers, 'getFullName', 'getPHID')); $comment_form->setCCs(mpull($ccs, 'getFullName', 'getPHID')); // TODO: This just makes the "Z" key work. Generalize this and remove // it at some point. $comment_form = phutil_tag('div', array('class' => 'differential-add-comment-panel'), $comment_form); } $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); Javelin::initBehavior('differential-user-select'); $page_pane = id(new DifferentialPrimaryPaneView())->setID($pane_id)->appendChild($comment_view); $signatures = DifferentialRequiredSignaturesField::loadForRevision($revision); $missing_signatures = false; foreach ($signatures as $phid => $signed) { if (!$signed) { $missing_signatures = true; } } if ($missing_signatures) { $signature_message = id(new PHUIInfoView())->setErrors(array(array(phutil_tag('strong', array(), pht('Content Hidden:')), ' ', pht('The content of this revision is hidden until the author has ' . 'signed all of the required legal agreements.')))); $page_pane->appendChild($signature_message); } else { $page_pane->appendChild(array($diff_history, $warning, $local_view, $toc_view, $other_view, $changeset_view)); } if ($comment_form) { $page_pane->appendChild($comment_form); } else { // TODO: For now, just use this to get "Login to Comment". $page_pane->appendChild(id(new PhabricatorApplicationTransactionCommentView())->setUser($user)->setRequestURI($request->getRequestURI())); } $object_id = 'D' . $revision->getID(); $content = array($revision_detail_box, $diff_detail_box, $page_pane); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($object_id, '/' . $object_id); $prefs = $user->loadPreferences(); $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; if ($prefs->getPreference($pref_filetree)) { $collapsed = $prefs->getPreference(PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED, false); $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())->setTitle('D' . $revision->getID())->setBaseURI(new PhutilURI('/D' . $revision->getID()))->setCollapsed((bool) $collapsed)->build($changesets); $nav->appendChild($content); $nav->setCrumbs($crumbs); $content = $nav; } else { array_unshift($content, $crumbs); } return $this->buildApplicationPage($content, array('title' => $object_id . ' ' . $revision->getTitle(), 'pageObjects' => array($revision->getPHID()))); }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $this->revisionID = $request->getURIData('id'); $viewer_is_anonymous = !$viewer->isLoggedIn(); $revision = id(new DifferentialRevisionQuery())->withIDs(array($this->revisionID))->setViewer($request->getUser())->needRelationships(true)->needReviewerStatus(true)->needReviewerAuthority(true)->executeOne(); if (!$revision) { return new Aphront404Response(); } $diffs = id(new DifferentialDiffQuery())->setViewer($request->getUser())->withRevisionIDs(array($this->revisionID))->execute(); $diffs = array_reverse($diffs, $preserve_keys = true); if (!$diffs) { throw new Exception(pht('This revision has no diffs. Something has gone quite wrong.')); } $revision->attachActiveDiff(last($diffs)); $diff_vs = $request->getInt('vs'); $target_id = $request->getInt('id'); $target = idx($diffs, $target_id, end($diffs)); $target_manual = $target; if (!$target_id) { foreach ($diffs as $diff) { if ($diff->getCreationMethod() != 'commit') { $target_manual = $diff; } } } if (empty($diffs[$diff_vs])) { $diff_vs = null; } $repository = null; $repository_phid = $target->getRepositoryPHID(); if ($repository_phid) { if ($repository_phid == $revision->getRepositoryPHID()) { $repository = $revision->getRepository(); } else { $repository = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withPHIDs(array($repository_phid))->executeOne(); } } list($changesets, $vs_map, $vs_changesets, $rendering_references) = $this->loadChangesetsAndVsMap($target, idx($diffs, $diff_vs), $repository); if ($request->getExists('download')) { return $this->buildRawDiffResponse($revision, $changesets, $vs_changesets, $vs_map, $repository); } $map = $vs_map; if (!$map) { $map = array_fill_keys(array_keys($changesets), 0); } $old_ids = array(); $new_ids = array(); foreach ($map as $id => $vs) { if ($vs <= 0) { $old_ids[] = $id; $new_ids[] = $id; } else { $new_ids[] = $id; $new_ids[] = $vs; } } $this->loadDiffProperties($diffs); $props = $target_manual->getDiffProperties(); $object_phids = array_merge($revision->getReviewers(), $revision->getCCPHIDs(), $revision->loadCommitPHIDs(), array($revision->getAuthorPHID(), $viewer->getPHID())); foreach ($revision->getAttached() as $type => $phids) { foreach ($phids as $phid => $info) { $object_phids[] = $phid; } } $field_list = PhabricatorCustomField::getObjectFields($revision, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($viewer); $field_list->readFieldsFromStorage($revision); $warning_handle_map = array(); foreach ($field_list->getFields() as $key => $field) { $req = $field->getRequiredHandlePHIDsForRevisionHeaderWarnings(); foreach ($req as $phid) { $warning_handle_map[$key][] = $phid; $object_phids[] = $phid; } } $handles = $this->loadViewerHandles($object_phids); $request_uri = $request->getRequestURI(); $limit = 100; $large = $request->getStr('large'); if (count($changesets) > $limit && !$large) { $count = count($changesets); $warning = new PHUIInfoView(); $warning->setTitle(pht('Very Large Diff')); $warning->setSeverity(PHUIInfoView::SEVERITY_WARNING); $warning->appendChild(hsprintf('%s <strong>%s</strong>', pht('This diff is very large and affects %s files. ' . 'You may load each file individually or ', new PhutilNumber($count)), phutil_tag('a', array('class' => 'button grey', 'href' => $request_uri->alter('large', 'true')->setFragment('toc')), pht('Show All Files Inline')))); $warning = $warning->render(); $old = array_select_keys($changesets, $old_ids); $new = array_select_keys($changesets, $new_ids); $query = id(new DifferentialInlineCommentQuery())->setViewer($viewer)->needHidden(true)->withRevisionPHIDs(array($revision->getPHID())); $inlines = $query->execute(); $inlines = $query->adjustInlinesForChangesets($inlines, $old, $new, $revision); $visible_changesets = array(); foreach ($inlines as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { $visible_changesets[$changeset_id] = $changesets[$changeset_id]; } } } else { $warning = null; $visible_changesets = $changesets; } $commit_hashes = mpull($diffs, 'getSourceControlBaseRevision'); $local_commits = idx($props, 'local:commits', array()); foreach ($local_commits as $local_commit) { $commit_hashes[] = idx($local_commit, 'tree'); $commit_hashes[] = idx($local_commit, 'local'); } $commit_hashes = array_unique(array_filter($commit_hashes)); if ($commit_hashes) { $commits_for_links = id(new DiffusionCommitQuery())->setViewer($viewer)->withIdentifiers($commit_hashes)->execute(); $commits_for_links = mpull($commits_for_links, null, 'getCommitIdentifier'); } else { $commits_for_links = array(); } $header = $this->buildHeader($revision); $subheader = $this->buildSubheaderView($revision); $details = $this->buildDetails($revision, $field_list); $curtain = $this->buildCurtain($revision); $whitespace = $request->getStr('whitespace', DifferentialChangesetParser::WHITESPACE_IGNORE_MOST); $repository = $revision->getRepository(); if ($repository) { $symbol_indexes = $this->buildSymbolIndexes($repository, $visible_changesets); } else { $symbol_indexes = array(); } $revision_warnings = $this->buildRevisionWarnings($revision, $field_list, $warning_handle_map, $handles); $info_view = null; if ($revision_warnings) { $info_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setErrors($revision_warnings); } $detail_diffs = array_select_keys($diffs, array($diff_vs, $target->getID())); $detail_diffs = mpull($detail_diffs, null, 'getPHID'); $this->loadHarbormasterData($detail_diffs); $diff_detail_box = $this->buildDiffDetailView($detail_diffs, $revision, $field_list); $unit_box = $this->buildUnitMessagesView($target, $revision); $comment_view = $this->buildTransactions($revision, $diff_vs ? $diffs[$diff_vs] : $target, $target, $old_ids, $new_ids); if (!$viewer_is_anonymous) { $comment_view->setQuoteRef('D' . $revision->getID()); $comment_view->setQuoteTargetID('comment-content'); } $changeset_view = id(new DifferentialChangesetListView())->setChangesets($changesets)->setVisibleChangesets($visible_changesets)->setStandaloneURI('/differential/changeset/')->setRawFileURIs('/differential/changeset/?view=old', '/differential/changeset/?view=new')->setUser($viewer)->setDiff($target)->setRenderingReferences($rendering_references)->setVsMap($vs_map)->setWhitespace($whitespace)->setSymbolIndexes($symbol_indexes)->setTitle(pht('Diff %s', $target->getID()))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY); if ($repository) { $changeset_view->setRepository($repository); } if (!$viewer_is_anonymous) { $changeset_view->setInlineCommentControllerURI('/differential/comment/inline/edit/' . $revision->getID() . '/'); } $history = id(new DifferentialRevisionUpdateHistoryView())->setUser($viewer)->setDiffs($diffs)->setSelectedVersusDiffID($diff_vs)->setSelectedDiffID($target->getID())->setSelectedWhitespace($whitespace)->setCommitsForLinks($commits_for_links); $local_table = id(new DifferentialLocalCommitsView())->setUser($viewer)->setLocalCommits(idx($props, 'local:commits'))->setCommitsForLinks($commits_for_links); if ($repository) { $other_revisions = $this->loadOtherRevisions($changesets, $target, $repository); } else { $other_revisions = array(); } $other_view = null; if ($other_revisions) { $other_view = $this->renderOtherRevisions($other_revisions); } $toc_view = $this->buildTableOfContents($changesets, $visible_changesets, $target->loadCoverageMap($viewer)); $tab_group = id(new PHUITabGroupView())->addTab(id(new PHUITabView())->setName(pht('Files'))->setKey('files')->appendChild($toc_view))->addTab(id(new PHUITabView())->setName(pht('History'))->setKey('history')->appendChild($history))->addTab(id(new PHUITabView())->setName(pht('Commits'))->setKey('commits')->appendChild($local_table)); $stack_graph = id(new DifferentialRevisionGraph())->setViewer($viewer)->setSeedPHID($revision->getPHID())->setLoadEntireGraph(true)->loadGraph(); if (!$stack_graph->isEmpty()) { $stack_table = $stack_graph->newGraphTable(); $parent_type = DifferentialRevisionDependsOnRevisionEdgeType::EDGECONST; $reachable = $stack_graph->getReachableObjects($parent_type); foreach ($reachable as $key => $reachable_revision) { if ($reachable_revision->isClosed()) { unset($reachable[$key]); } } if ($reachable) { $stack_name = pht('Stack (%s Open)', phutil_count($reachable)); $stack_color = PHUIListItemView::STATUS_FAIL; } else { $stack_name = pht('Stack'); $stack_color = null; } $tab_group->addTab(id(new PHUITabView())->setName($stack_name)->setKey('stack')->setColor($stack_color)->appendChild($stack_table)); } if ($other_view) { $tab_group->addTab(id(new PHUITabView())->setName(pht('Similar'))->setKey('similar')->appendChild($other_view)); } $tab_view = id(new PHUIObjectBoxView())->setHeaderText(pht('Revision Contents'))->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)->addTabGroup($tab_group); $comment_form = null; if (!$viewer_is_anonymous) { $comment_form = $this->buildCommentForm($revision, $field_list); } $signatures = DifferentialRequiredSignaturesField::loadForRevision($revision); $missing_signatures = false; foreach ($signatures as $phid => $signed) { if (!$signed) { $missing_signatures = true; } } $footer = array(); $signature_message = null; if ($missing_signatures) { $signature_message = id(new PHUIInfoView())->setTitle(pht('Content Hidden'))->appendChild(pht('The content of this revision is hidden until the author has ' . 'signed all of the required legal agreements.')); } else { $anchor = id(new PhabricatorAnchorView())->setAnchorName('toc')->setNavigationMarker(true); $footer[] = array($anchor, $warning, $tab_view, $changeset_view); } if ($comment_form) { $footer[] = $comment_form; } else { // TODO: For now, just use this to get "Login to Comment". $footer[] = id(new PhabricatorApplicationTransactionCommentView())->setUser($viewer)->setRequestURI($request->getRequestURI()); } $object_id = 'D' . $revision->getID(); $operations_box = $this->buildOperationsBox($revision); $crumbs = $this->buildApplicationCrumbs(); $crumbs->addTextCrumb($object_id, '/' . $object_id); $crumbs->setBorder(true); $filetree_on = $viewer->compareUserSetting(PhabricatorShowFiletreeSetting::SETTINGKEY, PhabricatorShowFiletreeSetting::VALUE_ENABLE_FILETREE); $nav = null; if ($filetree_on) { $collapsed_key = PhabricatorFiletreeVisibleSetting::SETTINGKEY; $collapsed_value = $viewer->getUserSetting($collapsed_key); $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())->setTitle('D' . $revision->getID())->setBaseURI(new PhutilURI('/D' . $revision->getID()))->setCollapsed((bool) $collapsed_value)->build($changesets); } // Haunt Mode $pane_id = celerity_generate_unique_node_id(); Javelin::initBehavior('differential-keyboard-navigation', array('haunt' => $pane_id)); Javelin::initBehavior('differential-user-select'); $view = id(new PHUITwoColumnView())->setHeader($header)->setSubheader($subheader)->setCurtain($curtain)->setID($pane_id)->setMainColumn(array($operations_box, $info_view, $details, $diff_detail_box, $unit_box, $comment_view, $signature_message))->setFooter($footer); $page = $this->newPage()->setTitle($object_id . ' ' . $revision->getTitle())->setCrumbs($crumbs)->setPageObjectPHIDs(array($revision->getPHID()))->appendChild($view); if ($nav) { $page->setNavigation($nav); } return $page; }
private function buildMergesTable(PhabricatorRepositoryCommit $commit) { $drequest = $this->getDiffusionRequest(); $repository = $drequest->getRepository(); $vcs = $repository->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: // These aren't supported under SVN. return null; } $limit = 50; $merges = $this->callConduitWithDiffusionRequest('diffusion.mergedcommitsquery', array('commit' => $drequest->getCommit(), 'limit' => $limit + 1)); if (!$merges) { return null; } $merges = DiffusionPathChange::newFromConduit($merges); $caption = null; if (count($merges) > $limit) { $merges = array_slice($merges, 0, $limit); $caption = new PHUIInfoView(); $caption->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $caption->appendChild(pht('This commit merges a very large number of changes. ' . 'Only the first %s are shown.', new PhutilNumber($limit))); } $history_table = new DiffusionHistoryTableView(); $history_table->setUser($this->getRequest()->getUser()); $history_table->setDiffusionRequest($drequest); $history_table->setHistory($merges); $history_table->loadRevisions(); $phids = $history_table->getRequiredHandlePHIDs(); $handles = $this->loadViewerHandles($phids); $history_table->setHandles($handles); $panel = new PHUIObjectBoxView(); $panel->setHeaderText(pht('Merged Changes')); $panel->setTable($history_table); if ($caption) { $panel->setInfoView($caption); } return $panel; }
public function handleRequest(AphrontRequest $request) { $viewer = $this->getViewer(); $id = $request->getURIData('id'); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($id))->needSubscriberPHIDs(true)->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery())->setViewer($viewer)->withIDs(array($workflow))->executeOne(); } $field_list = PhabricatorCustomField::getObjectFields($task, PhabricatorCustomField::ROLE_VIEW); $field_list->setViewer($viewer)->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = ManiphestTaskDependsOnTaskEdgeType::EDGECONST; $e_dep_by = ManiphestTaskDependedOnByTaskEdgeType::EDGECONST; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = ManiphestTaskHasMockEdgeType::EDGECONST; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery())->withSourcePHIDs(array($phid))->withEdgeTypes(array($e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock)); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), true); if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $handles = $viewer->loadHandles($phids); $info_view = null; if ($parent_task) { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?parent=' . $parent_task->getID())->setText(pht('Create Another Subtask'))); $info_view->appendChild(hsprintf('Created a subtask of <strong>%s</strong>.', $handles->renderHandle($parent_task->getPHID()))); } else { if ($workflow == 'create') { $info_view = new PHUIInfoView(); $info_view->setSeverity(PHUIInfoView::SEVERITY_NOTICE); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/?template=' . $task->getID())->setText(pht('Similar Task'))); $info_view->addButton(id(new PHUIButtonView())->setTag('a')->setHref('/maniphest/task/create/')->setText(pht('Empty Task'))); $info_view->appendChild(pht('New task created. Create another?')); } } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($viewer); $engine->setContextObject($task); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); $timeline = $this->buildTransactionTimeline($task, new ManiphestTransactionQuery(), $engine); $actions = $this->buildActionView($task); $monogram = $task->getMonogram(); $crumbs = $this->buildApplicationCrumbs()->addTextCrumb($monogram, '/' . $monogram); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView($task, $field_list, $edges, $actions, $handles); $description = $this->buildDescriptionView($task, $engine); $object_box = id(new PHUIObjectBoxView())->setHeader($header)->addPropertyList($properties); if ($description) { $object_box->addPropertyList($description); } $title = pht('%s %s', $monogram, $task->getTitle()); $comment_view = id(new ManiphestEditEngine())->setViewer($viewer)->buildEditEngineCommentView($task); $timeline->setQuoteRef($monogram); $comment_view->setTransactionTimeline($timeline); return $this->newPage()->setTitle($title)->setCrumbs($crumbs)->setPageObjectPHIDs(array($task->getPHID()))->appendChild(array($info_view, $object_box, $timeline, $comment_view)); }