public function processRequest() { $request = $this->getRequest(); $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page')); $macro_table = new PhabricatorFileImageMacro(); $macros = $macro_table->loadAllWhere('1 = 1 ORDER BY id DESC LIMIT %d, %d', $pager->getOffset(), $pager->getPageSize()); // Get an exact count since the size here is reasonably going to be a few // thousand at most in any reasonable case. $count = queryfx_one($macro_table->establishConnection('r'), 'SELECT COUNT(*) N FROM %T', $macro_table->getTableName()); $count = $count['N']; $pager->setCount($count); $pager->setURI($request->getRequestURI(), 'page'); $rows = array(); foreach ($macros as $macro) { $src = PhabricatorFileURI::getViewURIForPHID($macro->getFilePHID()); $rows[] = array(phutil_render_tag('a', array('href' => '/file/macro/edit/' . $macro->getID() . '/'), phutil_escape_html($macro->getName())), phutil_render_tag('a', array('href' => $src, 'target' => '_blank'), phutil_render_tag('img', array('src' => $src))), javelin_render_tag('a', array('href' => '/file/macro/delete/' . $macro->getID() . '/', 'sigil' => 'workflow', 'class' => 'grey small button'), 'Delete')); } $table = new AphrontTableView($rows); $table->setHeaders(array('Name', 'Image', '')); $table->setColumnClasses(array('pri', 'wide thumb', 'action')); $panel = new AphrontPanelView(); $panel->appendChild($table); $panel->setHeader('Image Macros'); $panel->setCreateButton('New Image Macro', '/file/macro/edit/'); $panel->appendChild($pager); return $this->buildStandardPageResponse($panel, array('title' => 'Image Macros', 'tab' => 'macros')); }
public final function willBeginExecution() { $request = $this->getRequest(); $user = new PhabricatorUser(); $phusr = $request->getCookie('phusr'); $phsid = $request->getCookie('phsid'); if ($phusr && $phsid) { $info = queryfx_one($user->establishConnection('r'), 'SELECT u.* FROM %T u JOIN %T s ON u.phid = s.userPHID AND s.type LIKE %> AND s.sessionKey = %s', $user->getTableName(), 'phabricator_session', 'web-', $phsid); if ($info) { $user->loadFromArray($info); } } $request->setUser($user); if ($user->getIsDisabled() && $this->shouldRequireEnabledUser()) { $disabled_user_controller = newv('PhabricatorDisabledUserController', array($request)); return $this->delegateToController($disabled_user_controller); } if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) { if ($user->getConsoleEnabled() || PhabricatorEnv::getEnvConfig('darkconsole.always-on')) { $console = new DarkConsoleCore(); $request->getApplicationConfiguration()->setConsole($console); } } if ($this->shouldRequireLogin() && !$user->getPHID()) { $login_controller = newv('PhabricatorLoginController', array($request)); return $this->delegateToController($login_controller); } if ($this->shouldRequireAdmin() && !$user->getIsAdmin()) { return new Aphront403Response(); } }
private function checkIfRepositoryIsFullyImported(PhabricatorRepository $repository) { // Check if the repository has the "Importing" flag set. We want to clear // the flag if we can. $importing = $repository->getDetail('importing'); if (!$importing) { // This repository isn't marked as "Importing", so we're done. return; } // Look for any commit which hasn't imported. $unparsed_commit = queryfx_one($repository->establishConnection('r'), 'SELECT * FROM %T WHERE repositoryID = %d AND (importStatus & %d) != %d LIMIT 1', id(new PhabricatorRepositoryCommit())->getTableName(), $repository->getID(), PhabricatorRepositoryCommit::IMPORTED_ALL, PhabricatorRepositoryCommit::IMPORTED_ALL); if ($unparsed_commit) { // We found a commit which still needs to import, so we can't clear the // flag. return; } // Clear the "importing" flag. $repository->openTransaction(); $repository->beginReadLocking(); $repository = $repository->reload(); $repository->setDetail('importing', false); $repository->save(); $repository->endReadLocking(); $repository->saveTransaction(); }
protected function doLock($wait) { $conn = $this->conn; if (!$conn) { // Try to reuse a connection from the connection pool. $conn = array_pop(self::$pool); } if (!$conn) { // NOTE: Using the 'repository' database somewhat arbitrarily, mostly // because the first client of locks is the repository daemons. We must // always use the same database for all locks, but don't access any // tables so we could use any valid database. We could build a // database-free connection instead, but that's kind of messy and we // might forget about it in the future if we vertically partition the // application. $dao = new PhabricatorRepository(); // NOTE: Using "force_new" to make sure each lock is on its own // connection. $conn = $dao->establishConnection('w', $force_new = true); // NOTE: Since MySQL will disconnect us if we're idle for too long, we set // the wait_timeout to an enormous value, to allow us to hold the // connection open indefinitely (or, at least, for 24 days). $max_allowed_timeout = 2147483; queryfx($conn, 'SET wait_timeout = %d', $max_allowed_timeout); } $result = queryfx_one($conn, 'SELECT GET_LOCK(%s, %f)', 'phabricator:' . $this->lockname, $wait); $ok = head($result); if (!$ok) { throw new PhutilLockException($this->getName()); } $this->conn = $conn; }
private function materializeProject(PhabricatorProject $project) { if ($project->isMilestone()) { return; } $material_type = PhabricatorProjectMaterializedMemberEdgeType::EDGECONST; $member_type = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; $project_phid = $project->getPHID(); $descendants = id(new PhabricatorProjectQuery())->setViewer($this->getViewer())->withAncestorProjectPHIDs(array($project->getPHID()))->withIsMilestone(false)->withHasSubprojects(false)->execute(); $descendant_phids = mpull($descendants, 'getPHID'); if ($descendant_phids) { $source_phids = $descendant_phids; $has_subprojects = true; } else { $source_phids = array($project->getPHID()); $has_subprojects = false; } $conn_w = $project->establishConnection('w'); $any_milestone = queryfx_one($conn_w, 'SELECT id FROM %T WHERE parentProjectPHID = %s AND milestoneNumber IS NOT NULL LIMIT 1', $project->getTableName(), $project_phid); $has_milestones = (bool) $any_milestone; $project->openTransaction(); // Delete any existing materialized member edges. queryfx($conn_w, 'DELETE FROM %T WHERE src = %s AND type = %s', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type); // Copy current member edges to create new materialized edges. queryfx($conn_w, 'INSERT IGNORE INTO %T (src, type, dst, dateCreated, seq) SELECT %s, %d, dst, dateCreated, seq FROM %T WHERE src IN (%Ls) AND type = %d', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type, PhabricatorEdgeConfig::TABLE_NAME_EDGE, $source_phids, $member_type); // Update the hasSubprojects flag. queryfx($conn_w, 'UPDATE %T SET hasSubprojects = %d WHERE id = %d', $project->getTableName(), (int) $has_subprojects, $project->getID()); // Update the hasMilestones flag. queryfx($conn_w, 'UPDATE %T SET hasMilestones = %d WHERE id = %d', $project->getTableName(), (int) $has_milestones, $project->getID()); $project->saveTransaction(); }
protected function getCustomTransactionNewValue(PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorProjectTransaction::TYPE_NAME: case PhabricatorProjectTransaction::TYPE_STATUS: case PhabricatorProjectTransaction::TYPE_IMAGE: case PhabricatorProjectTransaction::TYPE_ICON: case PhabricatorProjectTransaction::TYPE_COLOR: case PhabricatorProjectTransaction::TYPE_LOCKED: case PhabricatorProjectTransaction::TYPE_PARENT: return $xaction->getNewValue(); case PhabricatorProjectTransaction::TYPE_SLUGS: return $this->normalizeSlugs($xaction->getNewValue()); case PhabricatorProjectTransaction::TYPE_MILESTONE: $current = queryfx_one($object->establishConnection('w'), 'SELECT MAX(milestoneNumber) n FROM %T WHERE parentProjectPHID = %s', $object->getTableName(), $object->getParentProject()->getPHID()); if (!$current) { $number = 1; } else { $number = (int) $current['n'] + 1; } return $number; } return parent::getCustomTransactionNewValue($object, $xaction); }
public function countUnread(PhabricatorUser $user) { $conn = $this->establishConnection('r'); $data = queryfx_one($conn, 'SELECT COUNT(*) as count FROM %T WHERE userPHID = %s AND hasViewed = 0', $this->getTableName(), $user->getPHID()); return $data['count']; }
public static function loadXHeraldRulesHeader($phid) { $header = queryfx_one(id(new HeraldTranscript())->establishConnection('r'), 'SELECT * FROM %T WHERE phid = %s', self::TABLE_SAVED_HEADER, $phid); if ($header) { return idx($header, 'header'); } return null; }
protected function loadRandomPHID($table) { $conn_r = $table->establishConnection('r'); $row = queryfx_one($conn_r, 'SELECT phid FROM %T ORDER BY RAND() LIMIT 1', $table->getTableName()); if (!$row) { return null; } return $row['phid']; }
private function loadCommitSequence($commit_id) { $conn_r = id(new PhabricatorRepository())->establishConnection('r'); $path_change = queryfx_one($conn_r, 'SELECT commitSequence FROM %T WHERE repositoryID = %d AND commitID = %d LIMIT 1', PhabricatorRepository::TABLE_PATHCHANGE, $this->request->getRepository()->getID(), $commit_id); return reset($path_change); }
public static function loadRawConfigValue($key) { $conn_raw = id(new PhabricatorUser())->establishConnection('w'); try { $value = queryfx_one($conn_raw, 'SELECT @@%Q', $key); $value = $value['@@' . $key]; } catch (AphrontQueryException $ex) { $value = null; } return $value; }
public final function willBeginExecution() { $request = $this->getRequest(); $user = new PhabricatorUser(); $phusr = $request->getCookie('phusr'); $phsid = $request->getCookie('phsid'); if (strlen($phusr) && $phsid) { $info = queryfx_one($user->establishConnection('r'), 'SELECT u.* FROM %T u JOIN %T s ON u.phid = s.userPHID AND s.type LIKE %> AND s.sessionKey = %s', $user->getTableName(), 'phabricator_session', 'web-', $phsid); if ($info) { $user->loadFromArray($info); } } $translation = $user->getTranslation(); if ($translation && $translation != PhabricatorEnv::getEnvConfig('translation.provider')) { $translation = newv($translation, array()); PhutilTranslator::getInstance()->setLanguage($translation->getLanguage())->addTranslations($translation->getTranslations()); } $request->setUser($user); if ($user->getIsDisabled() && $this->shouldRequireEnabledUser()) { $disabled_user_controller = new PhabricatorDisabledUserController($request); return $this->delegateToController($disabled_user_controller); } $event = new PhabricatorEvent(PhabricatorEventType::TYPE_CONTROLLER_CHECKREQUEST, array('request' => $request, 'controller' => get_class($this))); $event->setUser($user); PhutilEventEngine::dispatchEvent($event); $checker_controller = $event->getValue('controller'); if ($checker_controller != get_class($this)) { return $this->delegateToController($checker_controller); } if (PhabricatorEnv::getEnvConfig('darkconsole.enabled')) { if ($user->getConsoleEnabled() || PhabricatorEnv::getEnvConfig('darkconsole.always-on')) { $console = new DarkConsoleCore(); $request->getApplicationConfiguration()->setConsole($console); } } if ($this->shouldRequireLogin() && !$user->getPHID()) { $login_controller = new PhabricatorLoginController($request); return $this->delegateToController($login_controller); } if ($this->shouldRequireEmailVerification()) { $email = $user->loadPrimaryEmail(); if (!$email) { throw new Exception("No primary email address associated with this account!"); } if (!$email->getIsVerified()) { $verify_controller = new PhabricatorMustVerifyEmailController($request); return $this->delegateToController($verify_controller); } } if ($this->shouldRequireAdmin() && !$user->getIsAdmin()) { return new Aphront403Response(); } }
protected function createComment() { $commit = $this->loadCommit(); // TODO: Write a real PathQuery object? $path_id = $this->getChangesetID(); $path = queryfx_one(id(new PhabricatorRepository())->establishConnection('r'), 'SELECT path FROM %T WHERE id = %d', PhabricatorRepository::TABLE_PATH, $path_id); if (!$path) { throw new Exception(pht('Invalid path ID!')); } return id(new PhabricatorAuditInlineComment())->setCommitPHID($commit->getPHID())->setPathID($path_id); }
public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $is_admin = $viewer->getIsAdmin(); $user = new PhabricatorUser(); $count = queryfx_one($user->establishConnection('r'), 'SELECT COUNT(*) N FROM %T', $user->getTableName()); $count = idx($count, 'N', 0); $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page', 0)); $pager->setCount($count); $pager->setURI($request->getRequestURI(), 'page'); $users = id(new PhabricatorPeopleQuery())->needPrimaryEmail(true)->executeWithOffsetPager($pager); $rows = array(); foreach ($users as $user) { $primary_email = $user->loadPrimaryEmail(); if ($primary_email && $primary_email->getIsVerified()) { $email = 'Verified'; } else { $email = 'Unverified'; } $status = array(); if ($user->getIsDisabled()) { $status[] = 'Disabled'; } if ($user->getIsAdmin()) { $status[] = 'Admin'; } if ($user->getIsSystemAgent()) { $status[] = 'System Agent'; } $status = implode(', ', $status); $rows[] = array(phabricator_date($user->getDateCreated(), $viewer), phabricator_time($user->getDateCreated(), $viewer), phutil_render_tag('a', array('href' => '/p/' . $user->getUsername() . '/'), phutil_escape_html($user->getUserName())), phutil_escape_html($user->getRealName()), $status, $email, phutil_render_tag('a', array('class' => 'button grey small', 'href' => '/people/edit/' . $user->getID() . '/'), 'Administrate User')); } $table = new AphrontTableView($rows); $table->setHeaders(array('Join Date', 'Time', 'Username', 'Real Name', 'Roles', 'Email', '')); $table->setColumnClasses(array(null, 'right', 'pri', 'wide', null, null, 'action')); $table->setColumnVisibility(array(true, true, true, true, $is_admin, $is_admin, $is_admin)); $panel = new AphrontPanelView(); $panel->setHeader('People (' . number_format($count) . ')'); $panel->appendChild($table); $panel->appendChild($pager); if ($is_admin) { $panel->addButton(phutil_render_tag('a', array('href' => '/people/edit/', 'class' => 'button green'), 'Create New Account')); if (PhabricatorEnv::getEnvConfig('ldap.auth-enabled')) { $panel->addButton(phutil_render_tag('a', array('href' => '/people/ldap/', 'class' => 'button green'), 'Import from LDAP')); } } $nav = $this->buildSideNavView(); $nav->selectFilter('people'); $nav->appendChild($panel); return $this->buildApplicationPage($nav, array('title' => 'People')); }
public function processRequest() { $request = $this->getRequest(); $macro_table = new PhabricatorFileImageMacro(); if ($request->getStr('name') !== null) { $macros = $macro_table->loadAllWhere('name LIKE %~', $request->getStr('name')); } else { $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page')); $macros = $macro_table->loadAllWhere('1 = 1 ORDER BY id DESC LIMIT %d, %d', $pager->getOffset(), $pager->getPageSize()); // Get an exact count since the size here is reasonably going to be a few // thousand at most in any reasonable case. $count = queryfx_one($macro_table->establishConnection('r'), 'SELECT COUNT(*) N FROM %T', $macro_table->getTableName()); $count = $count['N']; $pager->setCount($count); $pager->setURI($request->getRequestURI(), 'page'); } $file_phids = mpull($macros, 'getFilePHID'); $files = array(); if ($file_phids) { $files = id(new PhabricatorFile())->loadAllWhere("phid IN (%Ls)", $file_phids); $author_phids = mpull($files, 'getAuthorPHID', 'getPHID'); $handles = id(new PhabricatorObjectHandleData($author_phids))->loadHandles(); } $files_map = mpull($files, null, 'getPHID'); $rows = array(); foreach ($macros as $macro) { $file_phid = $macro->getFilePHID(); $file = idx($files_map, $file_phid); $author_link = isset($author_phids[$file_phid]) ? $handles[$author_phids[$file_phid]]->renderLink() : null; $rows[] = array(phutil_render_tag('a', array('href' => '/file/macro/edit/' . $macro->getID() . '/'), phutil_escape_html($macro->getName())), $author_link, phutil_render_tag('a', array('href' => $file ? $file->getBestURI() : null, 'target' => '_blank'), phutil_render_tag('img', array('src' => $file ? $file->getBestURI() : null))), javelin_render_tag('a', array('href' => '/file/macro/delete/' . $macro->getID() . '/', 'sigil' => 'workflow', 'class' => 'grey small button'), 'Delete')); } $table = new AphrontTableView($rows); $table->setHeaders(array('Name', 'Author', 'Image', '')); $table->setColumnClasses(array('pri', '', 'wide thumb', 'action')); $filter_form = id(new AphrontFormView())->setMethod('GET')->setAction('/file/macro/')->setUser($request->getUser())->appendChild(id(new AphrontFormTextControl())->setName('name')->setLabel('Name')->setValue($request->getStr('name')))->appendChild(id(new AphrontFormSubmitControl())->setValue('Filter Image Macros')); $filter_view = new AphrontListFilterView(); $filter_view->appendChild($filter_form); $filter_view->addButton(phutil_render_tag('a', array('href' => '/file/macro/edit/', 'class' => 'green button'), 'New Image Macro')); $panel = new AphrontPanelView(); $panel->appendChild($table); $panel->setHeader('Image Macros'); if ($request->getStr('name') === null) { $panel->appendChild($pager); } $side_nav = new PhabricatorFileSideNavView(); $side_nav->setSelectedFilter('all_macros'); $side_nav->appendChild($filter_view); $side_nav->appendChild($panel); return $this->buildStandardPageResponse($side_nav, array('title' => 'Image Macros')); }
protected function createComment() { // Verify commit and path correspond to actual objects. $commit_phid = $this->commitPHID; $path_id = $this->getChangesetID(); $commit = id(new PhabricatorRepositoryCommit())->loadOneWhere('phid = %s', $commit_phid); if (!$commit) { throw new Exception("Invalid commit ID!"); } // TODO: Write a real PathQuery object? $path = queryfx_one(id(new PhabricatorRepository())->establishConnection('r'), 'SELECT path FROM %T WHERE id = %d', PhabricatorRepository::TABLE_PATH, $path_id); if (!$path) { throw new Exception("Invalid path ID!"); } return id(new PhabricatorAuditInlineComment())->setCommitPHID($commit_phid)->setPathID($path_id); }
public function getEpoch() { if (PHP_INT_SIZE < 8) { // We're on a 32-bit machine. if (function_exists('bcadd')) { // Try to use the 'bc' extension. return bcdiv($this->chronologicalKey, bcpow(2, 32)); } else { // Do the math in MySQL. TODO: If we formalize a bc dependency, get // rid of this. // See: PhabricatorFeedStoryPublisher::generateChronologicalKey() $conn_r = id($this->establishConnection('r')); $result = queryfx_one($conn_r, 'SELECT (%s >> 32) as N', $this->chronologicalKey); return $result['N']; } } else { return $this->chronologicalKey >> 32; } }
private function getCommentVersion($object) { $xaction = $object->getApplicationTransactionTemplate(); try { $comment = $xaction->getApplicationTransactionCommentObject(); if (!$comment) { return 'none'; } } catch (Exception $ex) { return 'none'; } $comment_row = queryfx_one($comment->establishConnection('r'), 'SELECT c.id FROM %T x JOIN %T c ON x.phid = c.transactionPHID WHERE x.objectPHID = %s ORDER BY c.id DESC LIMIT 1', $xaction->getTableName(), $comment->getTableName(), $object->getPHID()); if (!$comment_row) { return 'none'; } return $comment_row['id']; }
public function execute(PhutilArgumentParser $args) { $console = PhutilConsole::getConsole(); $map = array('raw' => new PhabricatorFactRaw(), 'agg' => new PhabricatorFactAggregate()); foreach ($map as $type => $table) { $conn = $table->establishConnection('r'); $name = $table->getTableName(); $row = queryfx_one($conn, 'SELECT COUNT(*) N FROM %T', $name); $n = $row['N']; switch ($type) { case 'raw': $desc = pht('There are %d raw fact(s) in storage.', $n); break; case 'agg': $desc = pht('There are %d aggregate fact(s) in storage.', $n); break; } $console->writeOut("%s\n", $desc); } return 0; }
public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $is_admin = $viewer->getIsAdmin(); $user = new PhabricatorUser(); $count = queryfx_one($user->establishConnection('r'), 'SELECT COUNT(*) N FROM %T', $user->getTableName()); $count = idx($count, 'N', 0); $pager = new AphrontPagerView(); $pager->setOffset($request->getInt('page', 0)); $pager->setCount($count); $pager->setURI($request->getRequestURI(), 'page'); $users = id(new PhabricatorUser())->loadAllWhere('1 = 1 ORDER BY id DESC LIMIT %d, %d', $pager->getOffset(), $pager->getPageSize()); $rows = array(); foreach ($users as $user) { $status = ''; if ($user->getIsDisabled()) { $status = 'Disabled'; } else { if ($user->getIsAdmin()) { $status = 'Admin'; } else { $status = '-'; } } $rows[] = array(phabricator_date($user->getDateCreated(), $viewer), phabricator_time($user->getDateCreated(), $viewer), phutil_render_tag('a', array('href' => '/p/' . $user->getUsername() . '/'), phutil_escape_html($user->getUserName())), phutil_escape_html($user->getRealName()), $status, phutil_render_tag('a', array('class' => 'button grey small', 'href' => '/people/edit/' . $user->getID() . '/'), 'Administrate User')); } $table = new AphrontTableView($rows); $table->setHeaders(array('Join Date', 'Time', 'Username', 'Real Name', 'Status', '')); $table->setColumnClasses(array(null, 'right', 'pri', 'wide', null, 'action')); $table->setColumnVisibility(array(true, true, true, true, $is_admin, $is_admin)); $panel = new AphrontPanelView(); $panel->setHeader('People (' . number_format($count) . ')'); $panel->appendChild($table); $panel->appendChild($pager); if ($is_admin) { $panel->addButton(phutil_render_tag('a', array('href' => '/people/edit/', 'class' => 'button green'), 'Create New Account')); } return $this->buildStandardPageResponse($panel, array('title' => 'People', 'tab' => 'directory')); }
/** * Rebuild the PhabricatorSearchAbstractDocument that was used to index * an object out of the index itself. This is primarily useful for debugging, * as it allows you to inspect the search index representation of a * document. * * @param phid PHID of a document which exists in the search index. * @return null|PhabricatorSearchAbstractDocument Abstract document object * which corresponds to the original abstract document used to * build the document index. */ public function reconstructDocument($phid) { $dao_doc = new PhabricatorSearchDocument(); $dao_field = new PhabricatorSearchDocumentField(); $dao_relationship = new PhabricatorSearchDocumentRelationship(); $t_doc = $dao_doc->getTableName(); $t_field = $dao_field->getTableName(); $t_relationship = $dao_relationship->getTableName(); $doc = queryfx_one($dao_doc->establishConnection('r'), 'SELECT * FROM %T WHERE phid = %s', $t_doc, $phid); if (!$doc) { return null; } $fields = queryfx_all($dao_field->establishConnection('r'), 'SELECT * FROM %T WHERE phid = %s', $t_field, $phid); $relationships = queryfx_all($dao_relationship->establishConnection('r'), 'SELECT * FROM %T WHERE phid = %s', $t_relationship, $phid); $adoc = id(new PhabricatorSearchAbstractDocument())->setPHID($phid)->setDocumentType($doc['documentType'])->setDocumentTitle($doc['documentTitle'])->setDocumentCreated($doc['documentCreated'])->setDocumentModified($doc['documentModified']); foreach ($fields as $field) { $adoc->addField($field['field'], $field['corpus'], $field['auxPHID']); } foreach ($relationships as $relationship) { $adoc->addRelationship($relationship['relation'], $relationship['relatedPHID'], $relationship['relatedType'], $relationship['relatedTime']); } return $adoc; }
/** * Load the pull frequency for this repository, based on the time since the * last activity. * * We pull rarely used repositories less frequently. This finds the most * recent commit which is older than the current time (which prevents us from * spinning on repositories with a silly commit post-dated to some time in * 2037). We adjust the pull frequency based on when the most recent commit * occurred. * * @param int The minimum update interval to use, in seconds. * @return int Repository update interval, in seconds. */ public function loadUpdateInterval($minimum = 15) { // If a repository is still importing, always pull it as frequently as // possible. This prevents us from hanging for a long time at 99.9% when // importing an inactive repository. if ($this->isImporting()) { return $minimum; } $window_start = PhabricatorTime::getNow() + $minimum; $table = id(new PhabricatorRepositoryCommit()); $last_commit = queryfx_one($table->establishConnection('r'), 'SELECT epoch FROM %T WHERE repositoryID = %d AND epoch <= %d ORDER BY epoch DESC LIMIT 1', $table->getTableName(), $this->getID(), $window_start); if ($last_commit) { $time_since_commit = $window_start - $last_commit['epoch']; $last_few_days = phutil_units('3 days in seconds'); if ($time_since_commit <= $last_few_days) { // For repositories with activity in the recent past, we wait one // extra second for every 10 minutes since the last commit. This // shorter backoff is intended to handle weekends and other short // breaks from development. $smart_wait = $time_since_commit / 600; } else { // For repositories without recent activity, we wait one extra second // for every 4 minutes since the last commit. This longer backoff // handles rarely used repositories, up to the maximum. $smart_wait = $time_since_commit / 240; } // We'll never wait more than 6 hours to pull a repository. $longest_wait = phutil_units('6 hours in seconds'); $smart_wait = min($smart_wait, $longest_wait); $smart_wait = max($minimum, $smart_wait); } else { $smart_wait = $minimum; } return $smart_wait; }
/** * Authenticate the client making the request to a Phabricator user account. * * @param ConduitAPIRequest Request being executed. * @param dict Request metadata. * @return null|pair Null to indicate successful authentication, or * an error code and error message pair. */ private function authenticateUser(ConduitAPIRequest $api_request, array $metadata) { $request = $this->getRequest(); if ($request->getUser()->getPHID()) { $request->validateCSRF(); return $this->validateAuthenticatedUser($api_request, $request->getUser()); } // handle oauth $access_token = $request->getStr('access_token'); $method_scope = $metadata['scope']; if ($access_token && $method_scope != PhabricatorOAuthServerScope::SCOPE_NOT_ACCESSIBLE) { $token = id(new PhabricatorOAuthServerAccessToken())->loadOneWhere('token = %s', $access_token); if (!$token) { return array('ERR-INVALID-AUTH', 'Access token does not exist.'); } $oauth_server = new PhabricatorOAuthServer(); $valid = $oauth_server->validateAccessToken($token, $method_scope); if (!$valid) { return array('ERR-INVALID-AUTH', 'Access token is invalid.'); } // valid token, so let's log in the user! $user_phid = $token->getUserPHID(); $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $user_phid); if (!$user) { return array('ERR-INVALID-AUTH', 'Access token is for invalid user.'); } return $this->validateAuthenticatedUser($api_request, $user); } // Handle sessionless auth. TOOD: This is super messy. if (isset($metadata['authUser'])) { $user = id(new PhabricatorUser())->loadOneWhere('userName = %s', $metadata['authUser']); if (!$user) { return array('ERR-INVALID-AUTH', 'Authentication is invalid.'); } $token = idx($metadata, 'authToken'); $signature = idx($metadata, 'authSignature'); $certificate = $user->getConduitCertificate(); if (sha1($token . $certificate) !== $signature) { return array('ERR-INVALID-AUTH', 'Authentication is invalid.'); } return $this->validateAuthenticatedUser($api_request, $user); } $session_key = idx($metadata, 'sessionKey'); if (!$session_key) { return array('ERR-INVALID-SESSION', 'Session key is not present.'); } $session = queryfx_one(id(new PhabricatorUser())->establishConnection('r'), 'SELECT * FROM %T WHERE sessionKey = %s', PhabricatorUser::SESSION_TABLE, $session_key); if (!$session) { return array('ERR-INVALID-SESSION', 'Session key is invalid.'); } // TODO: Make sessions timeout. // TODO: When we pull a session, read connectionID from the session table. $user = id(new PhabricatorUser())->loadOneWhere('phid = %s', $session['userPHID']); if (!$user) { return array('ERR-INVALID-SESSION', 'Session is for nonexistent user.'); } return $this->validateAuthenticatedUser($api_request, $user); }
/** * Wait for tasks to complete. If tasks are not leased by other workers, they * will be executed in this process while waiting. * * @param list<int> List of queued task IDs to wait for. * @return void */ public static final function waitForTasks(array $task_ids) { if (!$task_ids) { return; } $task_table = new PhabricatorWorkerActiveTask(); $waiting = array_fuse($task_ids); while ($waiting) { $conn_w = $task_table->establishConnection('w'); // Check if any of the tasks we're waiting on are still queued. If they // are not, we're done waiting. $row = queryfx_one($conn_w, 'SELECT COUNT(*) N FROM %T WHERE id IN (%Ld)', $task_table->getTableName(), $waiting); if (!$row['N']) { // Nothing is queued anymore. Stop waiting. break; } $tasks = id(new PhabricatorWorkerLeaseQuery())->withIDs($waiting)->setLimit(1)->execute(); if (!$tasks) { // We were not successful in leasing anything. Sleep for a bit and // see if we have better luck later. sleep(1); continue; } $task = head($tasks)->executeTask(); $ex = $task->getExecutionException(); if ($ex) { throw $ex; } } $tasks = id(new PhabricatorWorkerArchiveTaskQuery())->withIDs($task_ids)->execute(); foreach ($tasks as $task) { if ($task->getResult() != PhabricatorWorkerArchiveTask::RESULT_SUCCESS) { throw new Exception(pht('Task %d failed!', $task->getID())); } } }
<?php // Switch PhabricatorWorkerActiveTask from auto-increment IDs to counter IDs. // Set the initial counter ID to be larger than any known task ID. $active_table = new PhabricatorWorkerActiveTask(); $archive_table = new PhabricatorWorkerArchiveTask(); $old_table = 'worker_task'; $conn_w = $active_table->establishConnection('w'); $active_auto = head(queryfx_one($conn_w, 'SELECT auto_increment FROM information_schema.tables WHERE table_name = %s AND table_schema = DATABASE()', $old_table)); $active_max = head(queryfx_one($conn_w, 'SELECT MAX(id) FROM %T', $old_table)); $archive_max = head(queryfx_one($conn_w, 'SELECT MAX(id) FROM %T', $archive_table->getTableName())); $initial_counter = max((int) $active_auto, (int) $active_max, (int) $archive_max); queryfx($conn_w, 'INSERT INTO %T (counterName, counterValue) VALUES (%s, %d) ON DUPLICATE KEY UPDATE counterValue = %d', LiskDAO::COUNTER_TABLE_NAME, $old_table, $initial_counter + 1, $initial_counter + 1);
#!/usr/bin/env php <?php $root = dirname(dirname(dirname(__FILE__))); require_once $root . '/scripts/__init_script__.php'; $commit = new PhabricatorRepositoryCommit(); $conn_w = id(new PhabricatorRepository())->establishConnection('w'); $sizes = queryfx_all($conn_w, 'SELECT repositoryID, count(*) N FROM %T GROUP BY repositoryID', $commit->getTableName()); $sizes = ipull($sizes, 'N', 'repositoryID'); $maxes = queryfx_all($conn_w, 'SELECT repositoryID, max(epoch) maxEpoch FROM %T GROUP BY repositoryID', $commit->getTableName()); $maxes = ipull($maxes, 'maxEpoch', 'repositoryID'); $repository_ids = array_keys($sizes + $maxes); echo pht('Updating %d repositories', count($repository_ids)); foreach ($repository_ids as $repository_id) { $last_commit = queryfx_one($conn_w, 'SELECT id FROM %T WHERE repositoryID = %d AND epoch = %d LIMIT 1', $commit->getTableName(), $repository_id, idx($maxes, $repository_id, 0)); if ($last_commit) { $last_commit = $last_commit['id']; } else { $last_commit = 0; } queryfx($conn_w, 'INSERT INTO %T (repositoryID, lastCommitID, size, epoch) VALUES (%d, %d, %d, %d) ON DUPLICATE KEY UPDATE lastCommitID = VALUES(lastCommitID), size = VALUES(size), epoch = VALUES(epoch)', PhabricatorRepository::TABLE_SUMMARY, $repository_id, $last_commit, idx($sizes, $repository_id, 0), idx($maxes, $repository_id, 0)); echo '.'; } echo "\n" . pht('Done.') . "\n";
public function getLegacyPatches(array $patches) { assert_instances_of($patches, 'PhabricatorStoragePatch'); try { $row = queryfx_one($this->getConn('meta_data'), 'SELECT version FROM %T', 'schema_version'); $version = $row['version']; } catch (AphrontQueryException $ex) { return array(); } $legacy = array(); foreach ($patches as $key => $patch) { if ($patch->getLegacy() !== false && $patch->getLegacy() <= $version) { $legacy[] = $key; } } return $legacy; }
protected function processDiffusionRequest(AphrontRequest $request) { $user = $request->getUser(); // This controller doesn't use blob/path stuff, just pass the dictionary // in directly instead of using the AphrontRequest parsing mechanism. $data = $request->getURIMap(); $data['user'] = $user; $drequest = DiffusionRequest::newFromDictionary($data); $this->diffusionRequest = $drequest; if ($request->getStr('diff')) { return $this->buildRawDiffResponse($drequest); } $repository = $drequest->getRepository(); $callsign = $repository->getCallsign(); $content = array(); $commit = id(new DiffusionCommitQuery())->setViewer($request->getUser())->withRepository($repository)->withIdentifiers(array($drequest->getCommit()))->needCommitData(true)->needAuditRequests(true)->executeOne(); $crumbs = $this->buildCrumbs(array('commit' => true)); if (!$commit) { $exists = $this->callConduitWithDiffusionRequest('diffusion.existsquery', array('commit' => $drequest->getCommit())); if (!$exists) { return new Aphront404Response(); } $error = id(new PHUIInfoView())->setTitle(pht('Commit Still Parsing'))->appendChild(pht('Failed to load the commit because the commit has not been ' . 'parsed yet.')); return $this->buildApplicationPage(array($crumbs, $error), array('title' => pht('Commit Still Parsing'))); } $audit_requests = $commit->getAudits(); $this->auditAuthorityPHIDs = PhabricatorAuditCommentEditor::loadAuditPHIDsForUser($user); $commit_data = $commit->getCommitData(); $is_foreign = $commit_data->getCommitDetail('foreign-svn-stub'); if ($is_foreign) { $subpath = $commit_data->getCommitDetail('svn-subpath'); $error_panel = new PHUIInfoView(); $error_panel->setTitle(pht('Commit Not Tracked')); $error_panel->setSeverity(PHUIInfoView::SEVERITY_WARNING); $error_panel->appendChild(pht("This Diffusion repository is configured to track only one " . "subdirectory of the entire Subversion repository, and this commit " . "didn't affect the tracked subdirectory ('%s'), so no " . "information is available.", $subpath)); $content[] = $error_panel; } else { $engine = PhabricatorMarkupEngine::newDifferentialMarkupEngine(); $engine->setConfig('viewer', $user); require_celerity_resource('phabricator-remarkup-css'); $parents = $this->callConduitWithDiffusionRequest('diffusion.commitparentsquery', array('commit' => $drequest->getCommit())); if ($parents) { $parents = id(new DiffusionCommitQuery())->setViewer($user)->withRepository($repository)->withIdentifiers($parents)->execute(); } $headsup_view = id(new PHUIHeaderView())->setHeader(nonempty($commit->getSummary(), pht('Commit Detail'))); $headsup_actions = $this->renderHeadsupActionList($commit, $repository); $commit_properties = $this->loadCommitProperties($commit, $commit_data, $parents, $audit_requests); $property_list = id(new PHUIPropertyListView())->setHasKeyboardShortcuts(true)->setUser($user)->setObject($commit); foreach ($commit_properties as $key => $value) { $property_list->addProperty($key, $value); } $message = $commit_data->getCommitMessage(); $revision = $commit->getCommitIdentifier(); $message = $this->linkBugtraq($message); $message = $engine->markupText($message); $property_list->invokeWillRenderEvent(); $property_list->setActionList($headsup_actions); $detail_list = new PHUIPropertyListView(); $detail_list->addSectionHeader(pht('Description'), PHUIPropertyListView::ICON_SUMMARY); $detail_list->addTextContent(phutil_tag('div', array('class' => 'diffusion-commit-message phabricator-remarkup'), $message)); $headsup_view->setTall(true); $object_box = id(new PHUIObjectBoxView())->setHeader($headsup_view)->addPropertyList($property_list)->addPropertyList($detail_list); $content[] = $object_box; } $content[] = $this->buildComments($commit); $hard_limit = 1000; if ($commit->isImported()) { $change_query = DiffusionPathChangeQuery::newFromDiffusionRequest($drequest); $change_query->setLimit($hard_limit + 1); $changes = $change_query->loadChanges(); } else { $changes = array(); } $was_limited = count($changes) > $hard_limit; if ($was_limited) { $changes = array_slice($changes, 0, $hard_limit); } $content[] = $this->buildMergesTable($commit); $highlighted_audits = $commit->getAuthorityAudits($user, $this->auditAuthorityPHIDs); $count = count($changes); $bad_commit = null; if ($count == 0) { $bad_commit = queryfx_one(id(new PhabricatorRepository())->establishConnection('r'), 'SELECT * FROM %T WHERE fullCommitName = %s', PhabricatorRepository::TABLE_BADCOMMIT, 'r' . $callsign . $commit->getCommitIdentifier()); } $show_changesets = false; if ($bad_commit) { $content[] = $this->renderStatusMessage(pht('Bad Commit'), $bad_commit['description']); } else { if ($is_foreign) { // Don't render anything else. } else { if (!$commit->isImported()) { $content[] = $this->renderStatusMessage(pht('Still Importing...'), pht('This commit is still importing. Changes will be visible once ' . 'the import finishes.')); } else { if (!count($changes)) { $content[] = $this->renderStatusMessage(pht('Empty Commit'), pht('This commit is empty and does not affect any paths.')); } else { if ($was_limited) { $content[] = $this->renderStatusMessage(pht('Enormous Commit'), pht('This commit is enormous, and affects more than %d files. ' . 'Changes are not shown.', $hard_limit)); } else { $show_changesets = true; // The user has clicked "Show All Changes", and we should show all the // changes inline even if there are more than the soft limit. $show_all_details = $request->getBool('show_all'); $change_panel = new PHUIObjectBoxView(); $header = new PHUIHeaderView(); $header->setHeader(pht('Changes (%s)', new PhutilNumber($count))); $change_panel->setID('toc'); if ($count > self::CHANGES_LIMIT && !$show_all_details) { $icon = id(new PHUIIconView())->setIconFont('fa-files-o'); $button = id(new PHUIButtonView())->setText(pht('Show All Changes'))->setHref('?show_all=true')->setTag('a')->setIcon($icon); $warning_view = id(new PHUIInfoView())->setSeverity(PHUIInfoView::SEVERITY_WARNING)->setTitle(pht('Very Large Commit'))->appendChild(pht('This commit is very large. Load each file individually.')); $change_panel->setInfoView($warning_view); $header->addActionLink($button); } $changesets = DiffusionPathChange::convertToDifferentialChangesets($user, $changes); // TODO: This table and panel shouldn't really be separate, but we need // to clean up the "Load All Files" interaction first. $change_table = $this->buildTableOfContents($changesets); $change_panel->setTable($change_table); $change_panel->setHeader($header); $content[] = $change_panel; $vcs = $repository->getVersionControlSystem(); switch ($vcs) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $vcs_supports_directory_changes = true; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $vcs_supports_directory_changes = false; break; default: throw new Exception(pht('Unknown VCS.')); } $references = array(); foreach ($changesets as $key => $changeset) { $file_type = $changeset->getFileType(); if ($file_type == DifferentialChangeType::FILE_DIRECTORY) { if (!$vcs_supports_directory_changes) { unset($changesets[$key]); continue; } } $references[$key] = $drequest->generateURI(array('action' => 'rendering-ref', 'path' => $changeset->getFilename())); } // TODO: Some parts of the views still rely on properties of the // DifferentialChangeset. Make the objects ephemeral to make sure we don't // accidentally save them, and then set their ID to the appropriate ID for // this application (the path IDs). $path_ids = array_flip(mpull($changes, 'getPath')); foreach ($changesets as $changeset) { $changeset->makeEphemeral(); $changeset->setID($path_ids[$changeset->getFilename()]); } if ($count <= self::CHANGES_LIMIT || $show_all_details) { $visible_changesets = $changesets; } else { $visible_changesets = array(); $inlines = PhabricatorAuditInlineComment::loadDraftAndPublishedComments($user, $commit->getPHID()); $path_ids = mpull($inlines, null, 'getPathID'); foreach ($changesets as $key => $changeset) { if (array_key_exists($changeset->getID(), $path_ids)) { $visible_changesets[$key] = $changeset; } } } $change_list_title = DiffusionView::nameCommit($repository, $commit->getCommitIdentifier()); $change_list = new DifferentialChangesetListView(); $change_list->setTitle($change_list_title); $change_list->setChangesets($changesets); $change_list->setVisibleChangesets($visible_changesets); $change_list->setRenderingReferences($references); $change_list->setRenderURI('/diffusion/' . $callsign . '/diff/'); $change_list->setRepository($repository); $change_list->setUser($user); // TODO: Try to setBranch() to something reasonable here? $change_list->setStandaloneURI('/diffusion/' . $callsign . '/diff/'); $change_list->setRawFileURIs(null, '/diffusion/' . $callsign . '/diff/?view=r'); $change_list->setInlineCommentControllerURI('/diffusion/inline/edit/' . phutil_escape_uri($commit->getPHID()) . '/'); $content[] = $change_list->render(); } } } } } $content[] = $this->renderAddCommentPanel($commit, $audit_requests); $commit_id = 'r' . $callsign . $commit->getCommitIdentifier(); $short_name = DiffusionView::nameCommit($repository, $commit->getCommitIdentifier()); $prefs = $user->loadPreferences(); $pref_filetree = PhabricatorUserPreferences::PREFERENCE_DIFF_FILETREE; $pref_collapse = PhabricatorUserPreferences::PREFERENCE_NAV_COLLAPSED; $show_filetree = $prefs->getPreference($pref_filetree); $collapsed = $prefs->getPreference($pref_collapse); if ($show_changesets && $show_filetree) { $nav = id(new DifferentialChangesetFileTreeSideNavBuilder())->setTitle($short_name)->setBaseURI(new PhutilURI('/' . $commit_id))->build($changesets)->setCrumbs($crumbs)->setCollapsed((bool) $collapsed)->appendChild($content); $content = $nav; } else { $content = array($crumbs, $content); } return $this->buildApplicationPage($content, array('title' => $commit_id, 'pageObjects' => array($commit->getPHID()))); }
/** * Returns the current value of a named counter. * * @param AphrontDatabaseConnection Database where the counter resides. * @param string Counter name to read. * @return int|null Current value, or `null` if the counter does not exist. * * @task util */ public static function loadCurrentCounterValue(AphrontDatabaseConnection $conn_r, $counter_name) { $row = queryfx_one($conn_r, 'SELECT counterValue FROM %T WHERE counterName = %s', self::COUNTER_TABLE_NAME, $counter_name); if (!$row) { return null; } return (int) $row['counterValue']; }
protected function isBadCommit($full_commit_name) { $repository = new PhabricatorRepository(); $bad_commit = queryfx_one($repository->establishConnection('w'), 'SELECT * FROM %T WHERE fullCommitName = %s', PhabricatorRepository::TABLE_BADCOMMIT, $full_commit_name); return (bool) $bad_commit; }