protected function execute(ConduitAPIRequest $request) { $client = $request->getValue('client'); $client_version = (int) $request->getValue('clientVersion'); $client_description = (string) $request->getValue('clientDescription'); $client_description = id(new PhutilUTF8StringTruncator())->setMaximumBytes(255)->truncateString($client_description); $username = (string) $request->getValue('user'); // Log the connection, regardless of the outcome of checks below. $connection = new PhabricatorConduitConnectionLog(); $connection->setClient($client); $connection->setClientVersion($client_version); $connection->setClientDescription($client_description); $connection->setUsername($username); $connection->save(); switch ($client) { case 'arc': $server_version = 6; $supported_versions = array($server_version => true, 4 => true, 5 => true); if (empty($supported_versions[$client_version])) { if ($server_version < $client_version) { $ex = new ConduitException('ERR-BAD-VERSION'); $ex->setErrorDescription(pht("Your '%s' client version is '%d', which is newer than the " . "server version, '%d'. Upgrade your Phabricator install.", 'arc', $client_version, $server_version)); } else { $ex = new ConduitException('NEW-ARC-VERSION'); $ex->setErrorDescription(pht('A new version of arc is available! You need to upgrade ' . 'to connect to this server (you are running version ' . '%d, the server is running version %d).', $client_version, $server_version)); } throw $ex; } break; default: // Allow new clients by default. break; } $token = $request->getValue('authToken'); $signature = $request->getValue('authSignature'); $user = id(new PhabricatorUser())->loadOneWhere('username = %s', $username); if (!$user) { throw new ConduitException('ERR-INVALID-USER'); } $session_key = null; if ($token && $signature) { $threshold = 60 * 15; $now = time(); if (abs($token - $now) > $threshold) { throw id(new ConduitException('ERR-INVALID-TOKEN'))->setErrorDescription(pht('The request you submitted is signed with a timestamp, but that ' . 'timestamp is not within %s of the current time. The ' . 'signed timestamp is %s (%s), and the current server time is ' . '%s (%s). This is a difference of %s seconds, but the ' . 'timestamp must differ from the server time by no more than ' . '%s seconds. Your client or server clock may not be set ' . 'correctly.', phutil_format_relative_time($threshold), $token, date('r', $token), $now, date('r', $now), $token - $now, $threshold)); } $valid = sha1($token . $user->getConduitCertificate()); if (!phutil_hashes_are_identical($valid, $signature)) { throw new ConduitException('ERR-INVALID-CERTIFICATE'); } $session_key = id(new PhabricatorAuthSessionEngine())->establishSession(PhabricatorAuthSession::TYPE_CONDUIT, $user->getPHID(), $partial = false); } else { throw new ConduitException('ERR-NO-CERTIFICATE'); } return array('connectionID' => $connection->getID(), 'sessionKey' => $session_key, 'userPHID' => $user->getPHID()); }
public function render() { $tasks = $this->getTasks(); $rows = array(); foreach ($tasks as $task) { $rows[] = array($task->getID(), $task->getTaskClass(), $task->getLeaseOwner(), $task->getLeaseExpires() ? phutil_format_relative_time($task->getLeaseExpires() - time()) : '-', $task->getPriority(), $task->getFailureCount(), phutil_tag('a', array('href' => '/daemon/task/' . $task->getID() . '/', 'class' => 'button small grey'), pht('View Task'))); } $table = new AphrontTableView($rows); $table->setHeaders(array(pht('ID'), pht('Class'), pht('Owner'), pht('Expires'), pht('Priority'), pht('Failures'), '')); $table->setColumnClasses(array('n', 'wide', '', '', 'n', 'n', 'action')); if (strlen($this->getNoDataString())) { $table->setNoDataString($this->getNoDataString()); } return $table; }
public function buildCurtainPanel($object) { $viewer = $this->getViewer(); $events = id(new PhrequentUserTimeQuery())->setViewer($viewer)->withObjectPHIDs(array($object->getPHID()))->needPreemptingEvents(true)->execute(); $event_groups = mgroup($events, 'getUserPHID'); if (!$events) { return; } $handles = $viewer->loadHandles(array_keys($event_groups)); $status_view = new PHUIStatusListView(); foreach ($event_groups as $user_phid => $event_group) { $item = new PHUIStatusItemView(); $item->setTarget($handles[$user_phid]->renderLink()); $state = 'stopped'; foreach ($event_group as $event) { if ($event->getDateEnded() === null) { if ($event->isPreempted()) { $state = 'suspended'; } else { $state = 'active'; break; } } } switch ($state) { case 'active': $item->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green', pht('Working Now')); break; case 'suspended': $item->setIcon(PHUIStatusItemView::ICON_CLOCK, 'yellow', pht('Interrupted')); break; case 'stopped': $item->setIcon(PHUIStatusItemView::ICON_CLOCK, 'bluegrey', pht('Not Working Now')); break; } $block = new PhrequentTimeBlock($event_group); $item->setNote(phutil_format_relative_time($block->getTimeSpentOnObject($object->getPHID(), time()))); $status_view->addItem($item); } return $this->newPanel()->setHeaderText(pht('Time Spent'))->setOrder(40000)->appendChild($status_view); }
public function processRequest(AphrontRequest $request) { $viewer = $request->getUser(); $accounts = id(new PhabricatorExternalAccountQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->execute(); $identity_phids = mpull($accounts, 'getPHID'); $identity_phids[] = $viewer->getPHID(); $sessions = id(new PhabricatorAuthSessionQuery())->setViewer($viewer)->withIdentityPHIDs($identity_phids)->execute(); $handles = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs($identity_phids)->execute(); $current_key = PhabricatorHash::digest($request->getCookie(PhabricatorCookies::COOKIE_SESSION)); $rows = array(); $rowc = array(); foreach ($sessions as $session) { $is_current = phutil_hashes_are_identical($session->getSessionKey(), $current_key); if ($is_current) { $rowc[] = 'highlighted'; $button = phutil_tag('a', array('class' => 'small grey button disabled'), pht('Current')); } else { $rowc[] = null; $button = javelin_tag('a', array('href' => '/auth/session/terminate/' . $session->getID() . '/', 'class' => 'small grey button', 'sigil' => 'workflow'), pht('Terminate')); } $hisec = $session->getHighSecurityUntil() - time(); $rows[] = array($handles[$session->getUserPHID()]->renderLink(), substr($session->getSessionKey(), 0, 6), $session->getType(), $hisec > 0 ? phutil_format_relative_time($hisec) : null, phabricator_datetime($session->getSessionStart(), $viewer), phabricator_date($session->getSessionExpires(), $viewer), $button); } $table = new AphrontTableView($rows); $table->setNoDataString(pht("You don't have any active sessions.")); $table->setRowClasses($rowc); $table->setHeaders(array(pht('Identity'), pht('Session'), pht('Type'), pht('HiSec'), pht('Created'), pht('Expires'), pht(''))); $table->setColumnClasses(array('wide', 'n', '', 'right', 'right', 'right', 'action')); $terminate_icon = id(new PHUIIconView())->setIconFont('fa-exclamation-triangle'); $terminate_button = id(new PHUIButtonView())->setText(pht('Terminate All Sessions'))->setHref('/auth/session/terminate/all/')->setTag('a')->setWorkflow(true)->setIcon($terminate_icon); $header = id(new PHUIHeaderView())->setHeader(pht('Active Login Sessions'))->addActionLink($terminate_button); $hisec = $viewer->getSession()->getHighSecurityUntil() - time(); if ($hisec > 0) { $hisec_icon = id(new PHUIIconView())->setIconFont('fa-lock'); $hisec_button = id(new PHUIButtonView())->setText(pht('Leave High Security'))->setHref('/auth/session/downgrade/')->setTag('a')->setWorkflow(true)->setIcon($hisec_icon); $header->addActionLink($hisec_button); } $panel = id(new PHUIObjectBoxView())->setHeader($header)->setTable($table); return $panel; }
public function processRequest() { $request = $this->getRequest(); $query = $request->getStr('q'); $repo_id = $request->getInt('repo'); $since = $request->getInt('since'); $limit = $request->getInt('limit'); $now = time(); $data = array(); // Dummy instances used for getting connections, table names, etc. $pr_commit = new PhabricatorRepositoryCommit(); $pr_commit_data = new PhabricatorRepositoryCommitData(); $conn = $pr_commit->establishConnection('r'); $rows = queryfx_all($conn, 'SELECT rc.phid as commitPHID, rc.authorPHID, rcd.authorName, SUBSTRING(rcd.commitMessage, 1, 100) AS shortMessage, rc.commitIdentifier, rc.epoch FROM %T rc INNER JOIN %T rcd ON rcd.commitID = rc.id WHERE repositoryID = %d AND rc.epoch >= %d AND ( rcd.commitMessage LIKE %~ OR rc.commitIdentifier LIKE %~ ) ORDER BY rc.epoch DESC LIMIT %d', $pr_commit->getTableName(), $pr_commit_data->getTableName(), $repo_id, $since, $query, $query, $limit); foreach ($rows as $row) { $full_commit_id = $row['commitIdentifier']; $short_commit_id = substr($full_commit_id, 0, 12); $first_line = $this->getFirstLine($row['shortMessage']); $data[] = array($full_commit_id, $short_commit_id, $row['authorName'], phutil_format_relative_time($now - $row['epoch']), $first_line); } return id(new AphrontAjaxResponse())->setContent($data); }
protected function printCurrentTracking() { $conduit = $this->getConduit(); $results = $conduit->callMethodSynchronous('phrequent.tracking', array()); $results = $results['data']; if (count($results) === 0) { echo phutil_console_format("%s\n", pht('Not currently tracking time against any object.')); return 0; } $phids_to_lookup = array(); foreach ($results as $result) { $phids_to_lookup[] = $result['phid']; } $phid_query = $conduit->callMethodSynchronous('phid.query', array('phids' => $phids_to_lookup)); $phid_map = array(); foreach ($phids_to_lookup as $lookup) { if (array_key_exists($lookup, $phid_query)) { $phid_map[$lookup] = $phid_query[$lookup]['fullName']; } else { $phid_map[$lookup] = pht('Unknown Object'); } } $table = id(new PhutilConsoleTable())->addColumn('type', array('title' => pht('Status')))->addColumn('time', array('title' => pht('Tracked'), 'align' => 'right'))->addColumn('name', array('title' => pht('Name')))->setBorders(false); $i = 0; foreach ($results as $result) { if ($i === 0) { $column_type = pht('In Progress'); } else { $column_type = pht('Suspended'); } $table->addRow(array('type' => '(' . $column_type . ')', 'time' => phutil_format_relative_time($result['time']), 'name' => $phid_map[$result['phid']])); $i++; } $table->draw(); return 0; }
private function buildPropertyListView(PhabricatorDaemonLog $daemon) { $request = $this->getRequest(); $viewer = $request->getUser(); $view = id(new PHUIPropertyListView())->setUser($viewer); $id = $daemon->getID(); $c_epoch = $daemon->getDateCreated(); $u_epoch = $daemon->getDateModified(); $unknown_time = PhabricatorDaemonLogQuery::getTimeUntilUnknown(); $dead_time = PhabricatorDaemonLogQuery::getTimeUntilDead(); $wait_time = PhutilDaemonOverseer::RESTART_WAIT; $details = null; $status = $daemon->getStatus(); switch ($status) { case PhabricatorDaemonLog::STATUS_RUNNING: $details = pht('This daemon is running normally and reported a status update ' . 'recently (within %s).', phutil_format_relative_time($unknown_time)); break; case PhabricatorDaemonLog::STATUS_UNKNOWN: $details = pht('This daemon has not reported a status update recently (within %s). ' . 'It may have exited abruptly. After %s, it will be presumed dead.', phutil_format_relative_time($unknown_time), phutil_format_relative_time($dead_time)); break; case PhabricatorDaemonLog::STATUS_DEAD: $details = pht('This daemon did not report a status update for %s. It is ' . 'presumed dead. Usually, this indicates that the daemon was ' . 'killed or otherwise exited abruptly with an error. You may ' . 'need to restart it.', phutil_format_relative_time($dead_time)); break; case PhabricatorDaemonLog::STATUS_WAIT: $details = pht('This daemon is running normally and reported a status update ' . 'recently (within %s). However, it encountered an error while ' . 'doing work and is waiting a little while (%s) to resume ' . 'processing. After encountering an error, daemons wait before ' . 'resuming work to avoid overloading services.', phutil_format_relative_time($unknown_time), phutil_format_relative_time($wait_time)); break; case PhabricatorDaemonLog::STATUS_EXITING: $details = pht('This daemon is shutting down gracefully.'); break; case PhabricatorDaemonLog::STATUS_EXITED: $details = pht('This daemon exited normally and is no longer running.'); break; } $view->addProperty(pht('Status Details'), $details); $view->addProperty(pht('Daemon Class'), $daemon->getDaemon()); $view->addProperty(pht('Host'), $daemon->getHost()); $view->addProperty(pht('PID'), $daemon->getPID()); $view->addProperty(pht('Started'), phabricator_datetime($c_epoch, $viewer)); $view->addProperty(pht('Seen'), pht('%s ago (%s)', phutil_format_relative_time(time() - $u_epoch), phabricator_datetime($u_epoch, $viewer))); $argv = $daemon->getArgv(); if (is_array($argv)) { $argv = implode("\n", $argv); } $view->addProperty(pht('Argv'), phutil_tag('textarea', array('style' => 'width: 100%; height: 12em;'), $argv)); $view->addProperty(pht('View Full Logs'), phutil_tag('tt', array(), "phabricator/ \$ ./bin/phd log --id {$id}")); return $view; }
public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $phid = $this->phid; $handle = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs(array($phid))->executeOne(); $done_uri = $handle->getURI(); $current_timer = null; switch ($this->verb) { case 'start': $button_text = pht('Start Tracking'); $title_text = pht('Start Tracking Time'); $inner_text = pht('What time did you start working?'); $action_text = pht('Start Timer'); $label_text = pht('Start Time'); break; case 'stop': $button_text = pht('Stop Tracking'); $title_text = pht('Stop Tracking Time'); $inner_text = pht('What time did you stop working?'); $action_text = pht('Stop Timer'); $label_text = pht('Stop Time'); $current_timer = id(new PhrequentUserTimeQuery())->setViewer($viewer)->withUserPHIDs(array($viewer->getPHID()))->withObjectPHIDs(array($phid))->withEnded(PhrequentUserTimeQuery::ENDED_NO)->executeOne(); if (!$current_timer) { return $this->newDialog()->setTitle(pht('Not Tracking Time'))->appendParagraph(pht('You are not currently tracking time on this object.'))->addCancelButton($done_uri); } break; default: return new Aphront404Response(); } $errors = array(); $v_note = null; $e_date = null; $timestamp = AphrontFormDateControlValue::newFromEpoch($viewer, time()); if ($request->isDialogFormPost()) { $v_note = $request->getStr('note'); $timestamp = AphrontFormDateControlValue::newFromRequest($request, 'epoch'); if (!$timestamp->isValid()) { $errors[] = pht('Please choose a valid date.'); $e_date = pht('Invalid'); } else { $max_time = PhabricatorTime::getNow(); if ($timestamp->getEpoch() > $max_time) { if ($this->isStoppingTracking()) { $errors[] = pht('You can not stop tracking time at a future time. Enter the ' . 'current time, or a time in the past.'); } else { $errors[] = pht('You can not start tracking time at a future time. Enter the ' . 'current time, or a time in the past.'); } $e_date = pht('Invalid'); } if ($this->isStoppingTracking()) { $min_time = $current_timer->getDateStarted(); if ($min_time > $timestamp->getEpoch()) { $errors[] = pht('Stop time must be after start time.'); $e_date = pht('Invalid'); } } } if (!$errors) { $editor = new PhrequentTrackingEditor(); if ($this->isStartingTracking()) { $editor->startTracking($viewer, $this->phid, $timestamp->getEpoch()); } else { if ($this->isStoppingTracking()) { $editor->stopTracking($viewer, $this->phid, $timestamp->getEpoch(), $v_note); } } return id(new AphrontRedirectResponse())->setURI($done_uri); } } $dialog = $this->newDialog()->setTitle($title_text)->setWidth(AphrontDialogView::WIDTH_FORM)->setErrors($errors)->appendParagraph($inner_text); $form = new PHUIFormLayoutView(); if ($this->isStoppingTracking()) { $start_time = $current_timer->getDateStarted(); $start_string = pht('%s (%s ago)', phabricator_datetime($start_time, $viewer), phutil_format_relative_time(PhabricatorTime::getNow() - $start_time)); $form->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Started At'))->setValue($start_string)); } $form->appendChild(id(new AphrontFormDateControl())->setUser($viewer)->setName('epoch')->setLabel($action_text)->setError($e_date)->setValue($timestamp)); if ($this->isStoppingTracking()) { $form->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Note'))->setName('note')->setValue($v_note)); } $dialog->appendChild($form); $dialog->addCancelButton($done_uri); $dialog->addSubmitButton($action_text); return $dialog; }
private function handlePropertyEvent($ui_event) { $user = $ui_event->getUser(); $object = $ui_event->getValue('object'); if (!$object || !$object->getPHID()) { // No object, or the object has no PHID yet.. return; } if (!$object instanceof PhrequentTrackableInterface) { // This object isn't a time trackable object. return; } if (!$this->canUseApplication($ui_event->getUser())) { return; } $events = id(new PhrequentUserTimeQuery())->setViewer($user)->withObjectPHIDs(array($object->getPHID()))->needPreemptingEvents(true)->execute(); $event_groups = mgroup($events, 'getUserPHID'); if (!$events) { return; } $handles = id(new PhabricatorHandleQuery())->setViewer($user)->withPHIDs(array_keys($event_groups))->execute(); $status_view = new PHUIStatusListView(); foreach ($event_groups as $user_phid => $event_group) { $item = new PHUIStatusItemView(); $item->setTarget($handles[$user_phid]->renderLink()); $state = 'stopped'; foreach ($event_group as $event) { if ($event->getDateEnded() === null) { if ($event->isPreempted()) { $state = 'suspended'; } else { $state = 'active'; break; } } } switch ($state) { case 'active': $item->setIcon(PHUIStatusItemView::ICON_CLOCK, 'green', pht('Working Now')); break; case 'suspended': $item->setIcon(PHUIStatusItemView::ICON_CLOCK, 'yellow', pht('Interrupted')); break; case 'stopped': $item->setIcon(PHUIStatusItemView::ICON_CLOCK, 'bluegrey', pht('Not Working Now')); break; } $block = new PhrequentTimeBlock($event_group); $item->setNote(phutil_format_relative_time($block->getTimeSpentOnObject($object->getPHID(), time()))); $status_view->addItem($item); } $view = $ui_event->getValue('view'); $view->addProperty(pht('Time Spent'), $status_view); }
private function buildRetryListView(PhabricatorWorkerTask $task) { $view = new PHUIPropertyListView(); $data = id(new PhabricatorWorkerTaskData())->load($task->getDataID()); $task->setData($data->getData()); $worker = $task->getWorkerInstance(); $view->addProperty(pht('Failure Count'), $task->getFailureCount()); $retry_count = $worker->getMaximumRetryCount(); if ($retry_count === null) { $max_retries = phutil_tag('em', array(), pht('Retries Forever')); $retry_count = INF; } else { $max_retries = $retry_count; } $view->addProperty(pht('Maximum Retries'), $max_retries); $projection = clone $task; $projection->makeEphemeral(); $next = array(); for ($ii = $task->getFailureCount(); $ii < $retry_count; $ii++) { $projection->setFailureCount($ii); $next[] = $worker->getWaitBeforeRetry($projection); if (count($next) > 10) { break; } } if ($next) { $cumulative = 0; foreach ($next as $key => $duration) { if ($duration === null) { $duration = 60; } $cumulative += $duration; $next[$key] = phutil_format_relative_time($cumulative); } if ($ii != $retry_count) { $next[] = '...'; } $retries_in = implode(', ', $next); } else { $retries_in = pht('No More Retries'); } $view->addProperty(pht('Retries After'), $retries_in); return $view; }
public function handleRequest(AphrontRequest $request) { $action = $request->getURIData('action'); $request_id = $request->getURIData('requestID'); $branch_id = $request->getURIData('branchID'); $viewer = $request->getViewer(); if ($request_id) { $pull = id(new ReleephRequestQuery())->setViewer($viewer)->withIDs(array($request_id))->requireCapabilities(array(PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT))->executeOne(); if (!$pull) { return new Aphront404Response(); } $branch = $pull->getBranch(); $is_edit = true; } else { $branch = id(new ReleephBranchQuery())->setViewer($viewer)->withIDs(array($branch_id))->executeOne(); if (!$branch) { return new Aphront404Response(); } $pull = id(new ReleephRequest())->setRequestUserPHID($viewer->getPHID())->setBranchID($branch->getID())->setInBranch(0)->attachBranch($branch); $is_edit = false; } $this->setBranch($branch); $product = $branch->getProduct(); $request_identifier = $request->getStr('requestIdentifierRaw'); $e_request_identifier = true; // Load all the ReleephFieldSpecifications $selector = $branch->getProduct()->getReleephFieldSelector(); $fields = $selector->getFieldSpecifications(); foreach ($fields as $field) { $field->setReleephProject($product)->setReleephBranch($branch)->setReleephRequest($pull); } $field_list = PhabricatorCustomField::getObjectFields($pull, PhabricatorCustomField::ROLE_EDIT); foreach ($field_list->getFields() as $field) { $field->setReleephProject($product)->setReleephBranch($branch)->setReleephRequest($pull); } $field_list->readFieldsFromStorage($pull); if ($branch_id) { $cancel_uri = $this->getApplicationURI('branch/' . $branch_id . '/'); } else { $cancel_uri = '/' . $pull->getMonogram(); } // Make edits $errors = array(); if ($request->isFormPost()) { $xactions = array(); // The commit-identifier being requested... if (!$is_edit) { if ($request_identifier === ReleephRequestTypeaheadControl::PLACEHOLDER) { $errors[] = pht('No commit ID was provided.'); $e_request_identifier = pht('Required'); } else { $pr_commit = null; $finder = id(new ReleephCommitFinder())->setUser($viewer)->setReleephProject($product); try { $pr_commit = $finder->fromPartial($request_identifier); } catch (Exception $e) { $e_request_identifier = pht('Invalid'); $errors[] = pht('Request %s is probably not a valid commit.', $request_identifier); $errors[] = $e->getMessage(); } if (!$errors) { $object_phid = $finder->getRequestedObjectPHID(); if (!$object_phid) { $object_phid = $pr_commit->getPHID(); } $pull->setRequestedObjectPHID($object_phid); } } if (!$errors) { $existing = id(new ReleephRequest())->loadOneWhere('requestCommitPHID = %s AND branchID = %d', $pr_commit->getPHID(), $branch->getID()); if ($existing) { return id(new AphrontRedirectResponse())->setURI('/releeph/request/edit/' . $existing->getID() . '?existing=1'); } $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_REQUEST)->setNewValue($pr_commit->getPHID()); $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_USER_INTENT)->setMetadataValue('isRQCreate', true)->setMetadataValue('userPHID', $viewer->getPHID())->setMetadataValue('isAuthoritative', $product->isAuthoritative($viewer))->setNewValue(ReleephRequest::INTENT_WANT); } } // TODO: This should happen implicitly while building transactions // instead. foreach ($field_list->getFields() as $field) { $field->readValueFromRequest($request); } if (!$errors) { foreach ($fields as $field) { if ($field->isEditable()) { try { $data = $request->getRequestData(); $value = idx($data, $field->getRequiredStorageKey()); $field->validate($value); $xactions[] = id(new ReleephRequestTransaction())->setTransactionType(ReleephRequestTransaction::TYPE_EDIT_FIELD)->setMetadataValue('fieldClass', get_class($field))->setNewValue($value); } catch (ReleephFieldParseException $ex) { $errors[] = $ex->getMessage(); } } } } if (!$errors) { $editor = id(new ReleephRequestTransactionalEditor())->setActor($viewer)->setContinueOnNoEffect(true)->setContentSourceFromRequest($request); $editor->applyTransactions($pull, $xactions); return id(new AphrontRedirectResponse())->setURI($cancel_uri); } } $handle_phids = array($pull->getRequestUserPHID(), $pull->getRequestCommitPHID()); $handle_phids = array_filter($handle_phids); if ($handle_phids) { $handles = id(new PhabricatorHandleQuery())->setViewer($viewer)->withPHIDs($handle_phids)->execute(); } else { $handles = array(); } $age_string = ''; if ($is_edit) { $age_string = phutil_format_relative_time(time() - $pull->getDateCreated()) . ' ago'; } // Warn the user if we've been redirected here because we tried to // re-request something. $notice_view = null; if ($request->getInt('existing')) { $notice_messages = array(pht('You are editing an existing pick request!'), pht('Requested %s by %s', $age_string, $handles[$pull->getRequestUserPHID()]->renderLink())); $notice_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_NOTICE)->setErrors($notice_messages); } $form = id(new AphrontFormView())->setUser($viewer); if ($is_edit) { $form->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Original Commit'))->setValue($handles[$pull->getRequestCommitPHID()]->renderLink()))->appendChild(id(new AphrontFormMarkupControl())->setLabel(pht('Requestor'))->setValue(hsprintf('%s %s', $handles[$pull->getRequestUserPHID()]->renderLink(), $age_string))); } else { $origin = null; $diff_rev_id = $request->getStr('D'); if ($diff_rev_id) { $diff_rev = id(new DifferentialRevisionQuery())->setViewer($viewer)->withIDs(array($diff_rev_id))->executeOne(); $origin = '/D' . $diff_rev->getID(); $title = sprintf('D%d: %s', $diff_rev_id, $diff_rev->getTitle()); $form->addHiddenInput('requestIdentifierRaw', 'D' . $diff_rev_id)->appendChild(id(new AphrontFormStaticControl())->setLabel(pht('Diff'))->setValue($title)); } else { $origin = $branch->getURI(); $repo = $product->getRepository(); $branch_cut_point = id(new PhabricatorRepositoryCommit())->loadOneWhere('phid = %s', $branch->getCutPointCommitPHID()); $form->appendChild(id(new ReleephRequestTypeaheadControl())->setName('requestIdentifierRaw')->setLabel(pht('Commit ID'))->setRepo($repo)->setValue($request_identifier)->setError($e_request_identifier)->setStartTime($branch_cut_point->getEpoch())->setCaption(pht('Start typing to autocomplete on commit title, ' . 'or give a Phabricator commit identifier like rFOO1234.'))); } } $field_list->appendFieldsToForm($form); $crumbs = $this->buildApplicationCrumbs(); if ($is_edit) { $title = pht('Edit Pull Request'); $submit_name = pht('Save'); $crumbs->addTextCrumb($pull->getMonogram(), '/' . $pull->getMonogram()); $crumbs->addTextCrumb(pht('Edit')); } else { $title = pht('Create Pull Request'); $submit_name = pht('Create Pull Request'); $crumbs->addTextCrumb(pht('New Pull Request')); } $form->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri, pht('Cancel'))->setValue($submit_name)); $box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->appendChild($form); return $this->buildApplicationPage(array($crumbs, $notice_view, $box), array('title' => $title)); }
protected function willRenderPage() { parent::willRenderPage(); if (!$this->getRequest()) { throw new Exception(pht('You must set the Request to render a PhabricatorStandardPageView.')); } $console = $this->getConsole(); require_celerity_resource('phabricator-core-css'); require_celerity_resource('phabricator-zindex-css'); require_celerity_resource('phui-button-css'); require_celerity_resource('phui-spacing-css'); require_celerity_resource('phui-form-css'); require_celerity_resource('sprite-gradient-css'); require_celerity_resource('phabricator-standard-page-view'); Javelin::initBehavior('workflow', array()); $request = $this->getRequest(); $user = null; if ($request) { $user = $request->getUser(); } if ($user) { $default_img_uri = celerity_get_resource_uri('rsrc/image/icon/fatcow/document_black.png'); $download_form = phabricator_form($user, array('action' => '#', 'method' => 'POST', 'class' => 'lightbox-download-form', 'sigil' => 'download'), phutil_tag('button', array(), pht('Download'))); Javelin::initBehavior('lightbox-attachments', array('defaultImageUri' => $default_img_uri, 'downloadForm' => $download_form)); } Javelin::initBehavior('aphront-form-disable-on-submit'); Javelin::initBehavior('toggle-class', array()); Javelin::initBehavior('konami', array()); Javelin::initBehavior('history-install'); Javelin::initBehavior('phabricator-gesture'); $current_token = null; if ($user) { $current_token = $user->getCSRFToken(); } Javelin::initBehavior('refresh-csrf', array('tokenName' => AphrontRequest::getCSRFTokenName(), 'header' => AphrontRequest::getCSRFHeaderName(), 'current' => $current_token)); Javelin::initBehavior('device'); if ($user->hasSession()) { $hisec = $user->getSession()->getHighSecurityUntil() - time(); if ($hisec > 0) { $remaining_time = phutil_format_relative_time($hisec); Javelin::initBehavior('high-security-warning', array('uri' => '/auth/session/downgrade/', 'message' => pht('Your session is in high security mode. When you ' . 'finish using it, click here to leave.', $remaining_time))); } } if ($console) { require_celerity_resource('aphront-dark-console-css'); $headers = array(); if (DarkConsoleXHProfPluginAPI::isProfilerStarted()) { $headers[DarkConsoleXHProfPluginAPI::getProfilerHeader()] = 'page'; } if (DarkConsoleServicesPlugin::isQueryAnalyzerRequested()) { $headers[DarkConsoleServicesPlugin::getQueryAnalyzerHeader()] = true; } Javelin::initBehavior('dark-console', array('uri' => pht('Main Request'), 'selected' => $user ? $user->getConsoleTab() : null, 'visible' => $user ? (int) $user->getConsoleVisible() : true, 'headers' => $headers)); // Change this to initBehavior when there is some behavior to initialize require_celerity_resource('javelin-behavior-error-log'); } if ($user) { $viewer = $user; } else { $viewer = new PhabricatorUser(); } $menu = id(new PhabricatorMainMenuView())->setUser($viewer); if ($this->getController()) { $menu->setController($this->getController()); } if ($this->getApplicationMenu()) { $menu->setApplicationMenu($this->getApplicationMenu()); } $this->menuContent = $menu->render(); }
private function buildClusterRepositoryStatus() { $viewer = $this->getViewer(); Javelin::initBehavior('phabricator-tooltips'); $all_services = id(new AlmanacServiceQuery())->setViewer($viewer)->withServiceTypes(array(AlmanacClusterRepositoryServiceType::SERVICETYPE))->needBindings(true)->needProperties(true)->execute(); $all_services = mpull($all_services, null, 'getPHID'); $all_repositories = id(new PhabricatorRepositoryQuery())->setViewer($viewer)->withHosted(PhabricatorRepositoryQuery::HOSTED_PHABRICATOR)->withTypes(array(PhabricatorRepositoryType::REPOSITORY_TYPE_GIT))->execute(); $all_repositories = mpull($all_repositories, null, 'getPHID'); $all_versions = id(new PhabricatorRepositoryWorkingCopyVersion())->loadAll(); $all_devices = $this->getDevices($all_services, false); $all_active_devices = $this->getDevices($all_services, true); $leader_versions = $this->getLeaderVersionsByRepository($all_repositories, $all_versions, $all_active_devices); $push_times = $this->loadLeaderPushTimes($leader_versions); $repository_groups = mgroup($all_repositories, 'getAlmanacServicePHID'); $repository_versions = mgroup($all_versions, 'getRepositoryPHID'); $rows = array(); foreach ($all_services as $service) { $service_phid = $service->getPHID(); if ($service->getAlmanacPropertyValue('closed')) { $status_icon = 'fa-folder'; $status_tip = pht('Closed'); } else { $status_icon = 'fa-folder-open green'; $status_tip = pht('Open'); } $status_icon = id(new PHUIIconView())->setIcon($status_icon)->addSigil('has-tooltip')->setMetadata(array('tip' => $status_tip)); $devices = idx($all_devices, $service_phid, array()); $active_devices = idx($all_active_devices, $service_phid, array()); $device_icon = 'fa-server green'; $device_label = pht('%s Active', phutil_count($active_devices)); $device_status = array(id(new PHUIIconView())->setIcon($device_icon), ' ', $device_label); $repositories = idx($repository_groups, $service_phid, array()); $repository_status = pht('%s', phutil_count($repositories)); $no_leader = array(); $full_sync = array(); $partial_sync = array(); $no_sync = array(); $lag = array(); // Threshold in seconds before we start complaining that repositories // are not synchronized when there is only one leader. $threshold = phutil_units('5 minutes in seconds'); $messages = array(); foreach ($repositories as $repository) { $repository_phid = $repository->getPHID(); $leader_version = idx($leader_versions, $repository_phid); if ($leader_version === null) { $no_leader[] = $repository; $messages[] = pht('Repository %s has an ambiguous leader.', $viewer->renderHandle($repository_phid)->render()); continue; } $versions = idx($repository_versions, $repository_phid, array()); $leaders = 0; foreach ($versions as $version) { if ($version->getRepositoryVersion() == $leader_version) { $leaders++; } } if ($leaders == count($active_devices)) { $full_sync[] = $repository; } else { $push_epoch = idx($push_times, $repository_phid); if ($push_epoch) { $duration = PhabricatorTime::getNow() - $push_epoch; $lag[] = $duration; } else { $duration = null; } if ($leaders >= 2 || $duration && $duration < $threshold) { $partial_sync[] = $repository; } else { $no_sync[] = $repository; if ($push_epoch) { $messages[] = pht('Repository %s has unreplicated changes (for %s).', $viewer->renderHandle($repository_phid)->render(), phutil_format_relative_time($duration)); } else { $messages[] = pht('Repository %s has unreplicated changes.', $viewer->renderHandle($repository_phid)->render()); } } } } $with_lag = false; if ($no_leader) { $replication_icon = 'fa-times red'; $replication_label = pht('Ambiguous Leader'); } else { if ($no_sync) { $replication_icon = 'fa-refresh yellow'; $replication_label = pht('Unsynchronized'); $with_lag = true; } else { if ($partial_sync) { $replication_icon = 'fa-refresh green'; $replication_label = pht('Partial'); $with_lag = true; } else { if ($full_sync) { $replication_icon = 'fa-check green'; $replication_label = pht('Synchronized'); } else { $replication_icon = 'fa-times grey'; $replication_label = pht('No Repositories'); } } } } if ($with_lag && $lag) { $lag_status = phutil_format_relative_time(max($lag)); $lag_status = pht(' (%s)', $lag_status); } else { $lag_status = null; } $replication_status = array(id(new PHUIIconView())->setIcon($replication_icon), ' ', $replication_label, $lag_status); $messages = phutil_implode_html(phutil_tag('br'), $messages); $rows[] = array($status_icon, $viewer->renderHandle($service->getPHID()), $device_status, $repository_status, $replication_status, $messages); } $table = id(new AphrontTableView($rows))->setNoDataString(pht('No repository cluster services are configured.'))->setHeaders(array(null, pht('Service'), pht('Devices'), pht('Repos'), pht('Sync'), pht('Messages')))->setColumnClasses(array(null, 'pri', null, null, null, 'wide')); $doc_href = PhabricatorEnv::getDoclink('Cluster: Repositories'); $header = id(new PHUIHeaderView())->setHeader(pht('Cluster Repository Status'))->addActionLink(id(new PHUIButtonView())->setIcon('fa-book')->setHref($doc_href)->setTag('a')->setText(pht('Documentation'))); return id(new PHUIObjectBoxView())->setHeader($header)->setTable($table); }
private function buildPropertySection(PhabricatorCalendarImport $import) { $viewer = $this->getViewer(); $properties = id(new PHUIPropertyListView())->setViewer($viewer); $engine = $import->getEngine(); $properties->addProperty(pht('Source Type'), $engine->getImportEngineTypeName()); if ($import->getIsDisabled()) { $auto_updates = phutil_tag('em', array(), pht('Import Disabled')); $has_trigger = false; } else { $frequency = $import->getTriggerFrequency(); $frequency_map = PhabricatorCalendarImport::getTriggerFrequencyMap(); $frequency_names = ipull($frequency_map, 'name'); $auto_updates = idx($frequency_names, $frequency, $frequency); if ($frequency == PhabricatorCalendarImport::FREQUENCY_ONCE) { $has_trigger = false; $auto_updates = phutil_tag('em', array(), $auto_updates); } else { $has_trigger = true; } } $properties->addProperty(pht('Automatic Updates'), $auto_updates); if ($has_trigger) { $trigger = id(new PhabricatorWorkerTriggerQuery())->setViewer($viewer)->withPHIDs(array($import->getTriggerPHID()))->needEvents(true)->executeOne(); if (!$trigger) { $next_trigger = phutil_tag('em', array(), pht('Invalid Trigger')); } else { $now = PhabricatorTime::getNow(); $next_epoch = $trigger->getNextEventPrediction(); $next_trigger = pht('%s (%s)', phabricator_datetime($next_epoch, $viewer), phutil_format_relative_time($next_epoch - $now)); } $properties->addProperty(pht('Next Update'), $next_trigger); } $engine->appendImportProperties($viewer, $import, $properties); return $properties; }