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;
 }