diff --git a/resources/sql/autopatches/20140211.dx.2.migcommenttext.php b/resources/sql/autopatches/20140211.dx.2.migcommenttext.php index 438e85b58..8a76690ec 100644 --- a/resources/sql/autopatches/20140211.dx.2.migcommenttext.php +++ b/resources/sql/autopatches/20140211.dx.2.migcommenttext.php @@ -1,71 +1,71 @@ establishConnection('w'); $rows = new LiskRawMigrationIterator($conn_w, 'differential_comment'); $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(); echo "Migrating Differential comment text to modern storage...\n"; foreach ($rows as $row) { $id = $row['id']; echo "Migrating Differential comment {$id}...\n"; if (!strlen($row['content'])) { echo "Comment has no text, continuing.\n"; continue; } $revision = id(new DifferentialRevision())->load($row['revisionID']); if (!$revision) { echo "Comment has no valid revision, continuing.\n"; continue; } $revision_phid = $revision->getPHID(); $dst_table = 'differential_inline_comment'; $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - DifferentialPHIDTypeRevision::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST); $comment_phid = PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_XCMT, - DifferentialPHIDTypeRevision::TYPECONST); + DifferentialRevisionPHIDType::TYPECONST); queryfx( $conn_w, 'INSERT IGNORE INTO %T (phid, transactionPHID, authorPHID, viewPolicy, editPolicy, commentVersion, content, contentSource, isDeleted, dateCreated, dateModified, revisionPHID, changesetID, legacyCommentID) VALUES (%s, %s, %s, %s, %s, %d, %s, %s, %d, %d, %d, %s, %nd, %d)', 'differential_transaction_comment', // phid, transactionPHID, authorPHID, viewPolicy, editPolicy $comment_phid, $xaction_phid, $row['authorPHID'], 'public', $row['authorPHID'], // commentVersion, content, contentSource, isDeleted 1, $row['content'], $content_source, 0, // dateCreated, dateModified, revisionPHID, changesetID, legacyCommentID $row['dateCreated'], $row['dateModified'], $revision_phid, null, $row['id']); } echo "Done.\n"; diff --git a/resources/sql/autopatches/20140212.dx.1.armageddon.php b/resources/sql/autopatches/20140212.dx.1.armageddon.php index db2fb1de7..1da7f6703 100644 --- a/resources/sql/autopatches/20140212.dx.1.armageddon.php +++ b/resources/sql/autopatches/20140212.dx.1.armageddon.php @@ -1,222 +1,222 @@ establishConnection('w'); $rows = new LiskRawMigrationIterator($conn_w, 'differential_comment'); $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(); echo "Migrating Differential comments to modern storage...\n"; foreach ($rows as $row) { $id = $row['id']; echo "Migrating comment {$id}...\n"; $revision = id(new DifferentialRevision())->load($row['revisionID']); if (!$revision) { echo "No revision, continuing.\n"; continue; } $revision_phid = $revision->getPHID(); $comments = queryfx_all( $conn_w, 'SELECT * FROM %T WHERE legacyCommentID = %d', 'differential_transaction_comment', $id); $main_comments = array(); $inline_comments = array(); foreach ($comments as $comment) { if ($comment['changesetID']) { $inline_comments[] = $comment; } else { $main_comments[] = $comment; } } $metadata = json_decode($row['metadata'], true); if (!is_array($metadata)) { $metadata = array(); } $key_cc = 'added-ccs'; $key_add_rev = 'added-reviewers'; $key_rem_rev = 'removed-reviewers'; $key_diff_id = 'diff-id'; $xactions = array(); // Build the main action transaction. switch ($row['action']) { case DifferentialAction::ACTION_COMMENT: case DifferentialAction::ACTION_ADDREVIEWERS: case DifferentialAction::ACTION_ADDCCS: case DifferentialAction::ACTION_UPDATE: case DifferentialTransaction::TYPE_INLINE: // These actions will have their transactions created by other rules. break; default: // Otherwise, this is a normal action (like an accept or reject). $xactions[] = array( 'type' => DifferentialTransaction::TYPE_ACTION, 'old' => null, 'new' => $row['action'], ); break; } // Build the diff update transaction, if one exists. $diff_id = idx($metadata, $key_diff_id); if (!is_scalar($diff_id)) { $diff_id = null; } if ($diff_id || $row['action'] == DifferentialAction::ACTION_UPDATE) { $xactions[] = array( 'type' => DifferentialTransaction::TYPE_UPDATE, 'old' => null, 'new' => $diff_id, ); } // Build the add/remove reviewers transaction, if one exists. $add_rev = idx($metadata, $key_add_rev, array()); if (!is_array($add_rev)) { $add_rev = array(); } $rem_rev = idx($metadata, $key_rem_rev, array()); if (!is_array($rem_rev)) { $rem_rev = array(); } if ($add_rev || $rem_rev) { $old = array(); foreach ($rem_rev as $phid) { if (!is_scalar($phid)) { continue; } $old[$phid] = array( 'src' => $revision_phid, 'type' => PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER, 'dst' => $phid, ); } $new = array(); foreach ($add_rev as $phid) { if (!is_scalar($phid)) { continue; } $new[$phid] = array( 'src' => $revision_phid, 'type' => PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER, 'dst' => $phid, ); } $xactions[] = array( 'type' => PhabricatorTransactions::TYPE_EDGE, 'old' => $old, 'new' => $new, 'meta' => array( 'edge:type' => PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER, ), ); } // Build the CC transaction, if one exists. $add_cc = idx($metadata, $key_cc, array()); if (!is_array($add_cc)) { $add_cc = array(); } if ($add_cc) { $xactions[] = array( 'type' => PhabricatorTransactions::TYPE_SUBSCRIBERS, 'old' => array(), 'new' => array_fuse($add_cc), ); } // Build the main comment transaction. foreach ($main_comments as $main) { $xactions[] = array( 'type' => PhabricatorTransactions::TYPE_COMMENT, 'old' => null, 'new' => null, 'phid' => $main['transactionPHID'], 'comment' => $main, ); } // Build inline comment transactions. foreach ($inline_comments as $inline) { $xactions[] = array( 'type' => DifferentialTransaction::TYPE_INLINE, 'old' => null, 'new' => null, 'phid' => $inline['transactionPHID'], 'comment' => $inline, ); } foreach ($xactions as $xaction) { // Generate a new PHID, if we don't already have one from the comment // table. We pregenerated into the comment table to make this a little // easier, so we only need to write to one table. $xaction_phid = idx($xaction, 'phid'); if (!$xaction_phid) { $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - DifferentialPHIDTypeRevision::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST); } unset($xaction['phid']); $comment_phid = null; $comment_version = 0; if (idx($xaction, 'comment')) { $comment_phid = $xaction['comment']['phid']; $comment_version = 1; } $old = idx($xaction, 'old'); $new = idx($xaction, 'new'); $meta = idx($xaction, 'meta', array()); queryfx( $conn_w, 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, commentPHID, commentVersion, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %ns, %d, %s, %ns, %ns, %s, %s, %d, %d)', 'differential_transaction', // PHID, authorPHID, objectPHID $xaction_phid, (string)$row['authorPHID'], $revision_phid, // viewPolicy, editPolicy, commentPHID, commentVersion 'public', (string)$row['authorPHID'], $comment_phid, $comment_version, // transactionType, oldValue, newValue, contentSource, metadata $xaction['type'], json_encode($old), json_encode($new), $content_source, json_encode($meta), // dates $row['dateCreated'], $row['dateModified']); } } echo "Done.\n"; diff --git a/resources/sql/patches/20130715.votecomments.php b/resources/sql/patches/20130715.votecomments.php index c4a30fa27..c60b13bb3 100644 --- a/resources/sql/patches/20130715.votecomments.php +++ b/resources/sql/patches/20130715.votecomments.php @@ -1,101 +1,101 @@ establishConnection('w'); $comments = new LiskRawMigrationIterator($conn_w, 'slowvote_comment'); $conn_w->openTransaction(); foreach ($comments as $comment) { $id = $comment['id']; $poll_id = $comment['pollID']; $author_phid = $comment['authorPHID']; $text = $comment['commentText']; $date_created = $comment['dateCreated']; $date_modified = $comment['dateModified']; echo "Migrating comment {$id}.\n"; $poll = id(new PhabricatorSlowvoteQuery()) ->setViewer($viewer) ->withIDs(array($poll_id)) ->executeOne(); if (!$poll) { echo "No poll.\n"; continue; } $user = id(new PhabricatorPeopleQuery()) ->setViewer($viewer) ->withPHIDs(array($author_phid)) ->executeOne(); if (!$user) { echo "No user.\n"; continue; } $comment_phid = PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_XCMT); $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - PhabricatorSlowvotePHIDTypePoll::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + PhabricatorSlowvotePollPHIDType::TYPECONST); $source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(); queryfx( $conn_w, 'INSERT INTO %T (phid, transactionPHID, authorPHID, viewPolicy, editPolicy, commentVersion, content, contentSource, isDeleted, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %d, %s, %s, %d, %d, %d)', $table_comment->getTableName(), $comment_phid, $xaction_phid, $user->getPHID(), PhabricatorPolicies::POLICY_PUBLIC, $user->getPHID(), 1, $text, $source, 0, $date_created, $date_modified); queryfx( $conn_w, 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, commentPHID, commentVersion, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %s, %d, %s, %s, %s, %s, %s, %d, %d)', $table_xaction->getTableName(), $xaction_phid, $user->getPHID(), $poll->getPHID(), PhabricatorPolicies::POLICY_PUBLIC, $user->getPHID(), $comment_phid, 1, PhabricatorTransactions::TYPE_COMMENT, null, null, $source, '{}', $date_created, $date_modified); } $conn_w->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/20130728.ponderxcomment.php b/resources/sql/patches/20130728.ponderxcomment.php index ebced3865..1fb65ade7 100644 --- a/resources/sql/patches/20130728.ponderxcomment.php +++ b/resources/sql/patches/20130728.ponderxcomment.php @@ -1,86 +1,86 @@ establishConnection('w'); $conn_w->openTransaction(); echo "Migrating Ponder comments to ApplicationTransactions...\n"; $rows = new LiskRawMigrationIterator($conn_w, 'ponder_comment'); foreach ($rows as $row) { $id = $row['id']; echo "Migrating {$id}...\n"; $type = phid_get_type($row['targetPHID']); switch ($type) { - case PonderPHIDTypeQuestion::TYPECONST: + case PonderQuestionPHIDType::TYPECONST: $table_obj = $qtable; $comment_obj = new PonderQuestionTransactionComment(); break; - case PonderPHIDTypeAnswer::TYPECONST: + case PonderAnswerPHIDType::TYPECONST: $table_obj = $atable; $comment_obj = new PonderAnswerTransactionComment(); break; } $comment_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, $type); $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, $type); queryfx( $conn_w, 'INSERT INTO %T (phid, transactionPHID, authorPHID, viewPolicy, editPolicy, commentVersion, content, contentSource, isDeleted, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %d, %s, %s, %d, %d, %d)', $comment_obj->getTableName(), $comment_phid, $xaction_phid, $row['authorPHID'], 'public', $row['authorPHID'], 1, $row['content'], PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(), 0, $row['dateCreated'], $row['dateModified']); queryfx( $conn_w, 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, commentPHID, commentVersion, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %s, %d, %s, %ns, %ns, %s, %s, %d, %d)', $table_obj->getTableName(), $xaction_phid, $row['authorPHID'], $row['targetPHID'], 'public', $row['authorPHID'], $comment_phid, 1, PhabricatorTransactions::TYPE_COMMENT, 'null', 'null', PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(), '[]', $row['dateCreated'], $row['dateModified']); } $conn_w->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/20130801.pastexactions.php b/resources/sql/patches/20130801.pastexactions.php index 1f48d9978..52d5a081d 100644 --- a/resources/sql/patches/20130801.pastexactions.php +++ b/resources/sql/patches/20130801.pastexactions.php @@ -1,48 +1,48 @@ establishConnection('w'); $conn_w->openTransaction(); echo "Adding transactions for existing paste objects...\n"; $rows = new LiskRawMigrationIterator($conn_w, 'pastebin_paste'); foreach ($rows as $row) { $id = $row['id']; echo "Adding transactions for paste id {$id}...\n"; $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST); queryfx( $conn_w, 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified, commentVersion) VALUES (%s, %s, %s, %s, %s, %s, %ns, %ns, %s, %s, %d, %d, %d)', $x_table->getTableName(), $xaction_phid, $row['authorPHID'], $row['phid'], 'public', $row['authorPHID'], PhabricatorPasteTransaction::TYPE_CONTENT, 'null', $row['filePHID'], PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(), '[]', $row['dateCreated'], $row['dateCreated'], 0); } $conn_w->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/20130802.heraldphids.php b/resources/sql/patches/20130802.heraldphids.php index 52f9de272..814bbddef 100644 --- a/resources/sql/patches/20130802.heraldphids.php +++ b/resources/sql/patches/20130802.heraldphids.php @@ -1,24 +1,24 @@ establishConnection('w'); echo "Assigning PHIDs to Herald Rules...\n"; foreach (new LiskMigrationIterator(new HeraldRule()) as $rule) { $id = $rule->getID(); echo "Rule {$id}.\n"; if ($rule->getPHID()) { continue; } queryfx( $conn_w, 'UPDATE %T SET phid = %s WHERE id = %d', $table->getTableName(), - PhabricatorPHID::generateNewPHID(HeraldPHIDTypeRule::TYPECONST), + PhabricatorPHID::generateNewPHID(HeraldRulePHIDType::TYPECONST), $rule->getID()); } echo "Done.\n"; diff --git a/resources/sql/patches/20130921.xmigratemaniphest.php b/resources/sql/patches/20130921.xmigratemaniphest.php index d2a306766..24614867f 100644 --- a/resources/sql/patches/20130921.xmigratemaniphest.php +++ b/resources/sql/patches/20130921.xmigratemaniphest.php @@ -1,148 +1,148 @@ establishConnection('w'); $rows = new LiskRawMigrationIterator($conn_w, 'maniphest_transaction'); $conn_w->openTransaction(); // NOTE: These were the correct table names at the time of this patch. $xaction_table_name = 'maniphest_transactionpro'; $comment_table_name = 'maniphest_transaction_comment'; foreach ($rows as $row) { $row_id = $row['id']; $task_id = $row['taskID']; echo "Migrating row {$row_id} (T{$task_id})...\n"; $task_row = queryfx_one( $conn_w, 'SELECT phid FROM %T WHERE id = %d', $task_table->getTableName(), $task_id); if (!$task_row) { echo "Skipping, no such task.\n"; continue; } $task_phid = $task_row['phid']; $has_comment = strlen(trim($row['comments'])); $xaction_type = $row['transactionType']; $xaction_old = $row['oldValue']; $xaction_new = $row['newValue']; $xaction_source = idx($row, 'contentSource', ''); $xaction_meta = $row['metadata']; // Convert "aux" (auxiliary field) transactions to proper CustomField // transactions. The formats are very similar, except that the type constant // is different and the auxiliary key should be prefixed. if ($xaction_type == 'aux') { $xaction_meta = @json_decode($xaction_meta, true); $xaction_meta = nonempty($xaction_meta, array()); $xaction_type = PhabricatorTransactions::TYPE_CUSTOMFIELD; $aux_key = idx($xaction_meta, 'aux:key'); if (!preg_match('/^std:maniphest:/', $aux_key)) { $aux_key = 'std:maniphest:'.$aux_key; } $xaction_meta = array( 'customfield:key' => $aux_key, ); $xaction_meta = json_encode($xaction_meta); } // If this transaction did something other than just leaving a comment, // insert a new transaction for that action. If there was a comment (or // a comment in addition to an action) we'll insert that below. if ($row['transactionType'] != 'comment') { $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - ManiphestPHIDTypeTask::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + ManiphestTaskPHIDType::TYPECONST); queryfx( $conn_w, 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, commentPHID, commentVersion, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %s, %d, %s, %ns, %ns, %s, %s, %d, %d)', $xaction_table_name, $xaction_phid, $row['authorPHID'], $task_phid, 'public', $row['authorPHID'], null, 0, $xaction_type, $xaction_old, $xaction_new, $xaction_source, $xaction_meta, $row['dateCreated'], $row['dateModified']); } // Now, if the old transaction has a comment, we insert an explicit new // transaction for it. if ($has_comment) { $comment_phid = PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_XCMT, - ManiphestPHIDTypeTask::TYPECONST); + ManiphestTaskPHIDType::TYPECONST); $comment_version = 1; $comment_xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - ManiphestPHIDTypeTask::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + ManiphestTaskPHIDType::TYPECONST); // Insert the comment data. queryfx( $conn_w, 'INSERT INTO %T (phid, transactionPHID, authorPHID, viewPolicy, editPolicy, commentVersion, content, contentSource, isDeleted, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %d, %s, %s, %d, %d, %d)', $comment_table_name, $comment_phid, $comment_xaction_phid, $row['authorPHID'], 'public', $row['authorPHID'], $comment_version, $row['comments'], $xaction_source, 0, $row['dateCreated'], $row['dateModified']); queryfx( $conn_w, 'INSERT INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, commentPHID, commentVersion, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %s, %d, %s, %ns, %ns, %s, %s, %d, %d)', $xaction_table_name, $comment_xaction_phid, $row['authorPHID'], $task_phid, 'public', $row['authorPHID'], $comment_phid, $comment_version, PhabricatorTransactions::TYPE_COMMENT, $xaction_old, $xaction_new, $xaction_source, $xaction_meta, $row['dateCreated'], $row['dateModified']); } } $conn_w->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/20130926.dinline.php b/resources/sql/patches/20130926.dinline.php index 75d67efdb..36632d910 100644 --- a/resources/sql/patches/20130926.dinline.php +++ b/resources/sql/patches/20130926.dinline.php @@ -1,90 +1,90 @@ establishConnection('w'); $conn_w->openTransaction(); $src_table = 'differential_inlinecomment'; $dst_table = 'differential_transaction_comment'; echo "Migrating Differential inline comments to new format...\n"; $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(); $rows = new LiskRawMigrationIterator($conn_w, $src_table); foreach ($rows as $row) { $id = $row['id']; $revision_id = $row['revisionID']; echo "Migrating inline #{$id} (D{$revision_id})...\n"; $revision_row = queryfx_one( $conn_w, 'SELECT phid FROM %T WHERE id = %d', $revision_table->getTableName(), $revision_id); if (!$revision_row) { continue; } $revision_phid = $revision_row['phid']; if ($row['commentID']) { $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - DifferentialPHIDTypeRevision::TYPECONST); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST); } else { $xaction_phid = null; } $comment_phid = PhabricatorPHID::generateNewPHID( PhabricatorPHIDConstants::PHID_TYPE_XCMT, - DifferentialPHIDTypeRevision::TYPECONST); + DifferentialRevisionPHIDType::TYPECONST); queryfx( $conn_w, 'INSERT IGNORE INTO %T (id, phid, transactionPHID, authorPHID, viewPolicy, editPolicy, commentVersion, content, contentSource, isDeleted, dateCreated, dateModified, revisionPHID, changesetID, isNewFile, lineNumber, lineLength, hasReplies, legacyCommentID) VALUES (%d, %s, %ns, %s, %s, %s, %d, %s, %s, %d, %d, %d, %s, %nd, %d, %d, %d, %d, %nd)', $dst_table, // id, phid, transactionPHID, authorPHID, viewPolicy, editPolicy $row['id'], $comment_phid, $xaction_phid, $row['authorPHID'], 'public', $row['authorPHID'], // commentVersion, content, contentSource, isDeleted 1, $row['content'], $content_source, 0, // dateCreated, dateModified, revisionPHID, changesetID $row['dateCreated'], $row['dateModified'], $revision_phid, $row['changesetID'], // isNewFile, lineNumber, lineLength, hasReplies, legacyCommentID $row['isNewFile'], $row['lineNumber'], $row['lineLength'], 0, $row['commentID']); } $conn_w->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/20131020.pxactionmig.php b/resources/sql/patches/20131020.pxactionmig.php index 04cdf7997..a58c719da 100644 --- a/resources/sql/patches/20131020.pxactionmig.php +++ b/resources/sql/patches/20131020.pxactionmig.php @@ -1,92 +1,92 @@ establishConnection('w'); $conn_w->openTransaction(); $src_table = 'project_legacytransaction'; $dst_table = 'project_transaction'; echo "Migrating Project transactions to new format...\n"; $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array())->serialize(); $rows = new LiskRawMigrationIterator($conn_w, $src_table); foreach ($rows as $row) { $id = $row['id']; $project_id = $row['projectID']; echo "Migrating transaction #{$id} (Project {$project_id})...\n"; $project_row = queryfx_one( $conn_w, 'SELECT phid FROM %T WHERE id = %d', $project_table->getTableName(), $project_id); if (!$project_row) { continue; } $project_phid = $project_row['phid']; $type_map = array( 'name' => PhabricatorProjectTransaction::TYPE_NAME, 'members' => PhabricatorProjectTransaction::TYPE_MEMBERS, 'status' => PhabricatorProjectTransaction::TYPE_STATUS, 'canview' => PhabricatorTransactions::TYPE_VIEW_POLICY, 'canedit' => PhabricatorTransactions::TYPE_EDIT_POLICY, 'canjoin' => PhabricatorTransactions::TYPE_JOIN_POLICY, ); $new_type = idx($type_map, $row['transactionType']); if (!$new_type) { continue; } $xaction_phid = PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, PhabricatorProjectPHIDTypeProject::TYPECONST); queryfx( $conn_w, 'INSERT IGNORE INTO %T (phid, authorPHID, objectPHID, viewPolicy, editPolicy, commentPHID, commentVersion, transactionType, oldValue, newValue, contentSource, metadata, dateCreated, dateModified) VALUES (%s, %s, %s, %s, %s, %ns, %d, %s, %s, %s, %s, %s, %d, %d)', $dst_table, // PHID, Author, Object $xaction_phid, $row['authorPHID'], $project_phid, // View, Edit, Comment, Version, Type 'public', $row['authorPHID'], null, 0, $new_type, // Old, New, Source, Meta, $row['oldValue'], $row['newValue'], $content_source, '{}', // Created, Modified $row['dateCreated'], $row['dateModified']); } $conn_w->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/20131106.diffphid.2.mig.php b/resources/sql/patches/20131106.diffphid.2.mig.php index eee7e3047..b7f502f47 100644 --- a/resources/sql/patches/20131106.diffphid.2.mig.php +++ b/resources/sql/patches/20131106.diffphid.2.mig.php @@ -1,47 +1,47 @@ establishConnection('w'); $size = 1000; $row_iter = id(new LiskMigrationIterator($diff_table))->setPageSize($size); $chunk_iter = new PhutilChunkedIterator($row_iter, $size); foreach ($chunk_iter as $chunk) { $sql = array(); foreach ($chunk as $diff) { $id = $diff->getID(); echo "Migrating diff ID {$id}...\n"; $phid = $diff->getPHID(); if (strlen($phid)) { continue; } - $type_diff = DifferentialPHIDTypeDiff::TYPECONST; + $type_diff = DifferentialDiffPHIDType::TYPECONST; $new_phid = PhabricatorPHID::generateNewPHID($type_diff); $sql[] = qsprintf( $conn_w, '(%d, %s)', $id, $new_phid); } if (!$sql) { continue; } foreach (PhabricatorLiskDAO::chunkSQL($sql, ', ') as $sql_chunk) { queryfx( $conn_w, 'INSERT IGNORE INTO %T (id, phid) VALUES %Q ON DUPLICATE KEY UPDATE phid = VALUES(phid)', $diff_table->getTableName(), $sql_chunk); } } echo "Done.\n"; diff --git a/resources/sql/patches/migrate-differential-dependencies.php b/resources/sql/patches/migrate-differential-dependencies.php index ea2f9c691..c24cbc412 100644 --- a/resources/sql/patches/migrate-differential-dependencies.php +++ b/resources/sql/patches/migrate-differential-dependencies.php @@ -1,29 +1,29 @@ openTransaction(); foreach (new LiskMigrationIterator($table) as $rev) { $id = $rev->getID(); echo "Revision {$id}: "; - $deps = $rev->getAttachedPHIDs(DifferentialPHIDTypeRevision::TYPECONST); + $deps = $rev->getAttachedPHIDs(DifferentialRevisionPHIDType::TYPECONST); if (!$deps) { echo "-\n"; continue; } $editor = new PhabricatorEdgeEditor(); foreach ($deps as $dep) { $editor->addEdge( $rev->getPHID(), PhabricatorEdgeConfig::TYPE_DREV_DEPENDS_ON_DREV, $dep); } $editor->save(); echo "OKAY\n"; } $table->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/migrate-maniphest-dependencies.php b/resources/sql/patches/migrate-maniphest-dependencies.php index b72d52be8..72222c7c4 100644 --- a/resources/sql/patches/migrate-maniphest-dependencies.php +++ b/resources/sql/patches/migrate-maniphest-dependencies.php @@ -1,29 +1,29 @@ openTransaction(); foreach (new LiskMigrationIterator($table) as $task) { $id = $task->getID(); echo "Task {$id}: "; - $deps = $task->getAttachedPHIDs(ManiphestPHIDTypeTask::TYPECONST); + $deps = $task->getAttachedPHIDs(ManiphestTaskPHIDType::TYPECONST); if (!$deps) { echo "-\n"; continue; } $editor = new PhabricatorEdgeEditor(); foreach ($deps as $dep) { $editor->addEdge( $task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK, $dep); } $editor->save(); echo "OKAY\n"; } $table->saveTransaction(); echo "Done.\n"; diff --git a/resources/sql/patches/migrate-maniphest-revisions.php b/resources/sql/patches/migrate-maniphest-revisions.php index eeb9a7f4e..0658cfda6 100644 --- a/resources/sql/patches/migrate-maniphest-revisions.php +++ b/resources/sql/patches/migrate-maniphest-revisions.php @@ -1,28 +1,28 @@ establishConnection('w'); foreach (new LiskMigrationIterator($table) as $task) { $id = $task->getID(); echo "Task {$id}: "; - $revs = $task->getAttachedPHIDs(DifferentialPHIDTypeRevision::TYPECONST); + $revs = $task->getAttachedPHIDs(DifferentialRevisionPHIDType::TYPECONST); if (!$revs) { echo "-\n"; continue; } $editor = new PhabricatorEdgeEditor(); foreach ($revs as $rev) { $editor->addEdge( $task->getPHID(), ManiphestTaskHasRevisionEdgeType::EDGECONST, $rev); } $editor->save(); echo "OKAY\n"; } echo "Done.\n"; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 2f753ed5c..ddd81c949 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,5682 +1,5682 @@ 2, 'class' => array( 'Aphront304Response' => 'aphront/response/Aphront304Response.php', 'Aphront400Response' => 'aphront/response/Aphront400Response.php', 'Aphront403Response' => 'aphront/response/Aphront403Response.php', 'Aphront404Response' => 'aphront/response/Aphront404Response.php', 'AphrontAbstractAttachedFileView' => 'view/control/AphrontAbstractAttachedFileView.php', 'AphrontAjaxResponse' => 'aphront/response/AphrontAjaxResponse.php', 'AphrontApplicationConfiguration' => 'aphront/configuration/AphrontApplicationConfiguration.php', 'AphrontBarView' => 'view/widget/bars/AphrontBarView.php', 'AphrontCSRFException' => 'aphront/exception/AphrontCSRFException.php', 'AphrontCalendarEventView' => 'applications/calendar/view/AphrontCalendarEventView.php', 'AphrontContextBarView' => 'view/layout/AphrontContextBarView.php', 'AphrontController' => 'aphront/AphrontController.php', 'AphrontCursorPagerView' => 'view/control/AphrontCursorPagerView.php', 'AphrontDefaultApplicationConfiguration' => 'aphront/configuration/AphrontDefaultApplicationConfiguration.php', 'AphrontDialogResponse' => 'aphront/response/AphrontDialogResponse.php', 'AphrontDialogView' => 'view/AphrontDialogView.php', 'AphrontErrorView' => 'view/form/AphrontErrorView.php', 'AphrontException' => 'aphront/exception/AphrontException.php', 'AphrontFileResponse' => 'aphront/response/AphrontFileResponse.php', 'AphrontFormCheckboxControl' => 'view/form/control/AphrontFormCheckboxControl.php', 'AphrontFormChooseButtonControl' => 'view/form/control/AphrontFormChooseButtonControl.php', 'AphrontFormControl' => 'view/form/control/AphrontFormControl.php', 'AphrontFormCropControl' => 'view/form/control/AphrontFormCropControl.php', 'AphrontFormDateControl' => 'view/form/control/AphrontFormDateControl.php', 'AphrontFormDividerControl' => 'view/form/control/AphrontFormDividerControl.php', 'AphrontFormFileControl' => 'view/form/control/AphrontFormFileControl.php', 'AphrontFormImageControl' => 'view/form/control/AphrontFormImageControl.php', 'AphrontFormInsetView' => 'view/form/AphrontFormInsetView.php', 'AphrontFormMarkupControl' => 'view/form/control/AphrontFormMarkupControl.php', 'AphrontFormPasswordControl' => 'view/form/control/AphrontFormPasswordControl.php', 'AphrontFormPolicyControl' => 'view/form/control/AphrontFormPolicyControl.php', 'AphrontFormRadioButtonControl' => 'view/form/control/AphrontFormRadioButtonControl.php', 'AphrontFormRecaptchaControl' => 'view/form/control/AphrontFormRecaptchaControl.php', 'AphrontFormSectionControl' => 'view/form/control/AphrontFormSectionControl.php', 'AphrontFormSelectControl' => 'view/form/control/AphrontFormSelectControl.php', 'AphrontFormStaticControl' => 'view/form/control/AphrontFormStaticControl.php', 'AphrontFormSubmitControl' => 'view/form/control/AphrontFormSubmitControl.php', 'AphrontFormTextAreaControl' => 'view/form/control/AphrontFormTextAreaControl.php', 'AphrontFormTextControl' => 'view/form/control/AphrontFormTextControl.php', 'AphrontFormTextWithSubmitControl' => 'view/form/control/AphrontFormTextWithSubmitControl.php', 'AphrontFormToggleButtonsControl' => 'view/form/control/AphrontFormToggleButtonsControl.php', 'AphrontFormTokenizerControl' => 'view/form/control/AphrontFormTokenizerControl.php', 'AphrontFormTypeaheadControl' => 'view/form/control/AphrontFormTypeaheadControl.php', 'AphrontFormView' => 'view/form/AphrontFormView.php', 'AphrontGlyphBarView' => 'view/widget/bars/AphrontGlyphBarView.php', 'AphrontHTMLResponse' => 'aphront/response/AphrontHTMLResponse.php', 'AphrontHTTPSink' => 'aphront/sink/AphrontHTTPSink.php', 'AphrontHTTPSinkTestCase' => 'aphront/sink/__tests__/AphrontHTTPSinkTestCase.php', 'AphrontIsolatedDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontIsolatedDatabaseConnectionTestCase.php', 'AphrontIsolatedHTTPSink' => 'aphront/sink/AphrontIsolatedHTTPSink.php', 'AphrontJSONResponse' => 'aphront/response/AphrontJSONResponse.php', 'AphrontJavelinView' => 'view/AphrontJavelinView.php', 'AphrontKeyboardShortcutsAvailableView' => 'view/widget/AphrontKeyboardShortcutsAvailableView.php', 'AphrontListFilterView' => 'view/layout/AphrontListFilterView.php', 'AphrontMiniPanelView' => 'view/layout/AphrontMiniPanelView.php', 'AphrontMoreView' => 'view/layout/AphrontMoreView.php', 'AphrontMultiColumnView' => 'view/layout/AphrontMultiColumnView.php', 'AphrontMySQLDatabaseConnectionTestCase' => 'infrastructure/storage/__tests__/AphrontMySQLDatabaseConnectionTestCase.php', 'AphrontNullView' => 'view/AphrontNullView.php', 'AphrontPHPHTTPSink' => 'aphront/sink/AphrontPHPHTTPSink.php', 'AphrontPageView' => 'view/page/AphrontPageView.php', 'AphrontPagerView' => 'view/control/AphrontPagerView.php', 'AphrontPanelView' => 'view/layout/AphrontPanelView.php', 'AphrontPlainTextResponse' => 'aphront/response/AphrontPlainTextResponse.php', 'AphrontProgressBarView' => 'view/widget/bars/AphrontProgressBarView.php', 'AphrontProxyResponse' => 'aphront/response/AphrontProxyResponse.php', 'AphrontRedirectResponse' => 'aphront/response/AphrontRedirectResponse.php', 'AphrontReloadResponse' => 'aphront/response/AphrontReloadResponse.php', 'AphrontRequest' => 'aphront/AphrontRequest.php', 'AphrontRequestFailureView' => 'view/page/AphrontRequestFailureView.php', 'AphrontRequestTestCase' => 'aphront/__tests__/AphrontRequestTestCase.php', 'AphrontResponse' => 'aphront/response/AphrontResponse.php', 'AphrontSideNavFilterView' => 'view/layout/AphrontSideNavFilterView.php', 'AphrontStackTraceView' => 'view/widget/AphrontStackTraceView.php', 'AphrontTableView' => 'view/control/AphrontTableView.php', 'AphrontTagView' => 'view/AphrontTagView.php', 'AphrontTokenizerTemplateView' => 'view/control/AphrontTokenizerTemplateView.php', 'AphrontTwoColumnView' => 'view/layout/AphrontTwoColumnView.php', 'AphrontTypeaheadTemplateView' => 'view/control/AphrontTypeaheadTemplateView.php', 'AphrontURIMapper' => 'aphront/AphrontURIMapper.php', 'AphrontUsageException' => 'aphront/exception/AphrontUsageException.php', 'AphrontView' => 'view/AphrontView.php', 'AphrontWebpageResponse' => 'aphront/response/AphrontWebpageResponse.php', 'AuditActionMenuEventListener' => 'applications/audit/events/AuditActionMenuEventListener.php', 'CalendarColors' => 'applications/calendar/constants/CalendarColors.php', 'CalendarConstants' => 'applications/calendar/constants/CalendarConstants.php', 'CalendarTimeUtil' => 'applications/calendar/util/CalendarTimeUtil.php', 'CalendarTimeUtilTestCase' => 'applications/calendar/__tests__/CalendarTimeUtilTestCase.php', 'CelerityAPI' => 'infrastructure/celerity/CelerityAPI.php', 'CelerityManagementMapWorkflow' => 'infrastructure/celerity/management/CelerityManagementMapWorkflow.php', 'CelerityManagementWorkflow' => 'infrastructure/celerity/management/CelerityManagementWorkflow.php', 'CelerityPhabricatorResourceController' => 'infrastructure/celerity/CelerityPhabricatorResourceController.php', 'CelerityPhabricatorResources' => 'infrastructure/celerity/resources/CelerityPhabricatorResources.php', 'CelerityPhysicalResources' => 'infrastructure/celerity/resources/CelerityPhysicalResources.php', 'CelerityResourceController' => 'infrastructure/celerity/CelerityResourceController.php', 'CelerityResourceGraph' => 'infrastructure/celerity/CelerityResourceGraph.php', 'CelerityResourceMap' => 'infrastructure/celerity/CelerityResourceMap.php', 'CelerityResourceTransformer' => 'infrastructure/celerity/CelerityResourceTransformer.php', 'CelerityResourceTransformerTestCase' => 'infrastructure/celerity/__tests__/CelerityResourceTransformerTestCase.php', 'CelerityResources' => 'infrastructure/celerity/resources/CelerityResources.php', 'CelerityResourcesOnDisk' => 'infrastructure/celerity/resources/CelerityResourcesOnDisk.php', 'CeleritySpriteGenerator' => 'infrastructure/celerity/CeleritySpriteGenerator.php', 'CelerityStaticResourceResponse' => 'infrastructure/celerity/CelerityStaticResourceResponse.php', 'ConduitAPIMethod' => 'applications/conduit/method/ConduitAPIMethod.php', 'ConduitAPIRequest' => 'applications/conduit/protocol/ConduitAPIRequest.php', 'ConduitAPIResponse' => 'applications/conduit/protocol/ConduitAPIResponse.php', 'ConduitAPI_arcanist_Method' => 'applications/arcanist/conduit/ConduitAPI_arcanist_Method.php', 'ConduitAPI_arcanist_projectinfo_Method' => 'applications/arcanist/conduit/ConduitAPI_arcanist_projectinfo_Method.php', 'ConduitAPI_audit_Method' => 'applications/audit/conduit/ConduitAPI_audit_Method.php', 'ConduitAPI_audit_query_Method' => 'applications/audit/conduit/ConduitAPI_audit_query_Method.php', 'ConduitAPI_chatlog_Method' => 'applications/chatlog/conduit/ConduitAPI_chatlog_Method.php', 'ConduitAPI_chatlog_query_Method' => 'applications/chatlog/conduit/ConduitAPI_chatlog_query_Method.php', 'ConduitAPI_chatlog_record_Method' => 'applications/chatlog/conduit/ConduitAPI_chatlog_record_Method.php', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/ConduitAPI_conduit_connect_Method.php', 'ConduitAPI_conduit_getcertificate_Method' => 'applications/conduit/method/ConduitAPI_conduit_getcertificate_Method.php', 'ConduitAPI_conduit_ping_Method' => 'applications/conduit/method/ConduitAPI_conduit_ping_Method.php', 'ConduitAPI_conduit_query_Method' => 'applications/conduit/method/ConduitAPI_conduit_query_Method.php', 'ConduitAPI_conpherence_Method' => 'applications/conpherence/conduit/ConduitAPI_conpherence_Method.php', 'ConduitAPI_conpherence_createthread_Method' => 'applications/conpherence/conduit/ConduitAPI_conpherence_createthread_Method.php', 'ConduitAPI_conpherence_querythread_Method' => 'applications/conpherence/conduit/ConduitAPI_conpherence_querythread_Method.php', 'ConduitAPI_conpherence_querytransaction_Method' => 'applications/conpherence/conduit/ConduitAPI_conpherence_querytransaction_Method.php', 'ConduitAPI_conpherence_updatethread_Method' => 'applications/conpherence/conduit/ConduitAPI_conpherence_updatethread_Method.php', 'ConduitAPI_differential_Method' => 'applications/differential/conduit/ConduitAPI_differential_Method.php', 'ConduitAPI_differential_close_Method' => 'applications/differential/conduit/ConduitAPI_differential_close_Method.php', 'ConduitAPI_differential_createcomment_Method' => 'applications/differential/conduit/ConduitAPI_differential_createcomment_Method.php', 'ConduitAPI_differential_creatediff_Method' => 'applications/differential/conduit/ConduitAPI_differential_creatediff_Method.php', 'ConduitAPI_differential_createinline_Method' => 'applications/differential/conduit/ConduitAPI_differential_createinline_Method.php', 'ConduitAPI_differential_createrawdiff_Method' => 'applications/differential/conduit/ConduitAPI_differential_createrawdiff_Method.php', 'ConduitAPI_differential_createrevision_Method' => 'applications/differential/conduit/ConduitAPI_differential_createrevision_Method.php', 'ConduitAPI_differential_find_Method' => 'applications/differential/conduit/ConduitAPI_differential_find_Method.php', 'ConduitAPI_differential_finishpostponedlinters_Method' => 'applications/differential/conduit/ConduitAPI_differential_finishpostponedlinters_Method.php', 'ConduitAPI_differential_getalldiffs_Method' => 'applications/differential/conduit/ConduitAPI_differential_getalldiffs_Method.php', 'ConduitAPI_differential_getcommitmessage_Method' => 'applications/differential/conduit/ConduitAPI_differential_getcommitmessage_Method.php', 'ConduitAPI_differential_getcommitpaths_Method' => 'applications/differential/conduit/ConduitAPI_differential_getcommitpaths_Method.php', 'ConduitAPI_differential_getdiff_Method' => 'applications/differential/conduit/ConduitAPI_differential_getdiff_Method.php', 'ConduitAPI_differential_getrawdiff_Method' => 'applications/differential/conduit/ConduitAPI_differential_getrawdiff_Method.php', 'ConduitAPI_differential_getrevision_Method' => 'applications/differential/conduit/ConduitAPI_differential_getrevision_Method.php', 'ConduitAPI_differential_getrevisioncomments_Method' => 'applications/differential/conduit/ConduitAPI_differential_getrevisioncomments_Method.php', 'ConduitAPI_differential_parsecommitmessage_Method' => 'applications/differential/conduit/ConduitAPI_differential_parsecommitmessage_Method.php', 'ConduitAPI_differential_query_Method' => 'applications/differential/conduit/ConduitAPI_differential_query_Method.php', 'ConduitAPI_differential_querydiffs_Method' => 'applications/differential/conduit/ConduitAPI_differential_querydiffs_Method.php', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/differential/conduit/ConduitAPI_differential_setdiffproperty_Method.php', 'ConduitAPI_differential_updaterevision_Method' => 'applications/differential/conduit/ConduitAPI_differential_updaterevision_Method.php', 'ConduitAPI_differential_updateunitresults_Method' => 'applications/differential/conduit/ConduitAPI_differential_updateunitresults_Method.php', 'ConduitAPI_diffusion_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_Method.php', 'ConduitAPI_diffusion_abstractquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_abstractquery_Method.php', 'ConduitAPI_diffusion_branchquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_branchquery_Method.php', 'ConduitAPI_diffusion_browsequery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_browsequery_Method.php', 'ConduitAPI_diffusion_commitparentsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_commitparentsquery_Method.php', 'ConduitAPI_diffusion_createcomment_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_createcomment_Method.php', 'ConduitAPI_diffusion_diffquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_diffquery_Method.php', 'ConduitAPI_diffusion_existsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_existsquery_Method.php', 'ConduitAPI_diffusion_filecontentquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_filecontentquery_Method.php', 'ConduitAPI_diffusion_findsymbols_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_findsymbols_Method.php', 'ConduitAPI_diffusion_getcommits_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getcommits_Method.php', 'ConduitAPI_diffusion_getlintmessages_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getlintmessages_Method.php', 'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_getrecentcommitsbypath_Method.php', 'ConduitAPI_diffusion_historyquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_historyquery_Method.php', 'ConduitAPI_diffusion_lastmodifiedquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_lastmodifiedquery_Method.php', 'ConduitAPI_diffusion_looksoon_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_looksoon_Method.php', 'ConduitAPI_diffusion_mergedcommitsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_mergedcommitsquery_Method.php', 'ConduitAPI_diffusion_querycommits_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_querycommits_Method.php', 'ConduitAPI_diffusion_querypaths_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_querypaths_Method.php', 'ConduitAPI_diffusion_rawdiffquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_rawdiffquery_Method.php', 'ConduitAPI_diffusion_readmequery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_readmequery_Method.php', 'ConduitAPI_diffusion_refsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_refsquery_Method.php', 'ConduitAPI_diffusion_resolverefs_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_resolverefs_Method.php', 'ConduitAPI_diffusion_searchquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_searchquery_Method.php', 'ConduitAPI_diffusion_tagsquery_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_tagsquery_Method.php', 'ConduitAPI_diffusion_updatecoverage_Method' => 'applications/diffusion/conduit/ConduitAPI_diffusion_updatecoverage_Method.php', 'ConduitAPI_feed_Method' => 'applications/feed/conduit/ConduitAPI_feed_Method.php', 'ConduitAPI_feed_publish_Method' => 'applications/feed/conduit/ConduitAPI_feed_publish_Method.php', 'ConduitAPI_feed_query_Method' => 'applications/feed/conduit/ConduitAPI_feed_query_Method.php', 'ConduitAPI_file_Method' => 'applications/files/conduit/ConduitAPI_file_Method.php', 'ConduitAPI_file_download_Method' => 'applications/files/conduit/ConduitAPI_file_download_Method.php', 'ConduitAPI_file_info_Method' => 'applications/files/conduit/ConduitAPI_file_info_Method.php', 'ConduitAPI_file_upload_Method' => 'applications/files/conduit/ConduitAPI_file_upload_Method.php', 'ConduitAPI_file_uploadhash_Method' => 'applications/files/conduit/ConduitAPI_file_uploadhash_Method.php', 'ConduitAPI_flag_Method' => 'applications/flag/conduit/ConduitAPI_flag_Method.php', 'ConduitAPI_flag_delete_Method' => 'applications/flag/conduit/ConduitAPI_flag_delete_Method.php', 'ConduitAPI_flag_edit_Method' => 'applications/flag/conduit/ConduitAPI_flag_edit_Method.php', 'ConduitAPI_flag_query_Method' => 'applications/flag/conduit/ConduitAPI_flag_query_Method.php', 'ConduitAPI_harbormaster_Method' => 'applications/harbormaster/conduit/ConduitAPI_harbormaster_Method.php', 'ConduitAPI_harbormaster_querybuildables_Method' => 'applications/harbormaster/conduit/ConduitAPI_harbormaster_querybuildables_Method.php', 'ConduitAPI_harbormaster_querybuilds_Method' => 'applications/harbormaster/conduit/ConduitAPI_harbormaster_querybuilds_Method.php', 'ConduitAPI_harbormaster_sendmessage_Method' => 'applications/harbormaster/conduit/ConduitAPI_harbormaster_sendmessage_Method.php', 'ConduitAPI_macro_Method' => 'applications/macro/conduit/ConduitAPI_macro_Method.php', 'ConduitAPI_macro_creatememe_Method' => 'applications/macro/conduit/ConduitAPI_macro_creatememe_Method.php', 'ConduitAPI_macro_query_Method' => 'applications/macro/conduit/ConduitAPI_macro_query_Method.php', 'ConduitAPI_maniphest_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_Method.php', 'ConduitAPI_maniphest_createtask_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_createtask_Method.php', 'ConduitAPI_maniphest_find_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_find_Method.php', 'ConduitAPI_maniphest_gettasktransactions_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_gettasktransactions_Method.php', 'ConduitAPI_maniphest_info_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_info_Method.php', 'ConduitAPI_maniphest_query_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_query_Method.php', 'ConduitAPI_maniphest_querystatuses_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_querystatuses_Method.php', 'ConduitAPI_maniphest_update_Method' => 'applications/maniphest/conduit/ConduitAPI_maniphest_update_Method.php', 'ConduitAPI_nuance_Method' => 'applications/nuance/conduit/ConduitAPI_nuance_Method.php', 'ConduitAPI_nuance_createitem_Method' => 'applications/nuance/conduit/ConduitAPI_nuance_createitem_Method.php', 'ConduitAPI_owners_Method' => 'applications/owners/conduit/ConduitAPI_owners_Method.php', 'ConduitAPI_owners_query_Method' => 'applications/owners/conduit/ConduitAPI_owners_query_Method.php', 'ConduitAPI_paste_Method' => 'applications/paste/conduit/ConduitAPI_paste_Method.php', 'ConduitAPI_paste_create_Method' => 'applications/paste/conduit/ConduitAPI_paste_create_Method.php', 'ConduitAPI_paste_info_Method' => 'applications/paste/conduit/ConduitAPI_paste_info_Method.php', 'ConduitAPI_paste_query_Method' => 'applications/paste/conduit/ConduitAPI_paste_query_Method.php', 'ConduitAPI_phame_Method' => 'applications/phame/conduit/ConduitAPI_phame_Method.php', 'ConduitAPI_phame_createpost_Method' => 'applications/phame/conduit/ConduitAPI_phame_createpost_Method.php', 'ConduitAPI_phame_query_Method' => 'applications/phame/conduit/ConduitAPI_phame_query_Method.php', 'ConduitAPI_phame_queryposts_Method' => 'applications/phame/conduit/ConduitAPI_phame_queryposts_Method.php', 'ConduitAPI_phid_Method' => 'applications/phid/conduit/ConduitAPI_phid_Method.php', 'ConduitAPI_phid_info_Method' => 'applications/phid/conduit/ConduitAPI_phid_info_Method.php', 'ConduitAPI_phid_lookup_Method' => 'applications/phid/conduit/ConduitAPI_phid_lookup_Method.php', 'ConduitAPI_phid_query_Method' => 'applications/phid/conduit/ConduitAPI_phid_query_Method.php', 'ConduitAPI_phragment_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_Method.php', 'ConduitAPI_phragment_getpatch_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_getpatch_Method.php', 'ConduitAPI_phragment_queryfragments_Method' => 'applications/phragment/conduit/ConduitAPI_phragment_queryfragments_Method.php', 'ConduitAPI_phrequent_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_Method.php', 'ConduitAPI_phrequent_pop_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_pop_Method.php', 'ConduitAPI_phrequent_push_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_push_Method.php', 'ConduitAPI_phrequent_tracking_Method' => 'applications/phrequent/conduit/ConduitAPI_phrequent_tracking_Method.php', 'ConduitAPI_phriction_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_Method.php', 'ConduitAPI_phriction_edit_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_edit_Method.php', 'ConduitAPI_phriction_history_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_history_Method.php', 'ConduitAPI_phriction_info_Method' => 'applications/phriction/conduit/ConduitAPI_phriction_info_Method.php', 'ConduitAPI_project_Method' => 'applications/project/conduit/ConduitAPI_project_Method.php', 'ConduitAPI_project_query_Method' => 'applications/project/conduit/ConduitAPI_project_query_Method.php', 'ConduitAPI_releeph_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_Method.php', 'ConduitAPI_releeph_getbranches_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_getbranches_Method.php', 'ConduitAPI_releeph_projectinfo_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_projectinfo_Method.php', 'ConduitAPI_releeph_querybranches_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_querybranches_Method.php', 'ConduitAPI_releeph_queryproducts_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_queryproducts_Method.php', 'ConduitAPI_releeph_queryrequests_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_queryrequests_Method.php', 'ConduitAPI_releeph_request_Method' => 'applications/releeph/conduit/ConduitAPI_releeph_request_Method.php', 'ConduitAPI_releephwork_canpush_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_canpush_Method.php', 'ConduitAPI_releephwork_getauthorinfo_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getauthorinfo_Method.php', 'ConduitAPI_releephwork_getbranch_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getbranch_Method.php', 'ConduitAPI_releephwork_getbranchcommitmessage_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getbranchcommitmessage_Method.php', 'ConduitAPI_releephwork_getcommitmessage_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_getcommitmessage_Method.php', 'ConduitAPI_releephwork_nextrequest_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_nextrequest_Method.php', 'ConduitAPI_releephwork_record_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_record_Method.php', 'ConduitAPI_releephwork_recordpickstatus_Method' => 'applications/releeph/conduit/work/ConduitAPI_releephwork_recordpickstatus_Method.php', 'ConduitAPI_remarkup_process_Method' => 'applications/remarkup/conduit/ConduitAPI_remarkup_process_Method.php', 'ConduitAPI_repository_Method' => 'applications/repository/conduit/ConduitAPI_repository_Method.php', 'ConduitAPI_repository_create_Method' => 'applications/repository/conduit/ConduitAPI_repository_create_Method.php', 'ConduitAPI_repository_query_Method' => 'applications/repository/conduit/ConduitAPI_repository_query_Method.php', 'ConduitAPI_slowvote_Method' => 'applications/slowvote/conduit/ConduitAPI_slowvote_Method.php', 'ConduitAPI_slowvote_info_Method' => 'applications/slowvote/conduit/ConduitAPI_slowvote_info_Method.php', 'ConduitAPI_token_Method' => 'applications/tokens/conduit/ConduitAPI_token_Method.php', 'ConduitAPI_token_give_Method' => 'applications/tokens/conduit/ConduitAPI_token_give_Method.php', 'ConduitAPI_token_given_Method' => 'applications/tokens/conduit/ConduitAPI_token_given_Method.php', 'ConduitAPI_token_query_Method' => 'applications/tokens/conduit/ConduitAPI_token_query_Method.php', 'ConduitAPI_user_Method' => 'applications/people/conduit/ConduitAPI_user_Method.php', 'ConduitAPI_user_addstatus_Method' => 'applications/people/conduit/ConduitAPI_user_addstatus_Method.php', 'ConduitAPI_user_disable_Method' => 'applications/people/conduit/ConduitAPI_user_disable_Method.php', 'ConduitAPI_user_enable_Method' => 'applications/people/conduit/ConduitAPI_user_enable_Method.php', 'ConduitAPI_user_find_Method' => 'applications/people/conduit/ConduitAPI_user_find_Method.php', 'ConduitAPI_user_info_Method' => 'applications/people/conduit/ConduitAPI_user_info_Method.php', 'ConduitAPI_user_query_Method' => 'applications/people/conduit/ConduitAPI_user_query_Method.php', 'ConduitAPI_user_removestatus_Method' => 'applications/people/conduit/ConduitAPI_user_removestatus_Method.php', 'ConduitAPI_user_whoami_Method' => 'applications/people/conduit/ConduitAPI_user_whoami_Method.php', 'ConduitCall' => 'applications/conduit/call/ConduitCall.php', 'ConduitCallTestCase' => 'applications/conduit/call/__tests__/ConduitCallTestCase.php', 'ConduitConnectionGarbageCollector' => 'applications/conduit/garbagecollector/ConduitConnectionGarbageCollector.php', 'ConduitException' => 'applications/conduit/protocol/ConduitException.php', 'ConduitLogGarbageCollector' => 'applications/conduit/garbagecollector/ConduitLogGarbageCollector.php', 'ConduitSSHWorkflow' => 'applications/conduit/ssh/ConduitSSHWorkflow.php', 'ConpherenceActionMenuEventListener' => 'applications/conpherence/events/ConpherenceActionMenuEventListener.php', 'ConpherenceConfigOptions' => 'applications/conpherence/config/ConpherenceConfigOptions.php', 'ConpherenceConstants' => 'applications/conpherence/constants/ConpherenceConstants.php', 'ConpherenceController' => 'applications/conpherence/controller/ConpherenceController.php', 'ConpherenceCreateThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceCreateThreadMailReceiver.php', 'ConpherenceDAO' => 'applications/conpherence/storage/ConpherenceDAO.php', 'ConpherenceEditor' => 'applications/conpherence/editor/ConpherenceEditor.php', 'ConpherenceFileWidgetView' => 'applications/conpherence/view/ConpherenceFileWidgetView.php', 'ConpherenceHovercardEventListener' => 'applications/conpherence/events/ConpherenceHovercardEventListener.php', 'ConpherenceLayoutView' => 'applications/conpherence/view/ConpherenceLayoutView.php', 'ConpherenceListController' => 'applications/conpherence/controller/ConpherenceListController.php', 'ConpherenceMenuItemView' => 'applications/conpherence/view/ConpherenceMenuItemView.php', 'ConpherenceNewController' => 'applications/conpherence/controller/ConpherenceNewController.php', 'ConpherenceNotificationPanelController' => 'applications/conpherence/controller/ConpherenceNotificationPanelController.php', 'ConpherenceParticipant' => 'applications/conpherence/storage/ConpherenceParticipant.php', 'ConpherenceParticipantCountQuery' => 'applications/conpherence/query/ConpherenceParticipantCountQuery.php', 'ConpherenceParticipantQuery' => 'applications/conpherence/query/ConpherenceParticipantQuery.php', 'ConpherenceParticipationStatus' => 'applications/conpherence/constants/ConpherenceParticipationStatus.php', 'ConpherencePeopleWidgetView' => 'applications/conpherence/view/ConpherencePeopleWidgetView.php', 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', 'ConpherenceSettings' => 'applications/conpherence/constants/ConpherenceSettings.php', 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', 'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php', 'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php', 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', 'ConpherenceTransactionComment' => 'applications/conpherence/storage/ConpherenceTransactionComment.php', 'ConpherenceTransactionQuery' => 'applications/conpherence/query/ConpherenceTransactionQuery.php', 'ConpherenceTransactionType' => 'applications/conpherence/constants/ConpherenceTransactionType.php', 'ConpherenceTransactionView' => 'applications/conpherence/view/ConpherenceTransactionView.php', 'ConpherenceUpdateActions' => 'applications/conpherence/constants/ConpherenceUpdateActions.php', 'ConpherenceUpdateController' => 'applications/conpherence/controller/ConpherenceUpdateController.php', 'ConpherenceViewController' => 'applications/conpherence/controller/ConpherenceViewController.php', 'ConpherenceWidgetController' => 'applications/conpherence/controller/ConpherenceWidgetController.php', 'ConpherenceWidgetView' => 'applications/conpherence/view/ConpherenceWidgetView.php', 'DarkConsoleController' => 'aphront/console/DarkConsoleController.php', 'DarkConsoleCore' => 'aphront/console/DarkConsoleCore.php', 'DarkConsoleDataController' => 'aphront/console/DarkConsoleDataController.php', 'DarkConsoleErrorLogPlugin' => 'aphront/console/plugin/DarkConsoleErrorLogPlugin.php', 'DarkConsoleErrorLogPluginAPI' => 'aphront/console/plugin/errorlog/DarkConsoleErrorLogPluginAPI.php', 'DarkConsoleEventPlugin' => 'aphront/console/plugin/DarkConsoleEventPlugin.php', 'DarkConsoleEventPluginAPI' => 'aphront/console/plugin/event/DarkConsoleEventPluginAPI.php', 'DarkConsolePlugin' => 'aphront/console/plugin/DarkConsolePlugin.php', 'DarkConsoleRequestPlugin' => 'aphront/console/plugin/DarkConsoleRequestPlugin.php', 'DarkConsoleServicesPlugin' => 'aphront/console/plugin/DarkConsoleServicesPlugin.php', 'DarkConsoleXHProfPlugin' => 'aphront/console/plugin/DarkConsoleXHProfPlugin.php', 'DarkConsoleXHProfPluginAPI' => 'aphront/console/plugin/xhprof/DarkConsoleXHProfPluginAPI.php', 'DatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DatabaseConfigurationProvider.php', 'DefaultDatabaseConfigurationProvider' => 'infrastructure/storage/configuration/DefaultDatabaseConfigurationProvider.php', 'DifferentialAction' => 'applications/differential/constants/DifferentialAction.php', 'DifferentialActionMenuEventListener' => 'applications/differential/event/DifferentialActionMenuEventListener.php', 'DifferentialAddCommentView' => 'applications/differential/view/DifferentialAddCommentView.php', 'DifferentialAffectedPath' => 'applications/differential/storage/DifferentialAffectedPath.php', 'DifferentialApplyPatchField' => 'applications/differential/customfield/DifferentialApplyPatchField.php', 'DifferentialArcanistProjectField' => 'applications/differential/customfield/DifferentialArcanistProjectField.php', 'DifferentialAsanaRepresentationField' => 'applications/differential/customfield/DifferentialAsanaRepresentationField.php', 'DifferentialAuditorsField' => 'applications/differential/customfield/DifferentialAuditorsField.php', 'DifferentialAuthorField' => 'applications/differential/customfield/DifferentialAuthorField.php', 'DifferentialBlameRevisionField' => 'applications/differential/customfield/DifferentialBlameRevisionField.php', 'DifferentialBranchField' => 'applications/differential/customfield/DifferentialBranchField.php', 'DifferentialCapabilityDefaultView' => 'applications/differential/capability/DifferentialCapabilityDefaultView.php', 'DifferentialChangeType' => 'applications/differential/constants/DifferentialChangeType.php', 'DifferentialChangesSinceLastUpdateField' => 'applications/differential/customfield/DifferentialChangesSinceLastUpdateField.php', 'DifferentialChangeset' => 'applications/differential/storage/DifferentialChangeset.php', 'DifferentialChangesetDetailView' => 'applications/differential/view/DifferentialChangesetDetailView.php', 'DifferentialChangesetFileTreeSideNavBuilder' => 'applications/differential/view/DifferentialChangesetFileTreeSideNavBuilder.php', 'DifferentialChangesetHTMLRenderer' => 'applications/differential/render/DifferentialChangesetHTMLRenderer.php', 'DifferentialChangesetListView' => 'applications/differential/view/DifferentialChangesetListView.php', 'DifferentialChangesetOneUpRenderer' => 'applications/differential/render/DifferentialChangesetOneUpRenderer.php', 'DifferentialChangesetOneUpTestRenderer' => 'applications/differential/render/DifferentialChangesetOneUpTestRenderer.php', 'DifferentialChangesetParser' => 'applications/differential/parser/DifferentialChangesetParser.php', 'DifferentialChangesetParserTestCase' => 'applications/differential/parser/__tests__/DifferentialChangesetParserTestCase.php', 'DifferentialChangesetQuery' => 'applications/differential/query/DifferentialChangesetQuery.php', 'DifferentialChangesetRenderer' => 'applications/differential/render/DifferentialChangesetRenderer.php', 'DifferentialChangesetTestRenderer' => 'applications/differential/render/DifferentialChangesetTestRenderer.php', 'DifferentialChangesetTwoUpRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpRenderer.php', 'DifferentialChangesetTwoUpTestRenderer' => 'applications/differential/render/DifferentialChangesetTwoUpTestRenderer.php', 'DifferentialChangesetViewController' => 'applications/differential/controller/DifferentialChangesetViewController.php', 'DifferentialCommentPreviewController' => 'applications/differential/controller/DifferentialCommentPreviewController.php', 'DifferentialCommentSaveController' => 'applications/differential/controller/DifferentialCommentSaveController.php', 'DifferentialCommitMessageParser' => 'applications/differential/parser/DifferentialCommitMessageParser.php', 'DifferentialCommitMessageParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCommitMessageParserTestCase.php', 'DifferentialCommitsField' => 'applications/differential/customfield/DifferentialCommitsField.php', 'DifferentialConflictsField' => 'applications/differential/customfield/DifferentialConflictsField.php', 'DifferentialController' => 'applications/differential/controller/DifferentialController.php', 'DifferentialCoreCustomField' => 'applications/differential/customfield/DifferentialCoreCustomField.php', 'DifferentialCustomField' => 'applications/differential/customfield/DifferentialCustomField.php', 'DifferentialCustomFieldDependsOnParser' => 'applications/differential/parser/DifferentialCustomFieldDependsOnParser.php', 'DifferentialCustomFieldDependsOnParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCustomFieldDependsOnParserTestCase.php', 'DifferentialCustomFieldNumericIndex' => 'applications/differential/storage/DifferentialCustomFieldNumericIndex.php', 'DifferentialCustomFieldRevertsParser' => 'applications/differential/parser/DifferentialCustomFieldRevertsParser.php', 'DifferentialCustomFieldRevertsParserTestCase' => 'applications/differential/parser/__tests__/DifferentialCustomFieldRevertsParserTestCase.php', 'DifferentialCustomFieldStorage' => 'applications/differential/storage/DifferentialCustomFieldStorage.php', 'DifferentialCustomFieldStringIndex' => 'applications/differential/storage/DifferentialCustomFieldStringIndex.php', 'DifferentialDAO' => 'applications/differential/storage/DifferentialDAO.php', 'DifferentialDependenciesField' => 'applications/differential/customfield/DifferentialDependenciesField.php', 'DifferentialDependsOnField' => 'applications/differential/customfield/DifferentialDependsOnField.php', 'DifferentialDiff' => 'applications/differential/storage/DifferentialDiff.php', 'DifferentialDiffCreateController' => 'applications/differential/controller/DifferentialDiffCreateController.php', + 'DifferentialDiffPHIDType' => 'applications/differential/phid/DifferentialDiffPHIDType.php', 'DifferentialDiffProperty' => 'applications/differential/storage/DifferentialDiffProperty.php', 'DifferentialDiffQuery' => 'applications/differential/query/DifferentialDiffQuery.php', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/DifferentialDiffTableOfContentsView.php', 'DifferentialDiffTestCase' => 'applications/differential/storage/__tests__/DifferentialDiffTestCase.php', 'DifferentialDiffViewController' => 'applications/differential/controller/DifferentialDiffViewController.php', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'applications/differential/doorkeeper/DifferentialDoorkeeperRevisionFeedStoryPublisher.php', 'DifferentialDraft' => 'applications/differential/storage/DifferentialDraft.php', 'DifferentialEditPolicyField' => 'applications/differential/customfield/DifferentialEditPolicyField.php', 'DifferentialFieldParseException' => 'applications/differential/exception/DifferentialFieldParseException.php', 'DifferentialFieldValidationException' => 'applications/differential/exception/DifferentialFieldValidationException.php', 'DifferentialGetWorkingCopy' => 'applications/differential/DifferentialGetWorkingCopy.php', 'DifferentialGitSVNIDField' => 'applications/differential/customfield/DifferentialGitSVNIDField.php', 'DifferentialHostField' => 'applications/differential/customfield/DifferentialHostField.php', 'DifferentialHovercardEventListener' => 'applications/differential/event/DifferentialHovercardEventListener.php', 'DifferentialHunk' => 'applications/differential/storage/DifferentialHunk.php', 'DifferentialHunkLegacy' => 'applications/differential/storage/DifferentialHunkLegacy.php', 'DifferentialHunkModern' => 'applications/differential/storage/DifferentialHunkModern.php', 'DifferentialHunkParser' => 'applications/differential/parser/DifferentialHunkParser.php', 'DifferentialHunkParserTestCase' => 'applications/differential/parser/__tests__/DifferentialHunkParserTestCase.php', 'DifferentialHunkQuery' => 'applications/differential/query/DifferentialHunkQuery.php', 'DifferentialHunkTestCase' => 'applications/differential/storage/__tests__/DifferentialHunkTestCase.php', 'DifferentialInlineComment' => 'applications/differential/storage/DifferentialInlineComment.php', 'DifferentialInlineCommentEditController' => 'applications/differential/controller/DifferentialInlineCommentEditController.php', 'DifferentialInlineCommentEditView' => 'applications/differential/view/DifferentialInlineCommentEditView.php', 'DifferentialInlineCommentPreviewController' => 'applications/differential/controller/DifferentialInlineCommentPreviewController.php', 'DifferentialInlineCommentQuery' => 'applications/differential/query/DifferentialInlineCommentQuery.php', 'DifferentialInlineCommentView' => 'applications/differential/view/DifferentialInlineCommentView.php', 'DifferentialJIRAIssuesField' => 'applications/differential/customfield/DifferentialJIRAIssuesField.php', 'DifferentialLandingActionMenuEventListener' => 'applications/differential/landing/DifferentialLandingActionMenuEventListener.php', 'DifferentialLandingStrategy' => 'applications/differential/landing/DifferentialLandingStrategy.php', 'DifferentialLandingToGitHub' => 'applications/differential/landing/DifferentialLandingToGitHub.php', 'DifferentialLandingToHostedGit' => 'applications/differential/landing/DifferentialLandingToHostedGit.php', 'DifferentialLandingToHostedMercurial' => 'applications/differential/landing/DifferentialLandingToHostedMercurial.php', 'DifferentialLintField' => 'applications/differential/customfield/DifferentialLintField.php', 'DifferentialLintStatus' => 'applications/differential/constants/DifferentialLintStatus.php', 'DifferentialLocalCommitsView' => 'applications/differential/view/DifferentialLocalCommitsView.php', 'DifferentialMail' => 'applications/differential/mail/DifferentialMail.php', 'DifferentialManiphestTasksField' => 'applications/differential/customfield/DifferentialManiphestTasksField.php', - 'DifferentialPHIDTypeDiff' => 'applications/differential/phid/DifferentialPHIDTypeDiff.php', - 'DifferentialPHIDTypeRevision' => 'applications/differential/phid/DifferentialPHIDTypeRevision.php', 'DifferentialParseCacheGarbageCollector' => 'applications/differential/garbagecollector/DifferentialParseCacheGarbageCollector.php', 'DifferentialParseRenderTestCase' => 'applications/differential/__tests__/DifferentialParseRenderTestCase.php', 'DifferentialPathField' => 'applications/differential/customfield/DifferentialPathField.php', 'DifferentialPrimaryPaneView' => 'applications/differential/view/DifferentialPrimaryPaneView.php', 'DifferentialProjectReviewersField' => 'applications/differential/customfield/DifferentialProjectReviewersField.php', 'DifferentialProjectsField' => 'applications/differential/customfield/DifferentialProjectsField.php', 'DifferentialRawDiffRenderer' => 'applications/differential/render/DifferentialRawDiffRenderer.php', 'DifferentialReleephRequestFieldSpecification' => 'applications/releeph/differential/DifferentialReleephRequestFieldSpecification.php', 'DifferentialRemarkupRule' => 'applications/differential/remarkup/DifferentialRemarkupRule.php', 'DifferentialReplyHandler' => 'applications/differential/mail/DifferentialReplyHandler.php', 'DifferentialRepositoryField' => 'applications/differential/customfield/DifferentialRepositoryField.php', 'DifferentialRepositoryLookup' => 'applications/differential/query/DifferentialRepositoryLookup.php', 'DifferentialRequiredSignaturesField' => 'applications/differential/customfield/DifferentialRequiredSignaturesField.php', 'DifferentialResultsTableView' => 'applications/differential/view/DifferentialResultsTableView.php', 'DifferentialRevertPlanField' => 'applications/differential/customfield/DifferentialRevertPlanField.php', 'DifferentialReviewedByField' => 'applications/differential/customfield/DifferentialReviewedByField.php', 'DifferentialReviewer' => 'applications/differential/storage/DifferentialReviewer.php', 'DifferentialReviewerStatus' => 'applications/differential/constants/DifferentialReviewerStatus.php', 'DifferentialReviewersField' => 'applications/differential/customfield/DifferentialReviewersField.php', 'DifferentialReviewersView' => 'applications/differential/view/DifferentialReviewersView.php', 'DifferentialRevision' => 'applications/differential/storage/DifferentialRevision.php', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/DifferentialRevisionControlSystem.php', 'DifferentialRevisionDetailView' => 'applications/differential/view/DifferentialRevisionDetailView.php', 'DifferentialRevisionEditController' => 'applications/differential/controller/DifferentialRevisionEditController.php', 'DifferentialRevisionHasTaskEdgeType' => 'applications/differential/edge/DifferentialRevisionHasTaskEdgeType.php', 'DifferentialRevisionIDField' => 'applications/differential/customfield/DifferentialRevisionIDField.php', 'DifferentialRevisionLandController' => 'applications/differential/controller/DifferentialRevisionLandController.php', 'DifferentialRevisionListController' => 'applications/differential/controller/DifferentialRevisionListController.php', 'DifferentialRevisionListView' => 'applications/differential/view/DifferentialRevisionListView.php', 'DifferentialRevisionMailReceiver' => 'applications/differential/mail/DifferentialRevisionMailReceiver.php', + 'DifferentialRevisionPHIDType' => 'applications/differential/phid/DifferentialRevisionPHIDType.php', 'DifferentialRevisionQuery' => 'applications/differential/query/DifferentialRevisionQuery.php', 'DifferentialRevisionSearchEngine' => 'applications/differential/query/DifferentialRevisionSearchEngine.php', 'DifferentialRevisionStatus' => 'applications/differential/constants/DifferentialRevisionStatus.php', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/DifferentialRevisionUpdateHistoryView.php', 'DifferentialRevisionViewController' => 'applications/differential/controller/DifferentialRevisionViewController.php', 'DifferentialSearchIndexer' => 'applications/differential/search/DifferentialSearchIndexer.php', 'DifferentialStoredCustomField' => 'applications/differential/customfield/DifferentialStoredCustomField.php', 'DifferentialSubscribersField' => 'applications/differential/customfield/DifferentialSubscribersField.php', 'DifferentialSummaryField' => 'applications/differential/customfield/DifferentialSummaryField.php', 'DifferentialTestPlanField' => 'applications/differential/customfield/DifferentialTestPlanField.php', 'DifferentialTitleField' => 'applications/differential/customfield/DifferentialTitleField.php', 'DifferentialTransaction' => 'applications/differential/storage/DifferentialTransaction.php', 'DifferentialTransactionComment' => 'applications/differential/storage/DifferentialTransactionComment.php', 'DifferentialTransactionEditor' => 'applications/differential/editor/DifferentialTransactionEditor.php', 'DifferentialTransactionQuery' => 'applications/differential/query/DifferentialTransactionQuery.php', 'DifferentialTransactionView' => 'applications/differential/view/DifferentialTransactionView.php', 'DifferentialUnitField' => 'applications/differential/customfield/DifferentialUnitField.php', 'DifferentialUnitStatus' => 'applications/differential/constants/DifferentialUnitStatus.php', 'DifferentialUnitTestResult' => 'applications/differential/constants/DifferentialUnitTestResult.php', 'DifferentialViewPolicyField' => 'applications/differential/customfield/DifferentialViewPolicyField.php', 'DiffusionArcanistProjectDatasource' => 'applications/diffusion/typeahead/DiffusionArcanistProjectDatasource.php', 'DiffusionAuditorDatasource' => 'applications/diffusion/typeahead/DiffusionAuditorDatasource.php', 'DiffusionBranchTableController' => 'applications/diffusion/controller/DiffusionBranchTableController.php', 'DiffusionBranchTableView' => 'applications/diffusion/view/DiffusionBranchTableView.php', 'DiffusionBrowseController' => 'applications/diffusion/controller/DiffusionBrowseController.php', 'DiffusionBrowseDirectoryController' => 'applications/diffusion/controller/DiffusionBrowseDirectoryController.php', 'DiffusionBrowseFileController' => 'applications/diffusion/controller/DiffusionBrowseFileController.php', 'DiffusionBrowseMainController' => 'applications/diffusion/controller/DiffusionBrowseMainController.php', 'DiffusionBrowseResultSet' => 'applications/diffusion/data/DiffusionBrowseResultSet.php', 'DiffusionBrowseSearchController' => 'applications/diffusion/controller/DiffusionBrowseSearchController.php', 'DiffusionBrowseTableView' => 'applications/diffusion/view/DiffusionBrowseTableView.php', 'DiffusionCapabilityCreateRepositories' => 'applications/diffusion/capability/DiffusionCapabilityCreateRepositories.php', 'DiffusionCapabilityDefaultEdit' => 'applications/diffusion/capability/DiffusionCapabilityDefaultEdit.php', 'DiffusionCapabilityDefaultPush' => 'applications/diffusion/capability/DiffusionCapabilityDefaultPush.php', 'DiffusionCapabilityDefaultView' => 'applications/diffusion/capability/DiffusionCapabilityDefaultView.php', 'DiffusionCapabilityPush' => 'applications/diffusion/capability/DiffusionCapabilityPush.php', 'DiffusionChangeController' => 'applications/diffusion/controller/DiffusionChangeController.php', 'DiffusionCommentListView' => 'applications/diffusion/view/DiffusionCommentListView.php', 'DiffusionCommentView' => 'applications/diffusion/view/DiffusionCommentView.php', 'DiffusionCommitBranchesController' => 'applications/diffusion/controller/DiffusionCommitBranchesController.php', 'DiffusionCommitChangeTableView' => 'applications/diffusion/view/DiffusionCommitChangeTableView.php', 'DiffusionCommitController' => 'applications/diffusion/controller/DiffusionCommitController.php', 'DiffusionCommitEditController' => 'applications/diffusion/controller/DiffusionCommitEditController.php', 'DiffusionCommitHasTaskEdgeType' => 'applications/diffusion/edge/DiffusionCommitHasTaskEdgeType.php', 'DiffusionCommitHash' => 'applications/diffusion/data/DiffusionCommitHash.php', 'DiffusionCommitHookEngine' => 'applications/diffusion/engine/DiffusionCommitHookEngine.php', 'DiffusionCommitHookRejectException' => 'applications/diffusion/exception/DiffusionCommitHookRejectException.php', 'DiffusionCommitQuery' => 'applications/diffusion/query/DiffusionCommitQuery.php', 'DiffusionCommitRef' => 'applications/diffusion/data/DiffusionCommitRef.php', 'DiffusionCommitRemarkupRule' => 'applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php', 'DiffusionCommitTagsController' => 'applications/diffusion/controller/DiffusionCommitTagsController.php', 'DiffusionController' => 'applications/diffusion/controller/DiffusionController.php', 'DiffusionDiffController' => 'applications/diffusion/controller/DiffusionDiffController.php', 'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'applications/diffusion/doorkeeper/DiffusionDoorkeeperCommitFeedStoryPublisher.php', 'DiffusionEmptyResultView' => 'applications/diffusion/view/DiffusionEmptyResultView.php', 'DiffusionExternalController' => 'applications/diffusion/controller/DiffusionExternalController.php', 'DiffusionFileContent' => 'applications/diffusion/data/DiffusionFileContent.php', 'DiffusionFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionFileContentQuery.php', 'DiffusionGitBranch' => 'applications/diffusion/data/DiffusionGitBranch.php', 'DiffusionGitBranchTestCase' => 'applications/diffusion/data/__tests__/DiffusionGitBranchTestCase.php', 'DiffusionGitFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionGitFileContentQuery.php', 'DiffusionGitFileContentQueryTestCase' => 'applications/diffusion/query/__tests__/DiffusionGitFileContentQueryTestCase.php', 'DiffusionGitRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionGitRawDiffQuery.php', 'DiffusionGitRequest' => 'applications/diffusion/request/DiffusionGitRequest.php', 'DiffusionGitResponse' => 'applications/diffusion/response/DiffusionGitResponse.php', 'DiffusionHistoryController' => 'applications/diffusion/controller/DiffusionHistoryController.php', 'DiffusionHistoryTableView' => 'applications/diffusion/view/DiffusionHistoryTableView.php', 'DiffusionHovercardEventListener' => 'applications/diffusion/events/DiffusionHovercardEventListener.php', 'DiffusionInlineCommentController' => 'applications/diffusion/controller/DiffusionInlineCommentController.php', 'DiffusionInlineCommentPreviewController' => 'applications/diffusion/controller/DiffusionInlineCommentPreviewController.php', 'DiffusionLastModifiedController' => 'applications/diffusion/controller/DiffusionLastModifiedController.php', 'DiffusionLintController' => 'applications/diffusion/controller/DiffusionLintController.php', 'DiffusionLintCountQuery' => 'applications/diffusion/query/DiffusionLintCountQuery.php', 'DiffusionLintDetailsController' => 'applications/diffusion/controller/DiffusionLintDetailsController.php', 'DiffusionLintSaveRunner' => 'applications/diffusion/DiffusionLintSaveRunner.php', 'DiffusionLowLevelCommitFieldsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitFieldsQuery.php', 'DiffusionLowLevelCommitQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelCommitQuery.php', 'DiffusionLowLevelGitRefQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelGitRefQuery.php', 'DiffusionLowLevelMercurialBranchesQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelMercurialBranchesQuery.php', 'DiffusionLowLevelParentsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelParentsQuery.php', 'DiffusionLowLevelQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelQuery.php', 'DiffusionLowLevelResolveRefsQuery' => 'applications/diffusion/query/lowlevel/DiffusionLowLevelResolveRefsQuery.php', 'DiffusionMercurialFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionMercurialFileContentQuery.php', 'DiffusionMercurialRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionMercurialRawDiffQuery.php', 'DiffusionMercurialRequest' => 'applications/diffusion/request/DiffusionMercurialRequest.php', 'DiffusionMercurialResponse' => 'applications/diffusion/response/DiffusionMercurialResponse.php', 'DiffusionMercurialWireProtocol' => 'applications/diffusion/protocol/DiffusionMercurialWireProtocol.php', 'DiffusionMirrorDeleteController' => 'applications/diffusion/controller/DiffusionMirrorDeleteController.php', 'DiffusionMirrorEditController' => 'applications/diffusion/controller/DiffusionMirrorEditController.php', 'DiffusionPathChange' => 'applications/diffusion/data/DiffusionPathChange.php', 'DiffusionPathChangeQuery' => 'applications/diffusion/query/pathchange/DiffusionPathChangeQuery.php', 'DiffusionPathCompleteController' => 'applications/diffusion/controller/DiffusionPathCompleteController.php', 'DiffusionPathIDQuery' => 'applications/diffusion/query/pathid/DiffusionPathIDQuery.php', 'DiffusionPathQuery' => 'applications/diffusion/query/DiffusionPathQuery.php', 'DiffusionPathQueryTestCase' => 'applications/diffusion/query/pathid/__tests__/DiffusionPathQueryTestCase.php', 'DiffusionPathTreeController' => 'applications/diffusion/controller/DiffusionPathTreeController.php', 'DiffusionPathValidateController' => 'applications/diffusion/controller/DiffusionPathValidateController.php', 'DiffusionPushEventViewController' => 'applications/diffusion/controller/DiffusionPushEventViewController.php', 'DiffusionPushLogController' => 'applications/diffusion/controller/DiffusionPushLogController.php', 'DiffusionPushLogListController' => 'applications/diffusion/controller/DiffusionPushLogListController.php', 'DiffusionPushLogListView' => 'applications/diffusion/view/DiffusionPushLogListView.php', 'DiffusionQuery' => 'applications/diffusion/query/DiffusionQuery.php', 'DiffusionRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionRawDiffQuery.php', 'DiffusionRefNotFoundException' => 'applications/diffusion/exception/DiffusionRefNotFoundException.php', 'DiffusionRenameHistoryQuery' => 'applications/diffusion/query/DiffusionRenameHistoryQuery.php', 'DiffusionRepositoryController' => 'applications/diffusion/controller/DiffusionRepositoryController.php', 'DiffusionRepositoryCreateController' => 'applications/diffusion/controller/DiffusionRepositoryCreateController.php', 'DiffusionRepositoryDatasource' => 'applications/diffusion/typeahead/DiffusionRepositoryDatasource.php', 'DiffusionRepositoryDefaultController' => 'applications/diffusion/controller/DiffusionRepositoryDefaultController.php', 'DiffusionRepositoryEditActionsController' => 'applications/diffusion/controller/DiffusionRepositoryEditActionsController.php', 'DiffusionRepositoryEditActivateController' => 'applications/diffusion/controller/DiffusionRepositoryEditActivateController.php', 'DiffusionRepositoryEditBasicController' => 'applications/diffusion/controller/DiffusionRepositoryEditBasicController.php', 'DiffusionRepositoryEditBranchesController' => 'applications/diffusion/controller/DiffusionRepositoryEditBranchesController.php', 'DiffusionRepositoryEditController' => 'applications/diffusion/controller/DiffusionRepositoryEditController.php', 'DiffusionRepositoryEditDangerousController' => 'applications/diffusion/controller/DiffusionRepositoryEditDangerousController.php', 'DiffusionRepositoryEditDeleteController' => 'applications/diffusion/controller/DiffusionRepositoryEditDeleteController.php', 'DiffusionRepositoryEditEncodingController' => 'applications/diffusion/controller/DiffusionRepositoryEditEncodingController.php', 'DiffusionRepositoryEditHostingController' => 'applications/diffusion/controller/DiffusionRepositoryEditHostingController.php', 'DiffusionRepositoryEditLocalController' => 'applications/diffusion/controller/DiffusionRepositoryEditLocalController.php', 'DiffusionRepositoryEditMainController' => 'applications/diffusion/controller/DiffusionRepositoryEditMainController.php', 'DiffusionRepositoryEditSubversionController' => 'applications/diffusion/controller/DiffusionRepositoryEditSubversionController.php', 'DiffusionRepositoryListController' => 'applications/diffusion/controller/DiffusionRepositoryListController.php', 'DiffusionRepositoryNewController' => 'applications/diffusion/controller/DiffusionRepositoryNewController.php', 'DiffusionRepositoryPath' => 'applications/diffusion/data/DiffusionRepositoryPath.php', 'DiffusionRepositoryRef' => 'applications/diffusion/data/DiffusionRepositoryRef.php', 'DiffusionRepositoryRemarkupRule' => 'applications/diffusion/remarkup/DiffusionRepositoryRemarkupRule.php', 'DiffusionRepositoryTag' => 'applications/diffusion/data/DiffusionRepositoryTag.php', 'DiffusionRequest' => 'applications/diffusion/request/DiffusionRequest.php', 'DiffusionResolveUserQuery' => 'applications/diffusion/query/DiffusionResolveUserQuery.php', 'DiffusionSSHGitReceivePackWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitReceivePackWorkflow.php', 'DiffusionSSHGitUploadPackWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitUploadPackWorkflow.php', 'DiffusionSSHGitWorkflow' => 'applications/diffusion/ssh/DiffusionSSHGitWorkflow.php', 'DiffusionSSHMercurialServeWorkflow' => 'applications/diffusion/ssh/DiffusionSSHMercurialServeWorkflow.php', 'DiffusionSSHMercurialWireClientProtocolChannel' => 'applications/diffusion/ssh/DiffusionSSHMercurialWireClientProtocolChannel.php', 'DiffusionSSHMercurialWireTestCase' => 'applications/diffusion/ssh/__tests__/DiffusionSSHMercurialWireTestCase.php', 'DiffusionSSHMercurialWorkflow' => 'applications/diffusion/ssh/DiffusionSSHMercurialWorkflow.php', 'DiffusionSSHSubversionServeWorkflow' => 'applications/diffusion/ssh/DiffusionSSHSubversionServeWorkflow.php', 'DiffusionSSHSubversionWorkflow' => 'applications/diffusion/ssh/DiffusionSSHSubversionWorkflow.php', 'DiffusionSSHWorkflow' => 'applications/diffusion/ssh/DiffusionSSHWorkflow.php', 'DiffusionServeController' => 'applications/diffusion/controller/DiffusionServeController.php', 'DiffusionSetPasswordPanel' => 'applications/diffusion/panel/DiffusionSetPasswordPanel.php', 'DiffusionSetupException' => 'applications/diffusion/exception/DiffusionSetupException.php', 'DiffusionSubversionWireProtocol' => 'applications/diffusion/protocol/DiffusionSubversionWireProtocol.php', 'DiffusionSubversionWireProtocolTestCase' => 'applications/diffusion/protocol/__tests__/DiffusionSubversionWireProtocolTestCase.php', 'DiffusionSvnFileContentQuery' => 'applications/diffusion/query/filecontent/DiffusionSvnFileContentQuery.php', 'DiffusionSvnRawDiffQuery' => 'applications/diffusion/query/rawdiff/DiffusionSvnRawDiffQuery.php', 'DiffusionSvnRequest' => 'applications/diffusion/request/DiffusionSvnRequest.php', 'DiffusionSymbolController' => 'applications/diffusion/controller/DiffusionSymbolController.php', 'DiffusionSymbolDatasource' => 'applications/diffusion/typeahead/DiffusionSymbolDatasource.php', 'DiffusionSymbolQuery' => 'applications/diffusion/query/DiffusionSymbolQuery.php', 'DiffusionTagListController' => 'applications/diffusion/controller/DiffusionTagListController.php', 'DiffusionTagListView' => 'applications/diffusion/view/DiffusionTagListView.php', 'DiffusionURITestCase' => 'applications/diffusion/request/__tests__/DiffusionURITestCase.php', 'DiffusionView' => 'applications/diffusion/view/DiffusionView.php', 'DivinerArticleAtomizer' => 'applications/diviner/atomizer/DivinerArticleAtomizer.php', 'DivinerAtom' => 'applications/diviner/atom/DivinerAtom.php', 'DivinerAtomCache' => 'applications/diviner/cache/DivinerAtomCache.php', 'DivinerAtomController' => 'applications/diviner/controller/DivinerAtomController.php', 'DivinerAtomListController' => 'applications/diviner/controller/DivinerAtomListController.php', + 'DivinerAtomPHIDType' => 'applications/diviner/phid/DivinerAtomPHIDType.php', 'DivinerAtomQuery' => 'applications/diviner/query/DivinerAtomQuery.php', 'DivinerAtomRef' => 'applications/diviner/atom/DivinerAtomRef.php', 'DivinerAtomSearchEngine' => 'applications/diviner/query/DivinerAtomSearchEngine.php', 'DivinerAtomizeWorkflow' => 'applications/diviner/workflow/DivinerAtomizeWorkflow.php', 'DivinerAtomizer' => 'applications/diviner/atomizer/DivinerAtomizer.php', 'DivinerBookController' => 'applications/diviner/controller/DivinerBookController.php', 'DivinerBookItemView' => 'applications/diviner/view/DivinerBookItemView.php', + 'DivinerBookPHIDType' => 'applications/diviner/phid/DivinerBookPHIDType.php', 'DivinerBookQuery' => 'applications/diviner/query/DivinerBookQuery.php', 'DivinerController' => 'applications/diviner/controller/DivinerController.php', 'DivinerDAO' => 'applications/diviner/storage/DivinerDAO.php', 'DivinerDefaultRenderer' => 'applications/diviner/renderer/DivinerDefaultRenderer.php', 'DivinerDiskCache' => 'applications/diviner/cache/DivinerDiskCache.php', 'DivinerFileAtomizer' => 'applications/diviner/atomizer/DivinerFileAtomizer.php', 'DivinerFindController' => 'applications/diviner/controller/DivinerFindController.php', 'DivinerGenerateWorkflow' => 'applications/diviner/workflow/DivinerGenerateWorkflow.php', 'DivinerLiveAtom' => 'applications/diviner/storage/DivinerLiveAtom.php', 'DivinerLiveBook' => 'applications/diviner/storage/DivinerLiveBook.php', 'DivinerLivePublisher' => 'applications/diviner/publisher/DivinerLivePublisher.php', 'DivinerLiveSymbol' => 'applications/diviner/storage/DivinerLiveSymbol.php', 'DivinerMainController' => 'applications/diviner/controller/DivinerMainController.php', - 'DivinerPHIDTypeAtom' => 'applications/diviner/phid/DivinerPHIDTypeAtom.php', - 'DivinerPHIDTypeBook' => 'applications/diviner/phid/DivinerPHIDTypeBook.php', 'DivinerPHPAtomizer' => 'applications/diviner/atomizer/DivinerPHPAtomizer.php', 'DivinerParameterTableView' => 'applications/diviner/view/DivinerParameterTableView.php', 'DivinerPublishCache' => 'applications/diviner/cache/DivinerPublishCache.php', 'DivinerPublisher' => 'applications/diviner/publisher/DivinerPublisher.php', 'DivinerRemarkupRuleSymbol' => 'applications/diviner/markup/DivinerRemarkupRuleSymbol.php', 'DivinerRenderer' => 'applications/diviner/renderer/DivinerRenderer.php', 'DivinerReturnTableView' => 'applications/diviner/view/DivinerReturnTableView.php', 'DivinerSectionView' => 'applications/diviner/view/DivinerSectionView.php', 'DivinerStaticPublisher' => 'applications/diviner/publisher/DivinerStaticPublisher.php', 'DivinerWorkflow' => 'applications/diviner/workflow/DivinerWorkflow.php', 'DoorkeeperBridge' => 'applications/doorkeeper/bridge/DoorkeeperBridge.php', 'DoorkeeperBridgeAsana' => 'applications/doorkeeper/bridge/DoorkeeperBridgeAsana.php', 'DoorkeeperBridgeJIRA' => 'applications/doorkeeper/bridge/DoorkeeperBridgeJIRA.php', 'DoorkeeperBridgeJIRATestCase' => 'applications/doorkeeper/bridge/__tests__/DoorkeeperBridgeJIRATestCase.php', 'DoorkeeperDAO' => 'applications/doorkeeper/storage/DoorkeeperDAO.php', 'DoorkeeperExternalObject' => 'applications/doorkeeper/storage/DoorkeeperExternalObject.php', 'DoorkeeperExternalObjectQuery' => 'applications/doorkeeper/query/DoorkeeperExternalObjectQuery.php', 'DoorkeeperFeedStoryPublisher' => 'applications/doorkeeper/engine/DoorkeeperFeedStoryPublisher.php', 'DoorkeeperFeedWorker' => 'applications/doorkeeper/worker/DoorkeeperFeedWorker.php', 'DoorkeeperFeedWorkerAsana' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerAsana.php', 'DoorkeeperFeedWorkerJIRA' => 'applications/doorkeeper/worker/DoorkeeperFeedWorkerJIRA.php', 'DoorkeeperImportEngine' => 'applications/doorkeeper/engine/DoorkeeperImportEngine.php', 'DoorkeeperMissingLinkException' => 'applications/doorkeeper/exception/DoorkeeperMissingLinkException.php', 'DoorkeeperObjectRef' => 'applications/doorkeeper/engine/DoorkeeperObjectRef.php', 'DoorkeeperRemarkupRule' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRule.php', 'DoorkeeperRemarkupRuleAsana' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRuleAsana.php', 'DoorkeeperRemarkupRuleJIRA' => 'applications/doorkeeper/remarkup/DoorkeeperRemarkupRuleJIRA.php', 'DoorkeeperTagView' => 'applications/doorkeeper/view/DoorkeeperTagView.php', 'DoorkeeperTagsController' => 'applications/doorkeeper/controller/DoorkeeperTagsController.php', 'DrydockAllocatorWorker' => 'applications/drydock/worker/DrydockAllocatorWorker.php', 'DrydockApacheWebrootInterface' => 'applications/drydock/interface/webroot/DrydockApacheWebrootInterface.php', 'DrydockBlueprint' => 'applications/drydock/storage/DrydockBlueprint.php', 'DrydockBlueprintController' => 'applications/drydock/controller/DrydockBlueprintController.php', 'DrydockBlueprintCreateController' => 'applications/drydock/controller/DrydockBlueprintCreateController.php', 'DrydockBlueprintEditController' => 'applications/drydock/controller/DrydockBlueprintEditController.php', 'DrydockBlueprintEditor' => 'applications/drydock/editor/DrydockBlueprintEditor.php', 'DrydockBlueprintImplementation' => 'applications/drydock/blueprint/DrydockBlueprintImplementation.php', 'DrydockBlueprintListController' => 'applications/drydock/controller/DrydockBlueprintListController.php', + 'DrydockBlueprintPHIDType' => 'applications/drydock/phid/DrydockBlueprintPHIDType.php', 'DrydockBlueprintQuery' => 'applications/drydock/query/DrydockBlueprintQuery.php', 'DrydockBlueprintScopeGuard' => 'applications/drydock/util/DrydockBlueprintScopeGuard.php', 'DrydockBlueprintSearchEngine' => 'applications/drydock/query/DrydockBlueprintSearchEngine.php', 'DrydockBlueprintTransaction' => 'applications/drydock/storage/DrydockBlueprintTransaction.php', 'DrydockBlueprintTransactionQuery' => 'applications/drydock/query/DrydockBlueprintTransactionQuery.php', 'DrydockBlueprintViewController' => 'applications/drydock/controller/DrydockBlueprintViewController.php', 'DrydockCapabilityCreateBlueprints' => 'applications/drydock/capability/DrydockCapabilityCreateBlueprints.php', 'DrydockCapabilityDefaultEdit' => 'applications/drydock/capability/DrydockCapabilityDefaultEdit.php', 'DrydockCapabilityDefaultView' => 'applications/drydock/capability/DrydockCapabilityDefaultView.php', 'DrydockCommandInterface' => 'applications/drydock/interface/command/DrydockCommandInterface.php', 'DrydockConsoleController' => 'applications/drydock/controller/DrydockConsoleController.php', 'DrydockConstants' => 'applications/drydock/constants/DrydockConstants.php', 'DrydockController' => 'applications/drydock/controller/DrydockController.php', 'DrydockDAO' => 'applications/drydock/storage/DrydockDAO.php', 'DrydockFilesystemInterface' => 'applications/drydock/interface/filesystem/DrydockFilesystemInterface.php', 'DrydockInterface' => 'applications/drydock/interface/DrydockInterface.php', 'DrydockLease' => 'applications/drydock/storage/DrydockLease.php', 'DrydockLeaseController' => 'applications/drydock/controller/DrydockLeaseController.php', 'DrydockLeaseListController' => 'applications/drydock/controller/DrydockLeaseListController.php', 'DrydockLeaseListView' => 'applications/drydock/view/DrydockLeaseListView.php', + 'DrydockLeasePHIDType' => 'applications/drydock/phid/DrydockLeasePHIDType.php', 'DrydockLeaseQuery' => 'applications/drydock/query/DrydockLeaseQuery.php', 'DrydockLeaseReleaseController' => 'applications/drydock/controller/DrydockLeaseReleaseController.php', 'DrydockLeaseSearchEngine' => 'applications/drydock/query/DrydockLeaseSearchEngine.php', 'DrydockLeaseStatus' => 'applications/drydock/constants/DrydockLeaseStatus.php', 'DrydockLeaseViewController' => 'applications/drydock/controller/DrydockLeaseViewController.php', 'DrydockLocalCommandInterface' => 'applications/drydock/interface/command/DrydockLocalCommandInterface.php', 'DrydockLocalHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockLocalHostBlueprintImplementation.php', 'DrydockLog' => 'applications/drydock/storage/DrydockLog.php', 'DrydockLogController' => 'applications/drydock/controller/DrydockLogController.php', 'DrydockLogListController' => 'applications/drydock/controller/DrydockLogListController.php', 'DrydockLogListView' => 'applications/drydock/view/DrydockLogListView.php', 'DrydockLogQuery' => 'applications/drydock/query/DrydockLogQuery.php', 'DrydockLogSearchEngine' => 'applications/drydock/query/DrydockLogSearchEngine.php', 'DrydockManagementCloseWorkflow' => 'applications/drydock/management/DrydockManagementCloseWorkflow.php', 'DrydockManagementCreateResourceWorkflow' => 'applications/drydock/management/DrydockManagementCreateResourceWorkflow.php', 'DrydockManagementLeaseWorkflow' => 'applications/drydock/management/DrydockManagementLeaseWorkflow.php', 'DrydockManagementReleaseWorkflow' => 'applications/drydock/management/DrydockManagementReleaseWorkflow.php', 'DrydockManagementWorkflow' => 'applications/drydock/management/DrydockManagementWorkflow.php', - 'DrydockPHIDTypeBlueprint' => 'applications/drydock/phid/DrydockPHIDTypeBlueprint.php', - 'DrydockPHIDTypeLease' => 'applications/drydock/phid/DrydockPHIDTypeLease.php', - 'DrydockPHIDTypeResource' => 'applications/drydock/phid/DrydockPHIDTypeResource.php', 'DrydockPreallocatedHostBlueprintImplementation' => 'applications/drydock/blueprint/DrydockPreallocatedHostBlueprintImplementation.php', 'DrydockQuery' => 'applications/drydock/query/DrydockQuery.php', 'DrydockResource' => 'applications/drydock/storage/DrydockResource.php', 'DrydockResourceCloseController' => 'applications/drydock/controller/DrydockResourceCloseController.php', 'DrydockResourceController' => 'applications/drydock/controller/DrydockResourceController.php', 'DrydockResourceListController' => 'applications/drydock/controller/DrydockResourceListController.php', 'DrydockResourceListView' => 'applications/drydock/view/DrydockResourceListView.php', + 'DrydockResourcePHIDType' => 'applications/drydock/phid/DrydockResourcePHIDType.php', 'DrydockResourceQuery' => 'applications/drydock/query/DrydockResourceQuery.php', 'DrydockResourceSearchEngine' => 'applications/drydock/query/DrydockResourceSearchEngine.php', 'DrydockResourceStatus' => 'applications/drydock/constants/DrydockResourceStatus.php', 'DrydockResourceViewController' => 'applications/drydock/controller/DrydockResourceViewController.php', 'DrydockSFTPFilesystemInterface' => 'applications/drydock/interface/filesystem/DrydockSFTPFilesystemInterface.php', 'DrydockSSHCommandInterface' => 'applications/drydock/interface/command/DrydockSSHCommandInterface.php', 'DrydockWebrootInterface' => 'applications/drydock/interface/webroot/DrydockWebrootInterface.php', 'DrydockWorkingCopyBlueprintImplementation' => 'applications/drydock/blueprint/DrydockWorkingCopyBlueprintImplementation.php', 'FeedPublisherHTTPWorker' => 'applications/feed/worker/FeedPublisherHTTPWorker.php', 'FeedPublisherWorker' => 'applications/feed/worker/FeedPublisherWorker.php', 'FeedPushWorker' => 'applications/feed/worker/FeedPushWorker.php', 'FileCreateMailReceiver' => 'applications/files/mail/FileCreateMailReceiver.php', 'FileMailReceiver' => 'applications/files/mail/FileMailReceiver.php', 'FileReplyHandler' => 'applications/files/mail/FileReplyHandler.php', 'HarbormasterBuild' => 'applications/harbormaster/storage/build/HarbormasterBuild.php', 'HarbormasterBuildActionController' => 'applications/harbormaster/controller/HarbormasterBuildActionController.php', 'HarbormasterBuildArtifact' => 'applications/harbormaster/storage/build/HarbormasterBuildArtifact.php', 'HarbormasterBuildArtifactQuery' => 'applications/harbormaster/query/HarbormasterBuildArtifactQuery.php', 'HarbormasterBuildCommand' => 'applications/harbormaster/storage/HarbormasterBuildCommand.php', 'HarbormasterBuildEngine' => 'applications/harbormaster/engine/HarbormasterBuildEngine.php', 'HarbormasterBuildItem' => 'applications/harbormaster/storage/build/HarbormasterBuildItem.php', + 'HarbormasterBuildItemPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildItemPHIDType.php', 'HarbormasterBuildItemQuery' => 'applications/harbormaster/query/HarbormasterBuildItemQuery.php', 'HarbormasterBuildLog' => 'applications/harbormaster/storage/build/HarbormasterBuildLog.php', + 'HarbormasterBuildLogPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php', 'HarbormasterBuildLogQuery' => 'applications/harbormaster/query/HarbormasterBuildLogQuery.php', 'HarbormasterBuildMessage' => 'applications/harbormaster/storage/HarbormasterBuildMessage.php', 'HarbormasterBuildMessageQuery' => 'applications/harbormaster/query/HarbormasterBuildMessageQuery.php', + 'HarbormasterBuildPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPHIDType.php', 'HarbormasterBuildPlan' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php', 'HarbormasterBuildPlanDatasource' => 'applications/harbormaster/typeahead/HarbormasterBuildPlanDatasource.php', 'HarbormasterBuildPlanEditor' => 'applications/harbormaster/editor/HarbormasterBuildPlanEditor.php', + 'HarbormasterBuildPlanPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php', 'HarbormasterBuildPlanQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanQuery.php', 'HarbormasterBuildPlanSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildPlanSearchEngine.php', 'HarbormasterBuildPlanTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransaction.php', 'HarbormasterBuildPlanTransactionComment' => 'applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransactionComment.php', 'HarbormasterBuildPlanTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildPlanTransactionQuery.php', 'HarbormasterBuildQuery' => 'applications/harbormaster/query/HarbormasterBuildQuery.php', 'HarbormasterBuildStep' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStep.php', 'HarbormasterBuildStepCoreCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCoreCustomField.php', 'HarbormasterBuildStepCustomField' => 'applications/harbormaster/customfield/HarbormasterBuildStepCustomField.php', 'HarbormasterBuildStepEditor' => 'applications/harbormaster/editor/HarbormasterBuildStepEditor.php', 'HarbormasterBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterBuildStepImplementation.php', + 'HarbormasterBuildStepPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php', 'HarbormasterBuildStepQuery' => 'applications/harbormaster/query/HarbormasterBuildStepQuery.php', 'HarbormasterBuildStepTransaction' => 'applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php', 'HarbormasterBuildStepTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildStepTransactionQuery.php', 'HarbormasterBuildTarget' => 'applications/harbormaster/storage/build/HarbormasterBuildTarget.php', + 'HarbormasterBuildTargetPHIDType' => 'applications/harbormaster/phid/HarbormasterBuildTargetPHIDType.php', 'HarbormasterBuildTargetQuery' => 'applications/harbormaster/query/HarbormasterBuildTargetQuery.php', 'HarbormasterBuildTransaction' => 'applications/harbormaster/storage/HarbormasterBuildTransaction.php', 'HarbormasterBuildTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildTransactionEditor.php', 'HarbormasterBuildTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildTransactionQuery.php', 'HarbormasterBuildViewController' => 'applications/harbormaster/controller/HarbormasterBuildViewController.php', 'HarbormasterBuildWorker' => 'applications/harbormaster/worker/HarbormasterBuildWorker.php', 'HarbormasterBuildable' => 'applications/harbormaster/storage/HarbormasterBuildable.php', 'HarbormasterBuildableActionController' => 'applications/harbormaster/controller/HarbormasterBuildableActionController.php', 'HarbormasterBuildableInterface' => 'applications/harbormaster/interface/HarbormasterBuildableInterface.php', 'HarbormasterBuildableListController' => 'applications/harbormaster/controller/HarbormasterBuildableListController.php', + 'HarbormasterBuildablePHIDType' => 'applications/harbormaster/phid/HarbormasterBuildablePHIDType.php', 'HarbormasterBuildableQuery' => 'applications/harbormaster/query/HarbormasterBuildableQuery.php', 'HarbormasterBuildableSearchEngine' => 'applications/harbormaster/query/HarbormasterBuildableSearchEngine.php', 'HarbormasterBuildableTransaction' => 'applications/harbormaster/storage/HarbormasterBuildableTransaction.php', 'HarbormasterBuildableTransactionEditor' => 'applications/harbormaster/editor/HarbormasterBuildableTransactionEditor.php', 'HarbormasterBuildableTransactionQuery' => 'applications/harbormaster/query/HarbormasterBuildableTransactionQuery.php', 'HarbormasterBuildableViewController' => 'applications/harbormaster/controller/HarbormasterBuildableViewController.php', 'HarbormasterCapabilityManagePlans' => 'applications/harbormaster/capability/HarbormasterCapabilityManagePlans.php', 'HarbormasterCommandBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterCommandBuildStepImplementation.php', 'HarbormasterController' => 'applications/harbormaster/controller/HarbormasterController.php', 'HarbormasterDAO' => 'applications/harbormaster/storage/HarbormasterDAO.php', 'HarbormasterHTTPRequestBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterHTTPRequestBuildStepImplementation.php', 'HarbormasterLeaseHostBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterLeaseHostBuildStepImplementation.php', 'HarbormasterManagementBuildWorkflow' => 'applications/harbormaster/management/HarbormasterManagementBuildWorkflow.php', 'HarbormasterManagementUpdateWorkflow' => 'applications/harbormaster/management/HarbormasterManagementUpdateWorkflow.php', 'HarbormasterManagementWorkflow' => 'applications/harbormaster/management/HarbormasterManagementWorkflow.php', 'HarbormasterObject' => 'applications/harbormaster/storage/HarbormasterObject.php', - 'HarbormasterPHIDTypeBuild' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php', - 'HarbormasterPHIDTypeBuildItem' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildItem.php', - 'HarbormasterPHIDTypeBuildLog' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildLog.php', - 'HarbormasterPHIDTypeBuildPlan' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildPlan.php', - 'HarbormasterPHIDTypeBuildStep' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildStep.php', - 'HarbormasterPHIDTypeBuildTarget' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildTarget.php', - 'HarbormasterPHIDTypeBuildable' => 'applications/harbormaster/phid/HarbormasterPHIDTypeBuildable.php', 'HarbormasterPlanController' => 'applications/harbormaster/controller/HarbormasterPlanController.php', 'HarbormasterPlanDisableController' => 'applications/harbormaster/controller/HarbormasterPlanDisableController.php', 'HarbormasterPlanEditController' => 'applications/harbormaster/controller/HarbormasterPlanEditController.php', 'HarbormasterPlanListController' => 'applications/harbormaster/controller/HarbormasterPlanListController.php', 'HarbormasterPlanOrderController' => 'applications/harbormaster/controller/HarbormasterPlanOrderController.php', 'HarbormasterPlanRunController' => 'applications/harbormaster/controller/HarbormasterPlanRunController.php', 'HarbormasterPlanViewController' => 'applications/harbormaster/controller/HarbormasterPlanViewController.php', 'HarbormasterPublishFragmentBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterPublishFragmentBuildStepImplementation.php', 'HarbormasterRemarkupRule' => 'applications/harbormaster/remarkup/HarbormasterRemarkupRule.php', 'HarbormasterScratchTable' => 'applications/harbormaster/storage/HarbormasterScratchTable.php', 'HarbormasterSleepBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterSleepBuildStepImplementation.php', 'HarbormasterStepAddController' => 'applications/harbormaster/controller/HarbormasterStepAddController.php', 'HarbormasterStepDeleteController' => 'applications/harbormaster/controller/HarbormasterStepDeleteController.php', 'HarbormasterStepEditController' => 'applications/harbormaster/controller/HarbormasterStepEditController.php', 'HarbormasterTargetWorker' => 'applications/harbormaster/worker/HarbormasterTargetWorker.php', 'HarbormasterThrowExceptionBuildStep' => 'applications/harbormaster/step/HarbormasterThrowExceptionBuildStep.php', 'HarbormasterUIEventListener' => 'applications/harbormaster/event/HarbormasterUIEventListener.php', 'HarbormasterUploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterUploadArtifactBuildStepImplementation.php', 'HarbormasterWaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/HarbormasterWaitForPreviousBuildStepImplementation.php', 'HarbormasterWorker' => 'applications/harbormaster/worker/HarbormasterWorker.php', 'HeraldAction' => 'applications/herald/storage/HeraldAction.php', 'HeraldAdapter' => 'applications/herald/adapter/HeraldAdapter.php', 'HeraldApplyTranscript' => 'applications/herald/storage/transcript/HeraldApplyTranscript.php', 'HeraldCapabilityManageGlobalRules' => 'applications/herald/capability/HeraldCapabilityManageGlobalRules.php', 'HeraldCommitAdapter' => 'applications/herald/adapter/HeraldCommitAdapter.php', 'HeraldCondition' => 'applications/herald/storage/HeraldCondition.php', 'HeraldConditionTranscript' => 'applications/herald/storage/transcript/HeraldConditionTranscript.php', 'HeraldController' => 'applications/herald/controller/HeraldController.php', 'HeraldCustomAction' => 'applications/herald/extension/HeraldCustomAction.php', 'HeraldDAO' => 'applications/herald/storage/HeraldDAO.php', 'HeraldDifferentialRevisionAdapter' => 'applications/herald/adapter/HeraldDifferentialRevisionAdapter.php', 'HeraldDisableController' => 'applications/herald/controller/HeraldDisableController.php', 'HeraldEditLogQuery' => 'applications/herald/query/HeraldEditLogQuery.php', 'HeraldEffect' => 'applications/herald/engine/HeraldEffect.php', 'HeraldEngine' => 'applications/herald/engine/HeraldEngine.php', 'HeraldInvalidActionException' => 'applications/herald/engine/exception/HeraldInvalidActionException.php', 'HeraldInvalidConditionException' => 'applications/herald/engine/exception/HeraldInvalidConditionException.php', 'HeraldInvalidFieldException' => 'applications/herald/engine/exception/HeraldInvalidFieldException.php', 'HeraldManiphestTaskAdapter' => 'applications/herald/adapter/HeraldManiphestTaskAdapter.php', 'HeraldNewController' => 'applications/herald/controller/HeraldNewController.php', 'HeraldObjectTranscript' => 'applications/herald/storage/transcript/HeraldObjectTranscript.php', - 'HeraldPHIDTypeRule' => 'applications/herald/phid/HeraldPHIDTypeRule.php', 'HeraldPholioMockAdapter' => 'applications/herald/adapter/HeraldPholioMockAdapter.php', 'HeraldPreCommitAdapter' => 'applications/diffusion/herald/HeraldPreCommitAdapter.php', 'HeraldPreCommitContentAdapter' => 'applications/diffusion/herald/HeraldPreCommitContentAdapter.php', 'HeraldPreCommitRefAdapter' => 'applications/diffusion/herald/HeraldPreCommitRefAdapter.php', 'HeraldRecursiveConditionsException' => 'applications/herald/engine/exception/HeraldRecursiveConditionsException.php', 'HeraldRemarkupRule' => 'applications/herald/remarkup/HeraldRemarkupRule.php', 'HeraldRepetitionPolicyConfig' => 'applications/herald/config/HeraldRepetitionPolicyConfig.php', 'HeraldRule' => 'applications/herald/storage/HeraldRule.php', 'HeraldRuleController' => 'applications/herald/controller/HeraldRuleController.php', 'HeraldRuleEdit' => 'applications/herald/storage/HeraldRuleEdit.php', 'HeraldRuleEditHistoryController' => 'applications/herald/controller/HeraldRuleEditHistoryController.php', 'HeraldRuleEditHistoryView' => 'applications/herald/view/HeraldRuleEditHistoryView.php', 'HeraldRuleEditor' => 'applications/herald/editor/HeraldRuleEditor.php', 'HeraldRuleListController' => 'applications/herald/controller/HeraldRuleListController.php', + 'HeraldRulePHIDType' => 'applications/herald/phid/HeraldRulePHIDType.php', 'HeraldRuleQuery' => 'applications/herald/query/HeraldRuleQuery.php', 'HeraldRuleSearchEngine' => 'applications/herald/query/HeraldRuleSearchEngine.php', 'HeraldRuleTransaction' => 'applications/herald/storage/HeraldRuleTransaction.php', 'HeraldRuleTransactionComment' => 'applications/herald/storage/HeraldRuleTransactionComment.php', 'HeraldRuleTranscript' => 'applications/herald/storage/transcript/HeraldRuleTranscript.php', 'HeraldRuleTypeConfig' => 'applications/herald/config/HeraldRuleTypeConfig.php', 'HeraldRuleViewController' => 'applications/herald/controller/HeraldRuleViewController.php', 'HeraldTestConsoleController' => 'applications/herald/controller/HeraldTestConsoleController.php', 'HeraldTransactionQuery' => 'applications/herald/query/HeraldTransactionQuery.php', 'HeraldTranscript' => 'applications/herald/storage/transcript/HeraldTranscript.php', 'HeraldTranscriptController' => 'applications/herald/controller/HeraldTranscriptController.php', 'HeraldTranscriptGarbageCollector' => 'applications/herald/garbagecollector/HeraldTranscriptGarbageCollector.php', 'HeraldTranscriptListController' => 'applications/herald/controller/HeraldTranscriptListController.php', 'HeraldTranscriptQuery' => 'applications/herald/query/HeraldTranscriptQuery.php', 'HeraldTranscriptSearchEngine' => 'applications/herald/query/HeraldTranscriptSearchEngine.php', 'HeraldTranscriptTestCase' => 'applications/herald/storage/__tests__/HeraldTranscriptTestCase.php', 'Javelin' => 'infrastructure/javelin/Javelin.php', 'JavelinReactorExample' => 'applications/uiexample/examples/JavelinReactorExample.php', 'JavelinUIExample' => 'applications/uiexample/examples/JavelinUIExample.php', 'JavelinViewExample' => 'applications/uiexample/examples/JavelinViewExample.php', 'JavelinViewExampleServerView' => 'applications/uiexample/examples/JavelinViewExampleServerView.php', 'LegalpadCapabilityCreateDocuments' => 'applications/legalpad/capability/LegalpadCapabilityCreateDocuments.php', 'LegalpadCapabilityDefaultEdit' => 'applications/legalpad/capability/LegalpadCapabilityDefaultEdit.php', 'LegalpadCapabilityDefaultView' => 'applications/legalpad/capability/LegalpadCapabilityDefaultView.php', 'LegalpadConstants' => 'applications/legalpad/constants/LegalpadConstants.php', 'LegalpadController' => 'applications/legalpad/controller/LegalpadController.php', 'LegalpadDAO' => 'applications/legalpad/storage/LegalpadDAO.php', 'LegalpadDocument' => 'applications/legalpad/storage/LegalpadDocument.php', 'LegalpadDocumentBody' => 'applications/legalpad/storage/LegalpadDocumentBody.php', 'LegalpadDocumentCommentController' => 'applications/legalpad/controller/LegalpadDocumentCommentController.php', 'LegalpadDocumentDatasource' => 'applications/legalpad/typeahead/LegalpadDocumentDatasource.php', 'LegalpadDocumentDoneController' => 'applications/legalpad/controller/LegalpadDocumentDoneController.php', 'LegalpadDocumentEditController' => 'applications/legalpad/controller/LegalpadDocumentEditController.php', 'LegalpadDocumentEditor' => 'applications/legalpad/editor/LegalpadDocumentEditor.php', 'LegalpadDocumentListController' => 'applications/legalpad/controller/LegalpadDocumentListController.php', 'LegalpadDocumentManageController' => 'applications/legalpad/controller/LegalpadDocumentManageController.php', 'LegalpadDocumentQuery' => 'applications/legalpad/query/LegalpadDocumentQuery.php', 'LegalpadDocumentRemarkupRule' => 'applications/legalpad/remarkup/LegalpadDocumentRemarkupRule.php', 'LegalpadDocumentSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSearchEngine.php', 'LegalpadDocumentSignController' => 'applications/legalpad/controller/LegalpadDocumentSignController.php', 'LegalpadDocumentSignature' => 'applications/legalpad/storage/LegalpadDocumentSignature.php', 'LegalpadDocumentSignatureAddController' => 'applications/legalpad/controller/LegalpadDocumentSignatureAddController.php', 'LegalpadDocumentSignatureListController' => 'applications/legalpad/controller/LegalpadDocumentSignatureListController.php', 'LegalpadDocumentSignatureQuery' => 'applications/legalpad/query/LegalpadDocumentSignatureQuery.php', 'LegalpadDocumentSignatureSearchEngine' => 'applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php', 'LegalpadDocumentSignatureVerificationController' => 'applications/legalpad/controller/LegalpadDocumentSignatureVerificationController.php', 'LegalpadDocumentSignatureViewController' => 'applications/legalpad/controller/LegalpadDocumentSignatureViewController.php', 'LegalpadMockMailReceiver' => 'applications/legalpad/mail/LegalpadMockMailReceiver.php', 'LegalpadReplyHandler' => 'applications/legalpad/mail/LegalpadReplyHandler.php', 'LegalpadTransaction' => 'applications/legalpad/storage/LegalpadTransaction.php', 'LegalpadTransactionComment' => 'applications/legalpad/storage/LegalpadTransactionComment.php', 'LegalpadTransactionQuery' => 'applications/legalpad/query/LegalpadTransactionQuery.php', 'LegalpadTransactionType' => 'applications/legalpad/constants/LegalpadTransactionType.php', 'LegalpadTransactionView' => 'applications/legalpad/view/LegalpadTransactionView.php', 'LiskChunkTestCase' => 'infrastructure/storage/lisk/__tests__/LiskChunkTestCase.php', 'LiskDAO' => 'infrastructure/storage/lisk/LiskDAO.php', 'LiskDAOSet' => 'infrastructure/storage/lisk/LiskDAOSet.php', 'LiskDAOTestCase' => 'infrastructure/storage/lisk/__tests__/LiskDAOTestCase.php', 'LiskEphemeralObjectException' => 'infrastructure/storage/lisk/LiskEphemeralObjectException.php', 'LiskFixtureTestCase' => 'infrastructure/storage/lisk/__tests__/LiskFixtureTestCase.php', 'LiskIsolationTestCase' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestCase.php', 'LiskIsolationTestDAO' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestDAO.php', 'LiskIsolationTestDAOException' => 'infrastructure/storage/lisk/__tests__/LiskIsolationTestDAOException.php', 'LiskMigrationIterator' => 'infrastructure/storage/lisk/LiskMigrationIterator.php', 'LiskRawMigrationIterator' => 'infrastructure/storage/lisk/LiskRawMigrationIterator.php', 'ManiphestActionMenuEventListener' => 'applications/maniphest/event/ManiphestActionMenuEventListener.php', 'ManiphestBatchEditController' => 'applications/maniphest/controller/ManiphestBatchEditController.php', 'ManiphestCapabilityBulkEdit' => 'applications/maniphest/capability/ManiphestCapabilityBulkEdit.php', 'ManiphestCapabilityDefaultEdit' => 'applications/maniphest/capability/ManiphestCapabilityDefaultEdit.php', 'ManiphestCapabilityDefaultView' => 'applications/maniphest/capability/ManiphestCapabilityDefaultView.php', 'ManiphestCapabilityEditAssign' => 'applications/maniphest/capability/ManiphestCapabilityEditAssign.php', 'ManiphestCapabilityEditPolicies' => 'applications/maniphest/capability/ManiphestCapabilityEditPolicies.php', 'ManiphestCapabilityEditPriority' => 'applications/maniphest/capability/ManiphestCapabilityEditPriority.php', 'ManiphestCapabilityEditProjects' => 'applications/maniphest/capability/ManiphestCapabilityEditProjects.php', 'ManiphestCapabilityEditStatus' => 'applications/maniphest/capability/ManiphestCapabilityEditStatus.php', 'ManiphestConfiguredCustomField' => 'applications/maniphest/field/ManiphestConfiguredCustomField.php', 'ManiphestConstants' => 'applications/maniphest/constants/ManiphestConstants.php', 'ManiphestController' => 'applications/maniphest/controller/ManiphestController.php', 'ManiphestCreateMailReceiver' => 'applications/maniphest/mail/ManiphestCreateMailReceiver.php', 'ManiphestCustomField' => 'applications/maniphest/field/ManiphestCustomField.php', 'ManiphestCustomFieldNumericIndex' => 'applications/maniphest/storage/ManiphestCustomFieldNumericIndex.php', 'ManiphestCustomFieldStatusParser' => 'applications/maniphest/field/parser/ManiphestCustomFieldStatusParser.php', 'ManiphestCustomFieldStatusParserTestCase' => 'applications/maniphest/field/parser/__tests__/ManiphestCustomFieldStatusParserTestCase.php', 'ManiphestCustomFieldStorage' => 'applications/maniphest/storage/ManiphestCustomFieldStorage.php', 'ManiphestCustomFieldStringIndex' => 'applications/maniphest/storage/ManiphestCustomFieldStringIndex.php', 'ManiphestDAO' => 'applications/maniphest/storage/ManiphestDAO.php', 'ManiphestExcelDefaultFormat' => 'applications/maniphest/export/ManiphestExcelDefaultFormat.php', 'ManiphestExcelFormat' => 'applications/maniphest/export/ManiphestExcelFormat.php', 'ManiphestExportController' => 'applications/maniphest/controller/ManiphestExportController.php', 'ManiphestHovercardEventListener' => 'applications/maniphest/event/ManiphestHovercardEventListener.php', 'ManiphestNameIndex' => 'applications/maniphest/storage/ManiphestNameIndex.php', 'ManiphestNameIndexEventListener' => 'applications/maniphest/event/ManiphestNameIndexEventListener.php', - 'ManiphestPHIDTypeTask' => 'applications/maniphest/phid/ManiphestPHIDTypeTask.php', 'ManiphestRemarkupRule' => 'applications/maniphest/remarkup/ManiphestRemarkupRule.php', 'ManiphestReplyHandler' => 'applications/maniphest/mail/ManiphestReplyHandler.php', 'ManiphestReportController' => 'applications/maniphest/controller/ManiphestReportController.php', 'ManiphestSearchIndexer' => 'applications/maniphest/search/ManiphestSearchIndexer.php', 'ManiphestStatusConfigOptionType' => 'applications/maniphest/config/ManiphestStatusConfigOptionType.php', 'ManiphestSubpriorityController' => 'applications/maniphest/controller/ManiphestSubpriorityController.php', 'ManiphestSubscribeController' => 'applications/maniphest/controller/ManiphestSubscribeController.php', 'ManiphestTask' => 'applications/maniphest/storage/ManiphestTask.php', 'ManiphestTaskDescriptionPreviewController' => 'applications/maniphest/controller/ManiphestTaskDescriptionPreviewController.php', 'ManiphestTaskDetailController' => 'applications/maniphest/controller/ManiphestTaskDetailController.php', 'ManiphestTaskEditController' => 'applications/maniphest/controller/ManiphestTaskEditController.php', 'ManiphestTaskHasCommitEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasCommitEdgeType.php', 'ManiphestTaskHasRevisionEdgeType' => 'applications/maniphest/edge/ManiphestTaskHasRevisionEdgeType.php', 'ManiphestTaskListController' => 'applications/maniphest/controller/ManiphestTaskListController.php', 'ManiphestTaskListView' => 'applications/maniphest/view/ManiphestTaskListView.php', 'ManiphestTaskMailReceiver' => 'applications/maniphest/mail/ManiphestTaskMailReceiver.php', 'ManiphestTaskOwner' => 'applications/maniphest/constants/ManiphestTaskOwner.php', + 'ManiphestTaskPHIDType' => 'applications/maniphest/phid/ManiphestTaskPHIDType.php', 'ManiphestTaskPriority' => 'applications/maniphest/constants/ManiphestTaskPriority.php', 'ManiphestTaskPriorityDatasource' => 'applications/maniphest/typeahead/ManiphestTaskPriorityDatasource.php', 'ManiphestTaskQuery' => 'applications/maniphest/query/ManiphestTaskQuery.php', 'ManiphestTaskResultListView' => 'applications/maniphest/view/ManiphestTaskResultListView.php', 'ManiphestTaskSearchEngine' => 'applications/maniphest/query/ManiphestTaskSearchEngine.php', 'ManiphestTaskStatus' => 'applications/maniphest/constants/ManiphestTaskStatus.php', 'ManiphestTaskStatusTestCase' => 'applications/maniphest/constants/__tests__/ManiphestTaskStatusTestCase.php', 'ManiphestTaskSubscriber' => 'applications/maniphest/storage/ManiphestTaskSubscriber.php', 'ManiphestTransaction' => 'applications/maniphest/storage/ManiphestTransaction.php', 'ManiphestTransactionComment' => 'applications/maniphest/storage/ManiphestTransactionComment.php', 'ManiphestTransactionEditor' => 'applications/maniphest/editor/ManiphestTransactionEditor.php', 'ManiphestTransactionPreviewController' => 'applications/maniphest/controller/ManiphestTransactionPreviewController.php', 'ManiphestTransactionQuery' => 'applications/maniphest/query/ManiphestTransactionQuery.php', 'ManiphestTransactionSaveController' => 'applications/maniphest/controller/ManiphestTransactionSaveController.php', 'ManiphestView' => 'applications/maniphest/view/ManiphestView.php', 'MetaMTAConstants' => 'applications/metamta/constants/MetaMTAConstants.php', 'MetaMTAMailReceivedGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailReceivedGarbageCollector.php', 'MetaMTAMailSentGarbageCollector' => 'applications/metamta/garbagecollector/MetaMTAMailSentGarbageCollector.php', 'MetaMTANotificationType' => 'applications/metamta/constants/MetaMTANotificationType.php', 'MetaMTAReceivedMailStatus' => 'applications/metamta/constants/MetaMTAReceivedMailStatus.php', 'NuanceCapabilitySourceDefaultEdit' => 'applications/nuance/capability/NuanceCapabilitySourceDefaultEdit.php', 'NuanceCapabilitySourceDefaultView' => 'applications/nuance/capability/NuanceCapabilitySourceDefaultView.php', 'NuanceCapabilitySourceManage' => 'applications/nuance/capability/NuanceCapabilitySourceManage.php', 'NuanceConstants' => 'applications/nuance/constants/NuanceConstants.php', 'NuanceController' => 'applications/nuance/controller/NuanceController.php', 'NuanceDAO' => 'applications/nuance/storage/NuanceDAO.php', 'NuanceItem' => 'applications/nuance/storage/NuanceItem.php', 'NuanceItemEditController' => 'applications/nuance/controller/NuanceItemEditController.php', 'NuanceItemEditor' => 'applications/nuance/editor/NuanceItemEditor.php', + 'NuanceItemPHIDType' => 'applications/nuance/phid/NuanceItemPHIDType.php', 'NuanceItemQuery' => 'applications/nuance/query/NuanceItemQuery.php', 'NuanceItemTransaction' => 'applications/nuance/storage/NuanceItemTransaction.php', 'NuanceItemTransactionComment' => 'applications/nuance/storage/NuanceItemTransactionComment.php', 'NuanceItemTransactionQuery' => 'applications/nuance/query/NuanceItemTransactionQuery.php', 'NuanceItemViewController' => 'applications/nuance/controller/NuanceItemViewController.php', - 'NuancePHIDTypeItem' => 'applications/nuance/phid/NuancePHIDTypeItem.php', - 'NuancePHIDTypeQueue' => 'applications/nuance/phid/NuancePHIDTypeQueue.php', - 'NuancePHIDTypeRequestor' => 'applications/nuance/phid/NuancePHIDTypeRequestor.php', - 'NuancePHIDTypeSource' => 'applications/nuance/phid/NuancePHIDTypeSource.php', 'NuancePhabricatorFormSourceDefinition' => 'applications/nuance/source/NuancePhabricatorFormSourceDefinition.php', 'NuanceQuery' => 'applications/nuance/query/NuanceQuery.php', 'NuanceQueue' => 'applications/nuance/storage/NuanceQueue.php', 'NuanceQueueEditController' => 'applications/nuance/controller/NuanceQueueEditController.php', 'NuanceQueueEditor' => 'applications/nuance/editor/NuanceQueueEditor.php', 'NuanceQueueItem' => 'applications/nuance/storage/NuanceQueueItem.php', + 'NuanceQueuePHIDType' => 'applications/nuance/phid/NuanceQueuePHIDType.php', 'NuanceQueueQuery' => 'applications/nuance/query/NuanceQueueQuery.php', 'NuanceQueueTransaction' => 'applications/nuance/storage/NuanceQueueTransaction.php', 'NuanceQueueTransactionComment' => 'applications/nuance/storage/NuanceQueueTransactionComment.php', 'NuanceQueueTransactionQuery' => 'applications/nuance/query/NuanceQueueTransactionQuery.php', 'NuanceQueueViewController' => 'applications/nuance/controller/NuanceQueueViewController.php', 'NuanceRequestor' => 'applications/nuance/storage/NuanceRequestor.php', 'NuanceRequestorEditController' => 'applications/nuance/controller/NuanceRequestorEditController.php', 'NuanceRequestorEditor' => 'applications/nuance/editor/NuanceRequestorEditor.php', + 'NuanceRequestorPHIDType' => 'applications/nuance/phid/NuanceRequestorPHIDType.php', 'NuanceRequestorQuery' => 'applications/nuance/query/NuanceRequestorQuery.php', 'NuanceRequestorSource' => 'applications/nuance/storage/NuanceRequestorSource.php', 'NuanceRequestorTransaction' => 'applications/nuance/storage/NuanceRequestorTransaction.php', 'NuanceRequestorTransactionComment' => 'applications/nuance/storage/NuanceRequestorTransactionComment.php', 'NuanceRequestorTransactionQuery' => 'applications/nuance/query/NuanceRequestorTransactionQuery.php', 'NuanceRequestorViewController' => 'applications/nuance/controller/NuanceRequestorViewController.php', 'NuanceSource' => 'applications/nuance/storage/NuanceSource.php', 'NuanceSourceDefinition' => 'applications/nuance/source/NuanceSourceDefinition.php', 'NuanceSourceEditController' => 'applications/nuance/controller/NuanceSourceEditController.php', 'NuanceSourceEditor' => 'applications/nuance/editor/NuanceSourceEditor.php', + 'NuanceSourcePHIDType' => 'applications/nuance/phid/NuanceSourcePHIDType.php', 'NuanceSourceQuery' => 'applications/nuance/query/NuanceSourceQuery.php', 'NuanceSourceTransaction' => 'applications/nuance/storage/NuanceSourceTransaction.php', 'NuanceSourceTransactionComment' => 'applications/nuance/storage/NuanceSourceTransactionComment.php', 'NuanceSourceTransactionQuery' => 'applications/nuance/query/NuanceSourceTransactionQuery.php', 'NuanceSourceViewController' => 'applications/nuance/controller/NuanceSourceViewController.php', 'NuanceTransaction' => 'applications/nuance/storage/NuanceTransaction.php', 'OwnersPackageReplyHandler' => 'applications/owners/mail/OwnersPackageReplyHandler.php', 'PHUI' => 'view/phui/PHUI.php', 'PHUIActionHeaderExample' => 'applications/uiexample/examples/PHUIActionHeaderExample.php', 'PHUIActionHeaderView' => 'view/phui/PHUIActionHeaderView.php', 'PHUIBoxExample' => 'applications/uiexample/examples/PHUIBoxExample.php', 'PHUIBoxView' => 'view/phui/PHUIBoxView.php', 'PHUIButtonBarExample' => 'applications/uiexample/examples/PHUIButtonBarExample.php', 'PHUIButtonBarView' => 'view/phui/PHUIButtonBarView.php', 'PHUIButtonExample' => 'applications/uiexample/examples/PHUIButtonExample.php', 'PHUIButtonView' => 'view/phui/PHUIButtonView.php', 'PHUICalendarListView' => 'view/phui/calendar/PHUICalendarListView.php', 'PHUICalendarMonthView' => 'view/phui/calendar/PHUICalendarMonthView.php', 'PHUICalendarWidgetView' => 'view/phui/calendar/PHUICalendarWidgetView.php', 'PHUIColorPalletteExample' => 'applications/uiexample/examples/PHUIColorPalletteExample.php', 'PHUIDocumentExample' => 'applications/uiexample/examples/PHUIDocumentExample.php', 'PHUIDocumentView' => 'view/phui/PHUIDocumentView.php', 'PHUIFeedStoryExample' => 'applications/uiexample/examples/PHUIFeedStoryExample.php', 'PHUIFeedStoryView' => 'view/phui/PHUIFeedStoryView.php', 'PHUIFormDividerControl' => 'view/form/control/PHUIFormDividerControl.php', 'PHUIFormFreeformDateControl' => 'view/form/control/PHUIFormFreeformDateControl.php', 'PHUIFormLayoutView' => 'view/form/PHUIFormLayoutView.php', 'PHUIFormMultiSubmitControl' => 'view/form/control/PHUIFormMultiSubmitControl.php', 'PHUIFormPageView' => 'view/form/PHUIFormPageView.php', 'PHUIHandleTagListView' => 'applications/phid/view/PHUIHandleTagListView.php', 'PHUIHeaderView' => 'view/phui/PHUIHeaderView.php', 'PHUIIconExample' => 'applications/uiexample/examples/PHUIIconExample.php', 'PHUIIconView' => 'view/phui/PHUIIconView.php', 'PHUIImageMaskExample' => 'applications/uiexample/examples/PHUIImageMaskExample.php', 'PHUIImageMaskView' => 'view/phui/PHUIImageMaskView.php', 'PHUIInfoPanelExample' => 'applications/uiexample/examples/PHUIInfoPanelExample.php', 'PHUIInfoPanelView' => 'view/phui/PHUIInfoPanelView.php', 'PHUIListExample' => 'applications/uiexample/examples/PHUIListExample.php', 'PHUIListItemView' => 'view/phui/PHUIListItemView.php', 'PHUIListView' => 'view/phui/PHUIListView.php', 'PHUIListViewTestCase' => 'view/layout/__tests__/PHUIListViewTestCase.php', 'PHUIObjectBoxView' => 'view/phui/PHUIObjectBoxView.php', 'PHUIObjectItemListExample' => 'applications/uiexample/examples/PHUIObjectItemListExample.php', 'PHUIObjectItemListView' => 'view/phui/PHUIObjectItemListView.php', 'PHUIObjectItemView' => 'view/phui/PHUIObjectItemView.php', 'PHUIPagedFormView' => 'view/form/PHUIPagedFormView.php', 'PHUIPinboardItemView' => 'view/phui/PHUIPinboardItemView.php', 'PHUIPinboardView' => 'view/phui/PHUIPinboardView.php', 'PHUIPropertyGroupView' => 'view/phui/PHUIPropertyGroupView.php', 'PHUIPropertyListExample' => 'applications/uiexample/examples/PHUIPropertyListExample.php', 'PHUIPropertyListView' => 'view/phui/PHUIPropertyListView.php', 'PHUIRemarkupPreviewPanel' => 'view/phui/PHUIRemarkupPreviewPanel.php', 'PHUIStatusItemView' => 'view/phui/PHUIStatusItemView.php', 'PHUIStatusListView' => 'view/phui/PHUIStatusListView.php', 'PHUITagExample' => 'applications/uiexample/examples/PHUITagExample.php', 'PHUITagView' => 'view/phui/PHUITagView.php', 'PHUITextExample' => 'applications/uiexample/examples/PHUITextExample.php', 'PHUITextView' => 'view/phui/PHUITextView.php', 'PHUITimelineEventView' => 'view/phui/PHUITimelineEventView.php', 'PHUITimelineExample' => 'applications/uiexample/examples/PHUITimelineExample.php', 'PHUITimelineView' => 'view/phui/PHUITimelineView.php', 'PHUIWorkboardView' => 'view/phui/PHUIWorkboardView.php', 'PHUIWorkpanelView' => 'view/phui/PHUIWorkpanelView.php', 'PackageCreateMail' => 'applications/owners/mail/PackageCreateMail.php', 'PackageDeleteMail' => 'applications/owners/mail/PackageDeleteMail.php', 'PackageMail' => 'applications/owners/mail/PackageMail.php', 'PackageModifyMail' => 'applications/owners/mail/PackageModifyMail.php', 'PassphraseAbstractKey' => 'applications/passphrase/keys/PassphraseAbstractKey.php', 'PassphraseController' => 'applications/passphrase/controller/PassphraseController.php', 'PassphraseCredential' => 'applications/passphrase/storage/PassphraseCredential.php', 'PassphraseCredentialControl' => 'applications/passphrase/view/PassphraseCredentialControl.php', 'PassphraseCredentialCreateController' => 'applications/passphrase/controller/PassphraseCredentialCreateController.php', 'PassphraseCredentialDestroyController' => 'applications/passphrase/controller/PassphraseCredentialDestroyController.php', 'PassphraseCredentialEditController' => 'applications/passphrase/controller/PassphraseCredentialEditController.php', 'PassphraseCredentialListController' => 'applications/passphrase/controller/PassphraseCredentialListController.php', 'PassphraseCredentialLockController' => 'applications/passphrase/controller/PassphraseCredentialLockController.php', + 'PassphraseCredentialPHIDType' => 'applications/passphrase/phid/PassphraseCredentialPHIDType.php', 'PassphraseCredentialPublicController' => 'applications/passphrase/controller/PassphraseCredentialPublicController.php', 'PassphraseCredentialQuery' => 'applications/passphrase/query/PassphraseCredentialQuery.php', 'PassphraseCredentialRevealController' => 'applications/passphrase/controller/PassphraseCredentialRevealController.php', 'PassphraseCredentialSearchEngine' => 'applications/passphrase/query/PassphraseCredentialSearchEngine.php', 'PassphraseCredentialTransaction' => 'applications/passphrase/storage/PassphraseCredentialTransaction.php', 'PassphraseCredentialTransactionEditor' => 'applications/passphrase/editor/PassphraseCredentialTransactionEditor.php', 'PassphraseCredentialTransactionQuery' => 'applications/passphrase/query/PassphraseCredentialTransactionQuery.php', 'PassphraseCredentialType' => 'applications/passphrase/credentialtype/PassphraseCredentialType.php', 'PassphraseCredentialTypePassword' => 'applications/passphrase/credentialtype/PassphraseCredentialTypePassword.php', 'PassphraseCredentialTypeSSHGeneratedKey' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHGeneratedKey.php', 'PassphraseCredentialTypeSSHPrivateKey' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKey.php', 'PassphraseCredentialTypeSSHPrivateKeyFile' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyFile.php', 'PassphraseCredentialTypeSSHPrivateKeyText' => 'applications/passphrase/credentialtype/PassphraseCredentialTypeSSHPrivateKeyText.php', 'PassphraseCredentialViewController' => 'applications/passphrase/controller/PassphraseCredentialViewController.php', 'PassphraseDAO' => 'applications/passphrase/storage/PassphraseDAO.php', - 'PassphrasePHIDTypeCredential' => 'applications/passphrase/phid/PassphrasePHIDTypeCredential.php', 'PassphrasePasswordKey' => 'applications/passphrase/keys/PassphrasePasswordKey.php', 'PassphraseRemarkupRule' => 'applications/passphrase/remarkup/PassphraseRemarkupRule.php', 'PassphraseSSHKey' => 'applications/passphrase/keys/PassphraseSSHKey.php', 'PassphraseSecret' => 'applications/passphrase/storage/PassphraseSecret.php', 'PasteCapabilityDefaultView' => 'applications/paste/capability/PasteCapabilityDefaultView.php', 'PasteCreateMailReceiver' => 'applications/paste/mail/PasteCreateMailReceiver.php', 'PasteEmbedView' => 'applications/paste/view/PasteEmbedView.php', 'PasteMockMailReceiver' => 'applications/paste/mail/PasteMockMailReceiver.php', 'PasteReplyHandler' => 'applications/paste/mail/PasteReplyHandler.php', 'PeopleCapabilityBrowseUserDirectory' => 'applications/people/capability/PeopleCapabilityBrowseUserDirectory.php', 'PeopleUserLogGarbageCollector' => 'applications/people/garbagecollector/PeopleUserLogGarbageCollector.php', 'Phabricator404Controller' => 'applications/base/controller/Phabricator404Controller.php', 'PhabricatorAWSConfigOptions' => 'applications/config/option/PhabricatorAWSConfigOptions.php', 'PhabricatorAccessControlTestCase' => 'applications/base/controller/__tests__/PhabricatorAccessControlTestCase.php', 'PhabricatorAccessLog' => 'infrastructure/log/PhabricatorAccessLog.php', 'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php', 'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php', 'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php', 'PhabricatorAllCapsTranslation' => 'infrastructure/internationalization/translation/PhabricatorAllCapsTranslation.php', 'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php', 'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php', 'PhabricatorAphlictManagementBuildWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php', 'PhabricatorAphlictManagementDebugWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php', 'PhabricatorAphlictManagementRestartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php', 'PhabricatorAphlictManagementStartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php', 'PhabricatorAphlictManagementStatusWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStatusWorkflow.php', 'PhabricatorAphlictManagementStopWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStopWorkflow.php', 'PhabricatorAphlictManagementWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php', 'PhabricatorAphrontBarExample' => 'applications/uiexample/examples/PhabricatorAphrontBarExample.php', 'PhabricatorAphrontViewTestCase' => 'view/__tests__/PhabricatorAphrontViewTestCase.php', 'PhabricatorAppSearchEngine' => 'applications/meta/query/PhabricatorAppSearchEngine.php', 'PhabricatorApplication' => 'applications/base/PhabricatorApplication.php', + 'PhabricatorApplicationApplicationPHIDType' => 'applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php', 'PhabricatorApplicationConfigOptions' => 'applications/config/option/PhabricatorApplicationConfigOptions.php', 'PhabricatorApplicationDatasource' => 'applications/meta/typeahead/PhabricatorApplicationDatasource.php', 'PhabricatorApplicationDetailViewController' => 'applications/meta/controller/PhabricatorApplicationDetailViewController.php', 'PhabricatorApplicationEditController' => 'applications/meta/controller/PhabricatorApplicationEditController.php', 'PhabricatorApplicationLaunchView' => 'applications/meta/view/PhabricatorApplicationLaunchView.php', - 'PhabricatorApplicationPHIDTypeApplication' => 'applications/meta/phid/PhabricatorApplicationPHIDTypeApplication.php', 'PhabricatorApplicationQuery' => 'applications/meta/query/PhabricatorApplicationQuery.php', 'PhabricatorApplicationSearchController' => 'applications/search/controller/PhabricatorApplicationSearchController.php', 'PhabricatorApplicationSearchEngine' => 'applications/search/engine/PhabricatorApplicationSearchEngine.php', 'PhabricatorApplicationSearchResultsControllerInterface' => 'applications/search/interface/PhabricatorApplicationSearchResultsControllerInterface.php', 'PhabricatorApplicationStatusView' => 'applications/meta/view/PhabricatorApplicationStatusView.php', 'PhabricatorApplicationTransaction' => 'applications/transactions/storage/PhabricatorApplicationTransaction.php', 'PhabricatorApplicationTransactionComment' => 'applications/transactions/storage/PhabricatorApplicationTransactionComment.php', 'PhabricatorApplicationTransactionCommentEditController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentEditController.php', 'PhabricatorApplicationTransactionCommentEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionCommentEditor.php', 'PhabricatorApplicationTransactionCommentHistoryController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentHistoryController.php', 'PhabricatorApplicationTransactionCommentQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionCommentQuery.php', 'PhabricatorApplicationTransactionCommentQuoteController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentQuoteController.php', 'PhabricatorApplicationTransactionCommentRemoveController' => 'applications/transactions/controller/PhabricatorApplicationTransactionCommentRemoveController.php', 'PhabricatorApplicationTransactionCommentView' => 'applications/transactions/view/PhabricatorApplicationTransactionCommentView.php', 'PhabricatorApplicationTransactionController' => 'applications/transactions/controller/PhabricatorApplicationTransactionController.php', 'PhabricatorApplicationTransactionDetailController' => 'applications/transactions/controller/PhabricatorApplicationTransactionDetailController.php', 'PhabricatorApplicationTransactionEditor' => 'applications/transactions/editor/PhabricatorApplicationTransactionEditor.php', 'PhabricatorApplicationTransactionFeedStory' => 'applications/transactions/feed/PhabricatorApplicationTransactionFeedStory.php', 'PhabricatorApplicationTransactionInterface' => 'applications/transactions/interface/PhabricatorApplicationTransactionInterface.php', 'PhabricatorApplicationTransactionNoEffectException' => 'applications/transactions/exception/PhabricatorApplicationTransactionNoEffectException.php', 'PhabricatorApplicationTransactionNoEffectResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionNoEffectResponse.php', - 'PhabricatorApplicationTransactionPHIDTypeTransaction' => 'applications/transactions/phid/PhabricatorApplicationTransactionPHIDTypeTransaction.php', 'PhabricatorApplicationTransactionQuery' => 'applications/transactions/query/PhabricatorApplicationTransactionQuery.php', 'PhabricatorApplicationTransactionResponse' => 'applications/transactions/response/PhabricatorApplicationTransactionResponse.php', 'PhabricatorApplicationTransactionStructureException' => 'applications/transactions/exception/PhabricatorApplicationTransactionStructureException.php', 'PhabricatorApplicationTransactionTextDiffDetailView' => 'applications/transactions/view/PhabricatorApplicationTransactionTextDiffDetailView.php', + 'PhabricatorApplicationTransactionTransactionPHIDType' => 'applications/transactions/phid/PhabricatorApplicationTransactionTransactionPHIDType.php', 'PhabricatorApplicationTransactionValidationError' => 'applications/transactions/error/PhabricatorApplicationTransactionValidationError.php', 'PhabricatorApplicationTransactionValidationException' => 'applications/transactions/exception/PhabricatorApplicationTransactionValidationException.php', 'PhabricatorApplicationTransactionValueController' => 'applications/transactions/controller/PhabricatorApplicationTransactionValueController.php', 'PhabricatorApplicationTransactionView' => 'applications/transactions/view/PhabricatorApplicationTransactionView.php', 'PhabricatorApplicationUninstallController' => 'applications/meta/controller/PhabricatorApplicationUninstallController.php', 'PhabricatorApplicationsApplication' => 'applications/meta/application/PhabricatorApplicationsApplication.php', 'PhabricatorApplicationsController' => 'applications/meta/controller/PhabricatorApplicationsController.php', 'PhabricatorApplicationsListController' => 'applications/meta/controller/PhabricatorApplicationsListController.php', 'PhabricatorAsanaAuthProvider' => 'applications/auth/provider/PhabricatorAsanaAuthProvider.php', 'PhabricatorAsanaConfigOptions' => 'applications/doorkeeper/option/PhabricatorAsanaConfigOptions.php', 'PhabricatorAuditActionConstants' => 'applications/audit/constants/PhabricatorAuditActionConstants.php', 'PhabricatorAuditAddCommentController' => 'applications/audit/controller/PhabricatorAuditAddCommentController.php', 'PhabricatorAuditApplication' => 'applications/audit/application/PhabricatorAuditApplication.php', 'PhabricatorAuditComment' => 'applications/audit/storage/PhabricatorAuditComment.php', 'PhabricatorAuditCommentEditor' => 'applications/audit/editor/PhabricatorAuditCommentEditor.php', 'PhabricatorAuditCommitStatusConstants' => 'applications/audit/constants/PhabricatorAuditCommitStatusConstants.php', 'PhabricatorAuditController' => 'applications/audit/controller/PhabricatorAuditController.php', 'PhabricatorAuditDAO' => 'applications/audit/storage/PhabricatorAuditDAO.php', 'PhabricatorAuditInlineComment' => 'applications/audit/storage/PhabricatorAuditInlineComment.php', 'PhabricatorAuditListController' => 'applications/audit/controller/PhabricatorAuditListController.php', 'PhabricatorAuditListView' => 'applications/audit/view/PhabricatorAuditListView.php', 'PhabricatorAuditMailReceiver' => 'applications/audit/mail/PhabricatorAuditMailReceiver.php', 'PhabricatorAuditManagementDeleteWorkflow' => 'applications/audit/management/PhabricatorAuditManagementDeleteWorkflow.php', 'PhabricatorAuditManagementWorkflow' => 'applications/audit/management/PhabricatorAuditManagementWorkflow.php', 'PhabricatorAuditPreviewController' => 'applications/audit/controller/PhabricatorAuditPreviewController.php', 'PhabricatorAuditReplyHandler' => 'applications/audit/mail/PhabricatorAuditReplyHandler.php', 'PhabricatorAuditStatusConstants' => 'applications/audit/constants/PhabricatorAuditStatusConstants.php', 'PhabricatorAuthAccountView' => 'applications/auth/view/PhabricatorAuthAccountView.php', 'PhabricatorAuthApplication' => 'applications/auth/application/PhabricatorAuthApplication.php', + 'PhabricatorAuthAuthFactorPHIDType' => 'applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php', 'PhabricatorAuthConfirmLinkController' => 'applications/auth/controller/PhabricatorAuthConfirmLinkController.php', 'PhabricatorAuthController' => 'applications/auth/controller/PhabricatorAuthController.php', 'PhabricatorAuthDAO' => 'applications/auth/storage/PhabricatorAuthDAO.php', 'PhabricatorAuthDisableController' => 'applications/auth/controller/config/PhabricatorAuthDisableController.php', 'PhabricatorAuthDowngradeSessionController' => 'applications/auth/controller/PhabricatorAuthDowngradeSessionController.php', 'PhabricatorAuthEditController' => 'applications/auth/controller/config/PhabricatorAuthEditController.php', 'PhabricatorAuthFactor' => 'applications/auth/factor/PhabricatorAuthFactor.php', 'PhabricatorAuthFactorConfig' => 'applications/auth/storage/PhabricatorAuthFactorConfig.php', 'PhabricatorAuthFactorTOTP' => 'applications/auth/factor/PhabricatorAuthFactorTOTP.php', 'PhabricatorAuthFactorTOTPTestCase' => 'applications/auth/factor/__tests__/PhabricatorAuthFactorTOTPTestCase.php', 'PhabricatorAuthFinishController' => 'applications/auth/controller/PhabricatorAuthFinishController.php', 'PhabricatorAuthHighSecurityRequiredException' => 'applications/auth/exception/PhabricatorAuthHighSecurityRequiredException.php', 'PhabricatorAuthHighSecurityToken' => 'applications/auth/data/PhabricatorAuthHighSecurityToken.php', 'PhabricatorAuthLinkController' => 'applications/auth/controller/PhabricatorAuthLinkController.php', 'PhabricatorAuthListController' => 'applications/auth/controller/config/PhabricatorAuthListController.php', 'PhabricatorAuthLoginController' => 'applications/auth/controller/PhabricatorAuthLoginController.php', 'PhabricatorAuthManagementLDAPWorkflow' => 'applications/auth/management/PhabricatorAuthManagementLDAPWorkflow.php', 'PhabricatorAuthManagementListFactorsWorkflow' => 'applications/auth/management/PhabricatorAuthManagementListFactorsWorkflow.php', 'PhabricatorAuthManagementRecoverWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRecoverWorkflow.php', 'PhabricatorAuthManagementRefreshWorkflow' => 'applications/auth/management/PhabricatorAuthManagementRefreshWorkflow.php', 'PhabricatorAuthManagementStripWorkflow' => 'applications/auth/management/PhabricatorAuthManagementStripWorkflow.php', 'PhabricatorAuthManagementWorkflow' => 'applications/auth/management/PhabricatorAuthManagementWorkflow.php', 'PhabricatorAuthNeedsApprovalController' => 'applications/auth/controller/PhabricatorAuthNeedsApprovalController.php', 'PhabricatorAuthNeedsMultiFactorController' => 'applications/auth/controller/PhabricatorAuthNeedsMultiFactorController.php', 'PhabricatorAuthNewController' => 'applications/auth/controller/config/PhabricatorAuthNewController.php', 'PhabricatorAuthOldOAuthRedirectController' => 'applications/auth/controller/PhabricatorAuthOldOAuthRedirectController.php', 'PhabricatorAuthOneTimeLoginController' => 'applications/auth/controller/PhabricatorAuthOneTimeLoginController.php', - 'PhabricatorAuthPHIDTypeAuthFactor' => 'applications/auth/phid/PhabricatorAuthPHIDTypeAuthFactor.php', 'PhabricatorAuthProvider' => 'applications/auth/provider/PhabricatorAuthProvider.php', 'PhabricatorAuthProviderConfig' => 'applications/auth/storage/PhabricatorAuthProviderConfig.php', 'PhabricatorAuthProviderConfigController' => 'applications/auth/controller/config/PhabricatorAuthProviderConfigController.php', 'PhabricatorAuthProviderConfigEditor' => 'applications/auth/editor/PhabricatorAuthProviderConfigEditor.php', 'PhabricatorAuthProviderConfigQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigQuery.php', 'PhabricatorAuthProviderConfigTransaction' => 'applications/auth/storage/PhabricatorAuthProviderConfigTransaction.php', 'PhabricatorAuthProviderConfigTransactionQuery' => 'applications/auth/query/PhabricatorAuthProviderConfigTransactionQuery.php', 'PhabricatorAuthRegisterController' => 'applications/auth/controller/PhabricatorAuthRegisterController.php', 'PhabricatorAuthSession' => 'applications/auth/storage/PhabricatorAuthSession.php', 'PhabricatorAuthSessionEngine' => 'applications/auth/engine/PhabricatorAuthSessionEngine.php', 'PhabricatorAuthSessionGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthSessionGarbageCollector.php', 'PhabricatorAuthSessionQuery' => 'applications/auth/query/PhabricatorAuthSessionQuery.php', 'PhabricatorAuthStartController' => 'applications/auth/controller/PhabricatorAuthStartController.php', 'PhabricatorAuthTemporaryToken' => 'applications/auth/storage/PhabricatorAuthTemporaryToken.php', 'PhabricatorAuthTemporaryTokenGarbageCollector' => 'applications/auth/garbagecollector/PhabricatorAuthTemporaryTokenGarbageCollector.php', 'PhabricatorAuthTemporaryTokenQuery' => 'applications/auth/query/PhabricatorAuthTemporaryTokenQuery.php', 'PhabricatorAuthTerminateSessionController' => 'applications/auth/controller/PhabricatorAuthTerminateSessionController.php', 'PhabricatorAuthTryFactorAction' => 'applications/auth/action/PhabricatorAuthTryFactorAction.php', 'PhabricatorAuthUnlinkController' => 'applications/auth/controller/PhabricatorAuthUnlinkController.php', 'PhabricatorAuthValidateController' => 'applications/auth/controller/PhabricatorAuthValidateController.php', 'PhabricatorAuthenticationConfigOptions' => 'applications/config/option/PhabricatorAuthenticationConfigOptions.php', 'PhabricatorAutoEventListener' => 'infrastructure/events/PhabricatorAutoEventListener.php', 'PhabricatorBarePageExample' => 'applications/uiexample/examples/PhabricatorBarePageExample.php', 'PhabricatorBarePageView' => 'view/page/PhabricatorBarePageView.php', 'PhabricatorBaseEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php', 'PhabricatorBaseProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBaseProtocolAdapter.php', 'PhabricatorBcryptPasswordHasher' => 'infrastructure/util/password/PhabricatorBcryptPasswordHasher.php', 'PhabricatorBitbucketAuthProvider' => 'applications/auth/provider/PhabricatorBitbucketAuthProvider.php', 'PhabricatorBot' => 'infrastructure/daemon/bot/PhabricatorBot.php', 'PhabricatorBotBaseStreamingProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotBaseStreamingProtocolAdapter.php', 'PhabricatorBotChannel' => 'infrastructure/daemon/bot/target/PhabricatorBotChannel.php', 'PhabricatorBotDebugLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotDebugLogHandler.php', 'PhabricatorBotFeedNotificationHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotFeedNotificationHandler.php', 'PhabricatorBotFlowdockProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorBotFlowdockProtocolAdapter.php', 'PhabricatorBotHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotHandler.php', 'PhabricatorBotLogHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotLogHandler.php', 'PhabricatorBotMacroHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotMacroHandler.php', 'PhabricatorBotMessage' => 'infrastructure/daemon/bot/PhabricatorBotMessage.php', 'PhabricatorBotObjectNameHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotObjectNameHandler.php', 'PhabricatorBotSymbolHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotSymbolHandler.php', 'PhabricatorBotTarget' => 'infrastructure/daemon/bot/target/PhabricatorBotTarget.php', 'PhabricatorBotUser' => 'infrastructure/daemon/bot/target/PhabricatorBotUser.php', 'PhabricatorBotWhatsNewHandler' => 'infrastructure/daemon/bot/handler/PhabricatorBotWhatsNewHandler.php', 'PhabricatorBuiltinPatchList' => 'infrastructure/storage/patch/PhabricatorBuiltinPatchList.php', 'PhabricatorBusyExample' => 'applications/uiexample/examples/PhabricatorBusyExample.php', 'PhabricatorCacheDAO' => 'applications/cache/storage/PhabricatorCacheDAO.php', 'PhabricatorCacheGeneralGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheGeneralGarbageCollector.php', 'PhabricatorCacheManagementPurgeWorkflow' => 'applications/cache/management/PhabricatorCacheManagementPurgeWorkflow.php', 'PhabricatorCacheManagementWorkflow' => 'applications/cache/management/PhabricatorCacheManagementWorkflow.php', 'PhabricatorCacheMarkupGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheMarkupGarbageCollector.php', 'PhabricatorCacheTTLGarbageCollector' => 'applications/cache/garbagecollector/PhabricatorCacheTTLGarbageCollector.php', 'PhabricatorCaches' => 'applications/cache/PhabricatorCaches.php', 'PhabricatorCalendarApplication' => 'applications/calendar/application/PhabricatorCalendarApplication.php', 'PhabricatorCalendarBrowseController' => 'applications/calendar/controller/PhabricatorCalendarBrowseController.php', 'PhabricatorCalendarController' => 'applications/calendar/controller/PhabricatorCalendarController.php', 'PhabricatorCalendarDAO' => 'applications/calendar/storage/PhabricatorCalendarDAO.php', 'PhabricatorCalendarEvent' => 'applications/calendar/storage/PhabricatorCalendarEvent.php', 'PhabricatorCalendarEventDeleteController' => 'applications/calendar/controller/PhabricatorCalendarEventDeleteController.php', 'PhabricatorCalendarEventEditController' => 'applications/calendar/controller/PhabricatorCalendarEventEditController.php', 'PhabricatorCalendarEventInvalidEpochException' => 'applications/calendar/exception/PhabricatorCalendarEventInvalidEpochException.php', 'PhabricatorCalendarEventListController' => 'applications/calendar/controller/PhabricatorCalendarEventListController.php', + 'PhabricatorCalendarEventPHIDType' => 'applications/calendar/phid/PhabricatorCalendarEventPHIDType.php', 'PhabricatorCalendarEventQuery' => 'applications/calendar/query/PhabricatorCalendarEventQuery.php', 'PhabricatorCalendarEventSearchEngine' => 'applications/calendar/query/PhabricatorCalendarEventSearchEngine.php', 'PhabricatorCalendarEventViewController' => 'applications/calendar/controller/PhabricatorCalendarEventViewController.php', 'PhabricatorCalendarHoliday' => 'applications/calendar/storage/PhabricatorCalendarHoliday.php', 'PhabricatorCalendarHolidayTestCase' => 'applications/calendar/storage/__tests__/PhabricatorCalendarHolidayTestCase.php', - 'PhabricatorCalendarPHIDTypeEvent' => 'applications/calendar/phid/PhabricatorCalendarPHIDTypeEvent.php', 'PhabricatorCalendarViewController' => 'applications/calendar/controller/PhabricatorCalendarViewController.php', 'PhabricatorCampfireProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorCampfireProtocolAdapter.php', 'PhabricatorChangeParserTestCase' => 'applications/repository/worker/__tests__/PhabricatorChangeParserTestCase.php', 'PhabricatorChangesetResponse' => 'infrastructure/diff/PhabricatorChangesetResponse.php', 'PhabricatorChatLogApplication' => 'applications/chatlog/application/PhabricatorChatLogApplication.php', 'PhabricatorChatLogChannel' => 'applications/chatlog/storage/PhabricatorChatLogChannel.php', 'PhabricatorChatLogChannelListController' => 'applications/chatlog/controller/PhabricatorChatLogChannelListController.php', 'PhabricatorChatLogChannelLogController' => 'applications/chatlog/controller/PhabricatorChatLogChannelLogController.php', 'PhabricatorChatLogChannelQuery' => 'applications/chatlog/query/PhabricatorChatLogChannelQuery.php', 'PhabricatorChatLogConstants' => 'applications/chatlog/constants/PhabricatorChatLogConstants.php', 'PhabricatorChatLogController' => 'applications/chatlog/controller/PhabricatorChatLogController.php', 'PhabricatorChatLogDAO' => 'applications/chatlog/storage/PhabricatorChatLogDAO.php', 'PhabricatorChatLogEvent' => 'applications/chatlog/storage/PhabricatorChatLogEvent.php', 'PhabricatorChatLogEventType' => 'applications/chatlog/constants/PhabricatorChatLogEventType.php', 'PhabricatorChatLogQuery' => 'applications/chatlog/query/PhabricatorChatLogQuery.php', 'PhabricatorCommitBranchesField' => 'applications/repository/customfield/PhabricatorCommitBranchesField.php', 'PhabricatorCommitCustomField' => 'applications/repository/customfield/PhabricatorCommitCustomField.php', 'PhabricatorCommitSearchEngine' => 'applications/audit/query/PhabricatorCommitSearchEngine.php', 'PhabricatorCommitTagsField' => 'applications/repository/customfield/PhabricatorCommitTagsField.php', 'PhabricatorCommonPasswords' => 'applications/auth/constants/PhabricatorCommonPasswords.php', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/PhabricatorConduitAPIController.php', 'PhabricatorConduitApplication' => 'applications/conduit/application/PhabricatorConduitApplication.php', 'PhabricatorConduitCertificateToken' => 'applications/conduit/storage/PhabricatorConduitCertificateToken.php', 'PhabricatorConduitConfigOptions' => 'applications/conduit/config/PhabricatorConduitConfigOptions.php', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/PhabricatorConduitConnectionLog.php', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/PhabricatorConduitConsoleController.php', 'PhabricatorConduitController' => 'applications/conduit/controller/PhabricatorConduitController.php', 'PhabricatorConduitDAO' => 'applications/conduit/storage/PhabricatorConduitDAO.php', 'PhabricatorConduitListController' => 'applications/conduit/controller/PhabricatorConduitListController.php', 'PhabricatorConduitLogController' => 'applications/conduit/controller/PhabricatorConduitLogController.php', 'PhabricatorConduitLogQuery' => 'applications/conduit/query/PhabricatorConduitLogQuery.php', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/PhabricatorConduitMethodCallLog.php', 'PhabricatorConduitMethodQuery' => 'applications/conduit/query/PhabricatorConduitMethodQuery.php', 'PhabricatorConduitSearchEngine' => 'applications/conduit/query/PhabricatorConduitSearchEngine.php', 'PhabricatorConduitTokenController' => 'applications/conduit/controller/PhabricatorConduitTokenController.php', 'PhabricatorConfigAllController' => 'applications/config/controller/PhabricatorConfigAllController.php', 'PhabricatorConfigApplication' => 'applications/config/application/PhabricatorConfigApplication.php', + 'PhabricatorConfigConfigPHIDType' => 'applications/config/phid/PhabricatorConfigConfigPHIDType.php', 'PhabricatorConfigController' => 'applications/config/controller/PhabricatorConfigController.php', 'PhabricatorConfigDatabaseSource' => 'infrastructure/env/PhabricatorConfigDatabaseSource.php', 'PhabricatorConfigDefaultSource' => 'infrastructure/env/PhabricatorConfigDefaultSource.php', 'PhabricatorConfigDictionarySource' => 'infrastructure/env/PhabricatorConfigDictionarySource.php', 'PhabricatorConfigEditController' => 'applications/config/controller/PhabricatorConfigEditController.php', 'PhabricatorConfigEditor' => 'applications/config/editor/PhabricatorConfigEditor.php', 'PhabricatorConfigEntry' => 'applications/config/storage/PhabricatorConfigEntry.php', 'PhabricatorConfigEntryDAO' => 'applications/config/storage/PhabricatorConfigEntryDAO.php', 'PhabricatorConfigEntryQuery' => 'applications/config/query/PhabricatorConfigEntryQuery.php', 'PhabricatorConfigFileSource' => 'infrastructure/env/PhabricatorConfigFileSource.php', 'PhabricatorConfigGroupController' => 'applications/config/controller/PhabricatorConfigGroupController.php', 'PhabricatorConfigIgnoreController' => 'applications/config/controller/PhabricatorConfigIgnoreController.php', 'PhabricatorConfigIssueListController' => 'applications/config/controller/PhabricatorConfigIssueListController.php', 'PhabricatorConfigIssueViewController' => 'applications/config/controller/PhabricatorConfigIssueViewController.php', 'PhabricatorConfigJSON' => 'applications/config/json/PhabricatorConfigJSON.php', 'PhabricatorConfigJSONOptionType' => 'applications/config/custom/PhabricatorConfigJSONOptionType.php', 'PhabricatorConfigListController' => 'applications/config/controller/PhabricatorConfigListController.php', 'PhabricatorConfigLocalSource' => 'infrastructure/env/PhabricatorConfigLocalSource.php', 'PhabricatorConfigManagementDeleteWorkflow' => 'applications/config/management/PhabricatorConfigManagementDeleteWorkflow.php', 'PhabricatorConfigManagementGetWorkflow' => 'applications/config/management/PhabricatorConfigManagementGetWorkflow.php', 'PhabricatorConfigManagementListWorkflow' => 'applications/config/management/PhabricatorConfigManagementListWorkflow.php', 'PhabricatorConfigManagementSetWorkflow' => 'applications/config/management/PhabricatorConfigManagementSetWorkflow.php', 'PhabricatorConfigManagementWorkflow' => 'applications/config/management/PhabricatorConfigManagementWorkflow.php', 'PhabricatorConfigOption' => 'applications/config/option/PhabricatorConfigOption.php', 'PhabricatorConfigOptionType' => 'applications/config/custom/PhabricatorConfigOptionType.php', - 'PhabricatorConfigPHIDTypeConfig' => 'applications/config/phid/PhabricatorConfigPHIDTypeConfig.php', 'PhabricatorConfigProxySource' => 'infrastructure/env/PhabricatorConfigProxySource.php', 'PhabricatorConfigResponse' => 'applications/config/response/PhabricatorConfigResponse.php', 'PhabricatorConfigSource' => 'infrastructure/env/PhabricatorConfigSource.php', 'PhabricatorConfigStackSource' => 'infrastructure/env/PhabricatorConfigStackSource.php', 'PhabricatorConfigTransaction' => 'applications/config/storage/PhabricatorConfigTransaction.php', 'PhabricatorConfigTransactionQuery' => 'applications/config/query/PhabricatorConfigTransactionQuery.php', 'PhabricatorConfigValidationException' => 'applications/config/exception/PhabricatorConfigValidationException.php', 'PhabricatorConfigWelcomeController' => 'applications/config/controller/PhabricatorConfigWelcomeController.php', 'PhabricatorConpherenceApplication' => 'applications/conpherence/application/PhabricatorConpherenceApplication.php', - 'PhabricatorConpherencePHIDTypeThread' => 'applications/conpherence/phid/PhabricatorConpherencePHIDTypeThread.php', + 'PhabricatorConpherenceThreadPHIDType' => 'applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php', 'PhabricatorContentSource' => 'applications/metamta/contentsource/PhabricatorContentSource.php', 'PhabricatorContentSourceView' => 'applications/metamta/contentsource/PhabricatorContentSourceView.php', 'PhabricatorController' => 'applications/base/controller/PhabricatorController.php', 'PhabricatorCookies' => 'applications/auth/constants/PhabricatorCookies.php', 'PhabricatorCoreConfigOptions' => 'applications/config/option/PhabricatorCoreConfigOptions.php', 'PhabricatorCountdown' => 'applications/countdown/storage/PhabricatorCountdown.php', 'PhabricatorCountdownApplication' => 'applications/countdown/application/PhabricatorCountdownApplication.php', 'PhabricatorCountdownCapabilityDefaultView' => 'applications/countdown/capability/PhabricatorCountdownCapabilityDefaultView.php', 'PhabricatorCountdownController' => 'applications/countdown/controller/PhabricatorCountdownController.php', + 'PhabricatorCountdownCountdownPHIDType' => 'applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php', 'PhabricatorCountdownDAO' => 'applications/countdown/storage/PhabricatorCountdownDAO.php', 'PhabricatorCountdownDeleteController' => 'applications/countdown/controller/PhabricatorCountdownDeleteController.php', 'PhabricatorCountdownEditController' => 'applications/countdown/controller/PhabricatorCountdownEditController.php', 'PhabricatorCountdownListController' => 'applications/countdown/controller/PhabricatorCountdownListController.php', - 'PhabricatorCountdownPHIDTypeCountdown' => 'applications/countdown/phid/PhabricatorCountdownPHIDTypeCountdown.php', 'PhabricatorCountdownQuery' => 'applications/countdown/query/PhabricatorCountdownQuery.php', 'PhabricatorCountdownRemarkupRule' => 'applications/countdown/remarkup/PhabricatorCountdownRemarkupRule.php', 'PhabricatorCountdownSearchEngine' => 'applications/countdown/query/PhabricatorCountdownSearchEngine.php', 'PhabricatorCountdownView' => 'applications/countdown/view/PhabricatorCountdownView.php', 'PhabricatorCountdownViewController' => 'applications/countdown/controller/PhabricatorCountdownViewController.php', 'PhabricatorCrumbView' => 'view/layout/PhabricatorCrumbView.php', 'PhabricatorCrumbsView' => 'view/layout/PhabricatorCrumbsView.php', 'PhabricatorCursorPagedPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorCursorPagedPolicyAwareQuery.php', 'PhabricatorCustomField' => 'infrastructure/customfield/field/PhabricatorCustomField.php', 'PhabricatorCustomFieldAttachment' => 'infrastructure/customfield/field/PhabricatorCustomFieldAttachment.php', 'PhabricatorCustomFieldConfigOptionType' => 'infrastructure/customfield/config/PhabricatorCustomFieldConfigOptionType.php', 'PhabricatorCustomFieldDataNotAvailableException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldDataNotAvailableException.php', 'PhabricatorCustomFieldImplementationIncompleteException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldImplementationIncompleteException.php', 'PhabricatorCustomFieldIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldIndexStorage.php', 'PhabricatorCustomFieldInterface' => 'infrastructure/customfield/interface/PhabricatorCustomFieldInterface.php', 'PhabricatorCustomFieldList' => 'infrastructure/customfield/field/PhabricatorCustomFieldList.php', 'PhabricatorCustomFieldMonogramParser' => 'infrastructure/customfield/parser/PhabricatorCustomFieldMonogramParser.php', 'PhabricatorCustomFieldNotAttachedException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotAttachedException.php', 'PhabricatorCustomFieldNotProxyException' => 'infrastructure/customfield/exception/PhabricatorCustomFieldNotProxyException.php', 'PhabricatorCustomFieldNumericIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldNumericIndexStorage.php', 'PhabricatorCustomFieldStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStorage.php', 'PhabricatorCustomFieldStringIndexStorage' => 'infrastructure/customfield/storage/PhabricatorCustomFieldStringIndexStorage.php', 'PhabricatorDaemon' => 'infrastructure/daemon/PhabricatorDaemon.php', 'PhabricatorDaemonCombinedLogController' => 'applications/daemon/controller/PhabricatorDaemonCombinedLogController.php', 'PhabricatorDaemonConsoleController' => 'applications/daemon/controller/PhabricatorDaemonConsoleController.php', 'PhabricatorDaemonController' => 'applications/daemon/controller/PhabricatorDaemonController.php', 'PhabricatorDaemonDAO' => 'applications/daemon/storage/PhabricatorDaemonDAO.php', 'PhabricatorDaemonEventListener' => 'applications/daemon/event/PhabricatorDaemonEventListener.php', 'PhabricatorDaemonLog' => 'applications/daemon/storage/PhabricatorDaemonLog.php', 'PhabricatorDaemonLogEvent' => 'applications/daemon/storage/PhabricatorDaemonLogEvent.php', 'PhabricatorDaemonLogEventGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonLogEventGarbageCollector.php', 'PhabricatorDaemonLogEventViewController' => 'applications/daemon/controller/PhabricatorDaemonLogEventViewController.php', 'PhabricatorDaemonLogEventsView' => 'applications/daemon/view/PhabricatorDaemonLogEventsView.php', 'PhabricatorDaemonLogGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonLogGarbageCollector.php', 'PhabricatorDaemonLogListController' => 'applications/daemon/controller/PhabricatorDaemonLogListController.php', 'PhabricatorDaemonLogListView' => 'applications/daemon/view/PhabricatorDaemonLogListView.php', 'PhabricatorDaemonLogQuery' => 'applications/daemon/query/PhabricatorDaemonLogQuery.php', 'PhabricatorDaemonLogViewController' => 'applications/daemon/controller/PhabricatorDaemonLogViewController.php', 'PhabricatorDaemonManagementDebugWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementDebugWorkflow.php', 'PhabricatorDaemonManagementLaunchWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementLaunchWorkflow.php', 'PhabricatorDaemonManagementListWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementListWorkflow.php', 'PhabricatorDaemonManagementLogWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementLogWorkflow.php', 'PhabricatorDaemonManagementRestartWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementRestartWorkflow.php', 'PhabricatorDaemonManagementStartWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementStartWorkflow.php', 'PhabricatorDaemonManagementStatusWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementStatusWorkflow.php', 'PhabricatorDaemonManagementStopWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementStopWorkflow.php', 'PhabricatorDaemonManagementWorkflow' => 'applications/daemon/management/PhabricatorDaemonManagementWorkflow.php', 'PhabricatorDaemonReference' => 'infrastructure/daemon/control/PhabricatorDaemonReference.php', 'PhabricatorDaemonTaskGarbageCollector' => 'applications/daemon/garbagecollector/PhabricatorDaemonTaskGarbageCollector.php', 'PhabricatorDaemonsApplication' => 'applications/daemon/application/PhabricatorDaemonsApplication.php', 'PhabricatorDashboard' => 'applications/dashboard/storage/PhabricatorDashboard.php', 'PhabricatorDashboardAddPanelController' => 'applications/dashboard/controller/PhabricatorDashboardAddPanelController.php', 'PhabricatorDashboardApplication' => 'applications/dashboard/application/PhabricatorDashboardApplication.php', 'PhabricatorDashboardController' => 'applications/dashboard/controller/PhabricatorDashboardController.php', 'PhabricatorDashboardCopyController' => 'applications/dashboard/controller/PhabricatorDashboardCopyController.php', 'PhabricatorDashboardDAO' => 'applications/dashboard/storage/PhabricatorDashboardDAO.php', + 'PhabricatorDashboardDashboardPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php', 'PhabricatorDashboardEditController' => 'applications/dashboard/controller/PhabricatorDashboardEditController.php', 'PhabricatorDashboardHistoryController' => 'applications/dashboard/controller/PhabricatorDashboardHistoryController.php', 'PhabricatorDashboardInstall' => 'applications/dashboard/storage/PhabricatorDashboardInstall.php', 'PhabricatorDashboardInstallController' => 'applications/dashboard/controller/PhabricatorDashboardInstallController.php', 'PhabricatorDashboardLayoutConfig' => 'applications/dashboard/layoutconfig/PhabricatorDashboardLayoutConfig.php', 'PhabricatorDashboardListController' => 'applications/dashboard/controller/PhabricatorDashboardListController.php', 'PhabricatorDashboardManageController' => 'applications/dashboard/controller/PhabricatorDashboardManageController.php', 'PhabricatorDashboardMovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardMovePanelController.php', - 'PhabricatorDashboardPHIDTypeDashboard' => 'applications/dashboard/phid/PhabricatorDashboardPHIDTypeDashboard.php', - 'PhabricatorDashboardPHIDTypePanel' => 'applications/dashboard/phid/PhabricatorDashboardPHIDTypePanel.php', 'PhabricatorDashboardPanel' => 'applications/dashboard/storage/PhabricatorDashboardPanel.php', 'PhabricatorDashboardPanelArchiveController' => 'applications/dashboard/controller/PhabricatorDashboardPanelArchiveController.php', 'PhabricatorDashboardPanelCoreCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCoreCustomField.php', 'PhabricatorDashboardPanelCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelCustomField.php', 'PhabricatorDashboardPanelEditController' => 'applications/dashboard/controller/PhabricatorDashboardPanelEditController.php', 'PhabricatorDashboardPanelListController' => 'applications/dashboard/controller/PhabricatorDashboardPanelListController.php', + 'PhabricatorDashboardPanelPHIDType' => 'applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php', 'PhabricatorDashboardPanelQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelQuery.php', 'PhabricatorDashboardPanelRenderController' => 'applications/dashboard/controller/PhabricatorDashboardPanelRenderController.php', 'PhabricatorDashboardPanelRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardPanelRenderingEngine.php', 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchApplicationCustomField.php', 'PhabricatorDashboardPanelSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardPanelSearchEngine.php', 'PhabricatorDashboardPanelSearchQueryCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelSearchQueryCustomField.php', 'PhabricatorDashboardPanelTabsCustomField' => 'applications/dashboard/customfield/PhabricatorDashboardPanelTabsCustomField.php', 'PhabricatorDashboardPanelTransaction' => 'applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php', 'PhabricatorDashboardPanelTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardPanelTransactionEditor.php', 'PhabricatorDashboardPanelTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardPanelTransactionQuery.php', 'PhabricatorDashboardPanelType' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelType.php', 'PhabricatorDashboardPanelTypeQuery' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeQuery.php', 'PhabricatorDashboardPanelTypeTabs' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeTabs.php', 'PhabricatorDashboardPanelTypeText' => 'applications/dashboard/paneltype/PhabricatorDashboardPanelTypeText.php', 'PhabricatorDashboardPanelViewController' => 'applications/dashboard/controller/PhabricatorDashboardPanelViewController.php', 'PhabricatorDashboardQuery' => 'applications/dashboard/query/PhabricatorDashboardQuery.php', 'PhabricatorDashboardRemarkupRule' => 'applications/dashboard/remarkup/PhabricatorDashboardRemarkupRule.php', 'PhabricatorDashboardRemovePanelController' => 'applications/dashboard/controller/PhabricatorDashboardRemovePanelController.php', 'PhabricatorDashboardRenderingEngine' => 'applications/dashboard/engine/PhabricatorDashboardRenderingEngine.php', 'PhabricatorDashboardSearchEngine' => 'applications/dashboard/query/PhabricatorDashboardSearchEngine.php', 'PhabricatorDashboardTransaction' => 'applications/dashboard/storage/PhabricatorDashboardTransaction.php', 'PhabricatorDashboardTransactionEditor' => 'applications/dashboard/editor/PhabricatorDashboardTransactionEditor.php', 'PhabricatorDashboardTransactionQuery' => 'applications/dashboard/query/PhabricatorDashboardTransactionQuery.php', 'PhabricatorDashboardUninstallController' => 'applications/dashboard/controller/PhabricatorDashboardUninstallController.php', 'PhabricatorDashboardViewController' => 'applications/dashboard/controller/PhabricatorDashboardViewController.php', 'PhabricatorDataNotAttachedException' => 'infrastructure/storage/lisk/PhabricatorDataNotAttachedException.php', 'PhabricatorDebugController' => 'applications/system/controller/PhabricatorDebugController.php', 'PhabricatorDefaultFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorDefaultFileStorageEngineSelector.php', 'PhabricatorDefaultSearchEngineSelector' => 'applications/search/selector/PhabricatorDefaultSearchEngineSelector.php', 'PhabricatorDestructibleInterface' => 'applications/system/interface/PhabricatorDestructibleInterface.php', 'PhabricatorDestructionEngine' => 'applications/system/engine/PhabricatorDestructionEngine.php', 'PhabricatorDeveloperConfigOptions' => 'applications/config/option/PhabricatorDeveloperConfigOptions.php', 'PhabricatorDifferenceEngine' => 'infrastructure/diff/PhabricatorDifferenceEngine.php', 'PhabricatorDifferentialApplication' => 'applications/differential/application/PhabricatorDifferentialApplication.php', 'PhabricatorDifferentialConfigOptions' => 'applications/differential/config/PhabricatorDifferentialConfigOptions.php', 'PhabricatorDifferentialRevisionTestDataGenerator' => 'applications/differential/lipsum/PhabricatorDifferentialRevisionTestDataGenerator.php', 'PhabricatorDiffusionApplication' => 'applications/diffusion/application/PhabricatorDiffusionApplication.php', 'PhabricatorDiffusionConfigOptions' => 'applications/diffusion/config/PhabricatorDiffusionConfigOptions.php', 'PhabricatorDisabledUserController' => 'applications/auth/controller/PhabricatorDisabledUserController.php', 'PhabricatorDisqusAuthProvider' => 'applications/auth/provider/PhabricatorDisqusAuthProvider.php', 'PhabricatorDisqusConfigOptions' => 'applications/config/option/PhabricatorDisqusConfigOptions.php', 'PhabricatorDivinerApplication' => 'applications/diviner/application/PhabricatorDivinerApplication.php', 'PhabricatorDoorkeeperApplication' => 'applications/doorkeeper/application/PhabricatorDoorkeeperApplication.php', 'PhabricatorDraft' => 'applications/draft/storage/PhabricatorDraft.php', 'PhabricatorDraftDAO' => 'applications/draft/storage/PhabricatorDraftDAO.php', 'PhabricatorDrydockApplication' => 'applications/drydock/application/PhabricatorDrydockApplication.php', 'PhabricatorEdgeConfig' => 'infrastructure/edges/constants/PhabricatorEdgeConfig.php', 'PhabricatorEdgeConstants' => 'infrastructure/edges/constants/PhabricatorEdgeConstants.php', 'PhabricatorEdgeCycleException' => 'infrastructure/edges/exception/PhabricatorEdgeCycleException.php', 'PhabricatorEdgeEditor' => 'infrastructure/edges/editor/PhabricatorEdgeEditor.php', 'PhabricatorEdgeGraph' => 'infrastructure/edges/util/PhabricatorEdgeGraph.php', 'PhabricatorEdgeQuery' => 'infrastructure/edges/query/PhabricatorEdgeQuery.php', 'PhabricatorEdgeTestCase' => 'infrastructure/edges/__tests__/PhabricatorEdgeTestCase.php', 'PhabricatorEdgeType' => 'infrastructure/edges/type/PhabricatorEdgeType.php', 'PhabricatorEditor' => 'infrastructure/PhabricatorEditor.php', 'PhabricatorEmailLoginController' => 'applications/auth/controller/PhabricatorEmailLoginController.php', 'PhabricatorEmailVerificationController' => 'applications/auth/controller/PhabricatorEmailVerificationController.php', 'PhabricatorEmptyQueryException' => 'infrastructure/query/PhabricatorEmptyQueryException.php', 'PhabricatorEnglishTranslation' => 'infrastructure/internationalization/translation/PhabricatorEnglishTranslation.php', 'PhabricatorEnv' => 'infrastructure/env/PhabricatorEnv.php', 'PhabricatorEnvTestCase' => 'infrastructure/env/__tests__/PhabricatorEnvTestCase.php', 'PhabricatorErrorExample' => 'applications/uiexample/examples/PhabricatorErrorExample.php', 'PhabricatorEvent' => 'infrastructure/events/PhabricatorEvent.php', 'PhabricatorEventEngine' => 'infrastructure/events/PhabricatorEventEngine.php', 'PhabricatorEventListener' => 'infrastructure/events/PhabricatorEventListener.php', 'PhabricatorEventType' => 'infrastructure/events/constant/PhabricatorEventType.php', 'PhabricatorExampleEventListener' => 'infrastructure/events/PhabricatorExampleEventListener.php', 'PhabricatorExtendingPhabricatorConfigOptions' => 'applications/config/option/PhabricatorExtendingPhabricatorConfigOptions.php', 'PhabricatorExternalAccount' => 'applications/people/storage/PhabricatorExternalAccount.php', 'PhabricatorExternalAccountQuery' => 'applications/auth/query/PhabricatorExternalAccountQuery.php', 'PhabricatorFacebookAuthProvider' => 'applications/auth/provider/PhabricatorFacebookAuthProvider.php', 'PhabricatorFactAggregate' => 'applications/fact/storage/PhabricatorFactAggregate.php', 'PhabricatorFactApplication' => 'applications/fact/application/PhabricatorFactApplication.php', 'PhabricatorFactChartController' => 'applications/fact/controller/PhabricatorFactChartController.php', 'PhabricatorFactController' => 'applications/fact/controller/PhabricatorFactController.php', 'PhabricatorFactCountEngine' => 'applications/fact/engine/PhabricatorFactCountEngine.php', 'PhabricatorFactCursor' => 'applications/fact/storage/PhabricatorFactCursor.php', 'PhabricatorFactDAO' => 'applications/fact/storage/PhabricatorFactDAO.php', 'PhabricatorFactDaemon' => 'applications/fact/daemon/PhabricatorFactDaemon.php', 'PhabricatorFactEngine' => 'applications/fact/engine/PhabricatorFactEngine.php', 'PhabricatorFactHomeController' => 'applications/fact/controller/PhabricatorFactHomeController.php', 'PhabricatorFactLastUpdatedEngine' => 'applications/fact/engine/PhabricatorFactLastUpdatedEngine.php', 'PhabricatorFactManagementAnalyzeWorkflow' => 'applications/fact/management/PhabricatorFactManagementAnalyzeWorkflow.php', 'PhabricatorFactManagementCursorsWorkflow' => 'applications/fact/management/PhabricatorFactManagementCursorsWorkflow.php', 'PhabricatorFactManagementDestroyWorkflow' => 'applications/fact/management/PhabricatorFactManagementDestroyWorkflow.php', 'PhabricatorFactManagementListWorkflow' => 'applications/fact/management/PhabricatorFactManagementListWorkflow.php', 'PhabricatorFactManagementStatusWorkflow' => 'applications/fact/management/PhabricatorFactManagementStatusWorkflow.php', 'PhabricatorFactManagementWorkflow' => 'applications/fact/management/PhabricatorFactManagementWorkflow.php', 'PhabricatorFactRaw' => 'applications/fact/storage/PhabricatorFactRaw.php', 'PhabricatorFactSimpleSpec' => 'applications/fact/spec/PhabricatorFactSimpleSpec.php', 'PhabricatorFactSpec' => 'applications/fact/spec/PhabricatorFactSpec.php', 'PhabricatorFactUpdateIterator' => 'applications/fact/extract/PhabricatorFactUpdateIterator.php', 'PhabricatorFeedApplication' => 'applications/feed/application/PhabricatorFeedApplication.php', 'PhabricatorFeedBuilder' => 'applications/feed/builder/PhabricatorFeedBuilder.php', 'PhabricatorFeedConfigOptions' => 'applications/feed/config/PhabricatorFeedConfigOptions.php', 'PhabricatorFeedConstants' => 'applications/feed/constants/PhabricatorFeedConstants.php', 'PhabricatorFeedController' => 'applications/feed/controller/PhabricatorFeedController.php', 'PhabricatorFeedDAO' => 'applications/feed/storage/PhabricatorFeedDAO.php', 'PhabricatorFeedDetailController' => 'applications/feed/controller/PhabricatorFeedDetailController.php', 'PhabricatorFeedListController' => 'applications/feed/controller/PhabricatorFeedListController.php', 'PhabricatorFeedManagementRepublishWorkflow' => 'applications/feed/management/PhabricatorFeedManagementRepublishWorkflow.php', 'PhabricatorFeedManagementWorkflow' => 'applications/feed/management/PhabricatorFeedManagementWorkflow.php', 'PhabricatorFeedPublicStreamController' => 'applications/feed/controller/PhabricatorFeedPublicStreamController.php', 'PhabricatorFeedQuery' => 'applications/feed/query/PhabricatorFeedQuery.php', 'PhabricatorFeedSearchEngine' => 'applications/feed/query/PhabricatorFeedSearchEngine.php', 'PhabricatorFeedStory' => 'applications/feed/story/PhabricatorFeedStory.php', 'PhabricatorFeedStoryAggregate' => 'applications/feed/story/PhabricatorFeedStoryAggregate.php', 'PhabricatorFeedStoryAudit' => 'applications/feed/story/PhabricatorFeedStoryAudit.php', 'PhabricatorFeedStoryCommit' => 'applications/feed/story/PhabricatorFeedStoryCommit.php', 'PhabricatorFeedStoryData' => 'applications/feed/storage/PhabricatorFeedStoryData.php', 'PhabricatorFeedStoryDifferential' => 'applications/feed/story/PhabricatorFeedStoryDifferential.php', 'PhabricatorFeedStoryDifferentialAggregate' => 'applications/feed/story/PhabricatorFeedStoryDifferentialAggregate.php', 'PhabricatorFeedStoryManiphestAggregate' => 'applications/feed/story/PhabricatorFeedStoryManiphestAggregate.php', 'PhabricatorFeedStoryNotification' => 'applications/notification/storage/PhabricatorFeedStoryNotification.php', 'PhabricatorFeedStoryPhriction' => 'applications/feed/story/PhabricatorFeedStoryPhriction.php', 'PhabricatorFeedStoryPublisher' => 'applications/feed/PhabricatorFeedStoryPublisher.php', 'PhabricatorFeedStoryReference' => 'applications/feed/storage/PhabricatorFeedStoryReference.php', 'PhabricatorFeedStoryStatus' => 'applications/feed/story/PhabricatorFeedStoryStatus.php', 'PhabricatorFeedStoryTypeConstants' => 'applications/feed/constants/PhabricatorFeedStoryTypeConstants.php', 'PhabricatorFile' => 'applications/files/storage/PhabricatorFile.php', 'PhabricatorFileBundleLoader' => 'applications/files/query/PhabricatorFileBundleLoader.php', 'PhabricatorFileCommentController' => 'applications/files/controller/PhabricatorFileCommentController.php', 'PhabricatorFileComposeController' => 'applications/files/controller/PhabricatorFileComposeController.php', 'PhabricatorFileController' => 'applications/files/controller/PhabricatorFileController.php', 'PhabricatorFileDAO' => 'applications/files/storage/PhabricatorFileDAO.php', 'PhabricatorFileDataController' => 'applications/files/controller/PhabricatorFileDataController.php', 'PhabricatorFileDeleteController' => 'applications/files/controller/PhabricatorFileDeleteController.php', 'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php', 'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php', + 'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php', 'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php', 'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php', 'PhabricatorFileLinkListView' => 'view/layout/PhabricatorFileLinkListView.php', 'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php', 'PhabricatorFileListController' => 'applications/files/controller/PhabricatorFileListController.php', - 'PhabricatorFilePHIDTypeFile' => 'applications/files/phid/PhabricatorFilePHIDTypeFile.php', 'PhabricatorFileQuery' => 'applications/files/query/PhabricatorFileQuery.php', 'PhabricatorFileSearchEngine' => 'applications/files/query/PhabricatorFileSearchEngine.php', 'PhabricatorFileShortcutController' => 'applications/files/controller/PhabricatorFileShortcutController.php', 'PhabricatorFileStorageBlob' => 'applications/files/storage/PhabricatorFileStorageBlob.php', 'PhabricatorFileStorageConfigurationException' => 'applications/files/exception/PhabricatorFileStorageConfigurationException.php', 'PhabricatorFileStorageEngine' => 'applications/files/engine/PhabricatorFileStorageEngine.php', 'PhabricatorFileStorageEngineSelector' => 'applications/files/engineselector/PhabricatorFileStorageEngineSelector.php', 'PhabricatorFileTemporaryGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileTemporaryGarbageCollector.php', 'PhabricatorFileTestCase' => 'applications/files/storage/__tests__/PhabricatorFileTestCase.php', 'PhabricatorFileTestDataGenerator' => 'applications/files/lipsum/PhabricatorFileTestDataGenerator.php', 'PhabricatorFileTransaction' => 'applications/files/storage/PhabricatorFileTransaction.php', 'PhabricatorFileTransactionComment' => 'applications/files/storage/PhabricatorFileTransactionComment.php', 'PhabricatorFileTransactionQuery' => 'applications/files/query/PhabricatorFileTransactionQuery.php', 'PhabricatorFileTransformController' => 'applications/files/controller/PhabricatorFileTransformController.php', 'PhabricatorFileUploadController' => 'applications/files/controller/PhabricatorFileUploadController.php', 'PhabricatorFileUploadDialogController' => 'applications/files/controller/PhabricatorFileUploadDialogController.php', 'PhabricatorFileUploadException' => 'applications/files/exception/PhabricatorFileUploadException.php', 'PhabricatorFilesApplication' => 'applications/files/application/PhabricatorFilesApplication.php', 'PhabricatorFilesConfigOptions' => 'applications/files/config/PhabricatorFilesConfigOptions.php', 'PhabricatorFilesManagementEnginesWorkflow' => 'applications/files/management/PhabricatorFilesManagementEnginesWorkflow.php', 'PhabricatorFilesManagementMigrateWorkflow' => 'applications/files/management/PhabricatorFilesManagementMigrateWorkflow.php', 'PhabricatorFilesManagementPurgeWorkflow' => 'applications/files/management/PhabricatorFilesManagementPurgeWorkflow.php', 'PhabricatorFilesManagementRebuildWorkflow' => 'applications/files/management/PhabricatorFilesManagementRebuildWorkflow.php', 'PhabricatorFilesManagementWorkflow' => 'applications/files/management/PhabricatorFilesManagementWorkflow.php', 'PhabricatorFlag' => 'applications/flag/storage/PhabricatorFlag.php', 'PhabricatorFlagColor' => 'applications/flag/constants/PhabricatorFlagColor.php', 'PhabricatorFlagConstants' => 'applications/flag/constants/PhabricatorFlagConstants.php', 'PhabricatorFlagController' => 'applications/flag/controller/PhabricatorFlagController.php', 'PhabricatorFlagDAO' => 'applications/flag/storage/PhabricatorFlagDAO.php', 'PhabricatorFlagDeleteController' => 'applications/flag/controller/PhabricatorFlagDeleteController.php', 'PhabricatorFlagEditController' => 'applications/flag/controller/PhabricatorFlagEditController.php', 'PhabricatorFlagListController' => 'applications/flag/controller/PhabricatorFlagListController.php', 'PhabricatorFlagQuery' => 'applications/flag/query/PhabricatorFlagQuery.php', 'PhabricatorFlagSearchEngine' => 'applications/flag/query/PhabricatorFlagSearchEngine.php', 'PhabricatorFlagSelectControl' => 'applications/flag/view/PhabricatorFlagSelectControl.php', 'PhabricatorFlaggableInterface' => 'applications/flag/interface/PhabricatorFlaggableInterface.php', 'PhabricatorFlagsApplication' => 'applications/flag/application/PhabricatorFlagsApplication.php', 'PhabricatorFlagsUIEventListener' => 'applications/flag/events/PhabricatorFlagsUIEventListener.php', 'PhabricatorFormExample' => 'applications/uiexample/examples/PhabricatorFormExample.php', 'PhabricatorGarbageCollector' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollector.php', 'PhabricatorGarbageCollectorConfigOptions' => 'applications/config/option/PhabricatorGarbageCollectorConfigOptions.php', 'PhabricatorGarbageCollectorDaemon' => 'infrastructure/daemon/garbagecollector/PhabricatorGarbageCollectorDaemon.php', 'PhabricatorGestureExample' => 'applications/uiexample/examples/PhabricatorGestureExample.php', 'PhabricatorGitGraphStream' => 'applications/repository/daemon/PhabricatorGitGraphStream.php', 'PhabricatorGitHubAuthProvider' => 'applications/auth/provider/PhabricatorGitHubAuthProvider.php', 'PhabricatorGlobalLock' => 'infrastructure/util/PhabricatorGlobalLock.php', 'PhabricatorGlobalUploadTargetView' => 'applications/files/view/PhabricatorGlobalUploadTargetView.php', 'PhabricatorGoogleAuthProvider' => 'applications/auth/provider/PhabricatorGoogleAuthProvider.php', 'PhabricatorHandleObjectSelectorDataView' => 'applications/phid/handle/view/PhabricatorHandleObjectSelectorDataView.php', 'PhabricatorHandleQuery' => 'applications/phid/query/PhabricatorHandleQuery.php', 'PhabricatorHarbormasterApplication' => 'applications/harbormaster/application/PhabricatorHarbormasterApplication.php', 'PhabricatorHarbormasterConfigOptions' => 'applications/harbormaster/config/PhabricatorHarbormasterConfigOptions.php', 'PhabricatorHash' => 'infrastructure/util/PhabricatorHash.php', 'PhabricatorHashTestCase' => 'infrastructure/util/__tests__/PhabricatorHashTestCase.php', 'PhabricatorHelpApplication' => 'applications/help/application/PhabricatorHelpApplication.php', 'PhabricatorHelpController' => 'applications/help/controller/PhabricatorHelpController.php', 'PhabricatorHelpEditorProtocolController' => 'applications/help/controller/PhabricatorHelpEditorProtocolController.php', 'PhabricatorHelpKeyboardShortcutController' => 'applications/help/controller/PhabricatorHelpKeyboardShortcutController.php', 'PhabricatorHeraldApplication' => 'applications/herald/application/PhabricatorHeraldApplication.php', 'PhabricatorHomeApplication' => 'applications/home/application/PhabricatorHomeApplication.php', 'PhabricatorHomeController' => 'applications/home/controller/PhabricatorHomeController.php', 'PhabricatorHomeMainController' => 'applications/home/controller/PhabricatorHomeMainController.php', 'PhabricatorHomeQuickCreateController' => 'applications/home/controller/PhabricatorHomeQuickCreateController.php', 'PhabricatorHovercardExample' => 'applications/uiexample/examples/PhabricatorHovercardExample.php', 'PhabricatorHovercardView' => 'view/widget/hovercard/PhabricatorHovercardView.php', 'PhabricatorHunksManagementMigrateWorkflow' => 'applications/differential/management/PhabricatorHunksManagementMigrateWorkflow.php', 'PhabricatorHunksManagementWorkflow' => 'applications/differential/management/PhabricatorHunksManagementWorkflow.php', 'PhabricatorIRCProtocolAdapter' => 'infrastructure/daemon/bot/adapter/PhabricatorIRCProtocolAdapter.php', 'PhabricatorImageTransformer' => 'applications/files/PhabricatorImageTransformer.php', 'PhabricatorInfrastructureTestCase' => '__tests__/PhabricatorInfrastructureTestCase.php', 'PhabricatorInlineCommentController' => 'infrastructure/diff/PhabricatorInlineCommentController.php', 'PhabricatorInlineCommentInterface' => 'infrastructure/diff/interface/PhabricatorInlineCommentInterface.php', 'PhabricatorInlineCommentPreviewController' => 'infrastructure/diff/PhabricatorInlineCommentPreviewController.php', 'PhabricatorInlineSummaryView' => 'infrastructure/diff/view/PhabricatorInlineSummaryView.php', 'PhabricatorInternationalizationManagementExtractWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementExtractWorkflow.php', 'PhabricatorInternationalizationManagementWorkflow' => 'infrastructure/internationalization/management/PhabricatorInternationalizationManagementWorkflow.php', 'PhabricatorIteratedMD5PasswordHasher' => 'infrastructure/util/password/PhabricatorIteratedMD5PasswordHasher.php', 'PhabricatorJIRAAuthProvider' => 'applications/auth/provider/PhabricatorJIRAAuthProvider.php', 'PhabricatorJavelinLinter' => 'infrastructure/lint/linter/PhabricatorJavelinLinter.php', 'PhabricatorJumpNavHandler' => 'applications/search/engine/PhabricatorJumpNavHandler.php', 'PhabricatorKeyValueDatabaseCache' => 'applications/cache/PhabricatorKeyValueDatabaseCache.php', 'PhabricatorLDAPAuthProvider' => 'applications/auth/provider/PhabricatorLDAPAuthProvider.php', 'PhabricatorLegacyEdgeType' => 'infrastructure/edges/type/PhabricatorLegacyEdgeType.php', 'PhabricatorLegalpadApplication' => 'applications/legalpad/application/PhabricatorLegalpadApplication.php', 'PhabricatorLegalpadConfigOptions' => 'applications/legalpad/config/PhabricatorLegalpadConfigOptions.php', - 'PhabricatorLegalpadPHIDTypeDocument' => 'applications/legalpad/phid/PhabricatorLegalpadPHIDTypeDocument.php', + 'PhabricatorLegalpadDocumentPHIDType' => 'applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php', 'PhabricatorLipsumArtist' => 'applications/lipsum/image/PhabricatorLipsumArtist.php', 'PhabricatorLipsumGenerateWorkflow' => 'applications/lipsum/management/PhabricatorLipsumGenerateWorkflow.php', 'PhabricatorLipsumManagementWorkflow' => 'applications/lipsum/management/PhabricatorLipsumManagementWorkflow.php', 'PhabricatorLipsumMondrianArtist' => 'applications/lipsum/image/PhabricatorLipsumMondrianArtist.php', 'PhabricatorLiskDAO' => 'infrastructure/storage/lisk/PhabricatorLiskDAO.php', 'PhabricatorLocalDiskFileStorageEngine' => 'applications/files/engine/PhabricatorLocalDiskFileStorageEngine.php', 'PhabricatorLocalTimeTestCase' => 'view/__tests__/PhabricatorLocalTimeTestCase.php', 'PhabricatorLogoutController' => 'applications/auth/controller/PhabricatorLogoutController.php', 'PhabricatorMacroApplication' => 'applications/macro/application/PhabricatorMacroApplication.php', 'PhabricatorMacroAudioController' => 'applications/macro/controller/PhabricatorMacroAudioController.php', 'PhabricatorMacroCapabilityManage' => 'applications/macro/capability/PhabricatorMacroCapabilityManage.php', 'PhabricatorMacroCommentController' => 'applications/macro/controller/PhabricatorMacroCommentController.php', 'PhabricatorMacroConfigOptions' => 'applications/macro/config/PhabricatorMacroConfigOptions.php', 'PhabricatorMacroController' => 'applications/macro/controller/PhabricatorMacroController.php', 'PhabricatorMacroDatasource' => 'applications/macro/typeahead/PhabricatorMacroDatasource.php', 'PhabricatorMacroDisableController' => 'applications/macro/controller/PhabricatorMacroDisableController.php', 'PhabricatorMacroEditController' => 'applications/macro/controller/PhabricatorMacroEditController.php', 'PhabricatorMacroEditor' => 'applications/macro/editor/PhabricatorMacroEditor.php', 'PhabricatorMacroListController' => 'applications/macro/controller/PhabricatorMacroListController.php', + 'PhabricatorMacroMacroPHIDType' => 'applications/macro/phid/PhabricatorMacroMacroPHIDType.php', 'PhabricatorMacroMailReceiver' => 'applications/macro/mail/PhabricatorMacroMailReceiver.php', 'PhabricatorMacroMemeController' => 'applications/macro/controller/PhabricatorMacroMemeController.php', 'PhabricatorMacroMemeDialogController' => 'applications/macro/controller/PhabricatorMacroMemeDialogController.php', - 'PhabricatorMacroPHIDTypeMacro' => 'applications/macro/phid/PhabricatorMacroPHIDTypeMacro.php', 'PhabricatorMacroQuery' => 'applications/macro/query/PhabricatorMacroQuery.php', 'PhabricatorMacroReplyHandler' => 'applications/macro/mail/PhabricatorMacroReplyHandler.php', 'PhabricatorMacroSearchEngine' => 'applications/macro/query/PhabricatorMacroSearchEngine.php', 'PhabricatorMacroTransaction' => 'applications/macro/storage/PhabricatorMacroTransaction.php', 'PhabricatorMacroTransactionComment' => 'applications/macro/storage/PhabricatorMacroTransactionComment.php', 'PhabricatorMacroTransactionQuery' => 'applications/macro/query/PhabricatorMacroTransactionQuery.php', 'PhabricatorMacroTransactionType' => 'applications/macro/constants/PhabricatorMacroTransactionType.php', 'PhabricatorMacroViewController' => 'applications/macro/controller/PhabricatorMacroViewController.php', 'PhabricatorMail' => 'applications/metamta/PhabricatorMail.php', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAdapter.php', 'PhabricatorMailImplementationAmazonSESAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationAmazonSESAdapter.php', 'PhabricatorMailImplementationMailgunAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationMailgunAdapter.php', 'PhabricatorMailImplementationPHPMailerAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerAdapter.php', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationPHPMailerLiteAdapter.php', 'PhabricatorMailImplementationSendGridAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationSendGridAdapter.php', 'PhabricatorMailImplementationTestAdapter' => 'applications/metamta/adapter/PhabricatorMailImplementationTestAdapter.php', 'PhabricatorMailManagementListInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListInboundWorkflow.php', 'PhabricatorMailManagementListOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementListOutboundWorkflow.php', 'PhabricatorMailManagementReceiveTestWorkflow' => 'applications/metamta/management/PhabricatorMailManagementReceiveTestWorkflow.php', 'PhabricatorMailManagementResendWorkflow' => 'applications/metamta/management/PhabricatorMailManagementResendWorkflow.php', 'PhabricatorMailManagementSendTestWorkflow' => 'applications/metamta/management/PhabricatorMailManagementSendTestWorkflow.php', 'PhabricatorMailManagementShowInboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowInboundWorkflow.php', 'PhabricatorMailManagementShowOutboundWorkflow' => 'applications/metamta/management/PhabricatorMailManagementShowOutboundWorkflow.php', 'PhabricatorMailManagementWorkflow' => 'applications/metamta/management/PhabricatorMailManagementWorkflow.php', 'PhabricatorMailReceiver' => 'applications/metamta/receiver/PhabricatorMailReceiver.php', 'PhabricatorMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorMailReceiverTestCase.php', 'PhabricatorMailReplyHandler' => 'applications/metamta/replyhandler/PhabricatorMailReplyHandler.php', 'PhabricatorMailgunConfigOptions' => 'applications/config/option/PhabricatorMailgunConfigOptions.php', 'PhabricatorMailingListDatasource' => 'applications/mailinglists/typeahead/PhabricatorMailingListDatasource.php', - 'PhabricatorMailingListPHIDTypeList' => 'applications/mailinglists/phid/PhabricatorMailingListPHIDTypeList.php', + 'PhabricatorMailingListListPHIDType' => 'applications/mailinglists/phid/PhabricatorMailingListListPHIDType.php', 'PhabricatorMailingListQuery' => 'applications/mailinglists/query/PhabricatorMailingListQuery.php', 'PhabricatorMailingListSearchEngine' => 'applications/mailinglists/query/PhabricatorMailingListSearchEngine.php', 'PhabricatorMailingListsApplication' => 'applications/mailinglists/application/PhabricatorMailingListsApplication.php', 'PhabricatorMailingListsController' => 'applications/mailinglists/controller/PhabricatorMailingListsController.php', 'PhabricatorMailingListsEditController' => 'applications/mailinglists/controller/PhabricatorMailingListsEditController.php', 'PhabricatorMailingListsListController' => 'applications/mailinglists/controller/PhabricatorMailingListsListController.php', 'PhabricatorMainMenuGroupView' => 'view/page/menu/PhabricatorMainMenuGroupView.php', 'PhabricatorMainMenuIconView' => 'view/page/menu/PhabricatorMainMenuIconView.php', 'PhabricatorMainMenuSearchView' => 'view/page/menu/PhabricatorMainMenuSearchView.php', 'PhabricatorMainMenuView' => 'view/page/menu/PhabricatorMainMenuView.php', 'PhabricatorManagementWorkflow' => 'infrastructure/management/PhabricatorManagementWorkflow.php', 'PhabricatorManiphestApplication' => 'applications/maniphest/application/PhabricatorManiphestApplication.php', 'PhabricatorManiphestConfigOptions' => 'applications/maniphest/config/PhabricatorManiphestConfigOptions.php', 'PhabricatorManiphestTaskTestDataGenerator' => 'applications/maniphest/lipsum/PhabricatorManiphestTaskTestDataGenerator.php', 'PhabricatorMarkupCache' => 'applications/cache/storage/PhabricatorMarkupCache.php', 'PhabricatorMarkupEngine' => 'infrastructure/markup/PhabricatorMarkupEngine.php', 'PhabricatorMarkupInterface' => 'infrastructure/markup/PhabricatorMarkupInterface.php', 'PhabricatorMarkupOneOff' => 'infrastructure/markup/PhabricatorMarkupOneOff.php', 'PhabricatorMarkupPreviewController' => 'infrastructure/markup/PhabricatorMarkupPreviewController.php', 'PhabricatorMercurialGraphStream' => 'applications/repository/daemon/PhabricatorMercurialGraphStream.php', 'PhabricatorMetaMTAActor' => 'applications/metamta/query/PhabricatorMetaMTAActor.php', 'PhabricatorMetaMTAActorQuery' => 'applications/metamta/query/PhabricatorMetaMTAActorQuery.php', 'PhabricatorMetaMTAApplication' => 'applications/metamta/application/PhabricatorMetaMTAApplication.php', 'PhabricatorMetaMTAAttachment' => 'applications/metamta/storage/PhabricatorMetaMTAAttachment.php', 'PhabricatorMetaMTAConfigOptions' => 'applications/config/option/PhabricatorMetaMTAConfigOptions.php', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/PhabricatorMetaMTAController.php', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/PhabricatorMetaMTADAO.php', 'PhabricatorMetaMTAEmailBodyParser' => 'applications/metamta/parser/PhabricatorMetaMTAEmailBodyParser.php', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'applications/metamta/parser/__tests__/PhabricatorMetaMTAEmailBodyParserTestCase.php', 'PhabricatorMetaMTAErrorMailAction' => 'applications/metamta/action/PhabricatorMetaMTAErrorMailAction.php', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/PhabricatorMetaMTAMail.php', 'PhabricatorMetaMTAMailBody' => 'applications/metamta/view/PhabricatorMetaMTAMailBody.php', 'PhabricatorMetaMTAMailBodyTestCase' => 'applications/metamta/view/__tests__/PhabricatorMetaMTAMailBodyTestCase.php', 'PhabricatorMetaMTAMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAMailTestCase.php', 'PhabricatorMetaMTAMailableDatasource' => 'applications/metamta/typeahead/PhabricatorMetaMTAMailableDatasource.php', 'PhabricatorMetaMTAMailgunReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTAMailgunReceiveController.php', 'PhabricatorMetaMTAMailingList' => 'applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php', 'PhabricatorMetaMTAMemberQuery' => 'applications/metamta/query/PhabricatorMetaMTAMemberQuery.php', 'PhabricatorMetaMTAPermanentFailureException' => 'applications/metamta/exception/PhabricatorMetaMTAPermanentFailureException.php', 'PhabricatorMetaMTAReceivedMail' => 'applications/metamta/storage/PhabricatorMetaMTAReceivedMail.php', 'PhabricatorMetaMTAReceivedMailProcessingException' => 'applications/metamta/exception/PhabricatorMetaMTAReceivedMailProcessingException.php', 'PhabricatorMetaMTAReceivedMailTestCase' => 'applications/metamta/storage/__tests__/PhabricatorMetaMTAReceivedMailTestCase.php', 'PhabricatorMetaMTASendGridReceiveController' => 'applications/metamta/controller/PhabricatorMetaMTASendGridReceiveController.php', 'PhabricatorMetaMTAWorker' => 'applications/metamta/PhabricatorMetaMTAWorker.php', 'PhabricatorMultiColumnExample' => 'applications/uiexample/examples/PhabricatorMultiColumnExample.php', 'PhabricatorMustVerifyEmailController' => 'applications/auth/controller/PhabricatorMustVerifyEmailController.php', 'PhabricatorMySQLConfigOptions' => 'applications/config/option/PhabricatorMySQLConfigOptions.php', 'PhabricatorMySQLFileStorageEngine' => 'applications/files/engine/PhabricatorMySQLFileStorageEngine.php', 'PhabricatorNamedQuery' => 'applications/search/storage/PhabricatorNamedQuery.php', 'PhabricatorNamedQueryQuery' => 'applications/search/query/PhabricatorNamedQueryQuery.php', 'PhabricatorNotificationAdHocFeedStory' => 'applications/notification/feed/PhabricatorNotificationAdHocFeedStory.php', 'PhabricatorNotificationBuilder' => 'applications/notification/builder/PhabricatorNotificationBuilder.php', 'PhabricatorNotificationClearController' => 'applications/notification/controller/PhabricatorNotificationClearController.php', 'PhabricatorNotificationClient' => 'applications/notification/client/PhabricatorNotificationClient.php', 'PhabricatorNotificationConfigOptions' => 'applications/config/option/PhabricatorNotificationConfigOptions.php', 'PhabricatorNotificationController' => 'applications/notification/controller/PhabricatorNotificationController.php', 'PhabricatorNotificationIndividualController' => 'applications/notification/controller/PhabricatorNotificationIndividualController.php', 'PhabricatorNotificationListController' => 'applications/notification/controller/PhabricatorNotificationListController.php', 'PhabricatorNotificationPanelController' => 'applications/notification/controller/PhabricatorNotificationPanelController.php', 'PhabricatorNotificationQuery' => 'applications/notification/query/PhabricatorNotificationQuery.php', 'PhabricatorNotificationStatusController' => 'applications/notification/controller/PhabricatorNotificationStatusController.php', 'PhabricatorNotificationStatusView' => 'applications/notification/view/PhabricatorNotificationStatusView.php', 'PhabricatorNotificationTestController' => 'applications/notification/controller/PhabricatorNotificationTestController.php', 'PhabricatorNotificationsApplication' => 'applications/notification/application/PhabricatorNotificationsApplication.php', 'PhabricatorNuanceApplication' => 'applications/nuance/application/PhabricatorNuanceApplication.php', 'PhabricatorOAuth1AuthProvider' => 'applications/auth/provider/PhabricatorOAuth1AuthProvider.php', 'PhabricatorOAuth2AuthProvider' => 'applications/auth/provider/PhabricatorOAuth2AuthProvider.php', 'PhabricatorOAuthAuthProvider' => 'applications/auth/provider/PhabricatorOAuthAuthProvider.php', 'PhabricatorOAuthClientAuthorization' => 'applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php', 'PhabricatorOAuthClientAuthorizationQuery' => 'applications/oauthserver/query/PhabricatorOAuthClientAuthorizationQuery.php', 'PhabricatorOAuthClientController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientController.php', 'PhabricatorOAuthClientDeleteController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientDeleteController.php', 'PhabricatorOAuthClientEditController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientEditController.php', 'PhabricatorOAuthClientListController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientListController.php', 'PhabricatorOAuthClientViewController' => 'applications/oauthserver/controller/client/PhabricatorOAuthClientViewController.php', 'PhabricatorOAuthResponse' => 'applications/oauthserver/PhabricatorOAuthResponse.php', 'PhabricatorOAuthServer' => 'applications/oauthserver/PhabricatorOAuthServer.php', 'PhabricatorOAuthServerAccessToken' => 'applications/oauthserver/storage/PhabricatorOAuthServerAccessToken.php', 'PhabricatorOAuthServerApplication' => 'applications/oauthserver/application/PhabricatorOAuthServerApplication.php', 'PhabricatorOAuthServerAuthController' => 'applications/oauthserver/controller/PhabricatorOAuthServerAuthController.php', 'PhabricatorOAuthServerAuthorizationCode' => 'applications/oauthserver/storage/PhabricatorOAuthServerAuthorizationCode.php', 'PhabricatorOAuthServerAuthorizationsSettingsPanel' => 'applications/oauthserver/panel/PhabricatorOAuthServerAuthorizationsSettingsPanel.php', 'PhabricatorOAuthServerCapabilityCreateClients' => 'applications/oauthserver/capability/PhabricatorOAuthServerCapabilityCreateClients.php', 'PhabricatorOAuthServerClient' => 'applications/oauthserver/storage/PhabricatorOAuthServerClient.php', + 'PhabricatorOAuthServerClientAuthorizationPHIDType' => 'applications/oauthserver/phid/PhabricatorOAuthServerClientAuthorizationPHIDType.php', + 'PhabricatorOAuthServerClientPHIDType' => 'applications/oauthserver/phid/PhabricatorOAuthServerClientPHIDType.php', 'PhabricatorOAuthServerClientQuery' => 'applications/oauthserver/query/PhabricatorOAuthServerClientQuery.php', 'PhabricatorOAuthServerClientSearchEngine' => 'applications/oauthserver/query/PhabricatorOAuthServerClientSearchEngine.php', 'PhabricatorOAuthServerController' => 'applications/oauthserver/controller/PhabricatorOAuthServerController.php', 'PhabricatorOAuthServerDAO' => 'applications/oauthserver/storage/PhabricatorOAuthServerDAO.php', - 'PhabricatorOAuthServerPHIDTypeClient' => 'applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClient.php', - 'PhabricatorOAuthServerPHIDTypeClientAuthorization' => 'applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClientAuthorization.php', 'PhabricatorOAuthServerScope' => 'applications/oauthserver/PhabricatorOAuthServerScope.php', 'PhabricatorOAuthServerTestCase' => 'applications/oauthserver/__tests__/PhabricatorOAuthServerTestCase.php', 'PhabricatorOAuthServerTestController' => 'applications/oauthserver/controller/PhabricatorOAuthServerTestController.php', 'PhabricatorOAuthServerTokenController' => 'applications/oauthserver/controller/PhabricatorOAuthServerTokenController.php', 'PhabricatorObjectHandle' => 'applications/phid/PhabricatorObjectHandle.php', 'PhabricatorObjectHandleConstants' => 'applications/phid/handle/const/PhabricatorObjectHandleConstants.php', 'PhabricatorObjectHandleStatus' => 'applications/phid/handle/const/PhabricatorObjectHandleStatus.php', 'PhabricatorObjectListQuery' => 'applications/phid/query/PhabricatorObjectListQuery.php', 'PhabricatorObjectListQueryTestCase' => 'applications/phid/query/__tests__/PhabricatorObjectListQueryTestCase.php', 'PhabricatorObjectMailReceiver' => 'applications/metamta/receiver/PhabricatorObjectMailReceiver.php', 'PhabricatorObjectMailReceiverTestCase' => 'applications/metamta/receiver/__tests__/PhabricatorObjectMailReceiverTestCase.php', 'PhabricatorObjectQuery' => 'applications/phid/query/PhabricatorObjectQuery.php', 'PhabricatorObjectSelectorDialog' => 'view/control/PhabricatorObjectSelectorDialog.php', 'PhabricatorOffsetPagedQuery' => 'infrastructure/query/PhabricatorOffsetPagedQuery.php', 'PhabricatorOwnerPathQuery' => 'applications/owners/query/PhabricatorOwnerPathQuery.php', 'PhabricatorOwnersApplication' => 'applications/owners/application/PhabricatorOwnersApplication.php', 'PhabricatorOwnersConfigOptions' => 'applications/owners/config/PhabricatorOwnersConfigOptions.php', 'PhabricatorOwnersController' => 'applications/owners/controller/PhabricatorOwnersController.php', 'PhabricatorOwnersDAO' => 'applications/owners/storage/PhabricatorOwnersDAO.php', 'PhabricatorOwnersDeleteController' => 'applications/owners/controller/PhabricatorOwnersDeleteController.php', 'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php', 'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php', 'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php', 'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php', - 'PhabricatorOwnersPHIDTypePackage' => 'applications/owners/phid/PhabricatorOwnersPHIDTypePackage.php', 'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php', 'PhabricatorOwnersPackageDatasource' => 'applications/owners/typeahead/PhabricatorOwnersPackageDatasource.php', + 'PhabricatorOwnersPackagePHIDType' => 'applications/owners/phid/PhabricatorOwnersPackagePHIDType.php', 'PhabricatorOwnersPackagePathValidator' => 'applications/repository/worker/commitchangeparser/PhabricatorOwnersPackagePathValidator.php', 'PhabricatorOwnersPackageQuery' => 'applications/owners/query/PhabricatorOwnersPackageQuery.php', 'PhabricatorOwnersPackageTestCase' => 'applications/owners/storage/__tests__/PhabricatorOwnersPackageTestCase.php', 'PhabricatorOwnersPath' => 'applications/owners/storage/PhabricatorOwnersPath.php', 'PhabricatorPHDConfigOptions' => 'applications/config/option/PhabricatorPHDConfigOptions.php', 'PhabricatorPHID' => 'applications/phid/storage/PhabricatorPHID.php', 'PhabricatorPHIDConstants' => 'applications/phid/PhabricatorPHIDConstants.php', 'PhabricatorPHIDInterface' => 'applications/phid/interface/PhabricatorPHIDInterface.php', 'PhabricatorPHIDType' => 'applications/phid/type/PhabricatorPHIDType.php', 'PhabricatorPHPASTApplication' => 'applications/phpast/application/PhabricatorPHPASTApplication.php', 'PhabricatorPHPMailerConfigOptions' => 'applications/config/option/PhabricatorPHPMailerConfigOptions.php', 'PhabricatorPagedFormExample' => 'applications/uiexample/examples/PhabricatorPagedFormExample.php', 'PhabricatorPassphraseApplication' => 'applications/passphrase/application/PhabricatorPassphraseApplication.php', 'PhabricatorPasswordAuthProvider' => 'applications/auth/provider/PhabricatorPasswordAuthProvider.php', 'PhabricatorPasswordHasher' => 'infrastructure/util/password/PhabricatorPasswordHasher.php', 'PhabricatorPasswordHasherTestCase' => 'infrastructure/util/password/__tests__/PhabricatorPasswordHasherTestCase.php', 'PhabricatorPasswordHasherUnavailableException' => 'infrastructure/util/password/PhabricatorPasswordHasherUnavailableException.php', 'PhabricatorPaste' => 'applications/paste/storage/PhabricatorPaste.php', 'PhabricatorPasteApplication' => 'applications/paste/application/PhabricatorPasteApplication.php', 'PhabricatorPasteCommentController' => 'applications/paste/controller/PhabricatorPasteCommentController.php', 'PhabricatorPasteConfigOptions' => 'applications/paste/config/PhabricatorPasteConfigOptions.php', 'PhabricatorPasteController' => 'applications/paste/controller/PhabricatorPasteController.php', 'PhabricatorPasteDAO' => 'applications/paste/storage/PhabricatorPasteDAO.php', 'PhabricatorPasteEditController' => 'applications/paste/controller/PhabricatorPasteEditController.php', 'PhabricatorPasteEditor' => 'applications/paste/editor/PhabricatorPasteEditor.php', 'PhabricatorPasteListController' => 'applications/paste/controller/PhabricatorPasteListController.php', - 'PhabricatorPastePHIDTypePaste' => 'applications/paste/phid/PhabricatorPastePHIDTypePaste.php', + 'PhabricatorPastePastePHIDType' => 'applications/paste/phid/PhabricatorPastePastePHIDType.php', 'PhabricatorPasteQuery' => 'applications/paste/query/PhabricatorPasteQuery.php', 'PhabricatorPasteRemarkupRule' => 'applications/paste/remarkup/PhabricatorPasteRemarkupRule.php', 'PhabricatorPasteSearchEngine' => 'applications/paste/query/PhabricatorPasteSearchEngine.php', 'PhabricatorPasteTestDataGenerator' => 'applications/paste/lipsum/PhabricatorPasteTestDataGenerator.php', 'PhabricatorPasteTransaction' => 'applications/paste/storage/PhabricatorPasteTransaction.php', 'PhabricatorPasteTransactionComment' => 'applications/paste/storage/PhabricatorPasteTransactionComment.php', 'PhabricatorPasteTransactionQuery' => 'applications/paste/query/PhabricatorPasteTransactionQuery.php', 'PhabricatorPasteViewController' => 'applications/paste/controller/PhabricatorPasteViewController.php', 'PhabricatorPeopleApplication' => 'applications/people/application/PhabricatorPeopleApplication.php', 'PhabricatorPeopleApproveController' => 'applications/people/controller/PhabricatorPeopleApproveController.php', 'PhabricatorPeopleCalendarController' => 'applications/people/controller/PhabricatorPeopleCalendarController.php', 'PhabricatorPeopleController' => 'applications/people/controller/PhabricatorPeopleController.php', 'PhabricatorPeopleCreateController' => 'applications/people/controller/PhabricatorPeopleCreateController.php', 'PhabricatorPeopleDatasource' => 'applications/people/typeahead/PhabricatorPeopleDatasource.php', 'PhabricatorPeopleDeleteController' => 'applications/people/controller/PhabricatorPeopleDeleteController.php', 'PhabricatorPeopleDisableController' => 'applications/people/controller/PhabricatorPeopleDisableController.php', 'PhabricatorPeopleEmpowerController' => 'applications/people/controller/PhabricatorPeopleEmpowerController.php', + 'PhabricatorPeopleExternalPHIDType' => 'applications/people/phid/PhabricatorPeopleExternalPHIDType.php', 'PhabricatorPeopleHovercardEventListener' => 'applications/people/event/PhabricatorPeopleHovercardEventListener.php', 'PhabricatorPeopleLdapController' => 'applications/people/controller/PhabricatorPeopleLdapController.php', 'PhabricatorPeopleListController' => 'applications/people/controller/PhabricatorPeopleListController.php', 'PhabricatorPeopleLogQuery' => 'applications/people/query/PhabricatorPeopleLogQuery.php', 'PhabricatorPeopleLogSearchEngine' => 'applications/people/query/PhabricatorPeopleLogSearchEngine.php', 'PhabricatorPeopleLogsController' => 'applications/people/controller/PhabricatorPeopleLogsController.php', 'PhabricatorPeopleNewController' => 'applications/people/controller/PhabricatorPeopleNewController.php', - 'PhabricatorPeoplePHIDTypeExternal' => 'applications/people/phid/PhabricatorPeoplePHIDTypeExternal.php', - 'PhabricatorPeoplePHIDTypeUser' => 'applications/people/phid/PhabricatorPeoplePHIDTypeUser.php', 'PhabricatorPeopleProfileController' => 'applications/people/controller/PhabricatorPeopleProfileController.php', 'PhabricatorPeopleProfileEditController' => 'applications/people/controller/PhabricatorPeopleProfileEditController.php', 'PhabricatorPeopleProfilePictureController' => 'applications/people/controller/PhabricatorPeopleProfilePictureController.php', 'PhabricatorPeopleQuery' => 'applications/people/query/PhabricatorPeopleQuery.php', 'PhabricatorPeopleRenameController' => 'applications/people/controller/PhabricatorPeopleRenameController.php', 'PhabricatorPeopleSearchEngine' => 'applications/people/query/PhabricatorPeopleSearchEngine.php', 'PhabricatorPeopleTestDataGenerator' => 'applications/people/lipsum/PhabricatorPeopleTestDataGenerator.php', + 'PhabricatorPeopleUserPHIDType' => 'applications/people/phid/PhabricatorPeopleUserPHIDType.php', 'PhabricatorPeopleWelcomeController' => 'applications/people/controller/PhabricatorPeopleWelcomeController.php', 'PhabricatorPersonaAuthProvider' => 'applications/auth/provider/PhabricatorPersonaAuthProvider.php', 'PhabricatorPhameApplication' => 'applications/phame/application/PhabricatorPhameApplication.php', + 'PhabricatorPhameBlogPHIDType' => 'applications/phame/phid/PhabricatorPhameBlogPHIDType.php', 'PhabricatorPhameConfigOptions' => 'applications/phame/config/PhabricatorPhameConfigOptions.php', - 'PhabricatorPhamePHIDTypeBlog' => 'applications/phame/phid/PhabricatorPhamePHIDTypeBlog.php', - 'PhabricatorPhamePHIDTypePost' => 'applications/phame/phid/PhabricatorPhamePHIDTypePost.php', + 'PhabricatorPhamePostPHIDType' => 'applications/phame/phid/PhabricatorPhamePostPHIDType.php', 'PhabricatorPhluxApplication' => 'applications/phlux/application/PhabricatorPhluxApplication.php', 'PhabricatorPholioApplication' => 'applications/pholio/application/PhabricatorPholioApplication.php', 'PhabricatorPholioConfigOptions' => 'applications/pholio/config/PhabricatorPholioConfigOptions.php', 'PhabricatorPholioMockTestDataGenerator' => 'applications/pholio/lipsum/PhabricatorPholioMockTestDataGenerator.php', 'PhabricatorPhortuneApplication' => 'applications/phortune/application/PhabricatorPhortuneApplication.php', 'PhabricatorPhortuneConfigOptions' => 'applications/phortune/option/PhabricatorPhortuneConfigOptions.php', 'PhabricatorPhragmentApplication' => 'applications/phragment/application/PhabricatorPhragmentApplication.php', 'PhabricatorPhrequentApplication' => 'applications/phrequent/application/PhabricatorPhrequentApplication.php', 'PhabricatorPhrequentConfigOptions' => 'applications/phrequent/config/PhabricatorPhrequentConfigOptions.php', 'PhabricatorPhrictionApplication' => 'applications/phriction/application/PhabricatorPhrictionApplication.php', 'PhabricatorPhrictionConfigOptions' => 'applications/phriction/config/PhabricatorPhrictionConfigOptions.php', 'PhabricatorPolicies' => 'applications/policy/constants/PhabricatorPolicies.php', 'PhabricatorPolicy' => 'applications/policy/storage/PhabricatorPolicy.php', 'PhabricatorPolicyApplication' => 'applications/policy/application/PhabricatorPolicyApplication.php', 'PhabricatorPolicyAwareQuery' => 'infrastructure/query/policy/PhabricatorPolicyAwareQuery.php', 'PhabricatorPolicyAwareTestQuery' => 'applications/policy/__tests__/PhabricatorPolicyAwareTestQuery.php', 'PhabricatorPolicyCapability' => 'applications/policy/capability/PhabricatorPolicyCapability.php', 'PhabricatorPolicyCapabilityCanEdit' => 'applications/policy/capability/PhabricatorPolicyCapabilityCanEdit.php', 'PhabricatorPolicyCapabilityCanJoin' => 'applications/policy/capability/PhabricatorPolicyCapabilityCanJoin.php', 'PhabricatorPolicyCapabilityCanView' => 'applications/policy/capability/PhabricatorPolicyCapabilityCanView.php', 'PhabricatorPolicyConfigOptions' => 'applications/policy/config/PhabricatorPolicyConfigOptions.php', 'PhabricatorPolicyConstants' => 'applications/policy/constants/PhabricatorPolicyConstants.php', 'PhabricatorPolicyController' => 'applications/policy/controller/PhabricatorPolicyController.php', 'PhabricatorPolicyDAO' => 'applications/policy/storage/PhabricatorPolicyDAO.php', 'PhabricatorPolicyDataTestCase' => 'applications/policy/__tests__/PhabricatorPolicyDataTestCase.php', 'PhabricatorPolicyEditController' => 'applications/policy/controller/PhabricatorPolicyEditController.php', 'PhabricatorPolicyException' => 'applications/policy/exception/PhabricatorPolicyException.php', 'PhabricatorPolicyExplainController' => 'applications/policy/controller/PhabricatorPolicyExplainController.php', 'PhabricatorPolicyFilter' => 'applications/policy/filter/PhabricatorPolicyFilter.php', 'PhabricatorPolicyInterface' => 'applications/policy/interface/PhabricatorPolicyInterface.php', 'PhabricatorPolicyManagementShowWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementShowWorkflow.php', 'PhabricatorPolicyManagementUnlockWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementUnlockWorkflow.php', 'PhabricatorPolicyManagementWorkflow' => 'applications/policy/management/PhabricatorPolicyManagementWorkflow.php', 'PhabricatorPolicyPHIDTypePolicy' => 'applications/policy/phid/PhabricatorPolicyPHIDTypePolicy.php', 'PhabricatorPolicyQuery' => 'applications/policy/query/PhabricatorPolicyQuery.php', 'PhabricatorPolicyRule' => 'applications/policy/rule/PhabricatorPolicyRule.php', 'PhabricatorPolicyRuleAdministrators' => 'applications/policy/rule/PhabricatorPolicyRuleAdministrators.php', 'PhabricatorPolicyRuleLegalpadSignature' => 'applications/policy/rule/PhabricatorPolicyRuleLegalpadSignature.php', 'PhabricatorPolicyRuleLunarPhase' => 'applications/policy/rule/PhabricatorPolicyRuleLunarPhase.php', 'PhabricatorPolicyRuleProjects' => 'applications/policy/rule/PhabricatorPolicyRuleProjects.php', 'PhabricatorPolicyRuleUsers' => 'applications/policy/rule/PhabricatorPolicyRuleUsers.php', 'PhabricatorPolicyTestCase' => 'applications/policy/__tests__/PhabricatorPolicyTestCase.php', 'PhabricatorPolicyTestObject' => 'applications/policy/__tests__/PhabricatorPolicyTestObject.php', 'PhabricatorPolicyType' => 'applications/policy/constants/PhabricatorPolicyType.php', 'PhabricatorPonderApplication' => 'applications/ponder/application/PhabricatorPonderApplication.php', 'PhabricatorProject' => 'applications/project/storage/PhabricatorProject.php', 'PhabricatorProjectApplication' => 'applications/project/application/PhabricatorProjectApplication.php', 'PhabricatorProjectArchiveController' => 'applications/project/controller/PhabricatorProjectArchiveController.php', 'PhabricatorProjectBoardController' => 'applications/project/controller/PhabricatorProjectBoardController.php', 'PhabricatorProjectBoardDeleteController' => 'applications/project/controller/PhabricatorProjectBoardDeleteController.php', 'PhabricatorProjectBoardEditController' => 'applications/project/controller/PhabricatorProjectBoardEditController.php', 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', 'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php', 'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php', + 'PhabricatorProjectColumnPHIDType' => 'applications/project/phid/PhabricatorProjectColumnPHIDType.php', 'PhabricatorProjectColumnQuery' => 'applications/project/query/PhabricatorProjectColumnQuery.php', 'PhabricatorProjectColumnTransaction' => 'applications/project/storage/PhabricatorProjectColumnTransaction.php', 'PhabricatorProjectColumnTransactionEditor' => 'applications/project/editor/PhabricatorProjectColumnTransactionEditor.php', 'PhabricatorProjectColumnTransactionQuery' => 'applications/project/query/PhabricatorProjectColumnTransactionQuery.php', 'PhabricatorProjectConfigOptions' => 'applications/project/config/PhabricatorProjectConfigOptions.php', 'PhabricatorProjectConfiguredCustomField' => 'applications/project/customfield/PhabricatorProjectConfiguredCustomField.php', 'PhabricatorProjectConstants' => 'applications/project/constants/PhabricatorProjectConstants.php', 'PhabricatorProjectController' => 'applications/project/controller/PhabricatorProjectController.php', 'PhabricatorProjectCreateController' => 'applications/project/controller/PhabricatorProjectCreateController.php', 'PhabricatorProjectCustomField' => 'applications/project/customfield/PhabricatorProjectCustomField.php', 'PhabricatorProjectCustomFieldNumericIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldNumericIndex.php', 'PhabricatorProjectCustomFieldStorage' => 'applications/project/storage/PhabricatorProjectCustomFieldStorage.php', 'PhabricatorProjectCustomFieldStringIndex' => 'applications/project/storage/PhabricatorProjectCustomFieldStringIndex.php', 'PhabricatorProjectDAO' => 'applications/project/storage/PhabricatorProjectDAO.php', 'PhabricatorProjectDatasource' => 'applications/project/typeahead/PhabricatorProjectDatasource.php', 'PhabricatorProjectDescriptionField' => 'applications/project/customfield/PhabricatorProjectDescriptionField.php', 'PhabricatorProjectEditDetailsController' => 'applications/project/controller/PhabricatorProjectEditDetailsController.php', 'PhabricatorProjectEditIconController' => 'applications/project/controller/PhabricatorProjectEditIconController.php', 'PhabricatorProjectEditMainController' => 'applications/project/controller/PhabricatorProjectEditMainController.php', 'PhabricatorProjectEditPictureController' => 'applications/project/controller/PhabricatorProjectEditPictureController.php', 'PhabricatorProjectEditorTestCase' => 'applications/project/editor/__tests__/PhabricatorProjectEditorTestCase.php', 'PhabricatorProjectIcon' => 'applications/project/icon/PhabricatorProjectIcon.php', 'PhabricatorProjectInterface' => 'applications/project/interface/PhabricatorProjectInterface.php', 'PhabricatorProjectListController' => 'applications/project/controller/PhabricatorProjectListController.php', 'PhabricatorProjectMembersEditController' => 'applications/project/controller/PhabricatorProjectMembersEditController.php', 'PhabricatorProjectMembersRemoveController' => 'applications/project/controller/PhabricatorProjectMembersRemoveController.php', 'PhabricatorProjectMoveController' => 'applications/project/controller/PhabricatorProjectMoveController.php', 'PhabricatorProjectNameCollisionException' => 'applications/project/exception/PhabricatorProjectNameCollisionException.php', 'PhabricatorProjectObjectHasProjectEdgeType' => 'applications/project/edge/PhabricatorProjectObjectHasProjectEdgeType.php', 'PhabricatorProjectOrUserDatasource' => 'applications/project/typeahead/PhabricatorProjectOrUserDatasource.php', - 'PhabricatorProjectPHIDTypeColumn' => 'applications/project/phid/PhabricatorProjectPHIDTypeColumn.php', - 'PhabricatorProjectPHIDTypeProject' => 'applications/project/phid/PhabricatorProjectPHIDTypeProject.php', 'PhabricatorProjectProfileController' => 'applications/project/controller/PhabricatorProjectProfileController.php', 'PhabricatorProjectProjectHasObjectEdgeType' => 'applications/project/edge/PhabricatorProjectProjectHasObjectEdgeType.php', + 'PhabricatorProjectProjectPHIDType' => 'applications/project/phid/PhabricatorProjectProjectPHIDType.php', 'PhabricatorProjectQuery' => 'applications/project/query/PhabricatorProjectQuery.php', 'PhabricatorProjectSearchEngine' => 'applications/project/query/PhabricatorProjectSearchEngine.php', 'PhabricatorProjectSearchIndexer' => 'applications/project/search/PhabricatorProjectSearchIndexer.php', 'PhabricatorProjectSlug' => 'applications/project/storage/PhabricatorProjectSlug.php', 'PhabricatorProjectStandardCustomField' => 'applications/project/customfield/PhabricatorProjectStandardCustomField.php', 'PhabricatorProjectStatus' => 'applications/project/constants/PhabricatorProjectStatus.php', 'PhabricatorProjectTestDataGenerator' => 'applications/project/lipsum/PhabricatorProjectTestDataGenerator.php', 'PhabricatorProjectTransaction' => 'applications/project/storage/PhabricatorProjectTransaction.php', 'PhabricatorProjectTransactionEditor' => 'applications/project/editor/PhabricatorProjectTransactionEditor.php', 'PhabricatorProjectTransactionQuery' => 'applications/project/query/PhabricatorProjectTransactionQuery.php', 'PhabricatorProjectUIEventListener' => 'applications/project/events/PhabricatorProjectUIEventListener.php', 'PhabricatorProjectUpdateController' => 'applications/project/controller/PhabricatorProjectUpdateController.php', 'PhabricatorProjectWatchController' => 'applications/project/controller/PhabricatorProjectWatchController.php', 'PhabricatorQuery' => 'infrastructure/query/PhabricatorQuery.php', 'PhabricatorRecaptchaConfigOptions' => 'applications/config/option/PhabricatorRecaptchaConfigOptions.php', 'PhabricatorRedirectController' => 'applications/base/controller/PhabricatorRedirectController.php', 'PhabricatorRefreshCSRFController' => 'applications/auth/controller/PhabricatorRefreshCSRFController.php', 'PhabricatorRegistrationProfile' => 'applications/people/storage/PhabricatorRegistrationProfile.php', 'PhabricatorReleephApplication' => 'applications/releeph/application/PhabricatorReleephApplication.php', 'PhabricatorReleephApplicationConfigOptions' => 'applications/releeph/config/PhabricatorReleephApplicationConfigOptions.php', 'PhabricatorRemarkupBlockInterpreterCowsay' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterCowsay.php', 'PhabricatorRemarkupBlockInterpreterFiglet' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterFiglet.php', 'PhabricatorRemarkupBlockInterpreterGraphviz' => 'infrastructure/markup/interpreter/PhabricatorRemarkupBlockInterpreterGraphviz.php', 'PhabricatorRemarkupControl' => 'view/form/control/PhabricatorRemarkupControl.php', 'PhabricatorRemarkupCustomBlockRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomBlockRule.php', 'PhabricatorRemarkupCustomInlineRule' => 'infrastructure/markup/rule/PhabricatorRemarkupCustomInlineRule.php', 'PhabricatorRemarkupExample' => 'applications/uiexample/examples/PhabricatorRemarkupExample.php', 'PhabricatorRemarkupRuleEmbedFile' => 'applications/files/remarkup/PhabricatorRemarkupRuleEmbedFile.php', 'PhabricatorRemarkupRuleIcon' => 'applications/macro/remarkup/PhabricatorRemarkupRuleIcon.php', 'PhabricatorRemarkupRuleImageMacro' => 'applications/macro/remarkup/PhabricatorRemarkupRuleImageMacro.php', 'PhabricatorRemarkupRuleMeme' => 'applications/macro/remarkup/PhabricatorRemarkupRuleMeme.php', 'PhabricatorRemarkupRuleMention' => 'applications/people/remarkup/PhabricatorRemarkupRuleMention.php', 'PhabricatorRemarkupRuleObject' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleObject.php', 'PhabricatorRemarkupRuleYoutube' => 'infrastructure/markup/rule/PhabricatorRemarkupRuleYoutube.php', 'PhabricatorRepositoriesApplication' => 'applications/repository/application/PhabricatorRepositoriesApplication.php', 'PhabricatorRepository' => 'applications/repository/storage/PhabricatorRepository.php', 'PhabricatorRepositoryArcanistProject' => 'applications/repository/storage/PhabricatorRepositoryArcanistProject.php', 'PhabricatorRepositoryArcanistProjectDeleteController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectDeleteController.php', 'PhabricatorRepositoryArcanistProjectEditController' => 'applications/repository/controller/PhabricatorRepositoryArcanistProjectEditController.php', + 'PhabricatorRepositoryArcanistProjectPHIDType' => 'applications/repository/phid/PhabricatorRepositoryArcanistProjectPHIDType.php', 'PhabricatorRepositoryArcanistProjectQuery' => 'applications/repository/query/PhabricatorRepositoryArcanistProjectQuery.php', 'PhabricatorRepositoryAuditRequest' => 'applications/repository/storage/PhabricatorRepositoryAuditRequest.php', 'PhabricatorRepositoryBranch' => 'applications/repository/storage/PhabricatorRepositoryBranch.php', 'PhabricatorRepositoryCommit' => 'applications/repository/storage/PhabricatorRepositoryCommit.php', 'PhabricatorRepositoryCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryCommitChangeParserWorker.php', 'PhabricatorRepositoryCommitData' => 'applications/repository/storage/PhabricatorRepositoryCommitData.php', 'PhabricatorRepositoryCommitHeraldWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php', 'PhabricatorRepositoryCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryCommitMessageParserWorker.php', 'PhabricatorRepositoryCommitOwnersWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitOwnersWorker.php', + 'PhabricatorRepositoryCommitPHIDType' => 'applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php', 'PhabricatorRepositoryCommitParserWorker' => 'applications/repository/worker/PhabricatorRepositoryCommitParserWorker.php', 'PhabricatorRepositoryCommitRef' => 'applications/repository/engine/PhabricatorRepositoryCommitRef.php', 'PhabricatorRepositoryCommitSearchIndexer' => 'applications/repository/search/PhabricatorRepositoryCommitSearchIndexer.php', 'PhabricatorRepositoryConfigOptions' => 'applications/repository/PhabricatorRepositoryConfigOptions.php', 'PhabricatorRepositoryController' => 'applications/repository/controller/PhabricatorRepositoryController.php', 'PhabricatorRepositoryDAO' => 'applications/repository/storage/PhabricatorRepositoryDAO.php', 'PhabricatorRepositoryDiscoveryEngine' => 'applications/repository/engine/PhabricatorRepositoryDiscoveryEngine.php', 'PhabricatorRepositoryEditor' => 'applications/repository/editor/PhabricatorRepositoryEditor.php', 'PhabricatorRepositoryEngine' => 'applications/repository/engine/PhabricatorRepositoryEngine.php', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryGitCommitChangeParserWorker.php', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryGitCommitMessageParserWorker.php', 'PhabricatorRepositoryGraphCache' => 'applications/repository/graphcache/PhabricatorRepositoryGraphCache.php', 'PhabricatorRepositoryGraphStream' => 'applications/repository/daemon/PhabricatorRepositoryGraphStream.php', 'PhabricatorRepositoryListController' => 'applications/repository/controller/PhabricatorRepositoryListController.php', 'PhabricatorRepositoryManagementCacheWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementCacheWorkflow.php', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementDiscoverWorkflow.php', 'PhabricatorRepositoryManagementEditWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementEditWorkflow.php', 'PhabricatorRepositoryManagementImportingWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementImportingWorkflow.php', 'PhabricatorRepositoryManagementListWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementListWorkflow.php', 'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementLookupUsersWorkflow.php', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMarkImportedWorkflow.php', 'PhabricatorRepositoryManagementMirrorWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementMirrorWorkflow.php', 'PhabricatorRepositoryManagementParentsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementParentsWorkflow.php', 'PhabricatorRepositoryManagementPullWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementPullWorkflow.php', 'PhabricatorRepositoryManagementRefsWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementRefsWorkflow.php', 'PhabricatorRepositoryManagementUpdateWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementUpdateWorkflow.php', 'PhabricatorRepositoryManagementWorkflow' => 'applications/repository/management/PhabricatorRepositoryManagementWorkflow.php', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositoryMercurialCommitChangeParserWorker.php', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositoryMercurialCommitMessageParserWorker.php', 'PhabricatorRepositoryMirror' => 'applications/repository/storage/PhabricatorRepositoryMirror.php', 'PhabricatorRepositoryMirrorEngine' => 'applications/repository/engine/PhabricatorRepositoryMirrorEngine.php', + 'PhabricatorRepositoryMirrorPHIDType' => 'applications/repository/phid/PhabricatorRepositoryMirrorPHIDType.php', 'PhabricatorRepositoryMirrorQuery' => 'applications/repository/query/PhabricatorRepositoryMirrorQuery.php', - 'PhabricatorRepositoryPHIDTypeArcanistProject' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeArcanistProject.php', - 'PhabricatorRepositoryPHIDTypeCommit' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php', - 'PhabricatorRepositoryPHIDTypeMirror' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php', - 'PhabricatorRepositoryPHIDTypePushEvent' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypePushEvent.php', - 'PhabricatorRepositoryPHIDTypePushLog' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypePushLog.php', - 'PhabricatorRepositoryPHIDTypeRepository' => 'applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php', 'PhabricatorRepositoryParsedChange' => 'applications/repository/data/PhabricatorRepositoryParsedChange.php', 'PhabricatorRepositoryPullEngine' => 'applications/repository/engine/PhabricatorRepositoryPullEngine.php', 'PhabricatorRepositoryPullLocalDaemon' => 'applications/repository/daemon/PhabricatorRepositoryPullLocalDaemon.php', 'PhabricatorRepositoryPushEvent' => 'applications/repository/storage/PhabricatorRepositoryPushEvent.php', + 'PhabricatorRepositoryPushEventPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPushEventPHIDType.php', 'PhabricatorRepositoryPushEventQuery' => 'applications/repository/query/PhabricatorRepositoryPushEventQuery.php', 'PhabricatorRepositoryPushLog' => 'applications/repository/storage/PhabricatorRepositoryPushLog.php', + 'PhabricatorRepositoryPushLogPHIDType' => 'applications/repository/phid/PhabricatorRepositoryPushLogPHIDType.php', 'PhabricatorRepositoryPushLogQuery' => 'applications/repository/query/PhabricatorRepositoryPushLogQuery.php', 'PhabricatorRepositoryPushLogSearchEngine' => 'applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php', 'PhabricatorRepositoryPushMailWorker' => 'applications/repository/worker/PhabricatorRepositoryPushMailWorker.php', 'PhabricatorRepositoryPushReplyHandler' => 'applications/repository/mail/PhabricatorRepositoryPushReplyHandler.php', 'PhabricatorRepositoryQuery' => 'applications/repository/query/PhabricatorRepositoryQuery.php', 'PhabricatorRepositoryRefCursor' => 'applications/repository/storage/PhabricatorRepositoryRefCursor.php', 'PhabricatorRepositoryRefCursorQuery' => 'applications/repository/query/PhabricatorRepositoryRefCursorQuery.php', 'PhabricatorRepositoryRefEngine' => 'applications/repository/engine/PhabricatorRepositoryRefEngine.php', + 'PhabricatorRepositoryRepositoryPHIDType' => 'applications/repository/phid/PhabricatorRepositoryRepositoryPHIDType.php', 'PhabricatorRepositorySearchEngine' => 'applications/repository/query/PhabricatorRepositorySearchEngine.php', 'PhabricatorRepositoryStatusMessage' => 'applications/repository/storage/PhabricatorRepositoryStatusMessage.php', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'applications/repository/worker/commitchangeparser/PhabricatorRepositorySvnCommitChangeParserWorker.php', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'applications/repository/worker/commitmessageparser/PhabricatorRepositorySvnCommitMessageParserWorker.php', 'PhabricatorRepositorySymbol' => 'applications/repository/storage/PhabricatorRepositorySymbol.php', 'PhabricatorRepositoryTestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryTestCase.php', 'PhabricatorRepositoryTransaction' => 'applications/repository/storage/PhabricatorRepositoryTransaction.php', 'PhabricatorRepositoryTransactionQuery' => 'applications/repository/query/PhabricatorRepositoryTransactionQuery.php', 'PhabricatorRepositoryType' => 'applications/repository/constants/PhabricatorRepositoryType.php', 'PhabricatorRepositoryURINormalizer' => 'applications/repository/data/PhabricatorRepositoryURINormalizer.php', 'PhabricatorRepositoryURINormalizerTestCase' => 'applications/repository/data/__tests__/PhabricatorRepositoryURINormalizerTestCase.php', 'PhabricatorRepositoryURITestCase' => 'applications/repository/storage/__tests__/PhabricatorRepositoryURITestCase.php', 'PhabricatorRepositoryVCSPassword' => 'applications/repository/storage/PhabricatorRepositoryVCSPassword.php', 'PhabricatorRobotsController' => 'applications/system/controller/PhabricatorRobotsController.php', 'PhabricatorS3FileStorageEngine' => 'applications/files/engine/PhabricatorS3FileStorageEngine.php', 'PhabricatorSMS' => 'infrastructure/sms/storage/PhabricatorSMS.php', 'PhabricatorSMSConfigOptions' => 'applications/config/option/PhabricatorSMSConfigOptions.php', 'PhabricatorSMSDAO' => 'infrastructure/sms/storage/PhabricatorSMSDAO.php', 'PhabricatorSMSDemultiplexWorker' => 'infrastructure/sms/worker/PhabricatorSMSDemultiplexWorker.php', 'PhabricatorSMSImplementationAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationAdapter.php', 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationTestBlackholeAdapter.php', 'PhabricatorSMSImplementationTwilioAdapter' => 'infrastructure/sms/adapter/PhabricatorSMSImplementationTwilioAdapter.php', 'PhabricatorSMSManagementListOutboundWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementListOutboundWorkflow.php', 'PhabricatorSMSManagementSendTestWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementSendTestWorkflow.php', 'PhabricatorSMSManagementShowOutboundWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementShowOutboundWorkflow.php', 'PhabricatorSMSManagementWorkflow' => 'infrastructure/sms/management/PhabricatorSMSManagementWorkflow.php', 'PhabricatorSMSSendWorker' => 'infrastructure/sms/worker/PhabricatorSMSSendWorker.php', 'PhabricatorSMSWorker' => 'infrastructure/sms/worker/PhabricatorSMSWorker.php', 'PhabricatorSQLPatchList' => 'infrastructure/storage/patch/PhabricatorSQLPatchList.php', 'PhabricatorSSHKeyGenerator' => 'infrastructure/util/PhabricatorSSHKeyGenerator.php', 'PhabricatorSSHLog' => 'infrastructure/log/PhabricatorSSHLog.php', 'PhabricatorSSHPassthruCommand' => 'infrastructure/ssh/PhabricatorSSHPassthruCommand.php', 'PhabricatorSSHWorkflow' => 'infrastructure/ssh/PhabricatorSSHWorkflow.php', 'PhabricatorSavedQuery' => 'applications/search/storage/PhabricatorSavedQuery.php', 'PhabricatorSavedQueryQuery' => 'applications/search/query/PhabricatorSavedQueryQuery.php', 'PhabricatorScopedEnv' => 'infrastructure/env/PhabricatorScopedEnv.php', 'PhabricatorSearchAbstractDocument' => 'applications/search/index/PhabricatorSearchAbstractDocument.php', 'PhabricatorSearchApplication' => 'applications/search/application/PhabricatorSearchApplication.php', 'PhabricatorSearchApplicationSearchEngine' => 'applications/search/query/PhabricatorSearchApplicationSearchEngine.php', 'PhabricatorSearchAttachController' => 'applications/search/controller/PhabricatorSearchAttachController.php', 'PhabricatorSearchBaseController' => 'applications/search/controller/PhabricatorSearchBaseController.php', 'PhabricatorSearchConfigOptions' => 'applications/search/config/PhabricatorSearchConfigOptions.php', 'PhabricatorSearchController' => 'applications/search/controller/PhabricatorSearchController.php', 'PhabricatorSearchDAO' => 'applications/search/storage/PhabricatorSearchDAO.php', 'PhabricatorSearchDatasource' => 'applications/search/typeahead/PhabricatorSearchDatasource.php', 'PhabricatorSearchDeleteController' => 'applications/search/controller/PhabricatorSearchDeleteController.php', 'PhabricatorSearchDocument' => 'applications/search/storage/document/PhabricatorSearchDocument.php', 'PhabricatorSearchDocumentField' => 'applications/search/storage/document/PhabricatorSearchDocumentField.php', 'PhabricatorSearchDocumentIndexer' => 'applications/search/index/PhabricatorSearchDocumentIndexer.php', 'PhabricatorSearchDocumentQuery' => 'applications/search/query/PhabricatorSearchDocumentQuery.php', 'PhabricatorSearchDocumentRelationship' => 'applications/search/storage/document/PhabricatorSearchDocumentRelationship.php', 'PhabricatorSearchEditController' => 'applications/search/controller/PhabricatorSearchEditController.php', 'PhabricatorSearchEngine' => 'applications/search/engine/PhabricatorSearchEngine.php', 'PhabricatorSearchEngineElastic' => 'applications/search/engine/PhabricatorSearchEngineElastic.php', 'PhabricatorSearchEngineMySQL' => 'applications/search/engine/PhabricatorSearchEngineMySQL.php', 'PhabricatorSearchEngineSelector' => 'applications/search/selector/PhabricatorSearchEngineSelector.php', 'PhabricatorSearchField' => 'applications/search/constants/PhabricatorSearchField.php', 'PhabricatorSearchHovercardController' => 'applications/search/controller/PhabricatorSearchHovercardController.php', 'PhabricatorSearchIndexer' => 'applications/search/index/PhabricatorSearchIndexer.php', 'PhabricatorSearchManagementIndexWorkflow' => 'applications/search/management/PhabricatorSearchManagementIndexWorkflow.php', 'PhabricatorSearchManagementWorkflow' => 'applications/search/management/PhabricatorSearchManagementWorkflow.php', 'PhabricatorSearchOrderController' => 'applications/search/controller/PhabricatorSearchOrderController.php', 'PhabricatorSearchQuery' => 'applications/search/storage/PhabricatorSearchQuery.php', 'PhabricatorSearchRelationship' => 'applications/search/constants/PhabricatorSearchRelationship.php', 'PhabricatorSearchResultView' => 'applications/search/view/PhabricatorSearchResultView.php', 'PhabricatorSearchSelectController' => 'applications/search/controller/PhabricatorSearchSelectController.php', 'PhabricatorSearchWorker' => 'applications/search/worker/PhabricatorSearchWorker.php', 'PhabricatorSecurityConfigOptions' => 'applications/config/option/PhabricatorSecurityConfigOptions.php', 'PhabricatorSendGridConfigOptions' => 'applications/config/option/PhabricatorSendGridConfigOptions.php', 'PhabricatorSettingsAddEmailAction' => 'applications/settings/action/PhabricatorSettingsAddEmailAction.php', 'PhabricatorSettingsAdjustController' => 'applications/settings/controller/PhabricatorSettingsAdjustController.php', 'PhabricatorSettingsApplication' => 'applications/settings/application/PhabricatorSettingsApplication.php', 'PhabricatorSettingsMainController' => 'applications/settings/controller/PhabricatorSettingsMainController.php', 'PhabricatorSettingsPanel' => 'applications/settings/panel/PhabricatorSettingsPanel.php', 'PhabricatorSettingsPanelAccount' => 'applications/settings/panel/PhabricatorSettingsPanelAccount.php', 'PhabricatorSettingsPanelActivity' => 'applications/settings/panel/PhabricatorSettingsPanelActivity.php', 'PhabricatorSettingsPanelConduit' => 'applications/settings/panel/PhabricatorSettingsPanelConduit.php', 'PhabricatorSettingsPanelConpherencePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelConpherencePreferences.php', 'PhabricatorSettingsPanelDeveloperPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDeveloperPreferences.php', 'PhabricatorSettingsPanelDiffPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDiffPreferences.php', 'PhabricatorSettingsPanelDisplayPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelDisplayPreferences.php', 'PhabricatorSettingsPanelEmailAddresses' => 'applications/settings/panel/PhabricatorSettingsPanelEmailAddresses.php', 'PhabricatorSettingsPanelEmailPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelEmailPreferences.php', 'PhabricatorSettingsPanelExternalAccounts' => 'applications/settings/panel/PhabricatorSettingsPanelExternalAccounts.php', 'PhabricatorSettingsPanelHomePreferences' => 'applications/settings/panel/PhabricatorSettingsPanelHomePreferences.php', 'PhabricatorSettingsPanelMultiFactor' => 'applications/settings/panel/PhabricatorSettingsPanelMultiFactor.php', 'PhabricatorSettingsPanelPassword' => 'applications/settings/panel/PhabricatorSettingsPanelPassword.php', 'PhabricatorSettingsPanelSSHKeys' => 'applications/settings/panel/PhabricatorSettingsPanelSSHKeys.php', 'PhabricatorSettingsPanelSearchPreferences' => 'applications/settings/panel/PhabricatorSettingsPanelSearchPreferences.php', 'PhabricatorSettingsPanelSessions' => 'applications/settings/panel/PhabricatorSettingsPanelSessions.php', 'PhabricatorSetupCheck' => 'applications/config/check/PhabricatorSetupCheck.php', 'PhabricatorSetupCheckAPC' => 'applications/config/check/PhabricatorSetupCheckAPC.php', 'PhabricatorSetupCheckAphlict' => 'applications/notification/setup/PhabricatorSetupCheckAphlict.php', 'PhabricatorSetupCheckAuth' => 'applications/config/check/PhabricatorSetupCheckAuth.php', 'PhabricatorSetupCheckBaseURI' => 'applications/config/check/PhabricatorSetupCheckBaseURI.php', 'PhabricatorSetupCheckBinaries' => 'applications/config/check/PhabricatorSetupCheckBinaries.php', 'PhabricatorSetupCheckDaemons' => 'applications/config/check/PhabricatorSetupCheckDaemons.php', 'PhabricatorSetupCheckDatabase' => 'applications/config/check/PhabricatorSetupCheckDatabase.php', 'PhabricatorSetupCheckExtensions' => 'applications/config/check/PhabricatorSetupCheckExtensions.php', 'PhabricatorSetupCheckExtraConfig' => 'applications/config/check/PhabricatorSetupCheckExtraConfig.php', 'PhabricatorSetupCheckFileinfo' => 'applications/config/check/PhabricatorSetupCheckFileinfo.php', 'PhabricatorSetupCheckGD' => 'applications/config/check/PhabricatorSetupCheckGD.php', 'PhabricatorSetupCheckImagemagick' => 'applications/config/check/PhabricatorSetupCheckImagemagick.php', 'PhabricatorSetupCheckInvalidConfig' => 'applications/config/check/PhabricatorSetupCheckInvalidConfig.php', 'PhabricatorSetupCheckMail' => 'applications/config/check/PhabricatorSetupCheckMail.php', 'PhabricatorSetupCheckMySQL' => 'applications/config/check/PhabricatorSetupCheckMySQL.php', 'PhabricatorSetupCheckPHPConfig' => 'applications/config/check/PhabricatorSetupCheckPHPConfig.php', 'PhabricatorSetupCheckPath' => 'applications/config/check/PhabricatorSetupCheckPath.php', 'PhabricatorSetupCheckPygment' => 'applications/config/check/PhabricatorSetupCheckPygment.php', 'PhabricatorSetupCheckRepositories' => 'applications/config/check/PhabricatorSetupCheckRepositories.php', 'PhabricatorSetupCheckStorage' => 'applications/config/check/PhabricatorSetupCheckStorage.php', 'PhabricatorSetupCheckTimezone' => 'applications/config/check/PhabricatorSetupCheckTimezone.php', 'PhabricatorSetupIssue' => 'applications/config/issue/PhabricatorSetupIssue.php', 'PhabricatorSetupIssueExample' => 'applications/uiexample/examples/PhabricatorSetupIssueExample.php', 'PhabricatorSetupIssueView' => 'applications/config/view/PhabricatorSetupIssueView.php', 'PhabricatorSlowvoteApplication' => 'applications/slowvote/application/PhabricatorSlowvoteApplication.php', 'PhabricatorSlowvoteCapabilityDefaultView' => 'applications/slowvote/capability/PhabricatorSlowvoteCapabilityDefaultView.php', 'PhabricatorSlowvoteChoice' => 'applications/slowvote/storage/PhabricatorSlowvoteChoice.php', 'PhabricatorSlowvoteCloseController' => 'applications/slowvote/controller/PhabricatorSlowvoteCloseController.php', 'PhabricatorSlowvoteComment' => 'applications/slowvote/storage/PhabricatorSlowvoteComment.php', 'PhabricatorSlowvoteCommentController' => 'applications/slowvote/controller/PhabricatorSlowvoteCommentController.php', 'PhabricatorSlowvoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteController.php', 'PhabricatorSlowvoteDAO' => 'applications/slowvote/storage/PhabricatorSlowvoteDAO.php', 'PhabricatorSlowvoteEditController' => 'applications/slowvote/controller/PhabricatorSlowvoteEditController.php', 'PhabricatorSlowvoteEditor' => 'applications/slowvote/editor/PhabricatorSlowvoteEditor.php', 'PhabricatorSlowvoteListController' => 'applications/slowvote/controller/PhabricatorSlowvoteListController.php', 'PhabricatorSlowvoteOption' => 'applications/slowvote/storage/PhabricatorSlowvoteOption.php', - 'PhabricatorSlowvotePHIDTypePoll' => 'applications/slowvote/phid/PhabricatorSlowvotePHIDTypePoll.php', 'PhabricatorSlowvotePoll' => 'applications/slowvote/storage/PhabricatorSlowvotePoll.php', 'PhabricatorSlowvotePollController' => 'applications/slowvote/controller/PhabricatorSlowvotePollController.php', + 'PhabricatorSlowvotePollPHIDType' => 'applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php', 'PhabricatorSlowvoteQuery' => 'applications/slowvote/query/PhabricatorSlowvoteQuery.php', 'PhabricatorSlowvoteSearchEngine' => 'applications/slowvote/query/PhabricatorSlowvoteSearchEngine.php', 'PhabricatorSlowvoteTransaction' => 'applications/slowvote/storage/PhabricatorSlowvoteTransaction.php', 'PhabricatorSlowvoteTransactionComment' => 'applications/slowvote/storage/PhabricatorSlowvoteTransactionComment.php', 'PhabricatorSlowvoteTransactionQuery' => 'applications/slowvote/query/PhabricatorSlowvoteTransactionQuery.php', 'PhabricatorSlowvoteVoteController' => 'applications/slowvote/controller/PhabricatorSlowvoteVoteController.php', 'PhabricatorSlug' => 'infrastructure/util/PhabricatorSlug.php', 'PhabricatorSlugTestCase' => 'infrastructure/util/__tests__/PhabricatorSlugTestCase.php', 'PhabricatorSortTableExample' => 'applications/uiexample/examples/PhabricatorSortTableExample.php', 'PhabricatorSourceCodeView' => 'view/layout/PhabricatorSourceCodeView.php', 'PhabricatorStandardCustomField' => 'infrastructure/customfield/standard/PhabricatorStandardCustomField.php', 'PhabricatorStandardCustomFieldBool' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldBool.php', 'PhabricatorStandardCustomFieldCredential' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldCredential.php', 'PhabricatorStandardCustomFieldDate' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldDate.php', 'PhabricatorStandardCustomFieldHeader' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldHeader.php', 'PhabricatorStandardCustomFieldInt' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldInt.php', 'PhabricatorStandardCustomFieldInterface' => 'infrastructure/customfield/interface/PhabricatorStandardCustomFieldInterface.php', 'PhabricatorStandardCustomFieldPHIDs' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldPHIDs.php', 'PhabricatorStandardCustomFieldRemarkup' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldRemarkup.php', 'PhabricatorStandardCustomFieldSelect' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldSelect.php', 'PhabricatorStandardCustomFieldText' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldText.php', 'PhabricatorStandardCustomFieldUsers' => 'infrastructure/customfield/standard/PhabricatorStandardCustomFieldUsers.php', 'PhabricatorStandardPageView' => 'view/page/PhabricatorStandardPageView.php', 'PhabricatorStatusController' => 'applications/system/controller/PhabricatorStatusController.php', 'PhabricatorStorageFixtureScopeGuard' => 'infrastructure/testing/fixture/PhabricatorStorageFixtureScopeGuard.php', 'PhabricatorStorageManagementAPI' => 'infrastructure/storage/management/PhabricatorStorageManagementAPI.php', 'PhabricatorStorageManagementDatabasesWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDatabasesWorkflow.php', 'PhabricatorStorageManagementDestroyWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDestroyWorkflow.php', 'PhabricatorStorageManagementDumpWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementDumpWorkflow.php', 'PhabricatorStorageManagementProbeWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementProbeWorkflow.php', 'PhabricatorStorageManagementStatusWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementStatusWorkflow.php', 'PhabricatorStorageManagementUpgradeWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementUpgradeWorkflow.php', 'PhabricatorStorageManagementWorkflow' => 'infrastructure/storage/management/workflow/PhabricatorStorageManagementWorkflow.php', 'PhabricatorStoragePatch' => 'infrastructure/storage/management/PhabricatorStoragePatch.php', 'PhabricatorSubscribableInterface' => 'applications/subscriptions/interface/PhabricatorSubscribableInterface.php', 'PhabricatorSubscribersQuery' => 'applications/subscriptions/query/PhabricatorSubscribersQuery.php', 'PhabricatorSubscriptionsApplication' => 'applications/subscriptions/application/PhabricatorSubscriptionsApplication.php', 'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php', 'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php', 'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php', 'PhabricatorSubscriptionsTransactionController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsTransactionController.php', 'PhabricatorSubscriptionsUIEventListener' => 'applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php', 'PhabricatorSupportApplication' => 'applications/support/application/PhabricatorSupportApplication.php', 'PhabricatorSymbolNameLinter' => 'infrastructure/lint/hook/PhabricatorSymbolNameLinter.php', 'PhabricatorSyntaxHighlighter' => 'infrastructure/markup/PhabricatorSyntaxHighlighter.php', 'PhabricatorSyntaxHighlightingConfigOptions' => 'applications/config/option/PhabricatorSyntaxHighlightingConfigOptions.php', 'PhabricatorSystemAction' => 'applications/system/action/PhabricatorSystemAction.php', 'PhabricatorSystemActionEngine' => 'applications/system/engine/PhabricatorSystemActionEngine.php', 'PhabricatorSystemActionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemActionGarbageCollector.php', 'PhabricatorSystemActionLog' => 'applications/system/storage/PhabricatorSystemActionLog.php', 'PhabricatorSystemActionRateLimitException' => 'applications/system/exception/PhabricatorSystemActionRateLimitException.php', 'PhabricatorSystemApplication' => 'applications/system/application/PhabricatorSystemApplication.php', 'PhabricatorSystemDAO' => 'applications/system/storage/PhabricatorSystemDAO.php', 'PhabricatorSystemDestructionGarbageCollector' => 'applications/system/garbagecollector/PhabricatorSystemDestructionGarbageCollector.php', 'PhabricatorSystemDestructionLog' => 'applications/system/storage/PhabricatorSystemDestructionLog.php', 'PhabricatorSystemRemoveDestroyWorkflow' => 'applications/system/management/PhabricatorSystemRemoveDestroyWorkflow.php', 'PhabricatorSystemRemoveLogWorkflow' => 'applications/system/management/PhabricatorSystemRemoveLogWorkflow.php', 'PhabricatorSystemRemoveWorkflow' => 'applications/system/management/PhabricatorSystemRemoveWorkflow.php', 'PhabricatorSystemSelectEncodingController' => 'applications/system/controller/PhabricatorSystemSelectEncodingController.php', 'PhabricatorSystemSelectHighlightController' => 'applications/system/controller/PhabricatorSystemSelectHighlightController.php', 'PhabricatorTaskmasterDaemon' => 'infrastructure/daemon/workers/PhabricatorTaskmasterDaemon.php', 'PhabricatorTestApplication' => 'applications/base/controller/__tests__/PhabricatorTestApplication.php', 'PhabricatorTestCase' => 'infrastructure/testing/PhabricatorTestCase.php', 'PhabricatorTestController' => 'applications/base/controller/__tests__/PhabricatorTestController.php', 'PhabricatorTestDataGenerator' => 'applications/lipsum/generator/PhabricatorTestDataGenerator.php', 'PhabricatorTestStorageEngine' => 'applications/files/engine/PhabricatorTestStorageEngine.php', 'PhabricatorTestWorker' => 'infrastructure/daemon/workers/__tests__/PhabricatorTestWorker.php', 'PhabricatorTime' => 'infrastructure/time/PhabricatorTime.php', 'PhabricatorTimeGuard' => 'infrastructure/time/PhabricatorTimeGuard.php', 'PhabricatorTimeTestCase' => 'infrastructure/time/__tests__/PhabricatorTimeTestCase.php', 'PhabricatorToken' => 'applications/tokens/storage/PhabricatorToken.php', 'PhabricatorTokenController' => 'applications/tokens/controller/PhabricatorTokenController.php', 'PhabricatorTokenCount' => 'applications/tokens/storage/PhabricatorTokenCount.php', 'PhabricatorTokenCountQuery' => 'applications/tokens/query/PhabricatorTokenCountQuery.php', 'PhabricatorTokenDAO' => 'applications/tokens/storage/PhabricatorTokenDAO.php', 'PhabricatorTokenGiveController' => 'applications/tokens/controller/PhabricatorTokenGiveController.php', 'PhabricatorTokenGiven' => 'applications/tokens/storage/PhabricatorTokenGiven.php', 'PhabricatorTokenGivenController' => 'applications/tokens/controller/PhabricatorTokenGivenController.php', 'PhabricatorTokenGivenEditor' => 'applications/tokens/editor/PhabricatorTokenGivenEditor.php', 'PhabricatorTokenGivenFeedStory' => 'applications/tokens/feed/PhabricatorTokenGivenFeedStory.php', 'PhabricatorTokenGivenQuery' => 'applications/tokens/query/PhabricatorTokenGivenQuery.php', 'PhabricatorTokenLeaderController' => 'applications/tokens/controller/PhabricatorTokenLeaderController.php', - 'PhabricatorTokenPHIDTypeToken' => 'applications/tokens/phid/PhabricatorTokenPHIDTypeToken.php', 'PhabricatorTokenQuery' => 'applications/tokens/query/PhabricatorTokenQuery.php', 'PhabricatorTokenReceiverInterface' => 'applications/tokens/interface/PhabricatorTokenReceiverInterface.php', 'PhabricatorTokenReceiverQuery' => 'applications/tokens/query/PhabricatorTokenReceiverQuery.php', + 'PhabricatorTokenTokenPHIDType' => 'applications/tokens/phid/PhabricatorTokenTokenPHIDType.php', 'PhabricatorTokenUIEventListener' => 'applications/tokens/event/PhabricatorTokenUIEventListener.php', 'PhabricatorTokensApplication' => 'applications/tokens/application/PhabricatorTokensApplication.php', 'PhabricatorTransactionView' => 'view/layout/PhabricatorTransactionView.php', 'PhabricatorTransactions' => 'applications/transactions/constants/PhabricatorTransactions.php', 'PhabricatorTransactionsApplication' => 'applications/transactions/application/PhabricatorTransactionsApplication.php', 'PhabricatorTransformedFile' => 'applications/files/storage/PhabricatorTransformedFile.php', 'PhabricatorTranslation' => 'infrastructure/internationalization/translation/PhabricatorTranslation.php', 'PhabricatorTranslationsConfigOptions' => 'applications/config/option/PhabricatorTranslationsConfigOptions.php', 'PhabricatorTrivialTestCase' => 'infrastructure/testing/__tests__/PhabricatorTrivialTestCase.php', 'PhabricatorTwitchAuthProvider' => 'applications/auth/provider/PhabricatorTwitchAuthProvider.php', 'PhabricatorTwitterAuthProvider' => 'applications/auth/provider/PhabricatorTwitterAuthProvider.php', 'PhabricatorTwoColumnExample' => 'applications/uiexample/examples/PhabricatorTwoColumnExample.php', 'PhabricatorTypeaheadApplication' => 'applications/typeahead/application/PhabricatorTypeaheadApplication.php', 'PhabricatorTypeaheadCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadCompositeDatasource.php', 'PhabricatorTypeaheadDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadDatasource.php', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadDatasourceController.php', 'PhabricatorTypeaheadModularDatasourceController' => 'applications/typeahead/controller/PhabricatorTypeaheadModularDatasourceController.php', 'PhabricatorTypeaheadMonogramDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadMonogramDatasource.php', 'PhabricatorTypeaheadNoOwnerDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadNoOwnerDatasource.php', 'PhabricatorTypeaheadOwnerDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadOwnerDatasource.php', 'PhabricatorTypeaheadResult' => 'applications/typeahead/storage/PhabricatorTypeaheadResult.php', 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'applications/typeahead/datasource/PhabricatorTypeaheadRuntimeCompositeDatasource.php', 'PhabricatorUIConfigOptions' => 'applications/config/option/PhabricatorUIConfigOptions.php', 'PhabricatorUIExample' => 'applications/uiexample/examples/PhabricatorUIExample.php', 'PhabricatorUIExampleRenderController' => 'applications/uiexample/controller/PhabricatorUIExampleRenderController.php', 'PhabricatorUIExamplesApplication' => 'applications/uiexample/application/PhabricatorUIExamplesApplication.php', 'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/PhabricatorUIListFilterExample.php', 'PhabricatorUINotificationExample' => 'applications/uiexample/examples/PhabricatorUINotificationExample.php', 'PhabricatorUIPagerExample' => 'applications/uiexample/examples/PhabricatorUIPagerExample.php', 'PhabricatorUIStatusExample' => 'applications/uiexample/examples/PhabricatorUIStatusExample.php', 'PhabricatorUITooltipExample' => 'applications/uiexample/examples/PhabricatorUITooltipExample.php', 'PhabricatorUnitsTestCase' => 'view/__tests__/PhabricatorUnitsTestCase.php', 'PhabricatorUser' => 'applications/people/storage/PhabricatorUser.php', 'PhabricatorUserBlurbField' => 'applications/people/customfield/PhabricatorUserBlurbField.php', 'PhabricatorUserConfigOptions' => 'applications/people/config/PhabricatorUserConfigOptions.php', 'PhabricatorUserConfiguredCustomField' => 'applications/people/customfield/PhabricatorUserConfiguredCustomField.php', 'PhabricatorUserConfiguredCustomFieldStorage' => 'applications/people/storage/PhabricatorUserConfiguredCustomFieldStorage.php', 'PhabricatorUserCustomField' => 'applications/people/customfield/PhabricatorUserCustomField.php', 'PhabricatorUserCustomFieldNumericIndex' => 'applications/people/storage/PhabricatorUserCustomFieldNumericIndex.php', 'PhabricatorUserCustomFieldStringIndex' => 'applications/people/storage/PhabricatorUserCustomFieldStringIndex.php', 'PhabricatorUserDAO' => 'applications/people/storage/PhabricatorUserDAO.php', 'PhabricatorUserEditor' => 'applications/people/editor/PhabricatorUserEditor.php', 'PhabricatorUserEditorTestCase' => 'applications/people/editor/__tests__/PhabricatorUserEditorTestCase.php', 'PhabricatorUserEmail' => 'applications/people/storage/PhabricatorUserEmail.php', 'PhabricatorUserEmailTestCase' => 'applications/people/storage/__tests__/PhabricatorUserEmailTestCase.php', 'PhabricatorUserLog' => 'applications/people/storage/PhabricatorUserLog.php', 'PhabricatorUserLogView' => 'applications/people/view/PhabricatorUserLogView.php', 'PhabricatorUserPreferences' => 'applications/settings/storage/PhabricatorUserPreferences.php', 'PhabricatorUserProfile' => 'applications/people/storage/PhabricatorUserProfile.php', 'PhabricatorUserProfileEditor' => 'applications/people/editor/PhabricatorUserProfileEditor.php', 'PhabricatorUserRealNameField' => 'applications/people/customfield/PhabricatorUserRealNameField.php', 'PhabricatorUserRolesField' => 'applications/people/customfield/PhabricatorUserRolesField.php', 'PhabricatorUserSSHKey' => 'applications/settings/storage/PhabricatorUserSSHKey.php', 'PhabricatorUserSearchIndexer' => 'applications/people/search/PhabricatorUserSearchIndexer.php', 'PhabricatorUserSinceField' => 'applications/people/customfield/PhabricatorUserSinceField.php', 'PhabricatorUserStatusField' => 'applications/people/customfield/PhabricatorUserStatusField.php', 'PhabricatorUserTestCase' => 'applications/people/storage/__tests__/PhabricatorUserTestCase.php', 'PhabricatorUserTitleField' => 'applications/people/customfield/PhabricatorUserTitleField.php', 'PhabricatorUserTransaction' => 'applications/people/storage/PhabricatorUserTransaction.php', 'PhabricatorVCSResponse' => 'applications/repository/response/PhabricatorVCSResponse.php', 'PhabricatorWordPressAuthProvider' => 'applications/auth/provider/PhabricatorWordPressAuthProvider.php', 'PhabricatorWorker' => 'infrastructure/daemon/workers/PhabricatorWorker.php', 'PhabricatorWorkerActiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerActiveTask.php', 'PhabricatorWorkerArchiveTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerArchiveTask.php', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerDAO.php', 'PhabricatorWorkerLeaseQuery' => 'infrastructure/daemon/workers/query/PhabricatorWorkerLeaseQuery.php', 'PhabricatorWorkerPermanentFailureException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerPermanentFailureException.php', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTask.php', 'PhabricatorWorkerTaskData' => 'infrastructure/daemon/workers/storage/PhabricatorWorkerTaskData.php', 'PhabricatorWorkerTaskDetailController' => 'applications/daemon/controller/PhabricatorWorkerTaskDetailController.php', 'PhabricatorWorkerTaskUpdateController' => 'applications/daemon/controller/PhabricatorWorkerTaskUpdateController.php', 'PhabricatorWorkerTestCase' => 'infrastructure/daemon/workers/__tests__/PhabricatorWorkerTestCase.php', 'PhabricatorWorkerYieldException' => 'infrastructure/daemon/workers/exception/PhabricatorWorkerYieldException.php', 'PhabricatorWorkingCopyDiscoveryTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyDiscoveryTestCase.php', 'PhabricatorWorkingCopyPullTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyPullTestCase.php', 'PhabricatorWorkingCopyTestCase' => 'applications/repository/engine/__tests__/PhabricatorWorkingCopyTestCase.php', 'PhabricatorXHPASTViewController' => 'applications/phpast/controller/PhabricatorXHPASTViewController.php', 'PhabricatorXHPASTViewDAO' => 'applications/phpast/storage/PhabricatorXHPASTViewDAO.php', 'PhabricatorXHPASTViewFrameController' => 'applications/phpast/controller/PhabricatorXHPASTViewFrameController.php', 'PhabricatorXHPASTViewFramesetController' => 'applications/phpast/controller/PhabricatorXHPASTViewFramesetController.php', 'PhabricatorXHPASTViewInputController' => 'applications/phpast/controller/PhabricatorXHPASTViewInputController.php', 'PhabricatorXHPASTViewPanelController' => 'applications/phpast/controller/PhabricatorXHPASTViewPanelController.php', 'PhabricatorXHPASTViewParseTree' => 'applications/phpast/storage/PhabricatorXHPASTViewParseTree.php', 'PhabricatorXHPASTViewRunController' => 'applications/phpast/controller/PhabricatorXHPASTViewRunController.php', 'PhabricatorXHPASTViewStreamController' => 'applications/phpast/controller/PhabricatorXHPASTViewStreamController.php', 'PhabricatorXHPASTViewTreeController' => 'applications/phpast/controller/PhabricatorXHPASTViewTreeController.php', 'PhabricatorXHProfApplication' => 'applications/xhprof/application/PhabricatorXHProfApplication.php', 'PhabricatorXHProfController' => 'applications/xhprof/controller/PhabricatorXHProfController.php', 'PhabricatorXHProfDAO' => 'applications/xhprof/storage/PhabricatorXHProfDAO.php', 'PhabricatorXHProfProfileController' => 'applications/xhprof/controller/PhabricatorXHProfProfileController.php', 'PhabricatorXHProfProfileSymbolView' => 'applications/xhprof/view/PhabricatorXHProfProfileSymbolView.php', 'PhabricatorXHProfProfileTopLevelView' => 'applications/xhprof/view/PhabricatorXHProfProfileTopLevelView.php', 'PhabricatorXHProfProfileView' => 'applications/xhprof/view/PhabricatorXHProfProfileView.php', 'PhabricatorXHProfSample' => 'applications/xhprof/storage/PhabricatorXHProfSample.php', 'PhabricatorXHProfSampleListController' => 'applications/xhprof/controller/PhabricatorXHProfSampleListController.php', 'PhameBasicBlogSkin' => 'applications/phame/skins/PhameBasicBlogSkin.php', 'PhameBasicTemplateBlogSkin' => 'applications/phame/skins/PhameBasicTemplateBlogSkin.php', 'PhameBlog' => 'applications/phame/storage/PhameBlog.php', 'PhameBlogDeleteController' => 'applications/phame/controller/blog/PhameBlogDeleteController.php', 'PhameBlogEditController' => 'applications/phame/controller/blog/PhameBlogEditController.php', 'PhameBlogFeedController' => 'applications/phame/controller/blog/PhameBlogFeedController.php', 'PhameBlogListController' => 'applications/phame/controller/blog/PhameBlogListController.php', 'PhameBlogLiveController' => 'applications/phame/controller/blog/PhameBlogLiveController.php', 'PhameBlogQuery' => 'applications/phame/query/PhameBlogQuery.php', 'PhameBlogSkin' => 'applications/phame/skins/PhameBlogSkin.php', 'PhameBlogViewController' => 'applications/phame/controller/blog/PhameBlogViewController.php', 'PhameCelerityResources' => 'applications/phame/celerity/PhameCelerityResources.php', 'PhameController' => 'applications/phame/controller/PhameController.php', 'PhameDAO' => 'applications/phame/storage/PhameDAO.php', 'PhamePost' => 'applications/phame/storage/PhamePost.php', 'PhamePostDeleteController' => 'applications/phame/controller/post/PhamePostDeleteController.php', 'PhamePostEditController' => 'applications/phame/controller/post/PhamePostEditController.php', 'PhamePostFramedController' => 'applications/phame/controller/post/PhamePostFramedController.php', 'PhamePostListController' => 'applications/phame/controller/post/PhamePostListController.php', 'PhamePostNewController' => 'applications/phame/controller/post/PhamePostNewController.php', 'PhamePostNotLiveController' => 'applications/phame/controller/post/PhamePostNotLiveController.php', 'PhamePostPreviewController' => 'applications/phame/controller/post/PhamePostPreviewController.php', 'PhamePostPublishController' => 'applications/phame/controller/post/PhamePostPublishController.php', 'PhamePostQuery' => 'applications/phame/query/PhamePostQuery.php', 'PhamePostUnpublishController' => 'applications/phame/controller/post/PhamePostUnpublishController.php', 'PhamePostView' => 'applications/phame/view/PhamePostView.php', 'PhamePostViewController' => 'applications/phame/controller/post/PhamePostViewController.php', 'PhameResourceController' => 'applications/phame/controller/PhameResourceController.php', 'PhameSkinSpecification' => 'applications/phame/skins/PhameSkinSpecification.php', 'PhluxController' => 'applications/phlux/controller/PhluxController.php', 'PhluxDAO' => 'applications/phlux/storage/PhluxDAO.php', 'PhluxEditController' => 'applications/phlux/controller/PhluxEditController.php', 'PhluxListController' => 'applications/phlux/controller/PhluxListController.php', - 'PhluxPHIDTypeVariable' => 'applications/phlux/phid/PhluxPHIDTypeVariable.php', 'PhluxTransaction' => 'applications/phlux/storage/PhluxTransaction.php', 'PhluxTransactionQuery' => 'applications/phlux/query/PhluxTransactionQuery.php', 'PhluxVariable' => 'applications/phlux/storage/PhluxVariable.php', 'PhluxVariableEditor' => 'applications/phlux/editor/PhluxVariableEditor.php', + 'PhluxVariablePHIDType' => 'applications/phlux/phid/PhluxVariablePHIDType.php', 'PhluxVariableQuery' => 'applications/phlux/query/PhluxVariableQuery.php', 'PhluxViewController' => 'applications/phlux/controller/PhluxViewController.php', 'PholioActionMenuEventListener' => 'applications/pholio/event/PholioActionMenuEventListener.php', 'PholioCapabilityDefaultEdit' => 'applications/pholio/capability/PholioCapabilityDefaultEdit.php', 'PholioCapabilityDefaultView' => 'applications/pholio/capability/PholioCapabilityDefaultView.php', 'PholioConstants' => 'applications/pholio/constants/PholioConstants.php', 'PholioController' => 'applications/pholio/controller/PholioController.php', 'PholioDAO' => 'applications/pholio/storage/PholioDAO.php', 'PholioImage' => 'applications/pholio/storage/PholioImage.php', + 'PholioImagePHIDType' => 'applications/pholio/phid/PholioImagePHIDType.php', 'PholioImageQuery' => 'applications/pholio/query/PholioImageQuery.php', 'PholioImageUploadController' => 'applications/pholio/controller/PholioImageUploadController.php', 'PholioInlineController' => 'applications/pholio/controller/PholioInlineController.php', 'PholioInlineListController' => 'applications/pholio/controller/PholioInlineListController.php', 'PholioInlineThumbController' => 'applications/pholio/controller/PholioInlineThumbController.php', 'PholioMock' => 'applications/pholio/storage/PholioMock.php', 'PholioMockCommentController' => 'applications/pholio/controller/PholioMockCommentController.php', 'PholioMockEditController' => 'applications/pholio/controller/PholioMockEditController.php', 'PholioMockEditor' => 'applications/pholio/editor/PholioMockEditor.php', 'PholioMockEmbedView' => 'applications/pholio/view/PholioMockEmbedView.php', 'PholioMockImagesView' => 'applications/pholio/view/PholioMockImagesView.php', 'PholioMockListController' => 'applications/pholio/controller/PholioMockListController.php', 'PholioMockMailReceiver' => 'applications/pholio/mail/PholioMockMailReceiver.php', + 'PholioMockPHIDType' => 'applications/pholio/phid/PholioMockPHIDType.php', 'PholioMockQuery' => 'applications/pholio/query/PholioMockQuery.php', 'PholioMockSearchEngine' => 'applications/pholio/query/PholioMockSearchEngine.php', 'PholioMockThumbGridView' => 'applications/pholio/view/PholioMockThumbGridView.php', 'PholioMockViewController' => 'applications/pholio/controller/PholioMockViewController.php', - 'PholioPHIDTypeImage' => 'applications/pholio/phid/PholioPHIDTypeImage.php', - 'PholioPHIDTypeMock' => 'applications/pholio/phid/PholioPHIDTypeMock.php', 'PholioRemarkupRule' => 'applications/pholio/remarkup/PholioRemarkupRule.php', 'PholioReplyHandler' => 'applications/pholio/mail/PholioReplyHandler.php', 'PholioSearchIndexer' => 'applications/pholio/search/PholioSearchIndexer.php', 'PholioTransaction' => 'applications/pholio/storage/PholioTransaction.php', 'PholioTransactionComment' => 'applications/pholio/storage/PholioTransactionComment.php', 'PholioTransactionQuery' => 'applications/pholio/query/PholioTransactionQuery.php', 'PholioTransactionType' => 'applications/pholio/constants/PholioTransactionType.php', 'PholioTransactionView' => 'applications/pholio/view/PholioTransactionView.php', 'PholioUploadedImageView' => 'applications/pholio/view/PholioUploadedImageView.php', 'PhortuneAccount' => 'applications/phortune/storage/PhortuneAccount.php', 'PhortuneAccountEditor' => 'applications/phortune/editor/PhortuneAccountEditor.php', 'PhortuneAccountQuery' => 'applications/phortune/query/PhortuneAccountQuery.php', 'PhortuneAccountTransaction' => 'applications/phortune/storage/PhortuneAccountTransaction.php', 'PhortuneAccountTransactionQuery' => 'applications/phortune/query/PhortuneAccountTransactionQuery.php', 'PhortuneAccountViewController' => 'applications/phortune/controller/PhortuneAccountViewController.php', 'PhortuneBalancedPaymentProvider' => 'applications/phortune/provider/PhortuneBalancedPaymentProvider.php', 'PhortuneCart' => 'applications/phortune/storage/PhortuneCart.php', 'PhortuneCartCheckoutController' => 'applications/phortune/controller/PhortuneCartCheckoutController.php', 'PhortuneCartController' => 'applications/phortune/controller/PhortuneCartController.php', 'PhortuneCartQuery' => 'applications/phortune/query/PhortuneCartQuery.php', 'PhortuneCartViewController' => 'applications/phortune/controller/PhortuneCartViewController.php', 'PhortuneCharge' => 'applications/phortune/storage/PhortuneCharge.php', 'PhortuneChargeQuery' => 'applications/phortune/query/PhortuneChargeQuery.php', 'PhortuneConstants' => 'applications/phortune/constants/PhortuneConstants.php', 'PhortuneController' => 'applications/phortune/controller/PhortuneController.php', 'PhortuneCreditCardForm' => 'applications/phortune/view/PhortuneCreditCardForm.php', 'PhortuneCurrency' => 'applications/phortune/currency/PhortuneCurrency.php', 'PhortuneCurrencyTestCase' => 'applications/phortune/currency/__tests__/PhortuneCurrencyTestCase.php', 'PhortuneDAO' => 'applications/phortune/storage/PhortuneDAO.php', 'PhortuneErrCode' => 'applications/phortune/constants/PhortuneErrCode.php', 'PhortuneLandingController' => 'applications/phortune/controller/PhortuneLandingController.php', 'PhortuneMonthYearExpiryControl' => 'applications/phortune/control/PhortuneMonthYearExpiryControl.php', 'PhortuneMultiplePaymentProvidersException' => 'applications/phortune/exception/PhortuneMultiplePaymentProvidersException.php', 'PhortuneNoPaymentProviderException' => 'applications/phortune/exception/PhortuneNoPaymentProviderException.php', 'PhortuneNotImplementedException' => 'applications/phortune/exception/PhortuneNotImplementedException.php', 'PhortunePaymentMethod' => 'applications/phortune/storage/PhortunePaymentMethod.php', 'PhortunePaymentMethodEditController' => 'applications/phortune/controller/PhortunePaymentMethodEditController.php', 'PhortunePaymentMethodListController' => 'applications/phortune/controller/PhortunePaymentMethodListController.php', 'PhortunePaymentMethodQuery' => 'applications/phortune/query/PhortunePaymentMethodQuery.php', 'PhortunePaymentMethodViewController' => 'applications/phortune/controller/PhortunePaymentMethodViewController.php', 'PhortunePaymentProvider' => 'applications/phortune/provider/PhortunePaymentProvider.php', 'PhortunePaymentProviderTestCase' => 'applications/phortune/provider/__tests__/PhortunePaymentProviderTestCase.php', 'PhortunePaypalPaymentProvider' => 'applications/phortune/provider/PhortunePaypalPaymentProvider.php', 'PhortuneProduct' => 'applications/phortune/storage/PhortuneProduct.php', 'PhortuneProductEditController' => 'applications/phortune/controller/PhortuneProductEditController.php', 'PhortuneProductEditor' => 'applications/phortune/editor/PhortuneProductEditor.php', 'PhortuneProductListController' => 'applications/phortune/controller/PhortuneProductListController.php', 'PhortuneProductPurchaseController' => 'applications/phortune/controller/PhortuneProductPurchaseController.php', 'PhortuneProductQuery' => 'applications/phortune/query/PhortuneProductQuery.php', 'PhortuneProductTransaction' => 'applications/phortune/storage/PhortuneProductTransaction.php', 'PhortuneProductTransactionQuery' => 'applications/phortune/query/PhortuneProductTransactionQuery.php', 'PhortuneProductViewController' => 'applications/phortune/controller/PhortuneProductViewController.php', 'PhortuneProviderController' => 'applications/phortune/controller/PhortuneProviderController.php', 'PhortunePurchase' => 'applications/phortune/storage/PhortunePurchase.php', 'PhortunePurchaseQuery' => 'applications/phortune/query/PhortunePurchaseQuery.php', 'PhortuneStripePaymentProvider' => 'applications/phortune/provider/PhortuneStripePaymentProvider.php', 'PhortuneTestExtraPaymentProvider' => 'applications/phortune/provider/__tests__/PhortuneTestExtraPaymentProvider.php', 'PhortuneTestPaymentProvider' => 'applications/phortune/provider/PhortuneTestPaymentProvider.php', 'PhortuneWePayPaymentProvider' => 'applications/phortune/provider/PhortuneWePayPaymentProvider.php', 'PhragmentBrowseController' => 'applications/phragment/controller/PhragmentBrowseController.php', 'PhragmentCapabilityCanCreate' => 'applications/phragment/capability/PhragmentCapabilityCanCreate.php', 'PhragmentController' => 'applications/phragment/controller/PhragmentController.php', 'PhragmentCreateController' => 'applications/phragment/controller/PhragmentCreateController.php', 'PhragmentDAO' => 'applications/phragment/storage/PhragmentDAO.php', 'PhragmentFragment' => 'applications/phragment/storage/PhragmentFragment.php', + 'PhragmentFragmentPHIDType' => 'applications/phragment/phid/PhragmentFragmentPHIDType.php', 'PhragmentFragmentQuery' => 'applications/phragment/query/PhragmentFragmentQuery.php', 'PhragmentFragmentVersion' => 'applications/phragment/storage/PhragmentFragmentVersion.php', + 'PhragmentFragmentVersionPHIDType' => 'applications/phragment/phid/PhragmentFragmentVersionPHIDType.php', 'PhragmentFragmentVersionQuery' => 'applications/phragment/query/PhragmentFragmentVersionQuery.php', 'PhragmentHistoryController' => 'applications/phragment/controller/PhragmentHistoryController.php', - 'PhragmentPHIDTypeFragment' => 'applications/phragment/phid/PhragmentPHIDTypeFragment.php', - 'PhragmentPHIDTypeFragmentVersion' => 'applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php', - 'PhragmentPHIDTypeSnapshot' => 'applications/phragment/phid/PhragmentPHIDTypeSnapshot.php', 'PhragmentPatchController' => 'applications/phragment/controller/PhragmentPatchController.php', 'PhragmentPatchUtil' => 'applications/phragment/util/PhragmentPatchUtil.php', 'PhragmentPolicyController' => 'applications/phragment/controller/PhragmentPolicyController.php', 'PhragmentRevertController' => 'applications/phragment/controller/PhragmentRevertController.php', 'PhragmentSnapshot' => 'applications/phragment/storage/PhragmentSnapshot.php', 'PhragmentSnapshotChild' => 'applications/phragment/storage/PhragmentSnapshotChild.php', 'PhragmentSnapshotChildQuery' => 'applications/phragment/query/PhragmentSnapshotChildQuery.php', 'PhragmentSnapshotCreateController' => 'applications/phragment/controller/PhragmentSnapshotCreateController.php', 'PhragmentSnapshotDeleteController' => 'applications/phragment/controller/PhragmentSnapshotDeleteController.php', + 'PhragmentSnapshotPHIDType' => 'applications/phragment/phid/PhragmentSnapshotPHIDType.php', 'PhragmentSnapshotPromoteController' => 'applications/phragment/controller/PhragmentSnapshotPromoteController.php', 'PhragmentSnapshotQuery' => 'applications/phragment/query/PhragmentSnapshotQuery.php', 'PhragmentSnapshotViewController' => 'applications/phragment/controller/PhragmentSnapshotViewController.php', 'PhragmentUpdateController' => 'applications/phragment/controller/PhragmentUpdateController.php', 'PhragmentVersionController' => 'applications/phragment/controller/PhragmentVersionController.php', 'PhragmentZIPController' => 'applications/phragment/controller/PhragmentZIPController.php', 'PhrequentController' => 'applications/phrequent/controller/PhrequentController.php', 'PhrequentDAO' => 'applications/phrequent/storage/PhrequentDAO.php', 'PhrequentListController' => 'applications/phrequent/controller/PhrequentListController.php', 'PhrequentSearchEngine' => 'applications/phrequent/query/PhrequentSearchEngine.php', 'PhrequentTimeBlock' => 'applications/phrequent/storage/PhrequentTimeBlock.php', 'PhrequentTimeBlockTestCase' => 'applications/phrequent/storage/__tests__/PhrequentTimeBlockTestCase.php', 'PhrequentTimeSlices' => 'applications/phrequent/storage/PhrequentTimeSlices.php', 'PhrequentTrackController' => 'applications/phrequent/controller/PhrequentTrackController.php', 'PhrequentTrackableInterface' => 'applications/phrequent/interface/PhrequentTrackableInterface.php', 'PhrequentTrackingEditor' => 'applications/phrequent/editor/PhrequentTrackingEditor.php', 'PhrequentUIEventListener' => 'applications/phrequent/event/PhrequentUIEventListener.php', 'PhrequentUserTime' => 'applications/phrequent/storage/PhrequentUserTime.php', 'PhrequentUserTimeQuery' => 'applications/phrequent/query/PhrequentUserTimeQuery.php', 'PhrictionActionConstants' => 'applications/phriction/constants/PhrictionActionConstants.php', 'PhrictionActionMenuEventListener' => 'applications/phriction/event/PhrictionActionMenuEventListener.php', 'PhrictionChangeType' => 'applications/phriction/constants/PhrictionChangeType.php', 'PhrictionConstants' => 'applications/phriction/constants/PhrictionConstants.php', 'PhrictionContent' => 'applications/phriction/storage/PhrictionContent.php', 'PhrictionController' => 'applications/phriction/controller/PhrictionController.php', 'PhrictionDAO' => 'applications/phriction/storage/PhrictionDAO.php', 'PhrictionDeleteController' => 'applications/phriction/controller/PhrictionDeleteController.php', 'PhrictionDiffController' => 'applications/phriction/controller/PhrictionDiffController.php', 'PhrictionDocument' => 'applications/phriction/storage/PhrictionDocument.php', 'PhrictionDocumentController' => 'applications/phriction/controller/PhrictionDocumentController.php', 'PhrictionDocumentEditor' => 'applications/phriction/editor/PhrictionDocumentEditor.php', + 'PhrictionDocumentPHIDType' => 'applications/phriction/phid/PhrictionDocumentPHIDType.php', 'PhrictionDocumentPreviewController' => 'applications/phriction/controller/PhrictionDocumentPreviewController.php', 'PhrictionDocumentQuery' => 'applications/phriction/query/PhrictionDocumentQuery.php', 'PhrictionDocumentStatus' => 'applications/phriction/constants/PhrictionDocumentStatus.php', 'PhrictionDocumentTestCase' => 'applications/phriction/storage/__tests__/PhrictionDocumentTestCase.php', 'PhrictionEditController' => 'applications/phriction/controller/PhrictionEditController.php', 'PhrictionHistoryController' => 'applications/phriction/controller/PhrictionHistoryController.php', 'PhrictionListController' => 'applications/phriction/controller/PhrictionListController.php', 'PhrictionMoveController' => 'applications/phriction/controller/PhrictionMoveController.php', 'PhrictionNewController' => 'applications/phriction/controller/PhrictionNewController.php', - 'PhrictionPHIDTypeDocument' => 'applications/phriction/phid/PhrictionPHIDTypeDocument.php', 'PhrictionRemarkupRule' => 'applications/phriction/remarkup/PhrictionRemarkupRule.php', 'PhrictionSearchEngine' => 'applications/phriction/query/PhrictionSearchEngine.php', 'PhrictionSearchIndexer' => 'applications/phriction/search/PhrictionSearchIndexer.php', 'PonderAddAnswerView' => 'applications/ponder/view/PonderAddAnswerView.php', 'PonderAnswer' => 'applications/ponder/storage/PonderAnswer.php', 'PonderAnswerCommentController' => 'applications/ponder/controller/PonderAnswerCommentController.php', 'PonderAnswerEditController' => 'applications/ponder/controller/PonderAnswerEditController.php', 'PonderAnswerEditor' => 'applications/ponder/editor/PonderAnswerEditor.php', 'PonderAnswerHistoryController' => 'applications/ponder/controller/PonderAnswerHistoryController.php', + 'PonderAnswerPHIDType' => 'applications/ponder/phid/PonderAnswerPHIDType.php', 'PonderAnswerQuery' => 'applications/ponder/query/PonderAnswerQuery.php', 'PonderAnswerSaveController' => 'applications/ponder/controller/PonderAnswerSaveController.php', 'PonderAnswerTransaction' => 'applications/ponder/storage/PonderAnswerTransaction.php', 'PonderAnswerTransactionComment' => 'applications/ponder/storage/PonderAnswerTransactionComment.php', 'PonderAnswerTransactionQuery' => 'applications/ponder/query/PonderAnswerTransactionQuery.php', 'PonderComment' => 'applications/ponder/storage/PonderComment.php', 'PonderCommentQuery' => 'applications/ponder/query/PonderCommentQuery.php', 'PonderConstants' => 'applications/ponder/constants/PonderConstants.php', 'PonderController' => 'applications/ponder/controller/PonderController.php', 'PonderDAO' => 'applications/ponder/storage/PonderDAO.php', 'PonderEditor' => 'applications/ponder/editor/PonderEditor.php', - 'PonderPHIDTypeAnswer' => 'applications/ponder/phid/PonderPHIDTypeAnswer.php', - 'PonderPHIDTypeQuestion' => 'applications/ponder/phid/PonderPHIDTypeQuestion.php', 'PonderQuestion' => 'applications/ponder/storage/PonderQuestion.php', 'PonderQuestionCommentController' => 'applications/ponder/controller/PonderQuestionCommentController.php', 'PonderQuestionEditController' => 'applications/ponder/controller/PonderQuestionEditController.php', 'PonderQuestionEditor' => 'applications/ponder/editor/PonderQuestionEditor.php', 'PonderQuestionHistoryController' => 'applications/ponder/controller/PonderQuestionHistoryController.php', 'PonderQuestionListController' => 'applications/ponder/controller/PonderQuestionListController.php', 'PonderQuestionMailReceiver' => 'applications/ponder/mail/PonderQuestionMailReceiver.php', + 'PonderQuestionPHIDType' => 'applications/ponder/phid/PonderQuestionPHIDType.php', 'PonderQuestionQuery' => 'applications/ponder/query/PonderQuestionQuery.php', 'PonderQuestionReplyHandler' => 'applications/ponder/mail/PonderQuestionReplyHandler.php', 'PonderQuestionSearchEngine' => 'applications/ponder/query/PonderQuestionSearchEngine.php', 'PonderQuestionStatus' => 'applications/ponder/constants/PonderQuestionStatus.php', 'PonderQuestionStatusController' => 'applications/ponder/controller/PonderQuestionStatusController.php', 'PonderQuestionTransaction' => 'applications/ponder/storage/PonderQuestionTransaction.php', 'PonderQuestionTransactionComment' => 'applications/ponder/storage/PonderQuestionTransactionComment.php', 'PonderQuestionTransactionQuery' => 'applications/ponder/query/PonderQuestionTransactionQuery.php', 'PonderQuestionViewController' => 'applications/ponder/controller/PonderQuestionViewController.php', 'PonderRemarkupRule' => 'applications/ponder/remarkup/PonderRemarkupRule.php', 'PonderSearchIndexer' => 'applications/ponder/search/PonderSearchIndexer.php', 'PonderTransactionFeedStory' => 'applications/ponder/feed/PonderTransactionFeedStory.php', 'PonderVotableInterface' => 'applications/ponder/storage/PonderVotableInterface.php', 'PonderVotableView' => 'applications/ponder/view/PonderVotableView.php', 'PonderVote' => 'applications/ponder/constants/PonderVote.php', 'PonderVoteEditor' => 'applications/ponder/editor/PonderVoteEditor.php', 'PonderVoteSaveController' => 'applications/ponder/controller/PonderVoteSaveController.php', 'ProjectBoardTaskCard' => 'applications/project/view/ProjectBoardTaskCard.php', 'ProjectCapabilityCreateProjects' => 'applications/project/capability/ProjectCapabilityCreateProjects.php', 'ProjectRemarkupRule' => 'applications/project/remarkup/ProjectRemarkupRule.php', 'QueryFormattingTestCase' => 'infrastructure/storage/__tests__/QueryFormattingTestCase.php', 'ReleephAuthorFieldSpecification' => 'applications/releeph/field/specification/ReleephAuthorFieldSpecification.php', 'ReleephBranch' => 'applications/releeph/storage/ReleephBranch.php', 'ReleephBranchAccessController' => 'applications/releeph/controller/branch/ReleephBranchAccessController.php', 'ReleephBranchCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephBranchCommitFieldSpecification.php', 'ReleephBranchController' => 'applications/releeph/controller/branch/ReleephBranchController.php', 'ReleephBranchCreateController' => 'applications/releeph/controller/branch/ReleephBranchCreateController.php', 'ReleephBranchEditController' => 'applications/releeph/controller/branch/ReleephBranchEditController.php', 'ReleephBranchEditor' => 'applications/releeph/editor/ReleephBranchEditor.php', 'ReleephBranchHistoryController' => 'applications/releeph/controller/branch/ReleephBranchHistoryController.php', 'ReleephBranchNamePreviewController' => 'applications/releeph/controller/branch/ReleephBranchNamePreviewController.php', + 'ReleephBranchPHIDType' => 'applications/releeph/phid/ReleephBranchPHIDType.php', 'ReleephBranchPreviewView' => 'applications/releeph/view/branch/ReleephBranchPreviewView.php', 'ReleephBranchQuery' => 'applications/releeph/query/ReleephBranchQuery.php', 'ReleephBranchSearchEngine' => 'applications/releeph/query/ReleephBranchSearchEngine.php', 'ReleephBranchTemplate' => 'applications/releeph/view/branch/ReleephBranchTemplate.php', 'ReleephBranchTransaction' => 'applications/releeph/storage/ReleephBranchTransaction.php', 'ReleephBranchTransactionQuery' => 'applications/releeph/query/ReleephBranchTransactionQuery.php', 'ReleephBranchViewController' => 'applications/releeph/controller/branch/ReleephBranchViewController.php', 'ReleephCommitFinder' => 'applications/releeph/commitfinder/ReleephCommitFinder.php', 'ReleephCommitFinderException' => 'applications/releeph/commitfinder/ReleephCommitFinderException.php', 'ReleephCommitMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephCommitMessageFieldSpecification.php', 'ReleephController' => 'applications/releeph/controller/ReleephController.php', 'ReleephDAO' => 'applications/releeph/storage/ReleephDAO.php', 'ReleephDefaultFieldSelector' => 'applications/releeph/field/selector/ReleephDefaultFieldSelector.php', 'ReleephDependsOnFieldSpecification' => 'applications/releeph/field/specification/ReleephDependsOnFieldSpecification.php', 'ReleephDiffChurnFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffChurnFieldSpecification.php', 'ReleephDiffMessageFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffMessageFieldSpecification.php', 'ReleephDiffSizeFieldSpecification' => 'applications/releeph/field/specification/ReleephDiffSizeFieldSpecification.php', 'ReleephFieldParseException' => 'applications/releeph/field/exception/ReleephFieldParseException.php', 'ReleephFieldSelector' => 'applications/releeph/field/selector/ReleephFieldSelector.php', 'ReleephFieldSpecification' => 'applications/releeph/field/specification/ReleephFieldSpecification.php', 'ReleephIntentFieldSpecification' => 'applications/releeph/field/specification/ReleephIntentFieldSpecification.php', 'ReleephLevelFieldSpecification' => 'applications/releeph/field/specification/ReleephLevelFieldSpecification.php', 'ReleephOriginalCommitFieldSpecification' => 'applications/releeph/field/specification/ReleephOriginalCommitFieldSpecification.php', - 'ReleephPHIDTypeBranch' => 'applications/releeph/phid/ReleephPHIDTypeBranch.php', - 'ReleephPHIDTypeProduct' => 'applications/releeph/phid/ReleephPHIDTypeProduct.php', - 'ReleephPHIDTypeRequest' => 'applications/releeph/phid/ReleephPHIDTypeRequest.php', 'ReleephProductActionController' => 'applications/releeph/controller/product/ReleephProductActionController.php', 'ReleephProductController' => 'applications/releeph/controller/product/ReleephProductController.php', 'ReleephProductCreateController' => 'applications/releeph/controller/product/ReleephProductCreateController.php', 'ReleephProductEditController' => 'applications/releeph/controller/product/ReleephProductEditController.php', 'ReleephProductEditor' => 'applications/releeph/editor/ReleephProductEditor.php', 'ReleephProductHistoryController' => 'applications/releeph/controller/product/ReleephProductHistoryController.php', 'ReleephProductListController' => 'applications/releeph/controller/product/ReleephProductListController.php', + 'ReleephProductPHIDType' => 'applications/releeph/phid/ReleephProductPHIDType.php', 'ReleephProductQuery' => 'applications/releeph/query/ReleephProductQuery.php', 'ReleephProductSearchEngine' => 'applications/releeph/query/ReleephProductSearchEngine.php', 'ReleephProductTransaction' => 'applications/releeph/storage/ReleephProductTransaction.php', 'ReleephProductTransactionQuery' => 'applications/releeph/query/ReleephProductTransactionQuery.php', 'ReleephProductViewController' => 'applications/releeph/controller/product/ReleephProductViewController.php', 'ReleephProject' => 'applications/releeph/storage/ReleephProject.php', 'ReleephReasonFieldSpecification' => 'applications/releeph/field/specification/ReleephReasonFieldSpecification.php', 'ReleephRequest' => 'applications/releeph/storage/ReleephRequest.php', 'ReleephRequestActionController' => 'applications/releeph/controller/request/ReleephRequestActionController.php', 'ReleephRequestCommentController' => 'applications/releeph/controller/request/ReleephRequestCommentController.php', 'ReleephRequestController' => 'applications/releeph/controller/request/ReleephRequestController.php', 'ReleephRequestDifferentialCreateController' => 'applications/releeph/controller/request/ReleephRequestDifferentialCreateController.php', 'ReleephRequestEditController' => 'applications/releeph/controller/request/ReleephRequestEditController.php', 'ReleephRequestMailReceiver' => 'applications/releeph/mail/ReleephRequestMailReceiver.php', + 'ReleephRequestPHIDType' => 'applications/releeph/phid/ReleephRequestPHIDType.php', 'ReleephRequestQuery' => 'applications/releeph/query/ReleephRequestQuery.php', 'ReleephRequestReplyHandler' => 'applications/releeph/mail/ReleephRequestReplyHandler.php', 'ReleephRequestSearchEngine' => 'applications/releeph/query/ReleephRequestSearchEngine.php', 'ReleephRequestStatus' => 'applications/releeph/constants/ReleephRequestStatus.php', 'ReleephRequestTransaction' => 'applications/releeph/storage/ReleephRequestTransaction.php', 'ReleephRequestTransactionComment' => 'applications/releeph/storage/ReleephRequestTransactionComment.php', 'ReleephRequestTransactionQuery' => 'applications/releeph/query/ReleephRequestTransactionQuery.php', 'ReleephRequestTransactionalEditor' => 'applications/releeph/editor/ReleephRequestTransactionalEditor.php', 'ReleephRequestTypeaheadControl' => 'applications/releeph/view/request/ReleephRequestTypeaheadControl.php', 'ReleephRequestTypeaheadController' => 'applications/releeph/controller/request/ReleephRequestTypeaheadController.php', 'ReleephRequestView' => 'applications/releeph/view/ReleephRequestView.php', 'ReleephRequestViewController' => 'applications/releeph/controller/request/ReleephRequestViewController.php', 'ReleephRequestorFieldSpecification' => 'applications/releeph/field/specification/ReleephRequestorFieldSpecification.php', 'ReleephRevisionFieldSpecification' => 'applications/releeph/field/specification/ReleephRevisionFieldSpecification.php', 'ReleephSeverityFieldSpecification' => 'applications/releeph/field/specification/ReleephSeverityFieldSpecification.php', 'ReleephSummaryFieldSpecification' => 'applications/releeph/field/specification/ReleephSummaryFieldSpecification.php', 'ShellLogView' => 'applications/harbormaster/view/ShellLogView.php', 'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php', 'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php', 'SubscriptionListDialogBuilder' => 'applications/subscriptions/view/SubscriptionListDialogBuilder.php', 'SubscriptionListStringBuilder' => 'applications/subscriptions/view/SubscriptionListStringBuilder.php', ), 'function' => array( '_phabricator_time_format' => 'view/viewutils.php', 'celerity_generate_unique_node_id' => 'infrastructure/celerity/api.php', 'celerity_get_resource_uri' => 'infrastructure/celerity/api.php', 'implode_selected_handle_links' => 'applications/phid/handle/view/render.php', 'javelin_tag' => 'infrastructure/javelin/markup.php', 'phabricator_date' => 'view/viewutils.php', 'phabricator_datetime' => 'view/viewutils.php', 'phabricator_form' => 'infrastructure/javelin/markup.php', 'phabricator_format_local_time' => 'view/viewutils.php', 'phabricator_on_relative_date' => 'view/viewutils.php', 'phabricator_relative_date' => 'view/viewutils.php', 'phabricator_time' => 'view/viewutils.php', 'phid_get_subtype' => 'applications/phid/utils.php', 'phid_get_type' => 'applications/phid/utils.php', 'phid_group_by_type' => 'applications/phid/utils.php', 'require_celerity_resource' => 'infrastructure/celerity/api.php', ), 'xmap' => array( 'Aphront304Response' => 'AphrontResponse', 'Aphront400Response' => 'AphrontResponse', 'Aphront403Response' => 'AphrontHTMLResponse', 'Aphront404Response' => 'AphrontHTMLResponse', 'AphrontAbstractAttachedFileView' => 'AphrontView', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontBarView' => 'AphrontView', 'AphrontCSRFException' => 'AphrontException', 'AphrontCalendarEventView' => 'AphrontView', 'AphrontContextBarView' => 'AphrontView', 'AphrontController' => 'Phobject', 'AphrontCursorPagerView' => 'AphrontView', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontException' => 'Exception', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormChooseButtonControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormCropControl' => 'AphrontFormControl', 'AphrontFormDateControl' => 'AphrontFormControl', 'AphrontFormDividerControl' => 'AphrontFormControl', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormImageControl' => 'AphrontFormControl', 'AphrontFormInsetView' => 'AphrontView', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormPasswordControl' => 'AphrontFormControl', 'AphrontFormPolicyControl' => 'AphrontFormControl', 'AphrontFormRadioButtonControl' => 'AphrontFormControl', 'AphrontFormRecaptchaControl' => 'AphrontFormControl', 'AphrontFormSectionControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormTextWithSubmitControl' => 'AphrontFormControl', 'AphrontFormToggleButtonsControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormTypeaheadControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontGlyphBarView' => 'AphrontBarView', 'AphrontHTMLResponse' => 'AphrontResponse', 'AphrontHTTPSinkTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', 'AphrontJSONResponse' => 'AphrontResponse', 'AphrontJavelinView' => 'AphrontView', 'AphrontKeyboardShortcutsAvailableView' => 'AphrontView', 'AphrontListFilterView' => 'AphrontView', 'AphrontMiniPanelView' => 'AphrontView', 'AphrontMoreView' => 'AphrontView', 'AphrontMultiColumnView' => 'AphrontView', 'AphrontMySQLDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontNullView' => 'AphrontView', 'AphrontPHPHTTPSink' => 'AphrontHTTPSink', 'AphrontPageView' => 'AphrontView', 'AphrontPagerView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontPlainTextResponse' => 'AphrontResponse', 'AphrontProgressBarView' => 'AphrontBarView', 'AphrontProxyResponse' => 'AphrontResponse', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontReloadResponse' => 'AphrontRedirectResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontRequestTestCase' => 'PhabricatorTestCase', 'AphrontSideNavFilterView' => 'AphrontView', 'AphrontStackTraceView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontTagView' => 'AphrontView', 'AphrontTokenizerTemplateView' => 'AphrontView', 'AphrontTwoColumnView' => 'AphrontView', 'AphrontTypeaheadTemplateView' => 'AphrontView', 'AphrontUsageException' => 'AphrontException', 'AphrontView' => array( 'Phobject', 'PhutilSafeHTMLProducerInterface', ), 'AphrontWebpageResponse' => 'AphrontHTMLResponse', 'AuditActionMenuEventListener' => 'PhabricatorEventListener', 'CalendarColors' => 'CalendarConstants', 'CalendarTimeUtilTestCase' => 'PhabricatorTestCase', 'CelerityManagementMapWorkflow' => 'CelerityManagementWorkflow', 'CelerityManagementWorkflow' => 'PhabricatorManagementWorkflow', 'CelerityPhabricatorResourceController' => 'CelerityResourceController', 'CelerityPhabricatorResources' => 'CelerityResourcesOnDisk', 'CelerityPhysicalResources' => 'CelerityResources', 'CelerityResourceController' => 'PhabricatorController', 'CelerityResourceGraph' => 'AbstractDirectedGraph', 'CelerityResourceTransformerTestCase' => 'PhabricatorTestCase', 'CelerityResourcesOnDisk' => 'CelerityPhysicalResources', 'ConduitAPIMethod' => array( 'Phobject', 'PhabricatorPolicyInterface', ), 'ConduitAPI_arcanist_Method' => 'ConduitAPIMethod', 'ConduitAPI_arcanist_projectinfo_Method' => 'ConduitAPI_arcanist_Method', 'ConduitAPI_audit_Method' => 'ConduitAPIMethod', 'ConduitAPI_audit_query_Method' => 'ConduitAPI_audit_Method', 'ConduitAPI_chatlog_Method' => 'ConduitAPIMethod', 'ConduitAPI_chatlog_query_Method' => 'ConduitAPI_chatlog_Method', 'ConduitAPI_chatlog_record_Method' => 'ConduitAPI_chatlog_Method', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_getcertificate_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_ping_Method' => 'ConduitAPIMethod', 'ConduitAPI_conduit_query_Method' => 'ConduitAPIMethod', 'ConduitAPI_conpherence_Method' => 'ConduitAPIMethod', 'ConduitAPI_conpherence_createthread_Method' => 'ConduitAPI_conpherence_Method', 'ConduitAPI_conpherence_querythread_Method' => 'ConduitAPI_conpherence_Method', 'ConduitAPI_conpherence_querytransaction_Method' => 'ConduitAPI_conpherence_Method', 'ConduitAPI_conpherence_updatethread_Method' => 'ConduitAPI_conpherence_Method', 'ConduitAPI_differential_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_close_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_createcomment_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_createinline_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_createrawdiff_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_createrevision_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_find_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_finishpostponedlinters_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getalldiffs_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getcommitmessage_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getcommitpaths_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getdiff_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getrawdiff_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getrevision_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_getrevisioncomments_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_parsecommitmessage_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_query_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_querydiffs_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_updaterevision_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_differential_updateunitresults_Method' => 'ConduitAPI_differential_Method', 'ConduitAPI_diffusion_Method' => 'ConduitAPIMethod', 'ConduitAPI_diffusion_abstractquery_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_branchquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_browsequery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_commitparentsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_createcomment_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_diffquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_existsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_filecontentquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_findsymbols_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_getcommits_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_getlintmessages_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_getrecentcommitsbypath_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_historyquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_lastmodifiedquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_looksoon_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_mergedcommitsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_querycommits_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_diffusion_querypaths_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_rawdiffquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_readmequery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_refsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_resolverefs_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_searchquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_tagsquery_Method' => 'ConduitAPI_diffusion_abstractquery_Method', 'ConduitAPI_diffusion_updatecoverage_Method' => 'ConduitAPI_diffusion_Method', 'ConduitAPI_feed_Method' => 'ConduitAPIMethod', 'ConduitAPI_feed_publish_Method' => 'ConduitAPI_feed_Method', 'ConduitAPI_feed_query_Method' => 'ConduitAPI_feed_Method', 'ConduitAPI_file_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_download_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_file_info_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_file_upload_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_file_uploadhash_Method' => 'ConduitAPI_file_Method', 'ConduitAPI_flag_Method' => 'ConduitAPIMethod', 'ConduitAPI_flag_delete_Method' => 'ConduitAPI_flag_Method', 'ConduitAPI_flag_edit_Method' => 'ConduitAPI_flag_Method', 'ConduitAPI_flag_query_Method' => 'ConduitAPI_flag_Method', 'ConduitAPI_harbormaster_Method' => 'ConduitAPIMethod', 'ConduitAPI_harbormaster_querybuildables_Method' => 'ConduitAPI_harbormaster_Method', 'ConduitAPI_harbormaster_querybuilds_Method' => 'ConduitAPI_harbormaster_Method', 'ConduitAPI_harbormaster_sendmessage_Method' => 'ConduitAPI_harbormaster_Method', 'ConduitAPI_macro_Method' => 'ConduitAPIMethod', 'ConduitAPI_macro_creatememe_Method' => 'ConduitAPI_macro_Method', 'ConduitAPI_macro_query_Method' => 'ConduitAPI_macro_Method', 'ConduitAPI_maniphest_Method' => 'ConduitAPIMethod', 'ConduitAPI_maniphest_createtask_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_find_Method' => 'ConduitAPI_maniphest_query_Method', 'ConduitAPI_maniphest_gettasktransactions_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_info_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_query_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_querystatuses_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_maniphest_update_Method' => 'ConduitAPI_maniphest_Method', 'ConduitAPI_nuance_Method' => 'ConduitAPIMethod', 'ConduitAPI_nuance_createitem_Method' => 'ConduitAPI_nuance_Method', 'ConduitAPI_owners_Method' => 'ConduitAPIMethod', 'ConduitAPI_owners_query_Method' => 'ConduitAPI_owners_Method', 'ConduitAPI_paste_Method' => 'ConduitAPIMethod', 'ConduitAPI_paste_create_Method' => 'ConduitAPI_paste_Method', 'ConduitAPI_paste_info_Method' => 'ConduitAPI_paste_Method', 'ConduitAPI_paste_query_Method' => 'ConduitAPI_paste_Method', 'ConduitAPI_phame_Method' => 'ConduitAPIMethod', 'ConduitAPI_phame_createpost_Method' => 'ConduitAPI_phame_Method', 'ConduitAPI_phame_query_Method' => 'ConduitAPI_phame_Method', 'ConduitAPI_phame_queryposts_Method' => 'ConduitAPI_phame_Method', 'ConduitAPI_phid_Method' => 'ConduitAPIMethod', 'ConduitAPI_phid_info_Method' => 'ConduitAPI_phid_Method', 'ConduitAPI_phid_lookup_Method' => 'ConduitAPI_phid_Method', 'ConduitAPI_phid_query_Method' => 'ConduitAPI_phid_Method', 'ConduitAPI_phragment_Method' => 'ConduitAPIMethod', 'ConduitAPI_phragment_getpatch_Method' => 'ConduitAPI_phragment_Method', 'ConduitAPI_phragment_queryfragments_Method' => 'ConduitAPI_phragment_Method', 'ConduitAPI_phrequent_Method' => 'ConduitAPIMethod', 'ConduitAPI_phrequent_pop_Method' => 'ConduitAPI_phrequent_Method', 'ConduitAPI_phrequent_push_Method' => 'ConduitAPI_phrequent_Method', 'ConduitAPI_phrequent_tracking_Method' => 'ConduitAPI_phrequent_Method', 'ConduitAPI_phriction_Method' => 'ConduitAPIMethod', 'ConduitAPI_phriction_edit_Method' => 'ConduitAPI_phriction_Method', 'ConduitAPI_phriction_history_Method' => 'ConduitAPI_phriction_Method', 'ConduitAPI_phriction_info_Method' => 'ConduitAPI_phriction_Method', 'ConduitAPI_project_Method' => 'ConduitAPIMethod', 'ConduitAPI_project_query_Method' => 'ConduitAPI_project_Method', 'ConduitAPI_releeph_Method' => 'ConduitAPIMethod', 'ConduitAPI_releeph_getbranches_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releeph_projectinfo_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releeph_querybranches_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releeph_queryproducts_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releeph_queryrequests_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releeph_request_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_canpush_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_getauthorinfo_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_getbranch_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_getbranchcommitmessage_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_getcommitmessage_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_nextrequest_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_record_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_releephwork_recordpickstatus_Method' => 'ConduitAPI_releeph_Method', 'ConduitAPI_remarkup_process_Method' => 'ConduitAPIMethod', 'ConduitAPI_repository_Method' => 'ConduitAPIMethod', 'ConduitAPI_repository_create_Method' => 'ConduitAPI_repository_Method', 'ConduitAPI_repository_query_Method' => 'ConduitAPI_repository_Method', 'ConduitAPI_slowvote_Method' => 'ConduitAPIMethod', 'ConduitAPI_slowvote_info_Method' => 'ConduitAPI_slowvote_Method', 'ConduitAPI_token_Method' => 'ConduitAPIMethod', 'ConduitAPI_token_give_Method' => 'ConduitAPI_token_Method', 'ConduitAPI_token_given_Method' => 'ConduitAPI_token_Method', 'ConduitAPI_token_query_Method' => 'ConduitAPI_token_Method', 'ConduitAPI_user_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_addstatus_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_disable_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_enable_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_find_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_info_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_query_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_removestatus_Method' => 'ConduitAPI_user_Method', 'ConduitAPI_user_whoami_Method' => 'ConduitAPI_user_Method', 'ConduitCallTestCase' => 'PhabricatorTestCase', 'ConduitConnectionGarbageCollector' => 'PhabricatorGarbageCollector', 'ConduitException' => 'Exception', 'ConduitLogGarbageCollector' => 'PhabricatorGarbageCollector', 'ConduitSSHWorkflow' => 'PhabricatorSSHWorkflow', 'ConpherenceActionMenuEventListener' => 'PhabricatorEventListener', 'ConpherenceConfigOptions' => 'PhabricatorApplicationConfigOptions', 'ConpherenceController' => 'PhabricatorController', 'ConpherenceCreateThreadMailReceiver' => 'PhabricatorMailReceiver', 'ConpherenceDAO' => 'PhabricatorLiskDAO', 'ConpherenceEditor' => 'PhabricatorApplicationTransactionEditor', 'ConpherenceFileWidgetView' => 'ConpherenceWidgetView', 'ConpherenceHovercardEventListener' => 'PhabricatorEventListener', 'ConpherenceLayoutView' => 'AphrontView', 'ConpherenceListController' => 'ConpherenceController', 'ConpherenceMenuItemView' => 'AphrontTagView', 'ConpherenceNewController' => 'ConpherenceController', 'ConpherenceNotificationPanelController' => 'ConpherenceController', 'ConpherenceParticipant' => 'ConpherenceDAO', 'ConpherenceParticipantCountQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceParticipantQuery' => 'PhabricatorOffsetPagedQuery', 'ConpherenceParticipationStatus' => 'ConpherenceConstants', 'ConpherencePeopleWidgetView' => 'ConpherenceWidgetView', 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', 'ConpherenceSettings' => 'ConpherenceConstants', 'ConpherenceThread' => array( 'ConpherenceDAO', 'PhabricatorPolicyInterface', ), 'ConpherenceThreadListView' => 'AphrontView', 'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver', 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ConpherenceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ConpherenceTransactionType' => 'ConpherenceConstants', 'ConpherenceTransactionView' => 'AphrontView', 'ConpherenceUpdateActions' => 'ConpherenceConstants', 'ConpherenceUpdateController' => 'ConpherenceController', 'ConpherenceViewController' => 'ConpherenceController', 'ConpherenceWidgetController' => 'ConpherenceController', 'ConpherenceWidgetView' => 'AphrontView', 'DarkConsoleController' => 'PhabricatorController', 'DarkConsoleDataController' => 'PhabricatorController', 'DarkConsoleErrorLogPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPlugin' => 'DarkConsolePlugin', 'DarkConsoleEventPluginAPI' => 'PhabricatorEventListener', 'DarkConsoleRequestPlugin' => 'DarkConsolePlugin', 'DarkConsoleServicesPlugin' => 'DarkConsolePlugin', 'DarkConsoleXHProfPlugin' => 'DarkConsolePlugin', 'DefaultDatabaseConfigurationProvider' => 'DatabaseConfigurationProvider', 'DifferentialActionMenuEventListener' => 'PhabricatorEventListener', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialAffectedPath' => 'DifferentialDAO', 'DifferentialApplyPatchField' => 'DifferentialCustomField', 'DifferentialArcanistProjectField' => 'DifferentialCustomField', 'DifferentialAsanaRepresentationField' => 'DifferentialCustomField', 'DifferentialAuditorsField' => 'DifferentialStoredCustomField', 'DifferentialAuthorField' => 'DifferentialCustomField', 'DifferentialBlameRevisionField' => 'DifferentialStoredCustomField', 'DifferentialBranchField' => 'DifferentialCustomField', 'DifferentialCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'DifferentialChangesSinceLastUpdateField' => 'DifferentialCustomField', 'DifferentialChangeset' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', ), 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetHTMLRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetOneUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetOneUpTestRenderer' => 'DifferentialChangesetTestRenderer', 'DifferentialChangesetParserTestCase' => 'PhabricatorTestCase', 'DifferentialChangesetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialChangesetTestRenderer' => 'DifferentialChangesetRenderer', 'DifferentialChangesetTwoUpRenderer' => 'DifferentialChangesetHTMLRenderer', 'DifferentialChangesetTwoUpTestRenderer' => 'DifferentialChangesetTestRenderer', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialCommentPreviewController' => 'DifferentialController', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialCommitMessageParserTestCase' => 'PhabricatorTestCase', 'DifferentialCommitsField' => 'DifferentialCustomField', 'DifferentialConflictsField' => 'DifferentialCustomField', 'DifferentialController' => 'PhabricatorController', 'DifferentialCoreCustomField' => 'DifferentialCustomField', 'DifferentialCustomField' => 'PhabricatorCustomField', 'DifferentialCustomFieldDependsOnParser' => 'PhabricatorCustomFieldMonogramParser', 'DifferentialCustomFieldDependsOnParserTestCase' => 'PhabricatorTestCase', 'DifferentialCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'DifferentialCustomFieldRevertsParser' => 'PhabricatorCustomFieldMonogramParser', 'DifferentialCustomFieldRevertsParserTestCase' => 'PhabricatorTestCase', 'DifferentialCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'DifferentialCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDependenciesField' => 'DifferentialCustomField', 'DifferentialDependsOnField' => 'DifferentialCustomField', 'DifferentialDiff' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', 'HarbormasterBuildableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'DifferentialDiffCreateController' => 'DifferentialController', + 'DifferentialDiffPHIDType' => 'PhabricatorPHIDType', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffTestCase' => 'ArcanistPhutilTestCase', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialDoorkeeperRevisionFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', 'DifferentialDraft' => 'DifferentialDAO', 'DifferentialEditPolicyField' => 'DifferentialCoreCustomField', 'DifferentialFieldParseException' => 'Exception', 'DifferentialFieldValidationException' => 'Exception', 'DifferentialGitSVNIDField' => 'DifferentialCustomField', 'DifferentialHostField' => 'DifferentialCustomField', 'DifferentialHovercardEventListener' => 'PhabricatorEventListener', 'DifferentialHunk' => array( 'DifferentialDAO', 'PhabricatorPolicyInterface', ), 'DifferentialHunkLegacy' => 'DifferentialHunk', 'DifferentialHunkModern' => 'DifferentialHunk', 'DifferentialHunkParserTestCase' => 'PhabricatorTestCase', 'DifferentialHunkQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialHunkTestCase' => 'ArcanistPhutilTestCase', 'DifferentialInlineComment' => 'PhabricatorInlineCommentInterface', 'DifferentialInlineCommentEditController' => 'PhabricatorInlineCommentController', 'DifferentialInlineCommentEditView' => 'AphrontView', 'DifferentialInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DifferentialInlineCommentQuery' => 'PhabricatorOffsetPagedQuery', 'DifferentialInlineCommentView' => 'AphrontView', 'DifferentialJIRAIssuesField' => 'DifferentialStoredCustomField', 'DifferentialLandingActionMenuEventListener' => 'PhabricatorEventListener', 'DifferentialLandingToGitHub' => 'DifferentialLandingStrategy', 'DifferentialLandingToHostedGit' => 'DifferentialLandingStrategy', 'DifferentialLandingToHostedMercurial' => 'DifferentialLandingStrategy', 'DifferentialLintField' => 'DifferentialCustomField', 'DifferentialLocalCommitsView' => 'AphrontView', 'DifferentialMail' => 'PhabricatorMail', 'DifferentialManiphestTasksField' => 'DifferentialCoreCustomField', - 'DifferentialPHIDTypeDiff' => 'PhabricatorPHIDType', - 'DifferentialPHIDTypeRevision' => 'PhabricatorPHIDType', 'DifferentialParseCacheGarbageCollector' => 'PhabricatorGarbageCollector', 'DifferentialParseRenderTestCase' => 'PhabricatorTestCase', 'DifferentialPathField' => 'DifferentialCustomField', 'DifferentialPrimaryPaneView' => 'AphrontView', 'DifferentialProjectReviewersField' => 'DifferentialCustomField', 'DifferentialProjectsField' => 'DifferentialCoreCustomField', 'DifferentialRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'DifferentialReplyHandler' => 'PhabricatorMailReplyHandler', 'DifferentialRepositoryField' => 'DifferentialCoreCustomField', 'DifferentialRepositoryLookup' => 'Phobject', 'DifferentialRequiredSignaturesField' => 'DifferentialCoreCustomField', 'DifferentialResultsTableView' => 'AphrontView', 'DifferentialRevertPlanField' => 'DifferentialStoredCustomField', 'DifferentialReviewedByField' => 'DifferentialCoreCustomField', 'DifferentialReviewersField' => 'DifferentialCoreCustomField', 'DifferentialReviewersView' => 'AphrontView', 'DifferentialRevision' => array( 'DifferentialDAO', 'PhabricatorTokenReceiverInterface', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhrequentTrackableInterface', 'HarbormasterBuildableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', ), 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionHasTaskEdgeType' => 'PhabricatorEdgeType', 'DifferentialRevisionIDField' => 'DifferentialCustomField', 'DifferentialRevisionLandController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionListView' => 'AphrontView', 'DifferentialRevisionMailReceiver' => 'PhabricatorObjectMailReceiver', + 'DifferentialRevisionPHIDType' => 'PhabricatorPHIDType', 'DifferentialRevisionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DifferentialRevisionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'DifferentialSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'DifferentialStoredCustomField' => 'DifferentialCustomField', 'DifferentialSubscribersField' => 'DifferentialCoreCustomField', 'DifferentialSummaryField' => 'DifferentialCoreCustomField', 'DifferentialTestPlanField' => 'DifferentialCoreCustomField', 'DifferentialTitleField' => 'DifferentialCoreCustomField', 'DifferentialTransaction' => 'PhabricatorApplicationTransaction', 'DifferentialTransactionComment' => 'PhabricatorApplicationTransactionComment', 'DifferentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'DifferentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DifferentialTransactionView' => 'PhabricatorApplicationTransactionView', 'DifferentialUnitField' => 'DifferentialCustomField', 'DifferentialViewPolicyField' => 'DifferentialCoreCustomField', 'DiffusionArcanistProjectDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionAuditorDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'DiffusionBranchTableController' => 'DiffusionController', 'DiffusionBranchTableView' => 'DiffusionView', 'DiffusionBrowseController' => 'DiffusionController', 'DiffusionBrowseDirectoryController' => 'DiffusionBrowseController', 'DiffusionBrowseFileController' => 'DiffusionBrowseController', 'DiffusionBrowseMainController' => 'DiffusionBrowseController', 'DiffusionBrowseSearchController' => 'DiffusionBrowseController', 'DiffusionBrowseTableView' => 'DiffusionView', 'DiffusionCapabilityCreateRepositories' => 'PhabricatorPolicyCapability', 'DiffusionCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'DiffusionCapabilityDefaultPush' => 'PhabricatorPolicyCapability', 'DiffusionCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'DiffusionCapabilityPush' => 'PhabricatorPolicyCapability', 'DiffusionChangeController' => 'DiffusionController', 'DiffusionCommentListView' => 'AphrontView', 'DiffusionCommentView' => 'AphrontView', 'DiffusionCommitBranchesController' => 'DiffusionController', 'DiffusionCommitChangeTableView' => 'DiffusionView', 'DiffusionCommitController' => 'DiffusionController', 'DiffusionCommitEditController' => 'DiffusionController', 'DiffusionCommitHasTaskEdgeType' => 'PhabricatorEdgeType', 'DiffusionCommitHash' => 'Phobject', 'DiffusionCommitHookEngine' => 'Phobject', 'DiffusionCommitHookRejectException' => 'Exception', 'DiffusionCommitQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DiffusionCommitRef' => 'Phobject', 'DiffusionCommitRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'DiffusionCommitTagsController' => 'DiffusionController', 'DiffusionController' => 'PhabricatorController', 'DiffusionDiffController' => 'DiffusionController', 'DiffusionDoorkeeperCommitFeedStoryPublisher' => 'DoorkeeperFeedStoryPublisher', 'DiffusionEmptyResultView' => 'DiffusionView', 'DiffusionExternalController' => 'DiffusionController', 'DiffusionFileContentQuery' => 'DiffusionQuery', 'DiffusionGitBranchTestCase' => 'PhabricatorTestCase', 'DiffusionGitFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionGitFileContentQueryTestCase' => 'PhabricatorTestCase', 'DiffusionGitRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionGitRequest' => 'DiffusionRequest', 'DiffusionGitResponse' => 'AphrontResponse', 'DiffusionHistoryController' => 'DiffusionController', 'DiffusionHistoryTableView' => 'DiffusionView', 'DiffusionHovercardEventListener' => 'PhabricatorEventListener', 'DiffusionInlineCommentController' => 'PhabricatorInlineCommentController', 'DiffusionInlineCommentPreviewController' => 'PhabricatorInlineCommentPreviewController', 'DiffusionLastModifiedController' => 'DiffusionController', 'DiffusionLintController' => 'DiffusionController', 'DiffusionLintCountQuery' => 'PhabricatorQuery', 'DiffusionLintDetailsController' => 'DiffusionController', 'DiffusionLowLevelCommitFieldsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelCommitQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelGitRefQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelMercurialBranchesQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelParentsQuery' => 'DiffusionLowLevelQuery', 'DiffusionLowLevelQuery' => 'Phobject', 'DiffusionLowLevelResolveRefsQuery' => 'DiffusionLowLevelQuery', 'DiffusionMercurialFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionMercurialRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionMercurialRequest' => 'DiffusionRequest', 'DiffusionMercurialResponse' => 'AphrontResponse', 'DiffusionMirrorDeleteController' => 'DiffusionController', 'DiffusionMirrorEditController' => 'DiffusionController', 'DiffusionPathCompleteController' => 'DiffusionController', 'DiffusionPathQueryTestCase' => 'PhabricatorTestCase', 'DiffusionPathTreeController' => 'DiffusionController', 'DiffusionPathValidateController' => 'DiffusionController', 'DiffusionPushEventViewController' => 'DiffusionPushLogController', 'DiffusionPushLogController' => 'DiffusionController', 'DiffusionPushLogListController' => 'DiffusionPushLogController', 'DiffusionPushLogListView' => 'AphrontView', 'DiffusionQuery' => 'PhabricatorQuery', 'DiffusionRawDiffQuery' => 'DiffusionQuery', 'DiffusionRefNotFoundException' => 'Exception', 'DiffusionRepositoryController' => 'DiffusionController', 'DiffusionRepositoryCreateController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionRepositoryDefaultController' => 'DiffusionController', 'DiffusionRepositoryEditActionsController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditActivateController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditBasicController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditBranchesController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditController' => 'DiffusionController', 'DiffusionRepositoryEditDangerousController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditDeleteController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditEncodingController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditHostingController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditLocalController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditMainController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryEditSubversionController' => 'DiffusionRepositoryEditController', 'DiffusionRepositoryListController' => 'DiffusionController', 'DiffusionRepositoryNewController' => 'DiffusionController', 'DiffusionRepositoryRef' => 'Phobject', 'DiffusionRepositoryRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'DiffusionResolveUserQuery' => 'Phobject', 'DiffusionSSHGitReceivePackWorkflow' => 'DiffusionSSHGitWorkflow', 'DiffusionSSHGitUploadPackWorkflow' => 'DiffusionSSHGitWorkflow', 'DiffusionSSHGitWorkflow' => 'DiffusionSSHWorkflow', 'DiffusionSSHMercurialServeWorkflow' => 'DiffusionSSHMercurialWorkflow', 'DiffusionSSHMercurialWireClientProtocolChannel' => 'PhutilProtocolChannel', 'DiffusionSSHMercurialWireTestCase' => 'PhabricatorTestCase', 'DiffusionSSHMercurialWorkflow' => 'DiffusionSSHWorkflow', 'DiffusionSSHSubversionServeWorkflow' => 'DiffusionSSHSubversionWorkflow', 'DiffusionSSHSubversionWorkflow' => 'DiffusionSSHWorkflow', 'DiffusionSSHWorkflow' => 'PhabricatorSSHWorkflow', 'DiffusionServeController' => 'DiffusionController', 'DiffusionSetPasswordPanel' => 'PhabricatorSettingsPanel', 'DiffusionSetupException' => 'AphrontUsageException', 'DiffusionSubversionWireProtocol' => 'Phobject', 'DiffusionSubversionWireProtocolTestCase' => 'PhabricatorTestCase', 'DiffusionSvnFileContentQuery' => 'DiffusionFileContentQuery', 'DiffusionSvnRawDiffQuery' => 'DiffusionRawDiffQuery', 'DiffusionSvnRequest' => 'DiffusionRequest', 'DiffusionSymbolController' => 'DiffusionController', 'DiffusionSymbolDatasource' => 'PhabricatorTypeaheadDatasource', 'DiffusionSymbolQuery' => 'PhabricatorOffsetPagedQuery', 'DiffusionTagListController' => 'DiffusionController', 'DiffusionTagListView' => 'DiffusionView', 'DiffusionURITestCase' => 'ArcanistPhutilTestCase', 'DiffusionView' => 'AphrontView', 'DivinerArticleAtomizer' => 'DivinerAtomizer', 'DivinerAtomCache' => 'DivinerDiskCache', 'DivinerAtomController' => 'DivinerController', 'DivinerAtomListController' => 'DivinerController', + 'DivinerAtomPHIDType' => 'PhabricatorPHIDType', 'DivinerAtomQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DivinerAtomSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DivinerAtomizeWorkflow' => 'DivinerWorkflow', 'DivinerBookController' => 'DivinerController', 'DivinerBookItemView' => 'AphrontTagView', + 'DivinerBookPHIDType' => 'PhabricatorPHIDType', 'DivinerBookQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DivinerController' => 'PhabricatorController', 'DivinerDAO' => 'PhabricatorLiskDAO', 'DivinerDefaultRenderer' => 'DivinerRenderer', 'DivinerFileAtomizer' => 'DivinerAtomizer', 'DivinerFindController' => 'DivinerController', 'DivinerGenerateWorkflow' => 'DivinerWorkflow', 'DivinerLiveAtom' => 'DivinerDAO', 'DivinerLiveBook' => array( 'DivinerDAO', 'PhabricatorPolicyInterface', ), 'DivinerLivePublisher' => 'DivinerPublisher', 'DivinerLiveSymbol' => array( 'DivinerDAO', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', ), 'DivinerMainController' => 'DivinerController', - 'DivinerPHIDTypeAtom' => 'PhabricatorPHIDType', - 'DivinerPHIDTypeBook' => 'PhabricatorPHIDType', 'DivinerPHPAtomizer' => 'DivinerAtomizer', 'DivinerParameterTableView' => 'AphrontTagView', 'DivinerPublishCache' => 'DivinerDiskCache', 'DivinerRemarkupRuleSymbol' => 'PhutilRemarkupRule', 'DivinerReturnTableView' => 'AphrontTagView', 'DivinerSectionView' => 'AphrontTagView', 'DivinerStaticPublisher' => 'DivinerPublisher', 'DivinerWorkflow' => 'PhabricatorManagementWorkflow', 'DoorkeeperBridge' => 'Phobject', 'DoorkeeperBridgeAsana' => 'DoorkeeperBridge', 'DoorkeeperBridgeJIRA' => 'DoorkeeperBridge', 'DoorkeeperBridgeJIRATestCase' => 'PhabricatorTestCase', 'DoorkeeperDAO' => 'PhabricatorLiskDAO', 'DoorkeeperExternalObject' => array( 'DoorkeeperDAO', 'PhabricatorPolicyInterface', ), 'DoorkeeperExternalObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DoorkeeperFeedWorker' => 'FeedPushWorker', 'DoorkeeperFeedWorkerAsana' => 'DoorkeeperFeedWorker', 'DoorkeeperFeedWorkerJIRA' => 'DoorkeeperFeedWorker', 'DoorkeeperImportEngine' => 'Phobject', 'DoorkeeperMissingLinkException' => 'Exception', 'DoorkeeperObjectRef' => 'Phobject', 'DoorkeeperRemarkupRule' => 'PhutilRemarkupRule', 'DoorkeeperRemarkupRuleAsana' => 'DoorkeeperRemarkupRule', 'DoorkeeperRemarkupRuleJIRA' => 'DoorkeeperRemarkupRule', 'DoorkeeperTagView' => 'AphrontView', 'DoorkeeperTagsController' => 'PhabricatorController', 'DrydockAllocatorWorker' => 'PhabricatorWorker', 'DrydockApacheWebrootInterface' => 'DrydockWebrootInterface', 'DrydockBlueprint' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockBlueprintController' => 'DrydockController', 'DrydockBlueprintCreateController' => 'DrydockBlueprintController', 'DrydockBlueprintEditController' => 'DrydockBlueprintController', 'DrydockBlueprintEditor' => 'PhabricatorApplicationTransactionEditor', 'DrydockBlueprintListController' => 'DrydockBlueprintController', + 'DrydockBlueprintPHIDType' => 'PhabricatorPHIDType', 'DrydockBlueprintQuery' => 'DrydockQuery', 'DrydockBlueprintSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockBlueprintTransaction' => 'PhabricatorApplicationTransaction', 'DrydockBlueprintTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'DrydockBlueprintViewController' => 'DrydockBlueprintController', 'DrydockCapabilityCreateBlueprints' => 'PhabricatorPolicyCapability', 'DrydockCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'DrydockCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'DrydockCommandInterface' => 'DrydockInterface', 'DrydockConsoleController' => 'DrydockController', 'DrydockController' => 'PhabricatorController', 'DrydockDAO' => 'PhabricatorLiskDAO', 'DrydockFilesystemInterface' => 'DrydockInterface', 'DrydockLease' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockLeaseController' => 'DrydockController', 'DrydockLeaseListController' => 'DrydockLeaseController', 'DrydockLeaseListView' => 'AphrontView', + 'DrydockLeasePHIDType' => 'PhabricatorPHIDType', 'DrydockLeaseQuery' => 'DrydockQuery', 'DrydockLeaseReleaseController' => 'DrydockLeaseController', 'DrydockLeaseSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockLeaseStatus' => 'DrydockConstants', 'DrydockLeaseViewController' => 'DrydockLeaseController', 'DrydockLocalCommandInterface' => 'DrydockCommandInterface', 'DrydockLocalHostBlueprintImplementation' => 'DrydockBlueprintImplementation', 'DrydockLog' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockLogController' => 'DrydockController', 'DrydockLogListController' => 'DrydockLogController', 'DrydockLogListView' => 'AphrontView', 'DrydockLogQuery' => 'DrydockQuery', 'DrydockLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockManagementCloseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementCreateResourceWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementLeaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementReleaseWorkflow' => 'DrydockManagementWorkflow', 'DrydockManagementWorkflow' => 'PhabricatorManagementWorkflow', - 'DrydockPHIDTypeBlueprint' => 'PhabricatorPHIDType', - 'DrydockPHIDTypeLease' => 'PhabricatorPHIDType', - 'DrydockPHIDTypeResource' => 'PhabricatorPHIDType', 'DrydockPreallocatedHostBlueprintImplementation' => 'DrydockBlueprintImplementation', 'DrydockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'DrydockResource' => array( 'DrydockDAO', 'PhabricatorPolicyInterface', ), 'DrydockResourceCloseController' => 'DrydockResourceController', 'DrydockResourceController' => 'DrydockController', 'DrydockResourceListController' => 'DrydockResourceController', 'DrydockResourceListView' => 'AphrontView', + 'DrydockResourcePHIDType' => 'PhabricatorPHIDType', 'DrydockResourceQuery' => 'DrydockQuery', 'DrydockResourceSearchEngine' => 'PhabricatorApplicationSearchEngine', 'DrydockResourceStatus' => 'DrydockConstants', 'DrydockResourceViewController' => 'DrydockResourceController', 'DrydockSFTPFilesystemInterface' => 'DrydockFilesystemInterface', 'DrydockSSHCommandInterface' => 'DrydockCommandInterface', 'DrydockWebrootInterface' => 'DrydockInterface', 'DrydockWorkingCopyBlueprintImplementation' => 'DrydockBlueprintImplementation', 'FeedPublisherHTTPWorker' => 'FeedPushWorker', 'FeedPublisherWorker' => 'FeedPushWorker', 'FeedPushWorker' => 'PhabricatorWorker', 'FileCreateMailReceiver' => 'PhabricatorMailReceiver', 'FileMailReceiver' => 'PhabricatorObjectMailReceiver', 'FileReplyHandler' => 'PhabricatorMailReplyHandler', 'HarbormasterBuild' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildActionController' => 'HarbormasterController', 'HarbormasterBuildArtifact' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildArtifactQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildCommand' => 'HarbormasterDAO', 'HarbormasterBuildEngine' => 'Phobject', 'HarbormasterBuildItem' => 'HarbormasterDAO', + 'HarbormasterBuildItemPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildItemQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildLog' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), + 'HarbormasterBuildLogPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildMessage' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), 'HarbormasterBuildMessageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'HarbormasterBuildPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildPlan' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', ), 'HarbormasterBuildPlanDatasource' => 'PhabricatorTypeaheadDatasource', 'HarbormasterBuildPlanEditor' => 'PhabricatorApplicationTransactionEditor', + 'HarbormasterBuildPlanPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildPlanQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildPlanSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildPlanTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildPlanTransactionComment' => 'PhabricatorApplicationTransactionComment', 'HarbormasterBuildPlanTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildStep' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', ), 'HarbormasterBuildStepCoreCustomField' => array( 'HarbormasterBuildStepCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'HarbormasterBuildStepCustomField' => 'PhabricatorCustomField', 'HarbormasterBuildStepEditor' => 'PhabricatorApplicationTransactionEditor', + 'HarbormasterBuildStepPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildStepQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildStepTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildStepTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildTarget' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', ), + 'HarbormasterBuildTargetPHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildTargetQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildViewController' => 'HarbormasterController', 'HarbormasterBuildWorker' => 'HarbormasterWorker', 'HarbormasterBuildable' => array( 'HarbormasterDAO', 'PhabricatorPolicyInterface', 'HarbormasterBuildableInterface', ), 'HarbormasterBuildableActionController' => 'HarbormasterController', 'HarbormasterBuildableListController' => 'HarbormasterController', + 'HarbormasterBuildablePHIDType' => 'PhabricatorPHIDType', 'HarbormasterBuildableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HarbormasterBuildableSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HarbormasterBuildableTransaction' => 'PhabricatorApplicationTransaction', 'HarbormasterBuildableTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'HarbormasterBuildableTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HarbormasterBuildableViewController' => 'HarbormasterController', 'HarbormasterCapabilityManagePlans' => 'PhabricatorPolicyCapability', 'HarbormasterCommandBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterController' => 'PhabricatorController', 'HarbormasterDAO' => 'PhabricatorLiskDAO', 'HarbormasterHTTPRequestBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterLeaseHostBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterManagementBuildWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementUpdateWorkflow' => 'HarbormasterManagementWorkflow', 'HarbormasterManagementWorkflow' => 'PhabricatorManagementWorkflow', 'HarbormasterObject' => 'HarbormasterDAO', - 'HarbormasterPHIDTypeBuild' => 'PhabricatorPHIDType', - 'HarbormasterPHIDTypeBuildItem' => 'PhabricatorPHIDType', - 'HarbormasterPHIDTypeBuildLog' => 'PhabricatorPHIDType', - 'HarbormasterPHIDTypeBuildPlan' => 'PhabricatorPHIDType', - 'HarbormasterPHIDTypeBuildStep' => 'PhabricatorPHIDType', - 'HarbormasterPHIDTypeBuildTarget' => 'PhabricatorPHIDType', - 'HarbormasterPHIDTypeBuildable' => 'PhabricatorPHIDType', 'HarbormasterPlanController' => 'HarbormasterController', 'HarbormasterPlanDisableController' => 'HarbormasterPlanController', 'HarbormasterPlanEditController' => 'HarbormasterPlanController', 'HarbormasterPlanListController' => 'HarbormasterPlanController', 'HarbormasterPlanOrderController' => 'HarbormasterController', 'HarbormasterPlanRunController' => 'HarbormasterController', 'HarbormasterPlanViewController' => 'HarbormasterPlanController', 'HarbormasterPublishFragmentBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'HarbormasterScratchTable' => 'HarbormasterDAO', 'HarbormasterSleepBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterStepAddController' => 'HarbormasterController', 'HarbormasterStepDeleteController' => 'HarbormasterController', 'HarbormasterStepEditController' => 'HarbormasterController', 'HarbormasterTargetWorker' => 'HarbormasterWorker', 'HarbormasterThrowExceptionBuildStep' => 'HarbormasterBuildStepImplementation', 'HarbormasterUIEventListener' => 'PhabricatorEventListener', 'HarbormasterUploadArtifactBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterWaitForPreviousBuildStepImplementation' => 'HarbormasterBuildStepImplementation', 'HarbormasterWorker' => 'PhabricatorWorker', 'HeraldAction' => 'HeraldDAO', 'HeraldApplyTranscript' => 'HeraldDAO', 'HeraldCapabilityManageGlobalRules' => 'PhabricatorPolicyCapability', 'HeraldCommitAdapter' => 'HeraldAdapter', 'HeraldCondition' => 'HeraldDAO', 'HeraldController' => 'PhabricatorController', 'HeraldDAO' => 'PhabricatorLiskDAO', 'HeraldDifferentialRevisionAdapter' => 'HeraldAdapter', 'HeraldDisableController' => 'HeraldController', 'HeraldEditLogQuery' => 'PhabricatorOffsetPagedQuery', 'HeraldInvalidActionException' => 'Exception', 'HeraldInvalidConditionException' => 'Exception', 'HeraldInvalidFieldException' => 'Exception', 'HeraldManiphestTaskAdapter' => 'HeraldAdapter', 'HeraldNewController' => 'HeraldController', - 'HeraldPHIDTypeRule' => 'PhabricatorPHIDType', 'HeraldPholioMockAdapter' => 'HeraldAdapter', 'HeraldPreCommitAdapter' => 'HeraldAdapter', 'HeraldPreCommitContentAdapter' => 'HeraldPreCommitAdapter', 'HeraldPreCommitRefAdapter' => 'HeraldPreCommitAdapter', 'HeraldRecursiveConditionsException' => 'Exception', 'HeraldRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'HeraldRule' => array( 'HeraldDAO', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'HeraldRuleController' => 'HeraldController', 'HeraldRuleEdit' => 'HeraldDAO', 'HeraldRuleEditHistoryController' => 'HeraldController', 'HeraldRuleEditHistoryView' => 'AphrontView', 'HeraldRuleEditor' => 'PhabricatorApplicationTransactionEditor', 'HeraldRuleListController' => 'HeraldController', + 'HeraldRulePHIDType' => 'PhabricatorPHIDType', 'HeraldRuleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HeraldRuleSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldRuleTransaction' => 'PhabricatorApplicationTransaction', 'HeraldRuleTransactionComment' => 'PhabricatorApplicationTransactionComment', 'HeraldRuleViewController' => 'HeraldController', 'HeraldTestConsoleController' => 'HeraldController', 'HeraldTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'HeraldTranscript' => array( 'HeraldDAO', 'PhabricatorPolicyInterface', ), 'HeraldTranscriptController' => 'HeraldController', 'HeraldTranscriptGarbageCollector' => 'PhabricatorGarbageCollector', 'HeraldTranscriptListController' => 'HeraldController', 'HeraldTranscriptQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'HeraldTranscriptSearchEngine' => 'PhabricatorApplicationSearchEngine', 'HeraldTranscriptTestCase' => 'PhabricatorTestCase', 'JavelinReactorExample' => 'PhabricatorUIExample', 'JavelinUIExample' => 'PhabricatorUIExample', 'JavelinViewExample' => 'PhabricatorUIExample', 'JavelinViewExampleServerView' => 'AphrontView', 'LegalpadCapabilityCreateDocuments' => 'PhabricatorPolicyCapability', 'LegalpadCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'LegalpadCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'LegalpadController' => 'PhabricatorController', 'LegalpadDAO' => 'PhabricatorLiskDAO', 'LegalpadDocument' => array( 'LegalpadDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorDestructibleInterface', ), 'LegalpadDocumentBody' => array( 'LegalpadDAO', 'PhabricatorMarkupInterface', ), 'LegalpadDocumentCommentController' => 'LegalpadController', 'LegalpadDocumentDatasource' => 'PhabricatorTypeaheadDatasource', 'LegalpadDocumentDoneController' => 'LegalpadController', 'LegalpadDocumentEditController' => 'LegalpadController', 'LegalpadDocumentEditor' => 'PhabricatorApplicationTransactionEditor', 'LegalpadDocumentListController' => 'LegalpadController', 'LegalpadDocumentManageController' => 'LegalpadController', 'LegalpadDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'LegalpadDocumentSearchEngine' => 'PhabricatorApplicationSearchEngine', 'LegalpadDocumentSignController' => 'LegalpadController', 'LegalpadDocumentSignature' => array( 'LegalpadDAO', 'PhabricatorPolicyInterface', ), 'LegalpadDocumentSignatureAddController' => 'LegalpadController', 'LegalpadDocumentSignatureListController' => 'LegalpadController', 'LegalpadDocumentSignatureQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'LegalpadDocumentSignatureSearchEngine' => 'PhabricatorApplicationSearchEngine', 'LegalpadDocumentSignatureVerificationController' => 'LegalpadController', 'LegalpadDocumentSignatureViewController' => 'LegalpadController', 'LegalpadMockMailReceiver' => 'PhabricatorObjectMailReceiver', 'LegalpadReplyHandler' => 'PhabricatorMailReplyHandler', 'LegalpadTransaction' => 'PhabricatorApplicationTransaction', 'LegalpadTransactionComment' => 'PhabricatorApplicationTransactionComment', 'LegalpadTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'LegalpadTransactionType' => 'LegalpadConstants', 'LegalpadTransactionView' => 'PhabricatorApplicationTransactionView', 'LiskChunkTestCase' => 'PhabricatorTestCase', 'LiskDAOTestCase' => 'PhabricatorTestCase', 'LiskEphemeralObjectException' => 'Exception', 'LiskFixtureTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestCase' => 'PhabricatorTestCase', 'LiskIsolationTestDAO' => 'LiskDAO', 'LiskIsolationTestDAOException' => 'Exception', 'LiskMigrationIterator' => 'PhutilBufferedIterator', 'LiskRawMigrationIterator' => 'PhutilBufferedIterator', 'ManiphestActionMenuEventListener' => 'PhabricatorEventListener', 'ManiphestBatchEditController' => 'ManiphestController', 'ManiphestCapabilityBulkEdit' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityEditAssign' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityEditPolicies' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityEditPriority' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityEditProjects' => 'PhabricatorPolicyCapability', 'ManiphestCapabilityEditStatus' => 'PhabricatorPolicyCapability', 'ManiphestConfiguredCustomField' => array( 'ManiphestCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'ManiphestController' => 'PhabricatorController', 'ManiphestCreateMailReceiver' => 'PhabricatorMailReceiver', 'ManiphestCustomField' => 'PhabricatorCustomField', 'ManiphestCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'ManiphestCustomFieldStatusParser' => 'PhabricatorCustomFieldMonogramParser', 'ManiphestCustomFieldStatusParserTestCase' => 'PhabricatorTestCase', 'ManiphestCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'ManiphestCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'ManiphestDAO' => 'PhabricatorLiskDAO', 'ManiphestExcelDefaultFormat' => 'ManiphestExcelFormat', 'ManiphestExportController' => 'ManiphestController', 'ManiphestHovercardEventListener' => 'PhabricatorEventListener', 'ManiphestNameIndex' => 'ManiphestDAO', 'ManiphestNameIndexEventListener' => 'PhabricatorEventListener', - 'ManiphestPHIDTypeTask' => 'PhabricatorPHIDType', 'ManiphestRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'ManiphestReplyHandler' => 'PhabricatorMailReplyHandler', 'ManiphestReportController' => 'ManiphestController', 'ManiphestSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'ManiphestStatusConfigOptionType' => 'PhabricatorConfigJSONOptionType', 'ManiphestSubpriorityController' => 'ManiphestController', 'ManiphestSubscribeController' => 'ManiphestController', 'ManiphestTask' => array( 'ManiphestDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhrequentTrackableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', 'PhabricatorApplicationTransactionInterface', ), 'ManiphestTaskDescriptionPreviewController' => 'ManiphestController', 'ManiphestTaskDetailController' => 'ManiphestController', 'ManiphestTaskEditController' => 'ManiphestController', 'ManiphestTaskHasCommitEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskHasRevisionEdgeType' => 'PhabricatorEdgeType', 'ManiphestTaskListController' => 'ManiphestController', 'ManiphestTaskListView' => 'ManiphestView', 'ManiphestTaskMailReceiver' => 'PhabricatorObjectMailReceiver', 'ManiphestTaskOwner' => 'ManiphestConstants', + 'ManiphestTaskPHIDType' => 'PhabricatorPHIDType', 'ManiphestTaskPriority' => 'ManiphestConstants', 'ManiphestTaskPriorityDatasource' => 'PhabricatorTypeaheadDatasource', 'ManiphestTaskQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ManiphestTaskResultListView' => 'ManiphestView', 'ManiphestTaskSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ManiphestTaskStatus' => 'ManiphestConstants', 'ManiphestTaskStatusTestCase' => 'PhabricatorTestCase', 'ManiphestTaskSubscriber' => 'ManiphestDAO', 'ManiphestTransaction' => 'PhabricatorApplicationTransaction', 'ManiphestTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ManiphestTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'ManiphestTransactionPreviewController' => 'ManiphestController', 'ManiphestTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ManiphestTransactionSaveController' => 'ManiphestController', 'ManiphestView' => 'AphrontView', 'MetaMTAMailReceivedGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTAMailSentGarbageCollector' => 'PhabricatorGarbageCollector', 'MetaMTANotificationType' => 'MetaMTAConstants', 'MetaMTAReceivedMailStatus' => 'MetaMTAConstants', 'NuanceCapabilitySourceDefaultEdit' => 'PhabricatorPolicyCapability', 'NuanceCapabilitySourceDefaultView' => 'PhabricatorPolicyCapability', 'NuanceCapabilitySourceManage' => 'PhabricatorPolicyCapability', 'NuanceController' => 'PhabricatorController', 'NuanceDAO' => 'PhabricatorLiskDAO', 'NuanceItem' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', ), 'NuanceItemEditController' => 'NuanceController', 'NuanceItemEditor' => 'PhabricatorApplicationTransactionEditor', + 'NuanceItemPHIDType' => 'PhabricatorPHIDType', 'NuanceItemQuery' => 'NuanceQuery', 'NuanceItemTransaction' => 'NuanceTransaction', 'NuanceItemTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceItemTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceItemViewController' => 'NuanceController', - 'NuancePHIDTypeItem' => 'PhabricatorPHIDType', - 'NuancePHIDTypeQueue' => 'PhabricatorPHIDType', - 'NuancePHIDTypeRequestor' => 'PhabricatorPHIDType', - 'NuancePHIDTypeSource' => 'PhabricatorPHIDType', 'NuancePhabricatorFormSourceDefinition' => 'NuanceSourceDefinition', 'NuanceQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'NuanceQueue' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', ), 'NuanceQueueEditController' => 'NuanceController', 'NuanceQueueEditor' => 'PhabricatorApplicationTransactionEditor', 'NuanceQueueItem' => 'NuanceDAO', + 'NuanceQueuePHIDType' => 'PhabricatorPHIDType', 'NuanceQueueQuery' => 'NuanceQuery', 'NuanceQueueTransaction' => 'NuanceTransaction', 'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceQueueViewController' => 'NuanceController', 'NuanceRequestor' => 'NuanceDAO', 'NuanceRequestorEditController' => 'NuanceController', 'NuanceRequestorEditor' => 'PhabricatorApplicationTransactionEditor', + 'NuanceRequestorPHIDType' => 'PhabricatorPHIDType', 'NuanceRequestorQuery' => 'NuanceQuery', 'NuanceRequestorSource' => 'NuanceDAO', 'NuanceRequestorTransaction' => 'NuanceTransaction', 'NuanceRequestorTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceRequestorTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceRequestorViewController' => 'NuanceController', 'NuanceSource' => array( 'NuanceDAO', 'PhabricatorPolicyInterface', ), 'NuanceSourceDefinition' => 'Phobject', 'NuanceSourceEditController' => 'NuanceController', 'NuanceSourceEditor' => 'PhabricatorApplicationTransactionEditor', + 'NuanceSourcePHIDType' => 'PhabricatorPHIDType', 'NuanceSourceQuery' => 'NuanceQuery', 'NuanceSourceTransaction' => 'NuanceTransaction', 'NuanceSourceTransactionComment' => 'PhabricatorApplicationTransactionComment', 'NuanceSourceTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'NuanceSourceViewController' => 'NuanceController', 'NuanceTransaction' => 'PhabricatorApplicationTransaction', 'OwnersPackageReplyHandler' => 'PhabricatorMailReplyHandler', 'PHUIActionHeaderExample' => 'PhabricatorUIExample', 'PHUIActionHeaderView' => 'AphrontView', 'PHUIBoxExample' => 'PhabricatorUIExample', 'PHUIBoxView' => 'AphrontTagView', 'PHUIButtonBarExample' => 'PhabricatorUIExample', 'PHUIButtonBarView' => 'AphrontTagView', 'PHUIButtonExample' => 'PhabricatorUIExample', 'PHUIButtonView' => 'AphrontTagView', 'PHUICalendarListView' => 'AphrontTagView', 'PHUICalendarMonthView' => 'AphrontView', 'PHUICalendarWidgetView' => 'AphrontTagView', 'PHUIColorPalletteExample' => 'PhabricatorUIExample', 'PHUIDocumentExample' => 'PhabricatorUIExample', 'PHUIDocumentView' => 'AphrontTagView', 'PHUIFeedStoryExample' => 'PhabricatorUIExample', 'PHUIFeedStoryView' => 'AphrontView', 'PHUIFormDividerControl' => 'AphrontFormControl', 'PHUIFormFreeformDateControl' => 'AphrontFormControl', 'PHUIFormLayoutView' => 'AphrontView', 'PHUIFormMultiSubmitControl' => 'AphrontFormControl', 'PHUIFormPageView' => 'AphrontView', 'PHUIHandleTagListView' => 'AphrontTagView', 'PHUIHeaderView' => 'AphrontView', 'PHUIIconExample' => 'PhabricatorUIExample', 'PHUIIconView' => 'AphrontTagView', 'PHUIImageMaskExample' => 'PhabricatorUIExample', 'PHUIImageMaskView' => 'AphrontTagView', 'PHUIInfoPanelExample' => 'PhabricatorUIExample', 'PHUIInfoPanelView' => 'AphrontView', 'PHUIListExample' => 'PhabricatorUIExample', 'PHUIListItemView' => 'AphrontTagView', 'PHUIListView' => 'AphrontTagView', 'PHUIListViewTestCase' => 'PhabricatorTestCase', 'PHUIObjectBoxView' => 'AphrontView', 'PHUIObjectItemListExample' => 'PhabricatorUIExample', 'PHUIObjectItemListView' => 'AphrontTagView', 'PHUIObjectItemView' => 'AphrontTagView', 'PHUIPagedFormView' => 'AphrontTagView', 'PHUIPinboardItemView' => 'AphrontView', 'PHUIPinboardView' => 'AphrontView', 'PHUIPropertyGroupView' => 'AphrontTagView', 'PHUIPropertyListExample' => 'PhabricatorUIExample', 'PHUIPropertyListView' => 'AphrontView', 'PHUIRemarkupPreviewPanel' => 'AphrontTagView', 'PHUIStatusItemView' => 'AphrontTagView', 'PHUIStatusListView' => 'AphrontTagView', 'PHUITagExample' => 'PhabricatorUIExample', 'PHUITagView' => 'AphrontTagView', 'PHUITextExample' => 'PhabricatorUIExample', 'PHUITextView' => 'AphrontTagView', 'PHUITimelineEventView' => 'AphrontView', 'PHUITimelineExample' => 'PhabricatorUIExample', 'PHUITimelineView' => 'AphrontView', 'PHUIWorkboardView' => 'AphrontTagView', 'PHUIWorkpanelView' => 'AphrontTagView', 'PackageCreateMail' => 'PackageMail', 'PackageDeleteMail' => 'PackageMail', 'PackageMail' => 'PhabricatorMail', 'PackageModifyMail' => 'PackageMail', 'PassphraseAbstractKey' => 'Phobject', 'PassphraseController' => 'PhabricatorController', 'PassphraseCredential' => array( 'PassphraseDAO', 'PhabricatorPolicyInterface', ), 'PassphraseCredentialControl' => 'AphrontFormControl', 'PassphraseCredentialCreateController' => 'PassphraseController', 'PassphraseCredentialDestroyController' => 'PassphraseController', 'PassphraseCredentialEditController' => 'PassphraseController', 'PassphraseCredentialListController' => 'PassphraseController', 'PassphraseCredentialLockController' => 'PassphraseController', + 'PassphraseCredentialPHIDType' => 'PhabricatorPHIDType', 'PassphraseCredentialPublicController' => 'PassphraseController', 'PassphraseCredentialQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PassphraseCredentialRevealController' => 'PassphraseController', 'PassphraseCredentialSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PassphraseCredentialTransaction' => 'PhabricatorApplicationTransaction', 'PassphraseCredentialTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PassphraseCredentialTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PassphraseCredentialType' => 'Phobject', 'PassphraseCredentialTypePassword' => 'PassphraseCredentialType', 'PassphraseCredentialTypeSSHGeneratedKey' => 'PassphraseCredentialTypeSSHPrivateKey', 'PassphraseCredentialTypeSSHPrivateKey' => 'PassphraseCredentialType', 'PassphraseCredentialTypeSSHPrivateKeyFile' => 'PassphraseCredentialTypeSSHPrivateKey', 'PassphraseCredentialTypeSSHPrivateKeyText' => 'PassphraseCredentialTypeSSHPrivateKey', 'PassphraseCredentialViewController' => 'PassphraseController', 'PassphraseDAO' => 'PhabricatorLiskDAO', - 'PassphrasePHIDTypeCredential' => 'PhabricatorPHIDType', 'PassphrasePasswordKey' => 'PassphraseAbstractKey', 'PassphraseRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PassphraseSSHKey' => 'PassphraseAbstractKey', 'PassphraseSecret' => 'PassphraseDAO', 'PasteCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'PasteCreateMailReceiver' => 'PhabricatorMailReceiver', 'PasteEmbedView' => 'AphrontView', 'PasteMockMailReceiver' => 'PhabricatorObjectMailReceiver', 'PasteReplyHandler' => 'PhabricatorMailReplyHandler', 'PeopleCapabilityBrowseUserDirectory' => 'PhabricatorPolicyCapability', 'PeopleUserLogGarbageCollector' => 'PhabricatorGarbageCollector', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAWSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAccessControlTestCase' => 'PhabricatorTestCase', 'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorActionListView' => 'AphrontView', 'PhabricatorActionView' => 'AphrontView', 'PhabricatorAllCapsTranslation' => 'PhabricatorTranslation', 'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorAnchorView' => 'AphrontView', 'PhabricatorAphlictManagementBuildWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementDebugWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementRestartWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStartWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStatusWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStopWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAphrontBarExample' => 'PhabricatorUIExample', 'PhabricatorAphrontViewTestCase' => 'PhabricatorTestCase', 'PhabricatorAppSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorApplication' => 'PhabricatorPolicyInterface', + 'PhabricatorApplicationApplicationPHIDType' => 'PhabricatorPHIDType', 'PhabricatorApplicationConfigOptions' => 'Phobject', 'PhabricatorApplicationDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorApplicationDetailViewController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationEditController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationLaunchView' => 'AphrontTagView', - 'PhabricatorApplicationPHIDTypeApplication' => 'PhabricatorPHIDType', 'PhabricatorApplicationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorApplicationStatusView' => 'AphrontView', 'PhabricatorApplicationTransaction' => array( 'PhabricatorLiskDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorApplicationTransactionComment' => array( 'PhabricatorLiskDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorApplicationTransactionCommentEditController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionCommentHistoryController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionCommentQuoteController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentRemoveController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionCommentView' => 'AphrontView', 'PhabricatorApplicationTransactionController' => 'PhabricatorController', 'PhabricatorApplicationTransactionDetailController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionEditor' => 'PhabricatorEditor', 'PhabricatorApplicationTransactionFeedStory' => 'PhabricatorFeedStory', 'PhabricatorApplicationTransactionNoEffectException' => 'Exception', 'PhabricatorApplicationTransactionNoEffectResponse' => 'AphrontProxyResponse', - 'PhabricatorApplicationTransactionPHIDTypeTransaction' => 'PhabricatorPHIDType', 'PhabricatorApplicationTransactionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorApplicationTransactionResponse' => 'AphrontProxyResponse', 'PhabricatorApplicationTransactionStructureException' => 'Exception', 'PhabricatorApplicationTransactionTextDiffDetailView' => 'AphrontView', + 'PhabricatorApplicationTransactionTransactionPHIDType' => 'PhabricatorPHIDType', 'PhabricatorApplicationTransactionValidationError' => 'Phobject', 'PhabricatorApplicationTransactionValidationException' => 'Exception', 'PhabricatorApplicationTransactionValueController' => 'PhabricatorApplicationTransactionController', 'PhabricatorApplicationTransactionView' => 'AphrontView', 'PhabricatorApplicationUninstallController' => 'PhabricatorApplicationsController', 'PhabricatorApplicationsApplication' => 'PhabricatorApplication', 'PhabricatorApplicationsController' => 'PhabricatorController', 'PhabricatorApplicationsListController' => 'PhabricatorApplicationsController', 'PhabricatorAsanaAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorAsanaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAuditAddCommentController' => 'PhabricatorAuditController', 'PhabricatorAuditApplication' => 'PhabricatorApplication', 'PhabricatorAuditComment' => array( 'PhabricatorAuditDAO', 'PhabricatorMarkupInterface', ), 'PhabricatorAuditCommentEditor' => 'PhabricatorEditor', 'PhabricatorAuditController' => 'PhabricatorController', 'PhabricatorAuditDAO' => 'PhabricatorLiskDAO', 'PhabricatorAuditInlineComment' => array( 'PhabricatorAuditDAO', 'PhabricatorInlineCommentInterface', ), 'PhabricatorAuditListController' => 'PhabricatorAuditController', 'PhabricatorAuditListView' => 'AphrontView', 'PhabricatorAuditMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorAuditManagementDeleteWorkflow' => 'PhabricatorAuditManagementWorkflow', 'PhabricatorAuditManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAuditPreviewController' => 'PhabricatorAuditController', 'PhabricatorAuditReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorAuthAccountView' => 'AphrontView', 'PhabricatorAuthApplication' => 'PhabricatorApplication', + 'PhabricatorAuthAuthFactorPHIDType' => 'PhabricatorPHIDType', 'PhabricatorAuthConfirmLinkController' => 'PhabricatorAuthController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorAuthDAO' => 'PhabricatorLiskDAO', 'PhabricatorAuthDisableController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthDowngradeSessionController' => 'PhabricatorAuthController', 'PhabricatorAuthEditController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthFactor' => 'Phobject', 'PhabricatorAuthFactorConfig' => 'PhabricatorAuthDAO', 'PhabricatorAuthFactorTOTP' => 'PhabricatorAuthFactor', 'PhabricatorAuthFactorTOTPTestCase' => 'PhabricatorTestCase', 'PhabricatorAuthFinishController' => 'PhabricatorAuthController', 'PhabricatorAuthHighSecurityRequiredException' => 'Exception', 'PhabricatorAuthLinkController' => 'PhabricatorAuthController', 'PhabricatorAuthListController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthLoginController' => 'PhabricatorAuthController', 'PhabricatorAuthManagementLDAPWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementListFactorsWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRecoverWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementRefreshWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementStripWorkflow' => 'PhabricatorAuthManagementWorkflow', 'PhabricatorAuthManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorAuthNeedsApprovalController' => 'PhabricatorAuthController', 'PhabricatorAuthNeedsMultiFactorController' => 'PhabricatorAuthController', 'PhabricatorAuthNewController' => 'PhabricatorAuthProviderConfigController', 'PhabricatorAuthOldOAuthRedirectController' => 'PhabricatorAuthController', 'PhabricatorAuthOneTimeLoginController' => 'PhabricatorAuthController', - 'PhabricatorAuthPHIDTypeAuthFactor' => 'PhabricatorPHIDType', 'PhabricatorAuthProviderConfig' => array( 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthProviderConfigController' => 'PhabricatorAuthController', 'PhabricatorAuthProviderConfigEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorAuthProviderConfigQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthProviderConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorAuthProviderConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorAuthRegisterController' => 'PhabricatorAuthController', 'PhabricatorAuthSession' => array( 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthSessionEngine' => 'Phobject', 'PhabricatorAuthSessionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorAuthSessionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthStartController' => 'PhabricatorAuthController', 'PhabricatorAuthTemporaryToken' => array( 'PhabricatorAuthDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorAuthTemporaryTokenGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorAuthTemporaryTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorAuthTerminateSessionController' => 'PhabricatorAuthController', 'PhabricatorAuthTryFactorAction' => 'PhabricatorSystemAction', 'PhabricatorAuthUnlinkController' => 'PhabricatorAuthController', 'PhabricatorAuthValidateController' => 'PhabricatorAuthController', 'PhabricatorAuthenticationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorAutoEventListener' => 'PhabricatorEventListener', 'PhabricatorBarePageExample' => 'PhabricatorUIExample', 'PhabricatorBarePageView' => 'AphrontPageView', 'PhabricatorBaseEnglishTranslation' => 'PhabricatorTranslation', 'PhabricatorBcryptPasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorBitbucketAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorBot' => 'PhabricatorDaemon', 'PhabricatorBotBaseStreamingProtocolAdapter' => 'PhabricatorBaseProtocolAdapter', 'PhabricatorBotChannel' => 'PhabricatorBotTarget', 'PhabricatorBotDebugLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFeedNotificationHandler' => 'PhabricatorBotHandler', 'PhabricatorBotFlowdockProtocolAdapter' => 'PhabricatorBotBaseStreamingProtocolAdapter', 'PhabricatorBotLogHandler' => 'PhabricatorBotHandler', 'PhabricatorBotMacroHandler' => 'PhabricatorBotHandler', 'PhabricatorBotObjectNameHandler' => 'PhabricatorBotHandler', 'PhabricatorBotSymbolHandler' => 'PhabricatorBotHandler', 'PhabricatorBotUser' => 'PhabricatorBotTarget', 'PhabricatorBotWhatsNewHandler' => 'PhabricatorBotHandler', 'PhabricatorBuiltinPatchList' => 'PhabricatorSQLPatchList', 'PhabricatorBusyExample' => 'PhabricatorUIExample', 'PhabricatorCacheDAO' => 'PhabricatorLiskDAO', 'PhabricatorCacheGeneralGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorCacheManagementPurgeWorkflow' => 'PhabricatorCacheManagementWorkflow', 'PhabricatorCacheManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorCacheMarkupGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorCacheTTLGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorCalendarApplication' => 'PhabricatorApplication', 'PhabricatorCalendarBrowseController' => 'PhabricatorCalendarController', 'PhabricatorCalendarController' => 'PhabricatorController', 'PhabricatorCalendarDAO' => 'PhabricatorLiskDAO', 'PhabricatorCalendarEvent' => array( 'PhabricatorCalendarDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorCalendarEventDeleteController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventEditController' => 'PhabricatorCalendarController', 'PhabricatorCalendarEventInvalidEpochException' => 'Exception', 'PhabricatorCalendarEventListController' => 'PhabricatorCalendarController', + 'PhabricatorCalendarEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCalendarEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCalendarEventSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCalendarEventViewController' => 'PhabricatorCalendarController', 'PhabricatorCalendarHoliday' => 'PhabricatorCalendarDAO', 'PhabricatorCalendarHolidayTestCase' => 'PhabricatorTestCase', - 'PhabricatorCalendarPHIDTypeEvent' => 'PhabricatorPHIDType', 'PhabricatorCalendarViewController' => 'PhabricatorCalendarController', 'PhabricatorCampfireProtocolAdapter' => 'PhabricatorBotBaseStreamingProtocolAdapter', 'PhabricatorChangeParserTestCase' => 'PhabricatorWorkingCopyTestCase', 'PhabricatorChangesetResponse' => 'AphrontProxyResponse', 'PhabricatorChatLogApplication' => 'PhabricatorApplication', 'PhabricatorChatLogChannel' => array( 'PhabricatorChatLogDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorChatLogChannelListController' => 'PhabricatorChatLogController', 'PhabricatorChatLogChannelLogController' => 'PhabricatorChatLogController', 'PhabricatorChatLogChannelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorChatLogController' => 'PhabricatorController', 'PhabricatorChatLogDAO' => 'PhabricatorLiskDAO', 'PhabricatorChatLogEvent' => array( 'PhabricatorChatLogDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorChatLogEventType' => 'PhabricatorChatLogConstants', 'PhabricatorChatLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCommitBranchesField' => 'PhabricatorCommitCustomField', 'PhabricatorCommitCustomField' => 'PhabricatorCustomField', 'PhabricatorCommitSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCommitTagsField' => 'PhabricatorCommitCustomField', 'PhabricatorCommonPasswords' => 'Phobject', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitApplication' => 'PhabricatorApplication', 'PhabricatorConduitCertificateToken' => 'PhabricatorConduitDAO', 'PhabricatorConduitConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitListController' => 'PhabricatorConduitController', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitMethodCallLog' => array( 'PhabricatorConduitDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorConduitMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConduitSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorConduitTokenController' => 'PhabricatorConduitController', 'PhabricatorConfigAllController' => 'PhabricatorConfigController', 'PhabricatorConfigApplication' => 'PhabricatorApplication', + 'PhabricatorConfigConfigPHIDType' => 'PhabricatorPHIDType', 'PhabricatorConfigController' => 'PhabricatorController', 'PhabricatorConfigDatabaseSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigDefaultSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigDictionarySource' => 'PhabricatorConfigSource', 'PhabricatorConfigEditController' => 'PhabricatorConfigController', 'PhabricatorConfigEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorConfigEntry' => array( 'PhabricatorConfigEntryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorConfigEntryDAO' => 'PhabricatorLiskDAO', 'PhabricatorConfigEntryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorConfigFileSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigGroupController' => 'PhabricatorConfigController', 'PhabricatorConfigIgnoreController' => 'PhabricatorApplicationsController', 'PhabricatorConfigIssueListController' => 'PhabricatorConfigController', 'PhabricatorConfigIssueViewController' => 'PhabricatorConfigController', 'PhabricatorConfigJSONOptionType' => 'PhabricatorConfigOptionType', 'PhabricatorConfigListController' => 'PhabricatorConfigController', 'PhabricatorConfigLocalSource' => 'PhabricatorConfigProxySource', 'PhabricatorConfigManagementDeleteWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementGetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementListWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementSetWorkflow' => 'PhabricatorConfigManagementWorkflow', 'PhabricatorConfigManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorConfigOption' => array( 'Phobject', 'PhabricatorMarkupInterface', ), - 'PhabricatorConfigPHIDTypeConfig' => 'PhabricatorPHIDType', 'PhabricatorConfigProxySource' => 'PhabricatorConfigSource', 'PhabricatorConfigResponse' => 'AphrontHTMLResponse', 'PhabricatorConfigStackSource' => 'PhabricatorConfigSource', 'PhabricatorConfigTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorConfigTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorConfigValidationException' => 'Exception', 'PhabricatorConfigWelcomeController' => 'PhabricatorConfigController', 'PhabricatorConpherenceApplication' => 'PhabricatorApplication', - 'PhabricatorConpherencePHIDTypeThread' => 'PhabricatorPHIDType', + 'PhabricatorConpherenceThreadPHIDType' => 'PhabricatorPHIDType', 'PhabricatorContentSourceView' => 'AphrontView', 'PhabricatorController' => 'AphrontController', 'PhabricatorCookies' => 'Phobject', 'PhabricatorCoreConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorCountdown' => array( 'PhabricatorCountdownDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorCountdownApplication' => 'PhabricatorApplication', 'PhabricatorCountdownCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'PhabricatorCountdownController' => 'PhabricatorController', + 'PhabricatorCountdownCountdownPHIDType' => 'PhabricatorPHIDType', 'PhabricatorCountdownDAO' => 'PhabricatorLiskDAO', 'PhabricatorCountdownDeleteController' => 'PhabricatorCountdownController', 'PhabricatorCountdownEditController' => 'PhabricatorCountdownController', 'PhabricatorCountdownListController' => 'PhabricatorCountdownController', - 'PhabricatorCountdownPHIDTypeCountdown' => 'PhabricatorPHIDType', 'PhabricatorCountdownQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorCountdownRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorCountdownSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorCountdownView' => 'AphrontTagView', 'PhabricatorCountdownViewController' => 'PhabricatorCountdownController', 'PhabricatorCrumbView' => 'AphrontView', 'PhabricatorCrumbsView' => 'AphrontView', 'PhabricatorCursorPagedPolicyAwareQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorCustomFieldConfigOptionType' => 'PhabricatorConfigOptionType', 'PhabricatorCustomFieldDataNotAvailableException' => 'Exception', 'PhabricatorCustomFieldImplementationIncompleteException' => 'Exception', 'PhabricatorCustomFieldIndexStorage' => 'PhabricatorLiskDAO', 'PhabricatorCustomFieldList' => 'Phobject', 'PhabricatorCustomFieldMonogramParser' => 'Phobject', 'PhabricatorCustomFieldNotAttachedException' => 'Exception', 'PhabricatorCustomFieldNotProxyException' => 'Exception', 'PhabricatorCustomFieldNumericIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorCustomFieldStorage' => 'PhabricatorLiskDAO', 'PhabricatorCustomFieldStringIndexStorage' => 'PhabricatorCustomFieldIndexStorage', 'PhabricatorDaemon' => 'PhutilDaemon', 'PhabricatorDaemonCombinedLogController' => 'PhabricatorDaemonController', 'PhabricatorDaemonConsoleController' => 'PhabricatorDaemonController', 'PhabricatorDaemonController' => 'PhabricatorController', 'PhabricatorDaemonDAO' => 'PhabricatorLiskDAO', 'PhabricatorDaemonEventListener' => 'PhabricatorEventListener', 'PhabricatorDaemonLog' => array( 'PhabricatorDaemonDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorDaemonLogEvent' => 'PhabricatorDaemonDAO', 'PhabricatorDaemonLogEventGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonLogEventViewController' => 'PhabricatorDaemonController', 'PhabricatorDaemonLogEventsView' => 'AphrontView', 'PhabricatorDaemonLogGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonLogListController' => 'PhabricatorDaemonController', 'PhabricatorDaemonLogListView' => 'AphrontView', 'PhabricatorDaemonLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDaemonLogViewController' => 'PhabricatorDaemonController', 'PhabricatorDaemonManagementDebugWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementLaunchWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementListWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementLogWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementRestartWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStartWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStatusWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementStopWorkflow' => 'PhabricatorDaemonManagementWorkflow', 'PhabricatorDaemonManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorDaemonTaskGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorDaemonsApplication' => 'PhabricatorApplication', 'PhabricatorDashboard' => array( 'PhabricatorDashboardDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorDashboardAddPanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardApplication' => 'PhabricatorApplication', 'PhabricatorDashboardController' => 'PhabricatorController', 'PhabricatorDashboardCopyController' => 'PhabricatorDashboardController', 'PhabricatorDashboardDAO' => 'PhabricatorLiskDAO', + 'PhabricatorDashboardDashboardPHIDType' => 'PhabricatorPHIDType', 'PhabricatorDashboardEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardHistoryController' => 'PhabricatorDashboardController', 'PhabricatorDashboardInstall' => 'PhabricatorDashboardDAO', 'PhabricatorDashboardInstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardListController' => 'PhabricatorDashboardController', 'PhabricatorDashboardManageController' => 'PhabricatorDashboardController', 'PhabricatorDashboardMovePanelController' => 'PhabricatorDashboardController', - 'PhabricatorDashboardPHIDTypeDashboard' => 'PhabricatorPHIDType', - 'PhabricatorDashboardPHIDTypePanel' => 'PhabricatorPHIDType', 'PhabricatorDashboardPanel' => array( 'PhabricatorDashboardDAO', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', ), 'PhabricatorDashboardPanelArchiveController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelCoreCustomField' => array( 'PhabricatorDashboardPanelCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorDashboardPanelCustomField' => 'PhabricatorCustomField', 'PhabricatorDashboardPanelEditController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelListController' => 'PhabricatorDashboardController', + 'PhabricatorDashboardPanelPHIDType' => 'PhabricatorPHIDType', 'PhabricatorDashboardPanelQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardPanelRenderController' => 'PhabricatorDashboardController', 'PhabricatorDashboardPanelRenderingEngine' => 'Phobject', 'PhabricatorDashboardPanelSearchApplicationCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardPanelSearchQueryCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelTabsCustomField' => 'PhabricatorStandardCustomField', 'PhabricatorDashboardPanelTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardPanelTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardPanelTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardPanelType' => 'Phobject', 'PhabricatorDashboardPanelTypeQuery' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelTypeTabs' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelTypeText' => 'PhabricatorDashboardPanelType', 'PhabricatorDashboardPanelViewController' => 'PhabricatorDashboardController', 'PhabricatorDashboardQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorDashboardRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorDashboardRemovePanelController' => 'PhabricatorDashboardController', 'PhabricatorDashboardRenderingEngine' => 'Phobject', 'PhabricatorDashboardSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorDashboardTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorDashboardTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorDashboardTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorDashboardUninstallController' => 'PhabricatorDashboardController', 'PhabricatorDashboardViewController' => 'PhabricatorDashboardController', 'PhabricatorDataNotAttachedException' => 'Exception', 'PhabricatorDebugController' => 'PhabricatorController', 'PhabricatorDefaultFileStorageEngineSelector' => 'PhabricatorFileStorageEngineSelector', 'PhabricatorDefaultSearchEngineSelector' => 'PhabricatorSearchEngineSelector', 'PhabricatorDestructionEngine' => 'Phobject', 'PhabricatorDeveloperConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDifferentialApplication' => 'PhabricatorApplication', 'PhabricatorDifferentialConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDifferentialRevisionTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorDiffusionApplication' => 'PhabricatorApplication', 'PhabricatorDiffusionConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDisabledUserController' => 'PhabricatorAuthController', 'PhabricatorDisqusAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorDisqusConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorDivinerApplication' => 'PhabricatorApplication', 'PhabricatorDoorkeeperApplication' => 'PhabricatorApplication', 'PhabricatorDraft' => 'PhabricatorDraftDAO', 'PhabricatorDraftDAO' => 'PhabricatorLiskDAO', 'PhabricatorDrydockApplication' => 'PhabricatorApplication', 'PhabricatorEdgeConfig' => 'PhabricatorEdgeConstants', 'PhabricatorEdgeCycleException' => 'Exception', 'PhabricatorEdgeEditor' => 'Phobject', 'PhabricatorEdgeGraph' => 'AbstractDirectedGraph', 'PhabricatorEdgeQuery' => 'PhabricatorQuery', 'PhabricatorEdgeTestCase' => 'PhabricatorTestCase', 'PhabricatorEdgeType' => 'Phobject', 'PhabricatorEditor' => 'Phobject', 'PhabricatorEmailLoginController' => 'PhabricatorAuthController', 'PhabricatorEmailVerificationController' => 'PhabricatorAuthController', 'PhabricatorEmptyQueryException' => 'Exception', 'PhabricatorEnglishTranslation' => 'PhabricatorBaseEnglishTranslation', 'PhabricatorEnvTestCase' => 'PhabricatorTestCase', 'PhabricatorErrorExample' => 'PhabricatorUIExample', 'PhabricatorEvent' => 'PhutilEvent', 'PhabricatorEventListener' => 'PhutilEventListener', 'PhabricatorEventType' => 'PhutilEventType', 'PhabricatorExampleEventListener' => 'PhabricatorEventListener', 'PhabricatorExtendingPhabricatorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorExternalAccount' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorExternalAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFacebookAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorFactAggregate' => 'PhabricatorFactDAO', 'PhabricatorFactApplication' => 'PhabricatorApplication', 'PhabricatorFactChartController' => 'PhabricatorFactController', 'PhabricatorFactController' => 'PhabricatorController', 'PhabricatorFactCountEngine' => 'PhabricatorFactEngine', 'PhabricatorFactCursor' => 'PhabricatorFactDAO', 'PhabricatorFactDAO' => 'PhabricatorLiskDAO', 'PhabricatorFactDaemon' => 'PhabricatorDaemon', 'PhabricatorFactHomeController' => 'PhabricatorFactController', 'PhabricatorFactLastUpdatedEngine' => 'PhabricatorFactEngine', 'PhabricatorFactManagementAnalyzeWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementCursorsWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementDestroyWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementListWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementStatusWorkflow' => 'PhabricatorFactManagementWorkflow', 'PhabricatorFactManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFactRaw' => 'PhabricatorFactDAO', 'PhabricatorFactSimpleSpec' => 'PhabricatorFactSpec', 'PhabricatorFactUpdateIterator' => 'PhutilBufferedIterator', 'PhabricatorFeedApplication' => 'PhabricatorApplication', 'PhabricatorFeedConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFeedController' => 'PhabricatorController', 'PhabricatorFeedDAO' => 'PhabricatorLiskDAO', 'PhabricatorFeedDetailController' => 'PhabricatorFeedController', 'PhabricatorFeedListController' => 'PhabricatorFeedController', 'PhabricatorFeedManagementRepublishWorkflow' => 'PhabricatorFeedManagementWorkflow', 'PhabricatorFeedManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFeedPublicStreamController' => 'PhabricatorFeedController', 'PhabricatorFeedQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFeedSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFeedStory' => 'PhabricatorPolicyInterface', 'PhabricatorFeedStoryAggregate' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryAudit' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryCommit' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryData' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryDifferential' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryDifferentialAggregate' => 'PhabricatorFeedStoryAggregate', 'PhabricatorFeedStoryManiphestAggregate' => 'PhabricatorFeedStoryAggregate', 'PhabricatorFeedStoryNotification' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryPhriction' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryReference' => 'PhabricatorFeedDAO', 'PhabricatorFeedStoryStatus' => 'PhabricatorFeedStory', 'PhabricatorFeedStoryTypeConstants' => 'PhabricatorFeedConstants', 'PhabricatorFile' => array( 'PhabricatorFileDAO', 'PhabricatorTokenReceiverInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorFileCommentController' => 'PhabricatorFileController', 'PhabricatorFileComposeController' => 'PhabricatorFileController', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileDataController' => 'PhabricatorFileController', 'PhabricatorFileDeleteController' => 'PhabricatorFileController', 'PhabricatorFileDropUploadController' => 'PhabricatorFileController', 'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhabricatorFileFilePHIDType' => 'PhabricatorPHIDType', 'PhabricatorFileImageMacro' => array( 'PhabricatorFileDAO', 'PhabricatorSubscribableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', ), 'PhabricatorFileInfoController' => 'PhabricatorFileController', 'PhabricatorFileLinkListView' => 'AphrontView', 'PhabricatorFileLinkView' => 'AphrontView', 'PhabricatorFileListController' => 'PhabricatorFileController', - 'PhabricatorFilePHIDTypeFile' => 'PhabricatorPHIDType', 'PhabricatorFileQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFileSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFileShortcutController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileStorageConfigurationException' => 'Exception', 'PhabricatorFileTemporaryGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorFileTestCase' => 'PhabricatorTestCase', 'PhabricatorFileTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorFileTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorFileTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorFileTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorFileTransformController' => 'PhabricatorFileController', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileUploadDialogController' => 'PhabricatorFileController', 'PhabricatorFileUploadException' => 'Exception', 'PhabricatorFilesApplication' => 'PhabricatorApplication', 'PhabricatorFilesConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorFilesManagementEnginesWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementMigrateWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementPurgeWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementRebuildWorkflow' => 'PhabricatorFilesManagementWorkflow', 'PhabricatorFilesManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorFlag' => array( 'PhabricatorFlagDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorFlagColor' => 'PhabricatorFlagConstants', 'PhabricatorFlagController' => 'PhabricatorController', 'PhabricatorFlagDAO' => 'PhabricatorLiskDAO', 'PhabricatorFlagDeleteController' => 'PhabricatorFlagController', 'PhabricatorFlagEditController' => 'PhabricatorFlagController', 'PhabricatorFlagListController' => 'PhabricatorFlagController', 'PhabricatorFlagQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorFlagSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorFlagSelectControl' => 'AphrontFormControl', 'PhabricatorFlaggableInterface' => 'PhabricatorPHIDInterface', 'PhabricatorFlagsApplication' => 'PhabricatorApplication', 'PhabricatorFlagsUIEventListener' => 'PhabricatorEventListener', 'PhabricatorFormExample' => 'PhabricatorUIExample', 'PhabricatorGarbageCollector' => 'Phobject', 'PhabricatorGarbageCollectorConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorGarbageCollectorDaemon' => 'PhabricatorDaemon', 'PhabricatorGestureExample' => 'PhabricatorUIExample', 'PhabricatorGitGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorGitHubAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorGlobalLock' => 'PhutilLock', 'PhabricatorGlobalUploadTargetView' => 'AphrontView', 'PhabricatorGoogleAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorHandleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorHarbormasterApplication' => 'PhabricatorApplication', 'PhabricatorHarbormasterConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorHashTestCase' => 'PhabricatorTestCase', 'PhabricatorHelpApplication' => 'PhabricatorApplication', 'PhabricatorHelpController' => 'PhabricatorController', 'PhabricatorHelpEditorProtocolController' => 'PhabricatorHelpController', 'PhabricatorHelpKeyboardShortcutController' => 'PhabricatorHelpController', 'PhabricatorHeraldApplication' => 'PhabricatorApplication', 'PhabricatorHomeApplication' => 'PhabricatorApplication', 'PhabricatorHomeController' => 'PhabricatorController', 'PhabricatorHomeMainController' => 'PhabricatorHomeController', 'PhabricatorHomeQuickCreateController' => 'PhabricatorHomeController', 'PhabricatorHovercardExample' => 'PhabricatorUIExample', 'PhabricatorHovercardView' => 'AphrontView', 'PhabricatorHunksManagementMigrateWorkflow' => 'PhabricatorHunksManagementWorkflow', 'PhabricatorHunksManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorIRCProtocolAdapter' => 'PhabricatorBaseProtocolAdapter', 'PhabricatorInfrastructureTestCase' => 'PhabricatorTestCase', 'PhabricatorInlineCommentController' => 'PhabricatorController', 'PhabricatorInlineCommentInterface' => 'PhabricatorMarkupInterface', 'PhabricatorInlineCommentPreviewController' => 'PhabricatorController', 'PhabricatorInlineSummaryView' => 'AphrontView', 'PhabricatorInternationalizationManagementExtractWorkflow' => 'PhabricatorInternationalizationManagementWorkflow', 'PhabricatorInternationalizationManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorIteratedMD5PasswordHasher' => 'PhabricatorPasswordHasher', 'PhabricatorJIRAAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorJavelinLinter' => 'ArcanistLinter', 'PhabricatorKeyValueDatabaseCache' => 'PhutilKeyValueCache', 'PhabricatorLDAPAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorLegacyEdgeType' => 'PhabricatorEdgeType', 'PhabricatorLegalpadApplication' => 'PhabricatorApplication', 'PhabricatorLegalpadConfigOptions' => 'PhabricatorApplicationConfigOptions', - 'PhabricatorLegalpadPHIDTypeDocument' => 'PhabricatorPHIDType', + 'PhabricatorLegalpadDocumentPHIDType' => 'PhabricatorPHIDType', 'PhabricatorLipsumGenerateWorkflow' => 'PhabricatorLipsumManagementWorkflow', 'PhabricatorLipsumManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorLipsumMondrianArtist' => 'PhabricatorLipsumArtist', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLocalDiskFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorLocalTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMacroApplication' => 'PhabricatorApplication', 'PhabricatorMacroAudioController' => 'PhabricatorMacroController', 'PhabricatorMacroCapabilityManage' => 'PhabricatorPolicyCapability', 'PhabricatorMacroCommentController' => 'PhabricatorMacroController', 'PhabricatorMacroConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMacroController' => 'PhabricatorController', 'PhabricatorMacroDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorMacroDisableController' => 'PhabricatorMacroController', 'PhabricatorMacroEditController' => 'PhabricatorMacroController', 'PhabricatorMacroEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorMacroListController' => 'PhabricatorMacroController', + 'PhabricatorMacroMacroPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMacroMailReceiver' => 'PhabricatorObjectMailReceiver', 'PhabricatorMacroMemeController' => 'PhabricatorMacroController', 'PhabricatorMacroMemeDialogController' => 'PhabricatorMacroController', - 'PhabricatorMacroPHIDTypeMacro' => 'PhabricatorPHIDType', 'PhabricatorMacroQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMacroReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorMacroSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorMacroTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorMacroTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorMacroTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorMacroViewController' => 'PhabricatorMacroController', 'PhabricatorMailImplementationAmazonSESAdapter' => 'PhabricatorMailImplementationPHPMailerLiteAdapter', 'PhabricatorMailImplementationMailgunAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationSendGridAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailImplementationTestAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMailManagementListInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementListOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementReceiveTestWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementResendWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementSendTestWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowInboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementShowOutboundWorkflow' => 'PhabricatorMailManagementWorkflow', 'PhabricatorMailManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorMailReceiverTestCase' => 'PhabricatorTestCase', 'PhabricatorMailgunConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMailingListDatasource' => 'PhabricatorTypeaheadDatasource', - 'PhabricatorMailingListPHIDTypeList' => 'PhabricatorPHIDType', + 'PhabricatorMailingListListPHIDType' => 'PhabricatorPHIDType', 'PhabricatorMailingListQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorMailingListSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorMailingListsApplication' => 'PhabricatorApplication', 'PhabricatorMailingListsController' => 'PhabricatorController', 'PhabricatorMailingListsEditController' => 'PhabricatorMailingListsController', 'PhabricatorMailingListsListController' => 'PhabricatorMailingListsController', 'PhabricatorMainMenuGroupView' => 'AphrontView', 'PhabricatorMainMenuIconView' => 'AphrontView', 'PhabricatorMainMenuSearchView' => 'AphrontView', 'PhabricatorMainMenuView' => 'AphrontView', 'PhabricatorManagementWorkflow' => 'PhutilArgumentWorkflow', 'PhabricatorManiphestApplication' => 'PhabricatorApplication', 'PhabricatorManiphestConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorManiphestTaskTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorMarkupCache' => 'PhabricatorCacheDAO', 'PhabricatorMarkupOneOff' => 'PhabricatorMarkupInterface', 'PhabricatorMarkupPreviewController' => 'PhabricatorController', 'PhabricatorMercurialGraphStream' => 'PhabricatorRepositoryGraphStream', 'PhabricatorMetaMTAActorQuery' => 'PhabricatorQuery', 'PhabricatorMetaMTAApplication' => 'PhabricatorApplication', 'PhabricatorMetaMTAConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAEmailBodyParserTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAErrorMailAction' => 'PhabricatorSystemAction', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailBodyTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTAMailableDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorMetaMTAMailgunReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailingList' => array( 'PhabricatorMetaMTADAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorMetaMTAMemberQuery' => 'PhabricatorQuery', 'PhabricatorMetaMTAPermanentFailureException' => 'Exception', 'PhabricatorMetaMTAReceivedMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAReceivedMailProcessingException' => 'Exception', 'PhabricatorMetaMTAReceivedMailTestCase' => 'PhabricatorTestCase', 'PhabricatorMetaMTASendGridReceiveController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAWorker' => 'PhabricatorWorker', 'PhabricatorMultiColumnExample' => 'PhabricatorUIExample', 'PhabricatorMustVerifyEmailController' => 'PhabricatorAuthController', 'PhabricatorMySQLConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorMySQLFileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorNamedQuery' => array( 'PhabricatorSearchDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorNamedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNotificationAdHocFeedStory' => 'PhabricatorFeedStory', 'PhabricatorNotificationClearController' => 'PhabricatorNotificationController', 'PhabricatorNotificationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorNotificationController' => 'PhabricatorController', 'PhabricatorNotificationIndividualController' => 'PhabricatorNotificationController', 'PhabricatorNotificationListController' => 'PhabricatorNotificationController', 'PhabricatorNotificationPanelController' => 'PhabricatorNotificationController', 'PhabricatorNotificationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorNotificationStatusController' => 'PhabricatorNotificationController', 'PhabricatorNotificationStatusView' => 'AphrontTagView', 'PhabricatorNotificationTestController' => 'PhabricatorNotificationController', 'PhabricatorNotificationsApplication' => 'PhabricatorApplication', 'PhabricatorNuanceApplication' => 'PhabricatorApplication', 'PhabricatorOAuth1AuthProvider' => 'PhabricatorOAuthAuthProvider', 'PhabricatorOAuth2AuthProvider' => 'PhabricatorOAuthAuthProvider', 'PhabricatorOAuthAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorOAuthClientAuthorization' => array( 'PhabricatorOAuthServerDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorOAuthClientAuthorizationQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOAuthClientController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthClientDeleteController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientEditController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientListController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthClientViewController' => 'PhabricatorOAuthClientController', 'PhabricatorOAuthResponse' => 'AphrontResponse', 'PhabricatorOAuthServerAccessToken' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerApplication' => 'PhabricatorApplication', 'PhabricatorOAuthServerAuthController' => 'PhabricatorAuthController', 'PhabricatorOAuthServerAuthorizationCode' => 'PhabricatorOAuthServerDAO', 'PhabricatorOAuthServerAuthorizationsSettingsPanel' => 'PhabricatorSettingsPanel', 'PhabricatorOAuthServerCapabilityCreateClients' => 'PhabricatorPolicyCapability', 'PhabricatorOAuthServerClient' => array( 'PhabricatorOAuthServerDAO', 'PhabricatorPolicyInterface', ), + 'PhabricatorOAuthServerClientAuthorizationPHIDType' => 'PhabricatorPHIDType', + 'PhabricatorOAuthServerClientPHIDType' => 'PhabricatorPHIDType', 'PhabricatorOAuthServerClientQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOAuthServerClientSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorOAuthServerController' => 'PhabricatorController', 'PhabricatorOAuthServerDAO' => 'PhabricatorLiskDAO', - 'PhabricatorOAuthServerPHIDTypeClient' => 'PhabricatorPHIDType', - 'PhabricatorOAuthServerPHIDTypeClientAuthorization' => 'PhabricatorPHIDType', 'PhabricatorOAuthServerTestCase' => 'PhabricatorTestCase', 'PhabricatorOAuthServerTestController' => 'PhabricatorOAuthServerController', 'PhabricatorOAuthServerTokenController' => 'PhabricatorAuthController', 'PhabricatorObjectHandle' => 'PhabricatorPolicyInterface', 'PhabricatorObjectHandleStatus' => 'PhabricatorObjectHandleConstants', 'PhabricatorObjectListQueryTestCase' => 'PhabricatorTestCase', 'PhabricatorObjectMailReceiver' => 'PhabricatorMailReceiver', 'PhabricatorObjectMailReceiverTestCase' => 'PhabricatorTestCase', 'PhabricatorObjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOffsetPagedQuery' => 'PhabricatorQuery', 'PhabricatorOwnersApplication' => 'PhabricatorApplication', 'PhabricatorOwnersConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorOwnersController' => 'PhabricatorController', 'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO', 'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController', 'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController', 'PhabricatorOwnersEditController' => 'PhabricatorOwnersController', 'PhabricatorOwnersListController' => 'PhabricatorOwnersController', 'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO', - 'PhabricatorOwnersPHIDTypePackage' => 'PhabricatorPHIDType', 'PhabricatorOwnersPackage' => array( 'PhabricatorOwnersDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorOwnersPackageDatasource' => 'PhabricatorTypeaheadDatasource', + 'PhabricatorOwnersPackagePHIDType' => 'PhabricatorPHIDType', 'PhabricatorOwnersPackageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorOwnersPackageTestCase' => 'PhabricatorTestCase', 'PhabricatorOwnersPath' => 'PhabricatorOwnersDAO', 'PhabricatorPHDConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPHPASTApplication' => 'PhabricatorApplication', 'PhabricatorPHPMailerConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPagedFormExample' => 'PhabricatorUIExample', 'PhabricatorPassphraseApplication' => 'PhabricatorApplication', 'PhabricatorPasswordAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorPasswordHasher' => 'Phobject', 'PhabricatorPasswordHasherTestCase' => 'PhabricatorTestCase', 'PhabricatorPasswordHasherUnavailableException' => 'Exception', 'PhabricatorPaste' => array( 'PhabricatorPasteDAO', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorProjectInterface', ), 'PhabricatorPasteApplication' => 'PhabricatorApplication', 'PhabricatorPasteCommentController' => 'PhabricatorPasteController', 'PhabricatorPasteConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPasteController' => 'PhabricatorController', 'PhabricatorPasteDAO' => 'PhabricatorLiskDAO', 'PhabricatorPasteEditController' => 'PhabricatorPasteController', 'PhabricatorPasteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorPasteListController' => 'PhabricatorPasteController', - 'PhabricatorPastePHIDTypePaste' => 'PhabricatorPHIDType', + 'PhabricatorPastePastePHIDType' => 'PhabricatorPHIDType', 'PhabricatorPasteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPasteRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PhabricatorPasteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPasteTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorPasteTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorPasteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorPasteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorPasteViewController' => 'PhabricatorPasteController', 'PhabricatorPeopleApplication' => 'PhabricatorApplication', 'PhabricatorPeopleApproveController' => 'PhabricatorPeopleController', 'PhabricatorPeopleCalendarController' => 'PhabricatorPeopleController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleCreateController' => 'PhabricatorPeopleController', 'PhabricatorPeopleDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorPeopleDeleteController' => 'PhabricatorPeopleController', 'PhabricatorPeopleDisableController' => 'PhabricatorPeopleController', 'PhabricatorPeopleEmpowerController' => 'PhabricatorPeopleController', + 'PhabricatorPeopleExternalPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPeopleHovercardEventListener' => 'PhabricatorEventListener', 'PhabricatorPeopleLdapController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleLogsController' => 'PhabricatorPeopleController', 'PhabricatorPeopleNewController' => 'PhabricatorPeopleController', - 'PhabricatorPeoplePHIDTypeExternal' => 'PhabricatorPHIDType', - 'PhabricatorPeoplePHIDTypeUser' => 'PhabricatorPHIDType', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfilePictureController' => 'PhabricatorPeopleController', 'PhabricatorPeopleQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPeopleRenameController' => 'PhabricatorPeopleController', 'PhabricatorPeopleSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorPeopleTestDataGenerator' => 'PhabricatorTestDataGenerator', + 'PhabricatorPeopleUserPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPeopleWelcomeController' => 'PhabricatorPeopleController', 'PhabricatorPersonaAuthProvider' => 'PhabricatorAuthProvider', 'PhabricatorPhameApplication' => 'PhabricatorApplication', + 'PhabricatorPhameBlogPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPhameConfigOptions' => 'PhabricatorApplicationConfigOptions', - 'PhabricatorPhamePHIDTypeBlog' => 'PhabricatorPHIDType', - 'PhabricatorPhamePHIDTypePost' => 'PhabricatorPHIDType', + 'PhabricatorPhamePostPHIDType' => 'PhabricatorPHIDType', 'PhabricatorPhluxApplication' => 'PhabricatorApplication', 'PhabricatorPholioApplication' => 'PhabricatorApplication', 'PhabricatorPholioConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPholioMockTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorPhortuneApplication' => 'PhabricatorApplication', 'PhabricatorPhortuneConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPhragmentApplication' => 'PhabricatorApplication', 'PhabricatorPhrequentApplication' => 'PhabricatorApplication', 'PhabricatorPhrequentConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPhrictionApplication' => 'PhabricatorApplication', 'PhabricatorPhrictionConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPolicies' => 'PhabricatorPolicyConstants', 'PhabricatorPolicy' => array( 'PhabricatorPolicyDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorPolicyApplication' => 'PhabricatorApplication', 'PhabricatorPolicyAwareQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorPolicyAwareTestQuery' => 'PhabricatorPolicyAwareQuery', 'PhabricatorPolicyCapability' => 'Phobject', 'PhabricatorPolicyCapabilityCanEdit' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCapabilityCanJoin' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyCapabilityCanView' => 'PhabricatorPolicyCapability', 'PhabricatorPolicyConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorPolicyController' => 'PhabricatorController', 'PhabricatorPolicyDAO' => 'PhabricatorLiskDAO', 'PhabricatorPolicyDataTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyEditController' => 'PhabricatorPolicyController', 'PhabricatorPolicyException' => 'Exception', 'PhabricatorPolicyExplainController' => 'PhabricatorPolicyController', 'PhabricatorPolicyInterface' => 'PhabricatorPHIDInterface', 'PhabricatorPolicyManagementShowWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementUnlockWorkflow' => 'PhabricatorPolicyManagementWorkflow', 'PhabricatorPolicyManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorPolicyPHIDTypePolicy' => 'PhabricatorPHIDType', 'PhabricatorPolicyQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorPolicyRuleAdministrators' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleLegalpadSignature' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleLunarPhase' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleProjects' => 'PhabricatorPolicyRule', 'PhabricatorPolicyRuleUsers' => 'PhabricatorPolicyRule', 'PhabricatorPolicyTestCase' => 'PhabricatorTestCase', 'PhabricatorPolicyTestObject' => 'PhabricatorPolicyInterface', 'PhabricatorPolicyType' => 'PhabricatorPolicyConstants', 'PhabricatorPonderApplication' => 'PhabricatorApplication', 'PhabricatorProject' => array( 'PhabricatorProjectDAO', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorProjectApplication' => 'PhabricatorApplication', 'PhabricatorProjectArchiveController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardController' => 'PhabricatorProjectController', 'PhabricatorProjectBoardDeleteController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardEditController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', 'PhabricatorProjectColumn' => array( 'PhabricatorProjectDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController', + 'PhabricatorProjectColumnPHIDType' => 'PhabricatorPHIDType', 'PhabricatorProjectColumnQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectColumnTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProjectColumnTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProjectColumnTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProjectConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorProjectConfiguredCustomField' => array( 'PhabricatorProjectStandardCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorProjectController' => 'PhabricatorController', 'PhabricatorProjectCreateController' => 'PhabricatorProjectController', 'PhabricatorProjectCustomField' => 'PhabricatorCustomField', 'PhabricatorProjectCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'PhabricatorProjectCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'PhabricatorProjectCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'PhabricatorProjectDAO' => 'PhabricatorLiskDAO', 'PhabricatorProjectDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorProjectDescriptionField' => 'PhabricatorProjectStandardCustomField', 'PhabricatorProjectEditDetailsController' => 'PhabricatorProjectController', 'PhabricatorProjectEditIconController' => 'PhabricatorProjectController', 'PhabricatorProjectEditMainController' => 'PhabricatorProjectController', 'PhabricatorProjectEditPictureController' => 'PhabricatorProjectController', 'PhabricatorProjectEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorProjectIcon' => 'Phobject', 'PhabricatorProjectListController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersEditController' => 'PhabricatorProjectController', 'PhabricatorProjectMembersRemoveController' => 'PhabricatorProjectController', 'PhabricatorProjectMoveController' => 'PhabricatorProjectController', 'PhabricatorProjectNameCollisionException' => 'Exception', 'PhabricatorProjectObjectHasProjectEdgeType' => 'PhabricatorEdgeType', 'PhabricatorProjectOrUserDatasource' => 'PhabricatorTypeaheadCompositeDatasource', - 'PhabricatorProjectPHIDTypeColumn' => 'PhabricatorPHIDType', - 'PhabricatorProjectPHIDTypeProject' => 'PhabricatorPHIDType', 'PhabricatorProjectProfileController' => 'PhabricatorProjectController', 'PhabricatorProjectProjectHasObjectEdgeType' => 'PhabricatorEdgeType', + 'PhabricatorProjectProjectPHIDType' => 'PhabricatorPHIDType', 'PhabricatorProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorProjectSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorProjectSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorProjectSlug' => 'PhabricatorProjectDAO', 'PhabricatorProjectStandardCustomField' => array( 'PhabricatorProjectCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorProjectTestDataGenerator' => 'PhabricatorTestDataGenerator', 'PhabricatorProjectTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorProjectTransactionEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorProjectTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorProjectUIEventListener' => 'PhabricatorEventListener', 'PhabricatorProjectUpdateController' => 'PhabricatorProjectController', 'PhabricatorProjectWatchController' => 'PhabricatorProjectController', 'PhabricatorRecaptchaConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRedirectController' => 'PhabricatorController', 'PhabricatorRefreshCSRFController' => 'PhabricatorAuthController', 'PhabricatorRegistrationProfile' => 'Phobject', 'PhabricatorReleephApplication' => 'PhabricatorApplication', 'PhabricatorReleephApplicationConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRemarkupBlockInterpreterCowsay' => 'PhutilRemarkupBlockInterpreter', 'PhabricatorRemarkupBlockInterpreterFiglet' => 'PhutilRemarkupBlockInterpreter', 'PhabricatorRemarkupBlockInterpreterGraphviz' => 'PhutilRemarkupBlockInterpreter', 'PhabricatorRemarkupControl' => 'AphrontFormTextAreaControl', 'PhabricatorRemarkupCustomBlockRule' => 'PhutilRemarkupEngineBlockRule', 'PhabricatorRemarkupCustomInlineRule' => 'PhutilRemarkupRule', 'PhabricatorRemarkupExample' => 'PhabricatorUIExample', 'PhabricatorRemarkupRuleEmbedFile' => 'PhabricatorRemarkupRuleObject', 'PhabricatorRemarkupRuleIcon' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleImageMacro' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleMeme' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleMention' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleObject' => 'PhutilRemarkupRule', 'PhabricatorRemarkupRuleYoutube' => 'PhutilRemarkupRule', 'PhabricatorRepositoriesApplication' => 'PhabricatorApplication', 'PhabricatorRepository' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorMarkupInterface', 'PhabricatorDestructibleInterface', 'PhabricatorProjectInterface', ), 'PhabricatorRepositoryArcanistProject' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorRepositoryArcanistProjectDeleteController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryArcanistProjectEditController' => 'PhabricatorRepositoryController', + 'PhabricatorRepositoryArcanistProjectPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryArcanistProjectQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryAuditRequest' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryBranch' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommit' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'HarbormasterBuildableInterface', 'PhabricatorCustomFieldInterface', ), 'PhabricatorRepositoryCommitChangeParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitData' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryCommitHeraldWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitMessageParserWorker' => 'PhabricatorRepositoryCommitParserWorker', 'PhabricatorRepositoryCommitOwnersWorker' => 'PhabricatorRepositoryCommitParserWorker', + 'PhabricatorRepositoryCommitPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryCommitParserWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryCommitSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorRepositoryConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorRepositoryController' => 'PhabricatorController', 'PhabricatorRepositoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorRepositoryDiscoveryEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorRepositoryGitCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryGitCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryGraphStream' => 'Phobject', 'PhabricatorRepositoryListController' => 'PhabricatorRepositoryController', 'PhabricatorRepositoryManagementCacheWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementDiscoverWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementEditWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementImportingWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementListWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementLookupUsersWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMarkImportedWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementMirrorWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementParentsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementPullWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementRefsWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementUpdateWorkflow' => 'PhabricatorRepositoryManagementWorkflow', 'PhabricatorRepositoryManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorRepositoryMercurialCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositoryMercurialCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositoryMirror' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryMirrorEngine' => 'PhabricatorRepositoryEngine', + 'PhabricatorRepositoryMirrorPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryMirrorQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', - 'PhabricatorRepositoryPHIDTypeArcanistProject' => 'PhabricatorPHIDType', - 'PhabricatorRepositoryPHIDTypeCommit' => 'PhabricatorPHIDType', - 'PhabricatorRepositoryPHIDTypeMirror' => 'PhabricatorPHIDType', - 'PhabricatorRepositoryPHIDTypePushEvent' => 'PhabricatorPHIDType', - 'PhabricatorRepositoryPHIDTypePushLog' => 'PhabricatorPHIDType', - 'PhabricatorRepositoryPHIDTypeRepository' => 'PhabricatorPHIDType', 'PhabricatorRepositoryParsedChange' => 'Phobject', 'PhabricatorRepositoryPullEngine' => 'PhabricatorRepositoryEngine', 'PhabricatorRepositoryPullLocalDaemon' => 'PhabricatorDaemon', 'PhabricatorRepositoryPushEvent' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), + 'PhabricatorRepositoryPushEventPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPushEventQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryPushLog' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), + 'PhabricatorRepositoryPushLogPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositoryPushLogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryPushLogSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorRepositoryPushMailWorker' => 'PhabricatorWorker', 'PhabricatorRepositoryPushReplyHandler' => 'PhabricatorMailReplyHandler', 'PhabricatorRepositoryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryRefCursor' => array( 'PhabricatorRepositoryDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorRepositoryRefCursorQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorRepositoryRefEngine' => 'PhabricatorRepositoryEngine', + 'PhabricatorRepositoryRepositoryPHIDType' => 'PhabricatorPHIDType', 'PhabricatorRepositorySearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorRepositoryStatusMessage' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositorySvnCommitChangeParserWorker' => 'PhabricatorRepositoryCommitChangeParserWorker', 'PhabricatorRepositorySvnCommitMessageParserWorker' => 'PhabricatorRepositoryCommitMessageParserWorker', 'PhabricatorRepositorySymbol' => 'PhabricatorRepositoryDAO', 'PhabricatorRepositoryTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorRepositoryTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorRepositoryURINormalizer' => 'Phobject', 'PhabricatorRepositoryURINormalizerTestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryURITestCase' => 'PhabricatorTestCase', 'PhabricatorRepositoryVCSPassword' => 'PhabricatorRepositoryDAO', 'PhabricatorRobotsController' => 'PhabricatorController', 'PhabricatorS3FileStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorSMS' => 'PhabricatorSMSDAO', 'PhabricatorSMSConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSMSDAO' => 'PhabricatorLiskDAO', 'PhabricatorSMSDemultiplexWorker' => 'PhabricatorSMSWorker', 'PhabricatorSMSImplementationTestBlackholeAdapter' => 'PhabricatorSMSImplementationAdapter', 'PhabricatorSMSImplementationTwilioAdapter' => 'PhabricatorSMSImplementationAdapter', 'PhabricatorSMSManagementListOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', 'PhabricatorSMSManagementSendTestWorkflow' => 'PhabricatorSMSManagementWorkflow', 'PhabricatorSMSManagementShowOutboundWorkflow' => 'PhabricatorSMSManagementWorkflow', 'PhabricatorSMSManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSMSSendWorker' => 'PhabricatorSMSWorker', 'PhabricatorSMSWorker' => 'PhabricatorWorker', 'PhabricatorSSHKeyGenerator' => 'Phobject', 'PhabricatorSSHLog' => 'Phobject', 'PhabricatorSSHPassthruCommand' => 'Phobject', 'PhabricatorSSHWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSavedQuery' => array( 'PhabricatorSearchDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorSavedQueryQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSearchApplication' => 'PhabricatorApplication', 'PhabricatorSearchApplicationSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSearchAttachController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchBaseController' => 'PhabricatorController', 'PhabricatorSearchConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSearchController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchDAO' => 'PhabricatorLiskDAO', 'PhabricatorSearchDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorSearchDeleteController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchDocument' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentField' => 'PhabricatorSearchDAO', 'PhabricatorSearchDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSearchDocumentRelationship' => 'PhabricatorSearchDAO', 'PhabricatorSearchEditController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchEngineElastic' => 'PhabricatorSearchEngine', 'PhabricatorSearchEngineMySQL' => 'PhabricatorSearchEngine', 'PhabricatorSearchHovercardController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchManagementIndexWorkflow' => 'PhabricatorSearchManagementWorkflow', 'PhabricatorSearchManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSearchOrderController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchQuery' => 'PhabricatorSearchDAO', 'PhabricatorSearchResultView' => 'AphrontView', 'PhabricatorSearchSelectController' => 'PhabricatorSearchBaseController', 'PhabricatorSearchWorker' => 'PhabricatorWorker', 'PhabricatorSecurityConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSendGridConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSettingsAddEmailAction' => 'PhabricatorSystemAction', 'PhabricatorSettingsAdjustController' => 'PhabricatorController', 'PhabricatorSettingsApplication' => 'PhabricatorApplication', 'PhabricatorSettingsMainController' => 'PhabricatorController', 'PhabricatorSettingsPanelAccount' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelActivity' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelConduit' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelConpherencePreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelDeveloperPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelDiffPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelDisplayPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelEmailAddresses' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelEmailPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelExternalAccounts' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelHomePreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelMultiFactor' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelPassword' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelSSHKeys' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelSearchPreferences' => 'PhabricatorSettingsPanel', 'PhabricatorSettingsPanelSessions' => 'PhabricatorSettingsPanel', 'PhabricatorSetupCheckAPC' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckAphlict' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckAuth' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckBaseURI' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckBinaries' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckDaemons' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckDatabase' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckExtensions' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckExtraConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckFileinfo' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckGD' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckImagemagick' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckInvalidConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckMail' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckMySQL' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckPHPConfig' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckPath' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckPygment' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckRepositories' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckStorage' => 'PhabricatorSetupCheck', 'PhabricatorSetupCheckTimezone' => 'PhabricatorSetupCheck', 'PhabricatorSetupIssueExample' => 'PhabricatorUIExample', 'PhabricatorSetupIssueView' => 'AphrontView', 'PhabricatorSlowvoteApplication' => 'PhabricatorApplication', 'PhabricatorSlowvoteCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'PhabricatorSlowvoteChoice' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteCloseController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteComment' => 'PhabricatorSlowvoteDAO', 'PhabricatorSlowvoteCommentController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteController' => 'PhabricatorController', 'PhabricatorSlowvoteDAO' => 'PhabricatorLiskDAO', 'PhabricatorSlowvoteEditController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorSlowvoteListController' => 'PhabricatorSlowvoteController', 'PhabricatorSlowvoteOption' => 'PhabricatorSlowvoteDAO', - 'PhabricatorSlowvotePHIDTypePoll' => 'PhabricatorPHIDType', 'PhabricatorSlowvotePoll' => array( 'PhabricatorSlowvoteDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorProjectInterface', ), 'PhabricatorSlowvotePollController' => 'PhabricatorSlowvoteController', + 'PhabricatorSlowvotePollPHIDType' => 'PhabricatorPHIDType', 'PhabricatorSlowvoteQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorSlowvoteSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhabricatorSlowvoteTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorSlowvoteTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PhabricatorSlowvoteTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhabricatorSlowvoteVoteController' => 'PhabricatorSlowvoteController', 'PhabricatorSlugTestCase' => 'PhabricatorTestCase', 'PhabricatorSortTableExample' => 'PhabricatorUIExample', 'PhabricatorSourceCodeView' => 'AphrontView', 'PhabricatorStandardCustomField' => 'PhabricatorCustomField', 'PhabricatorStandardCustomFieldBool' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldCredential' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldDate' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldHeader' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldInt' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldPHIDs' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldRemarkup' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldSelect' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldText' => 'PhabricatorStandardCustomField', 'PhabricatorStandardCustomFieldUsers' => 'PhabricatorStandardCustomFieldPHIDs', 'PhabricatorStandardPageView' => 'PhabricatorBarePageView', 'PhabricatorStatusController' => 'PhabricatorController', 'PhabricatorStorageManagementDatabasesWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDestroyWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementDumpWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementProbeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementStatusWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementUpgradeWorkflow' => 'PhabricatorStorageManagementWorkflow', 'PhabricatorStorageManagementWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 'PhabricatorSubscriptionsApplication' => 'PhabricatorApplication', 'PhabricatorSubscriptionsEditController' => 'PhabricatorController', 'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor', 'PhabricatorSubscriptionsListController' => 'PhabricatorController', 'PhabricatorSubscriptionsTransactionController' => 'PhabricatorController', 'PhabricatorSubscriptionsUIEventListener' => 'PhabricatorEventListener', 'PhabricatorSupportApplication' => 'PhabricatorApplication', 'PhabricatorSymbolNameLinter' => 'ArcanistXHPASTLintNamingHook', 'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorSystemActionEngine' => 'Phobject', 'PhabricatorSystemActionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorSystemActionLog' => 'PhabricatorSystemDAO', 'PhabricatorSystemActionRateLimitException' => 'Exception', 'PhabricatorSystemApplication' => 'PhabricatorApplication', 'PhabricatorSystemDAO' => 'PhabricatorLiskDAO', 'PhabricatorSystemDestructionGarbageCollector' => 'PhabricatorGarbageCollector', 'PhabricatorSystemDestructionLog' => 'PhabricatorSystemDAO', 'PhabricatorSystemRemoveDestroyWorkflow' => 'PhabricatorSystemRemoveWorkflow', 'PhabricatorSystemRemoveLogWorkflow' => 'PhabricatorSystemRemoveWorkflow', 'PhabricatorSystemRemoveWorkflow' => 'PhabricatorManagementWorkflow', 'PhabricatorSystemSelectEncodingController' => 'PhabricatorController', 'PhabricatorSystemSelectHighlightController' => 'PhabricatorController', 'PhabricatorTaskmasterDaemon' => 'PhabricatorDaemon', 'PhabricatorTestApplication' => 'PhabricatorApplication', 'PhabricatorTestCase' => 'ArcanistPhutilTestCase', 'PhabricatorTestController' => 'PhabricatorController', 'PhabricatorTestStorageEngine' => 'PhabricatorFileStorageEngine', 'PhabricatorTestWorker' => 'PhabricatorWorker', 'PhabricatorTimeTestCase' => 'PhabricatorTestCase', 'PhabricatorToken' => array( 'PhabricatorTokenDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorTokenController' => 'PhabricatorController', 'PhabricatorTokenCount' => 'PhabricatorTokenDAO', 'PhabricatorTokenCountQuery' => 'PhabricatorOffsetPagedQuery', 'PhabricatorTokenDAO' => 'PhabricatorLiskDAO', 'PhabricatorTokenGiveController' => 'PhabricatorTokenController', 'PhabricatorTokenGiven' => array( 'PhabricatorTokenDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorTokenGivenController' => 'PhabricatorTokenController', 'PhabricatorTokenGivenEditor' => 'PhabricatorEditor', 'PhabricatorTokenGivenFeedStory' => 'PhabricatorFeedStory', 'PhabricatorTokenGivenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenLeaderController' => 'PhabricatorTokenController', - 'PhabricatorTokenPHIDTypeToken' => 'PhabricatorPHIDType', 'PhabricatorTokenQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhabricatorTokenReceiverQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', + 'PhabricatorTokenTokenPHIDType' => 'PhabricatorPHIDType', 'PhabricatorTokenUIEventListener' => 'PhabricatorEventListener', 'PhabricatorTokensApplication' => 'PhabricatorApplication', 'PhabricatorTransactionView' => 'AphrontView', 'PhabricatorTransactionsApplication' => 'PhabricatorApplication', 'PhabricatorTransformedFile' => 'PhabricatorFileDAO', 'PhabricatorTranslationsConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorTrivialTestCase' => 'PhabricatorTestCase', 'PhabricatorTwitchAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorTwitterAuthProvider' => 'PhabricatorOAuth1AuthProvider', 'PhabricatorTwoColumnExample' => 'PhabricatorUIExample', 'PhabricatorTypeaheadApplication' => 'PhabricatorApplication', 'PhabricatorTypeaheadCompositeDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorTypeaheadDatasource' => 'Phobject', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorTypeaheadModularDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadMonogramDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorTypeaheadNoOwnerDatasource' => 'PhabricatorTypeaheadDatasource', 'PhabricatorTypeaheadOwnerDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorTypeaheadRuntimeCompositeDatasource' => 'PhabricatorTypeaheadCompositeDatasource', 'PhabricatorUIConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorUIExampleRenderController' => 'PhabricatorController', 'PhabricatorUIExamplesApplication' => 'PhabricatorApplication', 'PhabricatorUIListFilterExample' => 'PhabricatorUIExample', 'PhabricatorUINotificationExample' => 'PhabricatorUIExample', 'PhabricatorUIPagerExample' => 'PhabricatorUIExample', 'PhabricatorUIStatusExample' => 'PhabricatorUIExample', 'PhabricatorUITooltipExample' => 'PhabricatorUIExample', 'PhabricatorUnitsTestCase' => 'PhabricatorTestCase', 'PhabricatorUser' => array( 'PhabricatorUserDAO', 'PhutilPerson', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', 'PhabricatorDestructibleInterface', ), 'PhabricatorUserBlurbField' => 'PhabricatorUserCustomField', 'PhabricatorUserConfigOptions' => 'PhabricatorApplicationConfigOptions', 'PhabricatorUserConfiguredCustomField' => array( 'PhabricatorUserCustomField', 'PhabricatorStandardCustomFieldInterface', ), 'PhabricatorUserConfiguredCustomFieldStorage' => 'PhabricatorCustomFieldStorage', 'PhabricatorUserCustomField' => 'PhabricatorCustomField', 'PhabricatorUserCustomFieldNumericIndex' => 'PhabricatorCustomFieldNumericIndexStorage', 'PhabricatorUserCustomFieldStringIndex' => 'PhabricatorCustomFieldStringIndexStorage', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', 'PhabricatorUserEditor' => 'PhabricatorEditor', 'PhabricatorUserEditorTestCase' => 'PhabricatorTestCase', 'PhabricatorUserEmail' => 'PhabricatorUserDAO', 'PhabricatorUserEmailTestCase' => 'PhabricatorTestCase', 'PhabricatorUserLog' => array( 'PhabricatorUserDAO', 'PhabricatorPolicyInterface', ), 'PhabricatorUserLogView' => 'AphrontView', 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserProfileEditor' => 'PhabricatorApplicationTransactionEditor', 'PhabricatorUserRealNameField' => 'PhabricatorUserCustomField', 'PhabricatorUserRolesField' => 'PhabricatorUserCustomField', 'PhabricatorUserSSHKey' => 'PhabricatorUserDAO', 'PhabricatorUserSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PhabricatorUserSinceField' => 'PhabricatorUserCustomField', 'PhabricatorUserStatusField' => 'PhabricatorUserCustomField', 'PhabricatorUserTestCase' => 'PhabricatorTestCase', 'PhabricatorUserTitleField' => 'PhabricatorUserCustomField', 'PhabricatorUserTransaction' => 'PhabricatorApplicationTransaction', 'PhabricatorVCSResponse' => 'AphrontResponse', 'PhabricatorWordPressAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorWorkerActiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerArchiveTask' => 'PhabricatorWorkerTask', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerLeaseQuery' => 'PhabricatorQuery', 'PhabricatorWorkerPermanentFailureException' => 'Exception', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskDetailController' => 'PhabricatorDaemonController', 'PhabricatorWorkerTaskUpdateController' => 'PhabricatorDaemonController', 'PhabricatorWorkerTestCase' => 'PhabricatorTestCase', 'PhabricatorWorkerYieldException' => 'Exception', 'PhabricatorWorkingCopyDiscoveryTestCase' => 'PhabricatorWorkingCopyTestCase', 'PhabricatorWorkingCopyPullTestCase' => 'PhabricatorWorkingCopyTestCase', 'PhabricatorWorkingCopyTestCase' => 'PhabricatorTestCase', 'PhabricatorXHPASTViewController' => 'PhabricatorController', 'PhabricatorXHPASTViewDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHPASTViewFrameController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewFramesetController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewInputController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewPanelController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewParseTree' => 'PhabricatorXHPASTViewDAO', 'PhabricatorXHPASTViewRunController' => 'PhabricatorXHPASTViewController', 'PhabricatorXHPASTViewStreamController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHPASTViewTreeController' => 'PhabricatorXHPASTViewPanelController', 'PhabricatorXHProfApplication' => 'PhabricatorApplication', 'PhabricatorXHProfController' => 'PhabricatorController', 'PhabricatorXHProfDAO' => 'PhabricatorLiskDAO', 'PhabricatorXHProfProfileController' => 'PhabricatorXHProfController', 'PhabricatorXHProfProfileSymbolView' => 'PhabricatorXHProfProfileView', 'PhabricatorXHProfProfileTopLevelView' => 'PhabricatorXHProfProfileView', 'PhabricatorXHProfProfileView' => 'AphrontView', 'PhabricatorXHProfSample' => 'PhabricatorXHProfDAO', 'PhabricatorXHProfSampleListController' => 'PhabricatorXHProfController', 'PhameBasicBlogSkin' => 'PhameBlogSkin', 'PhameBasicTemplateBlogSkin' => 'PhameBasicBlogSkin', 'PhameBlog' => array( 'PhameDAO', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', ), 'PhameBlogDeleteController' => 'PhameController', 'PhameBlogEditController' => 'PhameController', 'PhameBlogFeedController' => 'PhameController', 'PhameBlogListController' => 'PhameController', 'PhameBlogLiveController' => 'PhameController', 'PhameBlogQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhameBlogSkin' => 'PhabricatorController', 'PhameBlogViewController' => 'PhameController', 'PhameCelerityResources' => 'CelerityResources', 'PhameController' => 'PhabricatorController', 'PhameDAO' => 'PhabricatorLiskDAO', 'PhamePost' => array( 'PhameDAO', 'PhabricatorPolicyInterface', 'PhabricatorMarkupInterface', 'PhabricatorTokenReceiverInterface', ), 'PhamePostDeleteController' => 'PhameController', 'PhamePostEditController' => 'PhameController', 'PhamePostFramedController' => 'PhameController', 'PhamePostListController' => 'PhameController', 'PhamePostNewController' => 'PhameController', 'PhamePostNotLiveController' => 'PhameController', 'PhamePostPreviewController' => 'PhameController', 'PhamePostPublishController' => 'PhameController', 'PhamePostQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhamePostUnpublishController' => 'PhameController', 'PhamePostView' => 'AphrontView', 'PhamePostViewController' => 'PhameController', 'PhameResourceController' => 'CelerityResourceController', 'PhluxController' => 'PhabricatorController', 'PhluxDAO' => 'PhabricatorLiskDAO', 'PhluxEditController' => 'PhluxController', 'PhluxListController' => 'PhluxController', - 'PhluxPHIDTypeVariable' => 'PhabricatorPHIDType', 'PhluxTransaction' => 'PhabricatorApplicationTransaction', 'PhluxTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhluxVariable' => array( 'PhluxDAO', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', ), 'PhluxVariableEditor' => 'PhabricatorApplicationTransactionEditor', + 'PhluxVariablePHIDType' => 'PhabricatorPHIDType', 'PhluxVariableQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhluxViewController' => 'PhluxController', 'PholioActionMenuEventListener' => 'PhabricatorEventListener', 'PholioCapabilityDefaultEdit' => 'PhabricatorPolicyCapability', 'PholioCapabilityDefaultView' => 'PhabricatorPolicyCapability', 'PholioController' => 'PhabricatorController', 'PholioDAO' => 'PhabricatorLiskDAO', 'PholioImage' => array( 'PholioDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', ), + 'PholioImagePHIDType' => 'PhabricatorPHIDType', 'PholioImageQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PholioImageUploadController' => 'PholioController', 'PholioInlineController' => 'PholioController', 'PholioInlineListController' => 'PholioController', 'PholioInlineThumbController' => 'PholioController', 'PholioMock' => array( 'PholioDAO', 'PhabricatorMarkupInterface', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorFlaggableInterface', 'PhabricatorApplicationTransactionInterface', 'PhabricatorProjectInterface', 'PhabricatorDestructibleInterface', ), 'PholioMockCommentController' => 'PholioController', 'PholioMockEditController' => 'PholioController', 'PholioMockEditor' => 'PhabricatorApplicationTransactionEditor', 'PholioMockEmbedView' => 'AphrontView', 'PholioMockImagesView' => 'AphrontView', 'PholioMockListController' => 'PholioController', 'PholioMockMailReceiver' => 'PhabricatorObjectMailReceiver', + 'PholioMockPHIDType' => 'PhabricatorPHIDType', 'PholioMockQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PholioMockSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PholioMockThumbGridView' => 'AphrontView', 'PholioMockViewController' => 'PholioController', - 'PholioPHIDTypeImage' => 'PhabricatorPHIDType', - 'PholioPHIDTypeMock' => 'PhabricatorPHIDType', 'PholioRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PholioReplyHandler' => 'PhabricatorMailReplyHandler', 'PholioSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PholioTransaction' => 'PhabricatorApplicationTransaction', 'PholioTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PholioTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PholioTransactionType' => 'PholioConstants', 'PholioTransactionView' => 'PhabricatorApplicationTransactionView', 'PholioUploadedImageView' => 'AphrontView', 'PhortuneAccount' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneAccountEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneAccountQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneAccountTransaction' => 'PhabricatorApplicationTransaction', 'PhortuneAccountTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortuneAccountViewController' => 'PhortuneController', 'PhortuneBalancedPaymentProvider' => 'PhortunePaymentProvider', 'PhortuneCart' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneCartCheckoutController' => 'PhortuneCartController', 'PhortuneCartController' => 'PhortuneController', 'PhortuneCartQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneCartViewController' => 'PhortuneCartController', 'PhortuneCharge' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneChargeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneController' => 'PhabricatorController', 'PhortuneCurrency' => 'Phobject', 'PhortuneCurrencyTestCase' => 'PhabricatorTestCase', 'PhortuneDAO' => 'PhabricatorLiskDAO', 'PhortuneErrCode' => 'PhortuneConstants', 'PhortuneLandingController' => 'PhortuneController', 'PhortuneMonthYearExpiryControl' => 'AphrontFormControl', 'PhortuneMultiplePaymentProvidersException' => 'Exception', 'PhortuneNoPaymentProviderException' => 'Exception', 'PhortuneNotImplementedException' => 'Exception', 'PhortunePaymentMethod' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortunePaymentMethodEditController' => 'PhortuneController', 'PhortunePaymentMethodListController' => 'PhabricatorController', 'PhortunePaymentMethodQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortunePaymentMethodViewController' => 'PhabricatorController', 'PhortunePaymentProviderTestCase' => 'PhabricatorTestCase', 'PhortunePaypalPaymentProvider' => 'PhortunePaymentProvider', 'PhortuneProduct' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortuneProductEditController' => 'PhabricatorController', 'PhortuneProductEditor' => 'PhabricatorApplicationTransactionEditor', 'PhortuneProductListController' => 'PhabricatorController', 'PhortuneProductPurchaseController' => 'PhortuneController', 'PhortuneProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneProductTransaction' => 'PhabricatorApplicationTransaction', 'PhortuneProductTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PhortuneProductViewController' => 'PhortuneController', 'PhortuneProviderController' => 'PhortuneController', 'PhortunePurchase' => array( 'PhortuneDAO', 'PhabricatorPolicyInterface', ), 'PhortunePurchaseQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhortuneStripePaymentProvider' => 'PhortunePaymentProvider', 'PhortuneTestExtraPaymentProvider' => 'PhortunePaymentProvider', 'PhortuneTestPaymentProvider' => 'PhortunePaymentProvider', 'PhortuneWePayPaymentProvider' => 'PhortunePaymentProvider', 'PhragmentBrowseController' => 'PhragmentController', 'PhragmentCapabilityCanCreate' => 'PhabricatorPolicyCapability', 'PhragmentController' => 'PhabricatorController', 'PhragmentCreateController' => 'PhragmentController', 'PhragmentDAO' => 'PhabricatorLiskDAO', 'PhragmentFragment' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), + 'PhragmentFragmentPHIDType' => 'PhabricatorPHIDType', 'PhragmentFragmentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentFragmentVersion' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), + 'PhragmentFragmentVersionPHIDType' => 'PhabricatorPHIDType', 'PhragmentFragmentVersionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentHistoryController' => 'PhragmentController', - 'PhragmentPHIDTypeFragment' => 'PhabricatorPHIDType', - 'PhragmentPHIDTypeFragmentVersion' => 'PhabricatorPHIDType', - 'PhragmentPHIDTypeSnapshot' => 'PhabricatorPHIDType', 'PhragmentPatchController' => 'PhragmentController', 'PhragmentPatchUtil' => 'Phobject', 'PhragmentPolicyController' => 'PhragmentController', 'PhragmentRevertController' => 'PhragmentController', 'PhragmentSnapshot' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), 'PhragmentSnapshotChild' => array( 'PhragmentDAO', 'PhabricatorPolicyInterface', ), 'PhragmentSnapshotChildQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentSnapshotCreateController' => 'PhragmentController', 'PhragmentSnapshotDeleteController' => 'PhragmentController', + 'PhragmentSnapshotPHIDType' => 'PhabricatorPHIDType', 'PhragmentSnapshotPromoteController' => 'PhragmentController', 'PhragmentSnapshotQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhragmentSnapshotViewController' => 'PhragmentController', 'PhragmentUpdateController' => 'PhragmentController', 'PhragmentVersionController' => 'PhragmentController', 'PhragmentZIPController' => 'PhragmentController', 'PhrequentController' => 'PhabricatorController', 'PhrequentDAO' => 'PhabricatorLiskDAO', 'PhrequentListController' => 'PhrequentController', 'PhrequentSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhrequentTimeBlock' => 'Phobject', 'PhrequentTimeBlockTestCase' => 'PhabricatorTestCase', 'PhrequentTimeSlices' => 'Phobject', 'PhrequentTrackController' => 'PhrequentController', 'PhrequentTrackingEditor' => 'PhabricatorEditor', 'PhrequentUIEventListener' => 'PhabricatorEventListener', 'PhrequentUserTime' => array( 'PhrequentDAO', 'PhabricatorPolicyInterface', ), 'PhrequentUserTimeQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionActionConstants' => 'PhrictionConstants', 'PhrictionActionMenuEventListener' => 'PhabricatorEventListener', 'PhrictionChangeType' => 'PhrictionConstants', 'PhrictionContent' => array( 'PhrictionDAO', 'PhabricatorMarkupInterface', ), 'PhrictionController' => 'PhabricatorController', 'PhrictionDAO' => 'PhabricatorLiskDAO', 'PhrictionDeleteController' => 'PhrictionController', 'PhrictionDiffController' => 'PhrictionController', 'PhrictionDocument' => array( 'PhrictionDAO', 'PhabricatorPolicyInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorDestructibleInterface', ), 'PhrictionDocumentController' => 'PhrictionController', 'PhrictionDocumentEditor' => 'PhabricatorEditor', + 'PhrictionDocumentPHIDType' => 'PhabricatorPHIDType', 'PhrictionDocumentPreviewController' => 'PhrictionController', 'PhrictionDocumentQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PhrictionDocumentStatus' => 'PhrictionConstants', 'PhrictionDocumentTestCase' => 'PhabricatorTestCase', 'PhrictionEditController' => 'PhrictionController', 'PhrictionHistoryController' => 'PhrictionController', 'PhrictionListController' => 'PhrictionController', 'PhrictionMoveController' => 'PhrictionController', 'PhrictionNewController' => 'PhrictionController', - 'PhrictionPHIDTypeDocument' => 'PhabricatorPHIDType', 'PhrictionRemarkupRule' => 'PhutilRemarkupRule', 'PhrictionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PhrictionSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PonderAddAnswerView' => 'AphrontView', 'PonderAnswer' => array( 'PonderDAO', 'PhabricatorMarkupInterface', 'PonderVotableInterface', 'PhabricatorPolicyInterface', 'PhabricatorFlaggableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorTokenReceiverInterface', ), 'PonderAnswerCommentController' => 'PonderController', 'PonderAnswerEditController' => 'PonderController', 'PonderAnswerEditor' => 'PonderEditor', 'PonderAnswerHistoryController' => 'PonderController', + 'PonderAnswerPHIDType' => 'PhabricatorPHIDType', 'PonderAnswerQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderAnswerSaveController' => 'PonderController', 'PonderAnswerTransaction' => 'PhabricatorApplicationTransaction', 'PonderAnswerTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderAnswerTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PonderComment' => array( 'PonderDAO', 'PhabricatorMarkupInterface', ), 'PonderCommentQuery' => 'PhabricatorQuery', 'PonderController' => 'PhabricatorController', 'PonderDAO' => 'PhabricatorLiskDAO', 'PonderEditor' => 'PhabricatorApplicationTransactionEditor', - 'PonderPHIDTypeAnswer' => 'PhabricatorPHIDType', - 'PonderPHIDTypeQuestion' => 'PhabricatorPHIDType', 'PonderQuestion' => array( 'PonderDAO', 'PhabricatorMarkupInterface', 'PonderVotableInterface', 'PhabricatorSubscribableInterface', 'PhabricatorFlaggableInterface', 'PhabricatorPolicyInterface', 'PhabricatorTokenReceiverInterface', 'PhabricatorProjectInterface', ), 'PonderQuestionCommentController' => 'PonderController', 'PonderQuestionEditController' => 'PonderController', 'PonderQuestionEditor' => 'PonderEditor', 'PonderQuestionHistoryController' => 'PonderController', 'PonderQuestionListController' => 'PonderController', 'PonderQuestionMailReceiver' => 'PhabricatorObjectMailReceiver', + 'PonderQuestionPHIDType' => 'PhabricatorPHIDType', 'PonderQuestionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'PonderQuestionReplyHandler' => 'PhabricatorMailReplyHandler', 'PonderQuestionSearchEngine' => 'PhabricatorApplicationSearchEngine', 'PonderQuestionStatus' => 'PonderConstants', 'PonderQuestionStatusController' => 'PonderController', 'PonderQuestionTransaction' => 'PhabricatorApplicationTransaction', 'PonderQuestionTransactionComment' => 'PhabricatorApplicationTransactionComment', 'PonderQuestionTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'PonderQuestionViewController' => 'PonderController', 'PonderRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'PonderSearchIndexer' => 'PhabricatorSearchDocumentIndexer', 'PonderTransactionFeedStory' => 'PhabricatorApplicationTransactionFeedStory', 'PonderVotableView' => 'AphrontView', 'PonderVote' => 'PonderConstants', 'PonderVoteEditor' => 'PhabricatorEditor', 'PonderVoteSaveController' => 'PonderController', 'ProjectCapabilityCreateProjects' => 'PhabricatorPolicyCapability', 'ProjectRemarkupRule' => 'PhabricatorRemarkupRuleObject', 'QueryFormattingTestCase' => 'PhabricatorTestCase', 'ReleephAuthorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranch' => array( 'ReleephDAO', 'PhabricatorPolicyInterface', ), 'ReleephBranchAccessController' => 'ReleephBranchController', 'ReleephBranchCommitFieldSpecification' => 'ReleephFieldSpecification', 'ReleephBranchController' => 'ReleephController', 'ReleephBranchCreateController' => 'ReleephProductController', 'ReleephBranchEditController' => 'ReleephBranchController', 'ReleephBranchEditor' => 'PhabricatorEditor', 'ReleephBranchHistoryController' => 'ReleephBranchController', 'ReleephBranchNamePreviewController' => 'ReleephController', + 'ReleephBranchPHIDType' => 'PhabricatorPHIDType', 'ReleephBranchPreviewView' => 'AphrontFormControl', 'ReleephBranchQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephBranchSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephBranchTransaction' => 'PhabricatorApplicationTransaction', 'ReleephBranchTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephBranchViewController' => array( 'ReleephBranchController', 'PhabricatorApplicationSearchResultsControllerInterface', ), 'ReleephCommitFinderException' => 'Exception', 'ReleephCommitMessageFieldSpecification' => 'ReleephFieldSpecification', 'ReleephController' => 'PhabricatorController', 'ReleephDAO' => 'PhabricatorLiskDAO', 'ReleephDefaultFieldSelector' => 'ReleephFieldSelector', 'ReleephDependsOnFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffChurnFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffMessageFieldSpecification' => 'ReleephFieldSpecification', 'ReleephDiffSizeFieldSpecification' => 'ReleephFieldSpecification', 'ReleephFieldParseException' => 'Exception', 'ReleephFieldSpecification' => array( 'PhabricatorCustomField', 'PhabricatorMarkupInterface', ), 'ReleephIntentFieldSpecification' => 'ReleephFieldSpecification', 'ReleephLevelFieldSpecification' => 'ReleephFieldSpecification', 'ReleephOriginalCommitFieldSpecification' => 'ReleephFieldSpecification', - 'ReleephPHIDTypeBranch' => 'PhabricatorPHIDType', - 'ReleephPHIDTypeProduct' => 'PhabricatorPHIDType', - 'ReleephPHIDTypeRequest' => 'PhabricatorPHIDType', 'ReleephProductActionController' => 'ReleephProductController', 'ReleephProductController' => 'ReleephController', 'ReleephProductCreateController' => 'ReleephProductController', 'ReleephProductEditController' => 'ReleephProductController', 'ReleephProductEditor' => 'PhabricatorApplicationTransactionEditor', 'ReleephProductHistoryController' => 'ReleephProductController', 'ReleephProductListController' => 'ReleephController', + 'ReleephProductPHIDType' => 'PhabricatorPHIDType', 'ReleephProductQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephProductSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephProductTransaction' => 'PhabricatorApplicationTransaction', 'ReleephProductTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephProductViewController' => array( 'ReleephProductController', 'PhabricatorApplicationSearchResultsControllerInterface', ), 'ReleephProject' => array( 'ReleephDAO', 'PhabricatorPolicyInterface', ), 'ReleephReasonFieldSpecification' => 'ReleephFieldSpecification', 'ReleephRequest' => array( 'ReleephDAO', 'PhabricatorPolicyInterface', 'PhabricatorCustomFieldInterface', ), 'ReleephRequestActionController' => 'ReleephRequestController', 'ReleephRequestCommentController' => 'ReleephRequestController', 'ReleephRequestController' => 'ReleephController', 'ReleephRequestDifferentialCreateController' => 'ReleephController', 'ReleephRequestEditController' => 'ReleephBranchController', 'ReleephRequestMailReceiver' => 'PhabricatorObjectMailReceiver', + 'ReleephRequestPHIDType' => 'PhabricatorPHIDType', 'ReleephRequestQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 'ReleephRequestReplyHandler' => 'PhabricatorMailReplyHandler', 'ReleephRequestSearchEngine' => 'PhabricatorApplicationSearchEngine', 'ReleephRequestTransaction' => 'PhabricatorApplicationTransaction', 'ReleephRequestTransactionComment' => 'PhabricatorApplicationTransactionComment', 'ReleephRequestTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 'ReleephRequestTransactionalEditor' => 'PhabricatorApplicationTransactionEditor', 'ReleephRequestTypeaheadControl' => 'AphrontFormControl', 'ReleephRequestTypeaheadController' => 'PhabricatorTypeaheadDatasourceController', 'ReleephRequestView' => 'AphrontView', 'ReleephRequestViewController' => 'ReleephBranchController', 'ReleephRequestorFieldSpecification' => 'ReleephFieldSpecification', 'ReleephRevisionFieldSpecification' => 'ReleephFieldSpecification', 'ReleephSeverityFieldSpecification' => 'ReleephLevelFieldSpecification', 'ReleephSummaryFieldSpecification' => 'ReleephFieldSpecification', 'ShellLogView' => 'AphrontView', 'SlowvoteEmbedView' => 'AphrontView', 'SlowvoteRemarkupRule' => 'PhabricatorRemarkupRuleObject', ), )); diff --git a/src/applications/auth/phid/PhabricatorAuthPHIDTypeAuthFactor.php b/src/applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php similarity index 91% rename from src/applications/auth/phid/PhabricatorAuthPHIDTypeAuthFactor.php rename to src/applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php index 58d239a7e..7de68cda6 100644 --- a/src/applications/auth/phid/PhabricatorAuthPHIDTypeAuthFactor.php +++ b/src/applications/auth/phid/PhabricatorAuthAuthFactorPHIDType.php @@ -1,35 +1,35 @@ $handle) { $factor = $objects[$phid]; $handle->setName($factor->getFactorName()); } } } diff --git a/src/applications/auth/storage/PhabricatorAuthFactorConfig.php b/src/applications/auth/storage/PhabricatorAuthFactorConfig.php index 6e22a10e0..2ea6d2754 100644 --- a/src/applications/auth/storage/PhabricatorAuthFactorConfig.php +++ b/src/applications/auth/storage/PhabricatorAuthFactorConfig.php @@ -1,42 +1,42 @@ array( 'properties' => self::SERIALIZATION_JSON, ), self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorAuthPHIDTypeAuthFactor::TYPECONST); + PhabricatorAuthAuthFactorPHIDType::TYPECONST); } public function getImplementation() { return idx(PhabricatorAuthFactor::getAllFactors(), $this->getFactorKey()); } public function requireImplementation() { $impl = $this->getImplementation(); if (!$impl) { throw new Exception( pht( 'Attempting to operate on multi-factor auth which has no '. 'corresponding implementation (factor key is "%s").', $this->getFactorKey())); } return $impl; } } diff --git a/src/applications/calendar/phid/PhabricatorCalendarPHIDTypeEvent.php b/src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php similarity index 91% rename from src/applications/calendar/phid/PhabricatorCalendarPHIDTypeEvent.php rename to src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php index a87eafba2..29486e95e 100644 --- a/src/applications/calendar/phid/PhabricatorCalendarPHIDTypeEvent.php +++ b/src/applications/calendar/phid/PhabricatorCalendarEventPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $event = $objects[$phid]; $id = $event->getID(); $handle->setName(pht('Event %d', $id)); } } } diff --git a/src/applications/calendar/storage/PhabricatorCalendarEvent.php b/src/applications/calendar/storage/PhabricatorCalendarEvent.php index 3f1a51a34..00eff6155 100644 --- a/src/applications/calendar/storage/PhabricatorCalendarEvent.php +++ b/src/applications/calendar/storage/PhabricatorCalendarEvent.php @@ -1,115 +1,115 @@ 'away', self::STATUS_SPORADIC => 'sporadic', ); public function getTextStatus() { return self::$statusTexts[$this->status]; } public function getStatusOptions() { return array( self::STATUS_AWAY => pht('Away'), self::STATUS_SPORADIC => pht('Sporadic'), ); } public function getHumanStatus() { $options = $this->getStatusOptions(); return $options[$this->status]; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorCalendarPHIDTypeEvent::TYPECONST); + PhabricatorCalendarEventPHIDType::TYPECONST); } public function getTerseSummary(PhabricatorUser $viewer) { $until = phabricator_date($this->dateTo, $viewer); if ($this->status == PhabricatorCalendarEvent::STATUS_SPORADIC) { return pht('Sporadic until %s', $until); } else { return pht('Away until %s', $until); } } public function setTextStatus($status) { $statuses = array_flip(self::$statusTexts); return $this->setStatus($statuses[$status]); } public function loadCurrentStatuses($user_phids) { if (!$user_phids) { return array(); } $statuses = $this->loadAllWhere( 'userPHID IN (%Ls) AND UNIX_TIMESTAMP() BETWEEN dateFrom AND dateTo', $user_phids); return mpull($statuses, null, 'getUserPHID'); } /** * Validates data and throws exceptions for non-sensical status * windows */ public function save() { if ($this->getDateTo() <= $this->getDateFrom()) { throw new PhabricatorCalendarEventInvalidEpochException(); } return parent::save(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::getMostOpenPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getUserPHID(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/config/phid/PhabricatorConfigPHIDTypeConfig.php b/src/applications/config/phid/PhabricatorConfigConfigPHIDType.php similarity index 91% rename from src/applications/config/phid/PhabricatorConfigPHIDTypeConfig.php rename to src/applications/config/phid/PhabricatorConfigConfigPHIDType.php index 793b63955..161b1e42f 100644 --- a/src/applications/config/phid/PhabricatorConfigPHIDTypeConfig.php +++ b/src/applications/config/phid/PhabricatorConfigConfigPHIDType.php @@ -1,38 +1,38 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $entry = $objects[$phid]; $key = $entry->getConfigKey(); $handle->setName($key); $handle->setURI("/config/edit/{$key}/"); } } } diff --git a/src/applications/config/storage/PhabricatorConfigEntry.php b/src/applications/config/storage/PhabricatorConfigEntry.php index 6401b0fd6..d2e16611b 100644 --- a/src/applications/config/storage/PhabricatorConfigEntry.php +++ b/src/applications/config/storage/PhabricatorConfigEntry.php @@ -1,64 +1,64 @@ true, self::CONFIG_SERIALIZATION => array( 'value' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorConfigPHIDTypeConfig::TYPECONST); + PhabricatorConfigConfigPHIDType::TYPECONST); } public static function loadConfigEntry($key) { $config_entry = id(new PhabricatorConfigEntry()) ->loadOneWhere( 'configKey = %s AND namespace = %s', $key, 'default'); if (!$config_entry) { $config_entry = id(new PhabricatorConfigEntry()) ->setConfigKey($key) ->setNamespace('default'); } return $config_entry; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return PhabricatorPolicies::POLICY_ADMIN; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/config/storage/PhabricatorConfigTransaction.php b/src/applications/config/storage/PhabricatorConfigTransaction.php index ccabf44d8..acfafeb10 100644 --- a/src/applications/config/storage/PhabricatorConfigTransaction.php +++ b/src/applications/config/storage/PhabricatorConfigTransaction.php @@ -1,118 +1,118 @@ getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_EDIT: // TODO: After T2213 show the actual values too; for now, we don't // have the tools to do it without making a bit of a mess of it. $old_del = idx($old, 'deleted'); $new_del = idx($new, 'deleted'); if ($old_del && !$new_del) { return pht( '%s created this configuration entry.', $this->renderHandleLink($author_phid)); } else if (!$old_del && $new_del) { return pht( '%s deleted this configuration entry.', $this->renderHandleLink($author_phid)); } else if ($old_del && $new_del) { // This is a bug. return pht( '%s deleted this configuration entry (again?).', $this->renderHandleLink($author_phid)); } else { return pht( '%s edited this configuration entry.', $this->renderHandleLink($author_phid)); } break; } return parent::getTitle(); } public function getIcon() { switch ($this->getTransactionType()) { case self::TYPE_EDIT: return 'fa-pencil'; } return parent::getIcon(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_EDIT: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { $old = $this->getOldValue(); $new = $this->getNewValue(); if ($old['deleted']) { $old_text = ''; } else { $old_text = PhabricatorConfigJSON::prettyPrintJSON($old['value']); } if ($new['deleted']) { $new_text = ''; } else { $new_text = PhabricatorConfigJSON::prettyPrintJSON($new['value']); } return $this->renderTextCorpusChangeDetails( $viewer, $old_text, $new_text); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_EDIT: $old_del = idx($old, 'deleted'); $new_del = idx($new, 'deleted'); if ($old_del && !$new_del) { return PhabricatorTransactions::COLOR_GREEN; } else if (!$old_del && $new_del) { return PhabricatorTransactions::COLOR_RED; } else { return PhabricatorTransactions::COLOR_BLUE; } break; } } } diff --git a/src/applications/conpherence/phid/PhabricatorConpherencePHIDTypeThread.php b/src/applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php similarity index 92% rename from src/applications/conpherence/phid/PhabricatorConpherencePHIDTypeThread.php rename to src/applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php index d644774b5..0577956bb 100644 --- a/src/applications/conpherence/phid/PhabricatorConpherencePHIDTypeThread.php +++ b/src/applications/conpherence/phid/PhabricatorConpherenceThreadPHIDType.php @@ -1,40 +1,40 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $thread = $objects[$phid]; $name = $thread->getTitle(); if (!strlen($name)) { $name = pht('[No Title]'); } $handle->setName($name); $handle->setFullName($name); $handle->setURI('/conpherence/'.$thread->getID().'/'); } } } diff --git a/src/applications/conpherence/storage/ConpherenceThread.php b/src/applications/conpherence/storage/ConpherenceThread.php index 93b8c4f94..9f249d684 100644 --- a/src/applications/conpherence/storage/ConpherenceThread.php +++ b/src/applications/conpherence/storage/ConpherenceThread.php @@ -1,197 +1,197 @@ setMessageCount(0) ->setTitle(''); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'recentParticipantPHIDs' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorConpherencePHIDTypeThread::TYPECONST); + PhabricatorConpherenceThreadPHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function attachParticipants(array $participants) { assert_instances_of($participants, 'ConpherenceParticipant'); $this->participants = $participants; return $this; } public function getParticipants() { return $this->assertAttached($this->participants); } public function getParticipant($phid) { $participants = $this->getParticipants(); return $participants[$phid]; } public function getParticipantPHIDs() { $participants = $this->getParticipants(); return array_keys($participants); } public function attachHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } public function getHandles() { return $this->assertAttached($this->handles); } public function attachTransactions(array $transactions) { assert_instances_of($transactions, 'ConpherenceTransaction'); $this->transactions = $transactions; return $this; } public function getTransactions() { return $this->assertAttached($this->transactions); } public function getTransactionsFrom($begin = 0, $amount = null) { $length = count($this->transactions); return array_slice( $this->getTransactions(), $length - $begin - $amount, $amount); } public function attachFilePHIDs(array $file_phids) { $this->filePHIDs = $file_phids; return $this; } public function getFilePHIDs() { return $this->assertAttached($this->filePHIDs); } public function attachWidgetData(array $widget_data) { $this->widgetData = $widget_data; return $this; } public function getWidgetData() { return $this->assertAttached($this->widgetData); } public function getDisplayData(PhabricatorUser $user) { $recent_phids = $this->getRecentParticipantPHIDs(); $handles = $this->getHandles(); // luck has little to do with it really; most recent participant who isn't // the user.... $lucky_phid = null; $lucky_index = null; foreach ($recent_phids as $index => $phid) { if ($phid == $user->getPHID()) { continue; } $lucky_phid = $phid; break; } reset($recent_phids); if ($lucky_phid) { $lucky_handle = $handles[$lucky_phid]; // this will be just the user talking to themselves. weirdos. } else { $lucky_handle = reset($handles); } $title = $js_title = $this->getTitle(); if (!$title) { $title = $lucky_handle->getName(); $js_title = pht('[No Title]'); } $img_src = $lucky_handle->getImageURI(); $count = 0; $final = false; $subtitle = null; foreach ($recent_phids as $phid) { if ($phid == $user->getPHID()) { continue; } $handle = $handles[$phid]; if ($subtitle) { if ($final) { $subtitle .= '...'; break; } else { $subtitle .= ', '; } } $subtitle .= $handle->getName(); $count++; $final = $count == 3; } $participants = $this->getParticipants(); $user_participation = $participants[$user->getPHID()]; $unread_count = $this->getMessageCount() - $user_participation->getSeenMessageCount(); return array( 'title' => $title, 'js_title' => $js_title, 'subtitle' => $subtitle, 'unread_count' => $unread_count, 'epoch' => $this->getDateModified(), 'image' => $img_src, ); } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return PhabricatorPolicies::POLICY_NOONE; } public function hasAutomaticCapability($capability, PhabricatorUser $user) { // this bad boy isn't even created yet so go nuts $user if (!$this->getID()) { return true; } $participants = $this->getParticipants(); return isset($participants[$user->getPHID()]); } public function describeAutomaticCapability($capability) { return pht('Participants in a thread can always view and edit it.'); } } diff --git a/src/applications/conpherence/storage/ConpherenceTransaction.php b/src/applications/conpherence/storage/ConpherenceTransaction.php index 69f7d1a05..a27b7ce35 100644 --- a/src/applications/conpherence/storage/ConpherenceTransaction.php +++ b/src/applications/conpherence/storage/ConpherenceTransaction.php @@ -1,150 +1,150 @@ getTransactionType()) { case ConpherenceTransactionType::TYPE_PARTICIPANTS: return pht( 'You can not add a participant who has already been added.'); break; } return parent::getNoEffectDescription(); } public function shouldHide() { $old = $this->getOldValue(); switch ($this->getTransactionType()) { case ConpherenceTransactionType::TYPE_PARTICIPANTS: return ($old === null); case ConpherenceTransactionType::TYPE_TITLE: case ConpherenceTransactionType::TYPE_DATE_MARKER: return false; case ConpherenceTransactionType::TYPE_FILES: return true; // we used to have them so just always hide case ConpherenceTransactionType::TYPE_PICTURE: case ConpherenceTransactionType::TYPE_PICTURE_CROP: return true; } return parent::shouldHide(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case ConpherenceTransactionType::TYPE_TITLE: if ($old && $new) { $title = pht( '%s renamed this conpherence from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } else if ($old) { $title = pht( '%s deleted the conpherence name "%s".', $this->renderHandleLink($author_phid), $old); } else { $title = pht( '%s named this conpherence "%s".', $this->renderHandleLink($author_phid), $new); } return $title; case ConpherenceTransactionType::TYPE_FILES: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { $title = pht( '%s edited files(s), added %d and removed %d.', $this->renderHandleLink($author_phid), count($add), count($rem)); } else if ($add) { $title = pht( '%s added %d files(s).', $this->renderHandleLink($author_phid), count($add)); } else { $title = pht( '%s removed %d file(s).', $this->renderHandleLink($author_phid), count($rem)); } return $title; break; case ConpherenceTransactionType::TYPE_PARTICIPANTS: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { $title = pht( '%s edited participant(s), added %d: %s; removed %d: %s.', $this->renderHandleLink($author_phid), count($add), $this->renderHandleList($add), count($rem), $this->renderHandleList($rem)); } else if ($add) { $title = pht( '%s added %d participant(s): %s.', $this->renderHandleLink($author_phid), count($add), $this->renderHandleList($add)); } else { $title = pht( '%s removed %d participant(s): %s.', $this->renderHandleLink($author_phid), count($rem), $this->renderHandleList($rem)); } return $title; break; } return parent::getTitle(); } public function getRequiredHandlePHIDs() { $phids = parent::getRequiredHandlePHIDs(); $old = $this->getOldValue(); $new = $this->getNewValue(); $phids[] = $this->getAuthorPHID(); switch ($this->getTransactionType()) { case ConpherenceTransactionType::TYPE_TITLE: case ConpherenceTransactionType::TYPE_FILES: case ConpherenceTransactionType::TYPE_DATE_MARKER: break; case ConpherenceTransactionType::TYPE_PARTICIPANTS: $phids = array_merge($phids, $this->getOldValue()); $phids = array_merge($phids, $this->getNewValue()); break; } return $phids; } } diff --git a/src/applications/countdown/phid/PhabricatorCountdownPHIDTypeCountdown.php b/src/applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php similarity index 95% rename from src/applications/countdown/phid/PhabricatorCountdownPHIDTypeCountdown.php rename to src/applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php index b859f80d5..852c5889e 100644 --- a/src/applications/countdown/phid/PhabricatorCountdownPHIDTypeCountdown.php +++ b/src/applications/countdown/phid/PhabricatorCountdownCountdownPHIDType.php @@ -1,69 +1,69 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $countdown = $objects[$phid]; $name = $countdown->getTitle(); $id = $countdown->getID(); $handle->setName("C{$id}"); $handle->setFullName("C{$id}: {$name}"); $handle->setURI("/countdown/{$id}/"); } } public function canLoadNamedObject($name) { return preg_match('/^C\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PhabricatorCountdownQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/countdown/storage/PhabricatorCountdown.php b/src/applications/countdown/storage/PhabricatorCountdown.php index 870a40b01..f1903d95c 100644 --- a/src/applications/countdown/storage/PhabricatorCountdown.php +++ b/src/applications/countdown/storage/PhabricatorCountdown.php @@ -1,66 +1,66 @@ setViewer($actor) ->withClasses(array('PhabricatorCountdownApplication')) ->executeOne(); $view_policy = $app->getPolicy( PhabricatorCountdownCapabilityDefaultView::CAPABILITY); return id(new PhabricatorCountdown()) ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) ->setEpoch(PhabricatorTime::getNow()); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorCountdownPHIDTypeCountdown::TYPECONST); + PhabricatorCountdownCountdownPHIDType::TYPECONST); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { return pht('The author of a countdown can always view and edit it.'); } } diff --git a/src/applications/dashboard/phid/PhabricatorDashboardPHIDTypeDashboard.php b/src/applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php similarity index 91% rename from src/applications/dashboard/phid/PhabricatorDashboardPHIDTypeDashboard.php rename to src/applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php index 67a27a892..e097dc161 100644 --- a/src/applications/dashboard/phid/PhabricatorDashboardPHIDTypeDashboard.php +++ b/src/applications/dashboard/phid/PhabricatorDashboardDashboardPHIDType.php @@ -1,38 +1,38 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $dashboard = $objects[$phid]; $id = $dashboard->getID(); $handle->setName($dashboard->getName()); $handle->setURI("/dashboard/view/{$id}/"); } } } diff --git a/src/applications/dashboard/phid/PhabricatorDashboardPHIDTypePanel.php b/src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php similarity index 96% rename from src/applications/dashboard/phid/PhabricatorDashboardPHIDTypePanel.php rename to src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php index ec552a242..725945f40 100644 --- a/src/applications/dashboard/phid/PhabricatorDashboardPHIDTypePanel.php +++ b/src/applications/dashboard/phid/PhabricatorDashboardPanelPHIDType.php @@ -1,73 +1,73 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $panel = $objects[$phid]; $name = $panel->getName(); $monogram = $panel->getMonogram(); $handle->setName($panel->getMonogram()); $handle->setFullName("{$monogram} {$name}"); $handle->setURI("/{$monogram}"); if ($panel->getIsArchived()) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } public function canLoadNamedObject($name) { return preg_match('/^W\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PhabricatorDashboardPanelQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboard.php b/src/applications/dashboard/storage/PhabricatorDashboard.php index ef4955df2..1d81a0b1e 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboard.php +++ b/src/applications/dashboard/storage/PhabricatorDashboard.php @@ -1,107 +1,107 @@ setName('') ->setViewPolicy(PhabricatorPolicies::POLICY_USER) ->setEditPolicy($actor->getPHID()) ->attachPanels(array()) ->attachPanelPHIDs(array()); } public static function copyDashboard( PhabricatorDashboard $dst, PhabricatorDashboard $src) { $dst->name = $src->name; $dst->layoutConfig = $src->layoutConfig; return $dst; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'layoutConfig' => self::SERIALIZATION_JSON), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorDashboardPHIDTypeDashboard::TYPECONST); + PhabricatorDashboardDashboardPHIDType::TYPECONST); } public function getLayoutConfigObject() { return PhabricatorDashboardLayoutConfig::newFromDictionary( $this->getLayoutConfig()); } public function setLayoutConfigFromObject( PhabricatorDashboardLayoutConfig $object) { $this->setLayoutConfig($object->toDictionary()); return $this; } public function attachPanelPHIDs(array $phids) { $this->panelPHIDs = $phids; return $this; } public function getPanelPHIDs() { return $this->assertAttached($this->panelPHIDs); } public function attachPanels(array $panels) { assert_instances_of($panels, 'PhabricatorDashboardPanel'); $this->panels = $panels; return $this; } public function getPanels() { return $this->assertAttached($this->panels); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php index 158a637d2..8b7467bd3 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardPanel.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanel.php @@ -1,134 +1,134 @@ setName('') ->setViewPolicy(PhabricatorPolicies::POLICY_USER) ->setEditPolicy($actor->getPHID()); } public static function copyPanel( PhabricatorDashboardPanel $dst, PhabricatorDashboardPanel $src) { $dst->name = $src->name; $dst->panelType = $src->panelType; $dst->properties = $src->properties; return $dst; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'properties' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorDashboardPHIDTypePanel::TYPECONST); + PhabricatorDashboardPanelPHIDType::TYPECONST); } public function getProperty($key, $default = null) { return idx($this->properties, $key, $default); } public function setProperty($key, $value) { $this->properties[$key] = $value; return $this; } public function getMonogram() { return 'W'.$this->getID(); } public function getImplementation() { return idx( PhabricatorDashboardPanelType::getAllPanelTypes(), $this->getPanelType()); } public function requireImplementation() { $impl = $this->getImplementation(); if (!$impl) { throw new Exception( pht( 'Attempting to use a panel in a way that requires an '. 'implementation, but the panel implementation ("%s") is unknown to '. 'Phabricator.', $this->getPanelType())); } return $impl; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return array(); } public function getCustomFieldBaseClass() { return 'PhabricatorDashboardPanelCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php b/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php index 9e0bcd338..828b0fdc7 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardPanelTransaction.php @@ -1,112 +1,112 @@ getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $author_link = $this->renderHandleLink($author_phid); $type = $this->getTransactionType(); switch ($type) { case self::TYPE_NAME: if (!strlen($old)) { return pht( '%s created this panel.', $author_link); } else { return pht( '%s renamed this panel from "%s" to "%s".', $author_link, $old, $new); } case self::TYPE_ARCHIVE: if ($new) { return pht( '%s archived this panel.', $author_link); } else { return pht( '%s activated this panel.', $author_link); } } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $author_link = $this->renderHandleLink($author_phid); $object_link = $this->renderHandleLink($object_phid); $type = $this->getTransactionType(); switch ($type) { case self::TYPE_NAME: if (!strlen($old)) { return pht( '%s created dashboard panel %s.', $author_link, $object_link); } else { return pht( '%s renamed dashboard panel %s from "%s" to "%s".', $author_link, $object_link, $old, $new); } case self::TYPE_ARCHIVE: if ($new) { return pht( '%s archived dashboard panel %s.', $author_link, $object_link); } else { return pht( '%s activated dashboard panel %s.', $author_link, $object_link); } } return parent::getTitleForFeed($story); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_NAME: if (!strlen($old)) { return PhabricatorTransactions::COLOR_GREEN; } break; } return parent::getColor(); } } diff --git a/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php b/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php index 5ab0f4b68..9b3f04bd2 100644 --- a/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php +++ b/src/applications/dashboard/storage/PhabricatorDashboardTransaction.php @@ -1,101 +1,101 @@ getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $author_link = $this->renderHandleLink($author_phid); $type = $this->getTransactionType(); switch ($type) { case self::TYPE_NAME: if (!strlen($old)) { return pht( '%s created this dashboard.', $author_link); } else { return pht( '%s renamed this dashboard from "%s" to "%s".', $author_link, $old, $new); } } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $author_link = $this->renderHandleLink($author_phid); $object_link = $this->renderHandleLink($object_phid); $type = $this->getTransactionType(); switch ($type) { case self::TYPE_NAME: if (!strlen($old)) { return pht( '%s created dashboard %s.', $author_link, $object_link); } else { return pht( '%s renamed dashboard %s from "%s" to "%s".', $author_link, $object_link, $old, $new); } } return parent::getTitleForFeed($story); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_NAME: if (!strlen($old)) { return PhabricatorTransactions::COLOR_GREEN; } break; } return parent::getColor(); } public function shouldHide() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_LAYOUT_MODE: return true; } return parent::shouldHide(); } } diff --git a/src/applications/differential/customfield/DifferentialAuditorsField.php b/src/applications/differential/customfield/DifferentialAuditorsField.php index 1e8207518..d84fe0eda 100644 --- a/src/applications/differential/customfield/DifferentialAuditorsField.php +++ b/src/applications/differential/customfield/DifferentialAuditorsField.php @@ -1,61 +1,60 @@ getValue()); } public function setValueFromStorage($value) { try { $this->setValue(phutil_json_decode($value)); } catch (PhutilJSONParserException $ex) { $this->setValue(array()); } return $this; } public function shouldAppearInCommitMessage() { return true; } public function shouldAllowEditInCommitMessage() { return true; } public function canDisableField() { return false; } public function getRequiredHandlePHIDsForCommitMessage() { return nonempty($this->getValue(), array()); } public function parseCommitMessageValue($value) { return $this->parseObjectList( $value, array( - PhabricatorPeoplePHIDTypeUser::TYPECONST, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, )); } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } - } diff --git a/src/applications/differential/customfield/DifferentialManiphestTasksField.php b/src/applications/differential/customfield/DifferentialManiphestTasksField.php index fbf05c708..0f34c12ab 100644 --- a/src/applications/differential/customfield/DifferentialManiphestTasksField.php +++ b/src/applications/differential/customfield/DifferentialManiphestTasksField.php @@ -1,114 +1,114 @@ getFieldName(); } public function readValueFromRevision(DifferentialRevision $revision) { if (!$revision->getPHID()) { return array(); } return PhabricatorEdgeQuery::loadDestinationPHIDs( $revision->getPHID(), DifferentialRevisionHasTaskEdgeType::EDGECONST); } public function getApplicationTransactionType() { return PhabricatorTransactions::TYPE_EDGE; } public function getApplicationTransactionMetadata() { return array( 'edge:type' => DifferentialRevisionHasTaskEdgeType::EDGECONST, ); } public function getNewValueForApplicationTransactions() { $edges = array(); foreach ($this->getValue() as $phid) { $edges[$phid] = $phid; } return array('=' => $edges); } public function getRequiredHandlePHIDsForPropertyView() { return $this->getValue(); } public function renderPropertyViewValue(array $handles) { return $this->renderHandleList($handles); } public function shouldAppearInCommitMessage() { return true; } public function shouldAllowEditInCommitMessage() { return true; } public function getCommitMessageLabels() { return array( 'Maniphest Task', 'Maniphest Tasks', ); } public function parseValueFromCommitMessage($value) { return $this->parseObjectList( $value, array( - ManiphestPHIDTypeTask::TYPECONST, + ManiphestTaskPHIDType::TYPECONST, )); } public function getRequiredHandlePHIDsForCommitMessage() { return $this->getRequiredHandlePHIDsForPropertyView(); } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } public function getProTips() { return array( pht( 'Write "Fixes T123" in your summary to automatically close the '. 'corresponding task when this change lands.'), ); } } diff --git a/src/applications/differential/customfield/DifferentialProjectsField.php b/src/applications/differential/customfield/DifferentialProjectsField.php index 72762bee6..ee50d1bd5 100644 --- a/src/applications/differential/customfield/DifferentialProjectsField.php +++ b/src/applications/differential/customfield/DifferentialProjectsField.php @@ -1,113 +1,113 @@ getPHID()) { return array(); } $projects = PhabricatorEdgeQuery::loadDestinationPHIDs( $revision->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); $projects = array_reverse($projects); return $projects; } public function getNewValueForApplicationTransactions() { return array('=' => array_fuse($this->getValue())); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getArr($this->getFieldKey())); } public function getRequiredHandlePHIDsForEdit() { return $this->getValue(); } public function renderEditControl(array $handles) { return id(new AphrontFormTokenizerControl()) ->setName($this->getFieldKey()) ->setDatasource(new PhabricatorProjectDatasource()) ->setValue($handles) ->setLabel($this->getFieldName()); } public function getApplicationTransactionType() { return PhabricatorTransactions::TYPE_EDGE; } public function shouldAppearInCommitMessage() { return true; } public function shouldAllowEditInCommitMessage() { return true; } public function shouldOverwriteWhenCommitMessageIsEdited() { return true; } public function getCommitMessageLabels() { return array( 'Project', 'Projects', ); } public function getRequiredHandlePHIDsForCommitMessage() { return $this->getValue(); } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } public function shouldAppearInConduitDictionary() { return true; } public function getApplicationTransactionMetadata() { return array( 'edge:type' => PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, ); } public function parseValueFromCommitMessage($value) { return $this->parseObjectList( $value, array( - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, )); } } diff --git a/src/applications/differential/customfield/DifferentialReviewedByField.php b/src/applications/differential/customfield/DifferentialReviewedByField.php index 1e4d49706..6f49c80fe 100644 --- a/src/applications/differential/customfield/DifferentialReviewedByField.php +++ b/src/applications/differential/customfield/DifferentialReviewedByField.php @@ -1,72 +1,72 @@ getReviewerStatus() as $reviewer) { switch ($reviewer->getStatus()) { case DifferentialReviewerStatus::STATUS_ACCEPTED: case DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER: $phids[] = $reviewer->getReviewerPHID(); break; } } return $phids; } public function shouldAppearInCommitMessage() { return true; } public function parseValueFromCommitMessage($value) { return $this->parseObjectList( $value, array( - PhabricatorPeoplePHIDTypeUser::TYPECONST, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, ), $allow_partial = true); } public function getRequiredHandlePHIDsForCommitMessage() { return $this->getValue(); } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } } diff --git a/src/applications/differential/customfield/DifferentialReviewersField.php b/src/applications/differential/customfield/DifferentialReviewersField.php index d3f24b7d3..2819a6401 100644 --- a/src/applications/differential/customfield/DifferentialReviewersField.php +++ b/src/applications/differential/customfield/DifferentialReviewersField.php @@ -1,225 +1,225 @@ getReviewerStatus(); } public function getNewValueForApplicationTransactions() { $specs = array(); foreach ($this->getValue() as $reviewer) { $specs[$reviewer->getReviewerPHID()] = array( 'data' => $reviewer->getEdgeData(), ); } return array('=' => $specs); } public function readValueFromRequest(AphrontRequest $request) { // Compute a new set of reviewer objects. For reviewers who haven't been // added or removed, retain their existing status. Also, respect the new // order. $old_status = $this->getValue(); $old_status = mpull($old_status, null, 'getReviewerPHID'); $new_phids = $request->getArr($this->getFieldKey()); $new_phids = array_fuse($new_phids); $new_status = array(); foreach ($new_phids as $new_phid) { if (empty($old_status[$new_phid])) { $new_status[$new_phid] = new DifferentialReviewer( $new_phid, array( 'status' => DifferentialReviewerStatus::STATUS_ADDED, )); } else { $new_status[$new_phid] = $old_status[$new_phid]; } } $this->setValue($new_status); } public function getRequiredHandlePHIDsForEdit() { return mpull($this->getValue(), 'getReviewerPHID'); } public function renderEditControl(array $handles) { return id(new AphrontFormTokenizerControl()) ->setName($this->getFieldKey()) ->setDatasource(new PhabricatorProjectOrUserDatasource()) ->setValue($handles) ->setError($this->getFieldError()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionType() { return PhabricatorTransactions::TYPE_EDGE; } public function getApplicationTransactionMetadata() { return array( 'edge:type' => PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER, ); } public function shouldAppearInPropertyView() { return true; } public function renderPropertyViewLabel() { return $this->getFieldName(); } public function getRequiredHandlePHIDsForPropertyView() { return mpull($this->getUserReviewers(), 'getReviewerPHID'); } public function renderPropertyViewValue(array $handles) { $reviewers = $this->getUserReviewers(); if (!$reviewers) { return phutil_tag('em', array(), pht('None')); } $view = id(new DifferentialReviewersView()) ->setUser($this->getViewer()) ->setReviewers($reviewers) ->setHandles($handles); // TODO: Active diff stuff. return $view; } private function getUserReviewers() { $reviewers = array(); foreach ($this->getObject()->getReviewerStatus() as $reviewer) { if ($reviewer->isUser()) { $reviewers[] = $reviewer; } } return $reviewers; } public function shouldAppearInCommitMessage() { return true; } public function shouldAppearInCommitMessageTemplate() { return true; } public function getCommitMessageLabels() { return array( 'Reviewer', 'Reviewers', ); } public function parseValueFromCommitMessage($value) { return $this->parseObjectList( $value, array( - PhabricatorPeoplePHIDTypeUser::TYPECONST, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, )); } public function getRequiredHandlePHIDsForCommitMessage() { return mpull($this->getValue(), 'getReviewerPHID'); } public function readValueFromCommitMessage($value) { $current_reviewers = $this->getObject()->getReviewerStatus(); $current_reviewers = mpull($current_reviewers, null, 'getReviewerPHID'); $reviewers = array(); foreach ($value as $phid) { $reviewer = idx($current_reviewers, $phid); if ($reviewer) { $reviewers[] = $reviewer; } else { $data = array( 'status' => DifferentialReviewerStatus::STATUS_ADDED, ); $reviewers[] = new DifferentialReviewer($phid, $data); } } $this->setValue($reviewers); return $this; } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } public function validateCommitMessageValue($value) { $author_phid = $this->getObject()->getAuthorPHID(); $config_self_accept_key = 'differential.allow-self-accept'; $allow_self_accept = PhabricatorEnv::getEnvConfig($config_self_accept_key); foreach ($value as $phid) { if (($phid == $author_phid) && !$allow_self_accept) { throw new DifferentialFieldValidationException( pht('The author of a revision can not be a reviewer.')); } } } public function getRequiredHandlePHIDsForRevisionHeaderWarnings() { return mpull($this->getValue(), 'getReviewerPHID'); } public function getWarningsForRevisionHeader(array $handles) { $revision = $this->getObject(); $status_needs_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; if ($revision->getStatus() != $status_needs_review) { return array(); } foreach ($this->getValue() as $reviewer) { if (!$handles[$reviewer->getReviewerPHID()]->isDisabled()) { return array(); } } $warnings = array(); if ($this->getValue()) { $warnings[] = pht( 'This revision needs review, but all specified reviewers are '. 'disabled or inactive.'); } else { $warnings[] = pht( 'This revision needs review, but there are no reviewers specified.'); } return $warnings; } } diff --git a/src/applications/differential/customfield/DifferentialSubscribersField.php b/src/applications/differential/customfield/DifferentialSubscribersField.php index eba9a6202..cb558fd02 100644 --- a/src/applications/differential/customfield/DifferentialSubscribersField.php +++ b/src/applications/differential/customfield/DifferentialSubscribersField.php @@ -1,96 +1,96 @@ getPHID()) { return array(); } return PhabricatorSubscribersQuery::loadSubscribersForPHID( $revision->getPHID()); } public function getNewValueForApplicationTransactions() { return array('=' => $this->getValue()); } public function readValueFromRequest(AphrontRequest $request) { $this->setValue($request->getArr($this->getFieldKey())); } public function getRequiredHandlePHIDsForEdit() { return $this->getValue(); } public function renderEditControl(array $handles) { return id(new AphrontFormTokenizerControl()) ->setName($this->getFieldKey()) ->setDatasource(new PhabricatorMetaMTAMailableDatasource()) ->setValue($handles) ->setError($this->getFieldError()) ->setLabel($this->getFieldName()); } public function getApplicationTransactionType() { return PhabricatorTransactions::TYPE_SUBSCRIBERS; } public function shouldAppearInCommitMessage() { return true; } public function shouldAllowEditInCommitMessage() { return true; } public function shouldAppearInCommitMessageTemplate() { return true; } public function getCommitMessageLabels() { return array( 'CC', 'CCs', 'Subscriber', 'Subscribers', ); } public function parseValueFromCommitMessage($value) { return $this->parseObjectList( $value, array( - PhabricatorPeoplePHIDTypeUser::TYPECONST, - PhabricatorProjectPHIDTypeProject::TYPECONST, - PhabricatorMailingListPHIDTypeList::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, + PhabricatorMailingListListPHIDType::TYPECONST, )); } public function getRequiredHandlePHIDsForCommitMessage() { return $this->getValue(); } public function renderCommitMessageValue(array $handles) { return $this->renderObjectList($handles); } } diff --git a/src/applications/differential/phid/DifferentialPHIDTypeDiff.php b/src/applications/differential/phid/DifferentialDiffPHIDType.php similarity index 91% rename from src/applications/differential/phid/DifferentialPHIDTypeDiff.php rename to src/applications/differential/phid/DifferentialDiffPHIDType.php index c5f6e44dc..887397d57 100644 --- a/src/applications/differential/phid/DifferentialPHIDTypeDiff.php +++ b/src/applications/differential/phid/DifferentialDiffPHIDType.php @@ -1,38 +1,38 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $diff = $objects[$phid]; $id = $diff->getID(); $handle->setName(pht('Diff %d', $id)); $handle->setURI("/differential/diff/{$id}/"); } } } diff --git a/src/applications/differential/phid/DifferentialPHIDTypeRevision.php b/src/applications/differential/phid/DifferentialRevisionPHIDType.php similarity index 96% rename from src/applications/differential/phid/DifferentialPHIDTypeRevision.php rename to src/applications/differential/phid/DifferentialRevisionPHIDType.php index 9e737f23d..0cc18afa9 100644 --- a/src/applications/differential/phid/DifferentialPHIDTypeRevision.php +++ b/src/applications/differential/phid/DifferentialRevisionPHIDType.php @@ -1,78 +1,78 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $revision = $objects[$phid]; $title = $revision->getTitle(); $id = $revision->getID(); $status = $revision->getStatus(); $handle->setName("D{$id}"); $handle->setURI("/D{$id}"); $handle->setFullName("D{$id}: {$title}"); if ($revision->isClosed()) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } public function canLoadNamedObject($name) { return preg_match('/^D\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new DifferentialRevisionQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/differential/query/DifferentialRevisionQuery.php b/src/applications/differential/query/DifferentialRevisionQuery.php index 4bc002ca2..55510e964 100644 --- a/src/applications/differential/query/DifferentialRevisionQuery.php +++ b/src/applications/differential/query/DifferentialRevisionQuery.php @@ -1,1169 +1,1169 @@ withStatus(DifferentialRevisionQuery::STATUS_OPEN) * ->execute(); * * @task config Query Configuration * @task exec Query Execution * @task internal Internals */ final class DifferentialRevisionQuery extends PhabricatorCursorPagedPolicyAwareQuery { private $pathIDs = array(); private $status = 'status-any'; const STATUS_ANY = 'status-any'; const STATUS_OPEN = 'status-open'; const STATUS_ACCEPTED = 'status-accepted'; const STATUS_NEEDS_REVIEW = 'status-needs-review'; const STATUS_NEEDS_REVISION = 'status-needs-revision'; const STATUS_CLOSED = 'status-closed'; const STATUS_ABANDONED = 'status-abandoned'; private $authors = array(); private $draftAuthors = array(); private $ccs = array(); private $reviewers = array(); private $revIDs = array(); private $commitHashes = array(); private $phids = array(); private $responsibles = array(); private $branches = array(); private $arcanistProjectPHIDs = array(); private $repositoryPHIDs; private $order = 'order-modified'; const ORDER_MODIFIED = 'order-modified'; const ORDER_CREATED = 'order-created'; /** * This is essentially a denormalized copy of the revision modified time that * should perform better for path queries with a LIMIT. Critically, when you * browse "/", every revision in that repository for all time will match so * the query benefits from being able to stop before fully materializing the * result set. */ const ORDER_PATH_MODIFIED = 'order-path-modified'; private $needRelationships = false; private $needActiveDiffs = false; private $needDiffIDs = false; private $needCommitPHIDs = false; private $needHashes = false; private $needReviewerStatus = false; private $needReviewerAuthority; private $needDrafts; private $needFlags; private $buildingGlobalOrder; /* -( Query Configuration )------------------------------------------------ */ /** * Filter results to revisions which affect a Diffusion path ID in a given * repository. You can call this multiple times to select revisions for * several paths. * * @param int Diffusion repository ID. * @param int Diffusion path ID. * @return this * @task config */ public function withPath($repository_id, $path_id) { $this->pathIDs[] = array( 'repositoryID' => $repository_id, 'pathID' => $path_id, ); return $this; } /** * Filter results to revisions authored by one of the given PHIDs. Calling * this function will clear anything set by previous calls to * @{method:withAuthors}. * * @param array List of PHIDs of authors * @return this * @task config */ public function withAuthors(array $author_phids) { $this->authors = $author_phids; return $this; } /** * Filter results to revisions with comments authored by the given PHIDs. * * @param array List of PHIDs of authors * @return this * @task config */ public function withDraftRepliesByAuthors(array $author_phids) { $this->draftAuthors = $author_phids; return $this; } /** * Filter results to revisions which CC one of the listed people. Calling this * function will clear anything set by previous calls to @{method:withCCs}. * * @param array List of PHIDs of subscribers. * @return this * @task config */ public function withCCs(array $cc_phids) { $this->ccs = $cc_phids; return $this; } /** * Filter results to revisions that have one of the provided PHIDs as * reviewers. Calling this function will clear anything set by previous calls * to @{method:withReviewers}. * * @param array List of PHIDs of reviewers * @return this * @task config */ public function withReviewers(array $reviewer_phids) { $this->reviewers = $reviewer_phids; return $this; } /** * Filter results to revisions that have one of the provided commit hashes. * Calling this function will clear anything set by previous calls to * @{method:withCommitHashes}. * * @param array List of pairs * @return this * @task config */ public function withCommitHashes(array $commit_hashes) { $this->commitHashes = $commit_hashes; return $this; } /** * Filter results to revisions with a given status. Provide a class constant, * such as `DifferentialRevisionQuery::STATUS_OPEN`. * * @param const Class STATUS constant, like STATUS_OPEN. * @return this * @task config */ public function withStatus($status_constant) { $this->status = $status_constant; return $this; } /** * Filter results to revisions on given branches. * * @param list List of branch names. * @return this * @task config */ public function withBranches(array $branches) { $this->branches = $branches; return $this; } /** * Filter results to only return revisions whose ids are in the given set. * * @param array List of revision ids * @return this * @task config */ public function withIDs(array $ids) { $this->revIDs = $ids; return $this; } /** * Filter results to only return revisions whose PHIDs are in the given set. * * @param array List of revision PHIDs * @return this * @task config */ public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } /** * Given a set of users, filter results to return only revisions they are * responsible for (i.e., they are either authors or reviewers). * * @param array List of user PHIDs. * @return this * @task config */ public function withResponsibleUsers(array $responsible_phids) { $this->responsibles = $responsible_phids; return $this; } /** * Filter results to only return revisions with a given set of arcanist * projects. * * @param array List of project PHIDs. * @return this * @task config */ public function withArcanistProjectPHIDs(array $arc_project_phids) { $this->arcanistProjectPHIDs = $arc_project_phids; return $this; } public function withRepositoryPHIDs(array $repository_phids) { $this->repositoryPHIDs = $repository_phids; return $this; } /** * Set result ordering. Provide a class constant, such as * `DifferentialRevisionQuery::ORDER_CREATED`. * * @task config */ public function setOrder($order_constant) { $this->order = $order_constant; return $this; } /** * Set whether or not the query will load and attach relationships. * * @param bool True to load and attach relationships. * @return this * @task config */ public function needRelationships($need_relationships) { $this->needRelationships = $need_relationships; return $this; } /** * Set whether or not the query should load the active diff for each * revision. * * @param bool True to load and attach diffs. * @return this * @task config */ public function needActiveDiffs($need_active_diffs) { $this->needActiveDiffs = $need_active_diffs; return $this; } /** * Set whether or not the query should load the associated commit PHIDs for * each revision. * * @param bool True to load and attach diffs. * @return this * @task config */ public function needCommitPHIDs($need_commit_phids) { $this->needCommitPHIDs = $need_commit_phids; return $this; } /** * Set whether or not the query should load associated diff IDs for each * revision. * * @param bool True to load and attach diff IDs. * @return this * @task config */ public function needDiffIDs($need_diff_ids) { $this->needDiffIDs = $need_diff_ids; return $this; } /** * Set whether or not the query should load associated commit hashes for each * revision. * * @param bool True to load and attach commit hashes. * @return this * @task config */ public function needHashes($need_hashes) { $this->needHashes = $need_hashes; return $this; } /** * Set whether or not the query should load associated reviewer status. * * @param bool True to load and attach reviewers. * @return this * @task config */ public function needReviewerStatus($need_reviewer_status) { $this->needReviewerStatus = $need_reviewer_status; return $this; } /** * Request information about the viewer's authority to act on behalf of each * reviewer. In particular, they have authority to act on behalf of projects * they are a member of. * * @param bool True to load and attach authority. * @return this * @task config */ public function needReviewerAuthority($need_reviewer_authority) { $this->needReviewerAuthority = $need_reviewer_authority; return $this; } public function needFlags($need_flags) { $this->needFlags = $need_flags; return $this; } public function needDrafts($need_drafts) { $this->needDrafts = $need_drafts; return $this; } /* -( Query Execution )---------------------------------------------------- */ /** * Execute the query as configured, returning matching * @{class:DifferentialRevision} objects. * * @return list List of matching DifferentialRevision objects. * @task exec */ public function loadPage() { $table = new DifferentialRevision(); $conn_r = $table->establishConnection('r'); $data = $this->loadData(); return $table->loadAllFromArray($data); } public function willFilterPage(array $revisions) { $viewer = $this->getViewer(); $repository_phids = mpull($revisions, 'getRepositoryPHID'); $repository_phids = array_filter($repository_phids); $repositories = array(); if ($repository_phids) { $repositories = id(new PhabricatorRepositoryQuery()) ->setViewer($this->getViewer()) ->withPHIDs($repository_phids) ->execute(); $repositories = mpull($repositories, null, 'getPHID'); } // If a revision is associated with a repository: // // - the viewer must be able to see the repository; or // - the viewer must have an automatic view capability. // // In the latter case, we'll load the revision but not load the repository. $can_view = PhabricatorPolicyCapability::CAN_VIEW; foreach ($revisions as $key => $revision) { $repo_phid = $revision->getRepositoryPHID(); if (!$repo_phid) { // The revision has no associated repository. Attach `null` and move on. $revision->attachRepository(null); continue; } $repository = idx($repositories, $repo_phid); if ($repository) { // The revision has an associated repository, and the viewer can see // it. Attach it and move on. $revision->attachRepository($repository); continue; } if ($revision->hasAutomaticCapability($can_view, $viewer)) { // The revision has an associated repository which the viewer can not // see, but the viewer has an automatic capability on this revision. // Load the revision without attaching a repository. $revision->attachRepository(null); continue; } if ($this->getViewer()->isOmnipotent()) { // The viewer is omnipotent. Allow the revision to load even without // a repository. $revision->attachRepository(null); continue; } // The revision has an associated repository, and the viewer can't see // it, and the viewer has no special capabilities. Filter out this // revision. $this->didRejectResult($revision); unset($revisions[$key]); } if (!$revisions) { return array(); } $table = new DifferentialRevision(); $conn_r = $table->establishConnection('r'); if ($this->needRelationships) { $this->loadRelationships($conn_r, $revisions); } if ($this->needCommitPHIDs) { $this->loadCommitPHIDs($conn_r, $revisions); } $need_active = $this->needActiveDiffs; $need_ids = $need_active || $this->needDiffIDs; if ($need_ids) { $this->loadDiffIDs($conn_r, $revisions); } if ($need_active) { $this->loadActiveDiffs($conn_r, $revisions); } if ($this->needHashes) { $this->loadHashes($conn_r, $revisions); } if ($this->needReviewerStatus || $this->needReviewerAuthority) { $this->loadReviewers($conn_r, $revisions); } return $revisions; } protected function didFilterPage(array $revisions) { $viewer = $this->getViewer(); if ($this->needFlags) { $flags = id(new PhabricatorFlagQuery()) ->setViewer($viewer) ->withOwnerPHIDs(array($viewer->getPHID())) ->withObjectPHIDs(mpull($revisions, 'getPHID')) ->execute(); $flags = mpull($flags, null, 'getObjectPHID'); foreach ($revisions as $revision) { $revision->attachFlag( $viewer, idx($flags, $revision->getPHID())); } } if ($this->needDrafts) { $drafts = id(new DifferentialDraft())->loadAllWhere( 'authorPHID = %s AND objectPHID IN (%Ls)', $viewer->getPHID(), mpull($revisions, 'getPHID')); $drafts = mgroup($drafts, 'getObjectPHID'); foreach ($revisions as $revision) { $revision->attachDrafts( $viewer, idx($drafts, $revision->getPHID(), array())); } } return $revisions; } private function loadData() { $table = new DifferentialRevision(); $conn_r = $table->establishConnection('r'); $selects = array(); // NOTE: If the query includes "responsiblePHIDs", we execute it as a // UNION of revisions they own and revisions they're reviewing. This has // much better performance than doing it with JOIN/WHERE. if ($this->responsibles) { $basic_authors = $this->authors; $basic_reviewers = $this->reviewers; $authority_projects = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withMemberPHIDs($this->responsibles) ->execute(); $authority_phids = mpull($authority_projects, 'getPHID'); try { // Build the query where the responsible users are authors. $this->authors = array_merge($basic_authors, $this->responsibles); $this->reviewers = $basic_reviewers; $selects[] = $this->buildSelectStatement($conn_r); // Build the query where the responsible users are reviewers, or // projects they are members of are reviewers. $this->authors = $basic_authors; $this->reviewers = array_merge( $basic_reviewers, $this->responsibles, $authority_phids); $selects[] = $this->buildSelectStatement($conn_r); // Put everything back like it was. $this->authors = $basic_authors; $this->reviewers = $basic_reviewers; } catch (Exception $ex) { $this->authors = $basic_authors; $this->reviewers = $basic_reviewers; throw $ex; } } else { $selects[] = $this->buildSelectStatement($conn_r); } if (count($selects) > 1) { $this->buildingGlobalOrder = true; $query = qsprintf( $conn_r, '%Q %Q %Q', implode(' UNION DISTINCT ', $selects), $this->buildOrderClause($conn_r), $this->buildLimitClause($conn_r)); } else { $query = head($selects); } return queryfx_all($conn_r, '%Q', $query); } private function buildSelectStatement(AphrontDatabaseConnection $conn_r) { $table = new DifferentialRevision(); $select = qsprintf( $conn_r, 'SELECT r.* FROM %T r', $table->getTableName()); $joins = $this->buildJoinsClause($conn_r); $where = $this->buildWhereClause($conn_r); $group_by = $this->buildGroupByClause($conn_r); $this->buildingGlobalOrder = false; $order_by = $this->buildOrderClause($conn_r); $limit = $this->buildLimitClause($conn_r); return qsprintf( $conn_r, '(%Q %Q %Q %Q %Q %Q)', $select, $joins, $where, $group_by, $order_by, $limit); } /* -( Internals )---------------------------------------------------------- */ /** * @task internal */ private function buildJoinsClause($conn_r) { $joins = array(); if ($this->pathIDs) { $path_table = new DifferentialAffectedPath(); $joins[] = qsprintf( $conn_r, 'JOIN %T p ON p.revisionID = r.id', $path_table->getTableName()); } if ($this->commitHashes) { $joins[] = qsprintf( $conn_r, 'JOIN %T hash_rel ON hash_rel.revisionID = r.id', ArcanistDifferentialRevisionHash::TABLE_NAME); } if ($this->ccs) { $joins[] = qsprintf( $conn_r, 'JOIN %T e_ccs ON e_ccs.src = r.phid '. 'AND e_ccs.type = %s '. 'AND e_ccs.dst in (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER, $this->ccs); } if ($this->reviewers) { $joins[] = qsprintf( $conn_r, 'JOIN %T e_reviewers ON e_reviewers.src = r.phid '. 'AND e_reviewers.type = %s '. 'AND e_reviewers.dst in (%Ls)', PhabricatorEdgeConfig::TABLE_NAME_EDGE, PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER, $this->reviewers); } if ($this->draftAuthors) { $differential_draft = new DifferentialDraft(); $joins[] = qsprintf( $conn_r, 'JOIN %T has_draft ON has_draft.objectPHID = r.phid '. 'AND has_draft.authorPHID IN (%Ls)', $differential_draft->getTableName(), $this->draftAuthors); } $joins = implode(' ', $joins); return $joins; } /** * @task internal */ private function buildWhereClause($conn_r) { $where = array(); if ($this->pathIDs) { $path_clauses = array(); $repo_info = igroup($this->pathIDs, 'repositoryID'); foreach ($repo_info as $repository_id => $paths) { $path_clauses[] = qsprintf( $conn_r, '(p.repositoryID = %d AND p.pathID IN (%Ld))', $repository_id, ipull($paths, 'pathID')); } $path_clauses = '('.implode(' OR ', $path_clauses).')'; $where[] = $path_clauses; } if ($this->authors) { $where[] = qsprintf( $conn_r, 'r.authorPHID IN (%Ls)', $this->authors); } if ($this->revIDs) { $where[] = qsprintf( $conn_r, 'r.id IN (%Ld)', $this->revIDs); } if ($this->repositoryPHIDs) { $where[] = qsprintf( $conn_r, 'r.repositoryPHID IN (%Ls)', $this->repositoryPHIDs); } if ($this->commitHashes) { $hash_clauses = array(); foreach ($this->commitHashes as $info) { list($type, $hash) = $info; $hash_clauses[] = qsprintf( $conn_r, '(hash_rel.type = %s AND hash_rel.hash = %s)', $type, $hash); } $hash_clauses = '('.implode(' OR ', $hash_clauses).')'; $where[] = $hash_clauses; } if ($this->phids) { $where[] = qsprintf( $conn_r, 'r.phid IN (%Ls)', $this->phids); } if ($this->branches) { $where[] = qsprintf( $conn_r, 'r.branchName in (%Ls)', $this->branches); } if ($this->arcanistProjectPHIDs) { $where[] = qsprintf( $conn_r, 'r.arcanistProjectPHID in (%Ls)', $this->arcanistProjectPHIDs); } switch ($this->status) { case self::STATUS_ANY: break; case self::STATUS_OPEN: $where[] = qsprintf( $conn_r, 'r.status IN (%Ld)', DifferentialRevisionStatus::getOpenStatuses()); break; case self::STATUS_NEEDS_REVIEW: $where[] = qsprintf( $conn_r, 'r.status IN (%Ld)', array( ArcanistDifferentialRevisionStatus::NEEDS_REVIEW, )); break; case self::STATUS_NEEDS_REVISION: $where[] = qsprintf( $conn_r, 'r.status IN (%Ld)', array( ArcanistDifferentialRevisionStatus::NEEDS_REVISION, )); break; case self::STATUS_ACCEPTED: $where[] = qsprintf( $conn_r, 'r.status IN (%Ld)', array( ArcanistDifferentialRevisionStatus::ACCEPTED, )); break; case self::STATUS_CLOSED: $where[] = qsprintf( $conn_r, 'r.status IN (%Ld)', DifferentialRevisionStatus::getClosedStatuses()); break; case self::STATUS_ABANDONED: $where[] = qsprintf( $conn_r, 'r.status IN (%Ld)', array( ArcanistDifferentialRevisionStatus::ABANDONED, )); break; default: throw new Exception( "Unknown revision status filter constant '{$this->status}'!"); } $where[] = $this->buildPagingClause($conn_r); return $this->formatWhereClause($where); } /** * @task internal */ private function buildGroupByClause($conn_r) { $join_triggers = array_merge( $this->pathIDs, $this->ccs, $this->reviewers); $needs_distinct = (count($join_triggers) > 1); if ($needs_distinct) { return 'GROUP BY r.id'; } else { return ''; } } private function loadCursorObject($id) { $results = id(new DifferentialRevisionQuery()) ->setViewer($this->getPagingViewer()) ->withIDs(array((int)$id)) ->execute(); return head($results); } protected function buildPagingClause(AphrontDatabaseConnection $conn_r) { $default = parent::buildPagingClause($conn_r); $before_id = $this->getBeforeID(); $after_id = $this->getAfterID(); if (!$before_id && !$after_id) { return $default; } if ($before_id) { $cursor = $this->loadCursorObject($before_id); } else { $cursor = $this->loadCursorObject($after_id); } if (!$cursor) { return null; } $columns = array(); switch ($this->order) { case self::ORDER_CREATED: return $default; case self::ORDER_MODIFIED: $columns[] = array( 'name' => 'r.dateModified', 'value' => $cursor->getDateModified(), 'type' => 'int', ); break; case self::ORDER_PATH_MODIFIED: $columns[] = array( 'name' => 'p.epoch', 'value' => $cursor->getDateCreated(), 'type' => 'int', ); break; } $columns[] = array( 'name' => 'r.id', 'value' => $cursor->getID(), 'type' => 'int', ); return $this->buildPagingClauseFromMultipleColumns( $conn_r, $columns, array( 'reversed' => (bool)($before_id xor $this->getReversePaging()), )); } protected function getPagingColumn() { $is_global = $this->buildingGlobalOrder; switch ($this->order) { case self::ORDER_MODIFIED: if ($is_global) { return 'dateModified'; } return 'r.dateModified'; case self::ORDER_CREATED: if ($is_global) { return 'id'; } return 'r.id'; case self::ORDER_PATH_MODIFIED: if (!$this->pathIDs) { throw new Exception( 'To use ORDER_PATH_MODIFIED, you must specify withPath().'); } return 'p.epoch'; default: throw new Exception("Unknown query order constant '{$this->order}'."); } } private function loadRelationships($conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $type_reviewer = PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER; $type_subscriber = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER; $edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($revisions, 'getPHID')) ->withEdgeTypes(array($type_reviewer, $type_subscriber)) ->setOrder(PhabricatorEdgeQuery::ORDER_OLDEST_FIRST) ->execute(); $type_map = array( DifferentialRevision::RELATION_REVIEWER => $type_reviewer, DifferentialRevision::RELATION_SUBSCRIBED => $type_subscriber, ); foreach ($revisions as $revision) { $data = array(); foreach ($type_map as $rel_type => $edge_type) { $revision_edges = $edges[$revision->getPHID()][$edge_type]; foreach ($revision_edges as $dst_phid => $edge_data) { $data[] = array( 'relation' => $rel_type, 'objectPHID' => $dst_phid, 'reasonPHID' => null, ); } } $revision->attachRelationships($data); } } private function loadCommitPHIDs($conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $commit_phids = queryfx_all( $conn_r, 'SELECT * FROM %T WHERE revisionID IN (%Ld)', DifferentialRevision::TABLE_COMMIT, mpull($revisions, 'getID')); $commit_phids = igroup($commit_phids, 'revisionID'); foreach ($revisions as $revision) { $phids = idx($commit_phids, $revision->getID(), array()); $phids = ipull($phids, 'commitPHID'); $revision->attachCommitPHIDs($phids); } } private function loadDiffIDs($conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $diff_table = new DifferentialDiff(); $diff_ids = queryfx_all( $conn_r, 'SELECT revisionID, id FROM %T WHERE revisionID IN (%Ld) ORDER BY id DESC', $diff_table->getTableName(), mpull($revisions, 'getID')); $diff_ids = igroup($diff_ids, 'revisionID'); foreach ($revisions as $revision) { $ids = idx($diff_ids, $revision->getID(), array()); $ids = ipull($ids, 'id'); $revision->attachDiffIDs($ids); } } private function loadActiveDiffs($conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $diff_table = new DifferentialDiff(); $load_ids = array(); foreach ($revisions as $revision) { $diffs = $revision->getDiffIDs(); if ($diffs) { $load_ids[] = max($diffs); } } $active_diffs = array(); if ($load_ids) { $active_diffs = $diff_table->loadAllWhere( 'id IN (%Ld)', $load_ids); } $active_diffs = mpull($active_diffs, null, 'getRevisionID'); foreach ($revisions as $revision) { $revision->attachActiveDiff(idx($active_diffs, $revision->getID())); } } private function loadHashes( AphrontDatabaseConnection $conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $data = queryfx_all( $conn_r, 'SELECT * FROM %T WHERE revisionID IN (%Ld)', 'differential_revisionhash', mpull($revisions, 'getID')); $data = igroup($data, 'revisionID'); foreach ($revisions as $revision) { $hashes = idx($data, $revision->getID(), array()); $list = array(); foreach ($hashes as $hash) { $list[] = array($hash['type'], $hash['hash']); } $revision->attachHashes($list); } } private function loadReviewers( AphrontDatabaseConnection $conn_r, array $revisions) { assert_instances_of($revisions, 'DifferentialRevision'); $edge_type = PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER; $edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($revisions, 'getPHID')) ->withEdgeTypes(array($edge_type)) ->needEdgeData(true) ->setOrder(PhabricatorEdgeQuery::ORDER_OLDEST_FIRST) ->execute(); $viewer = $this->getViewer(); $viewer_phid = $viewer->getPHID(); $allow_key = 'differential.allow-self-accept'; $allow_self = PhabricatorEnv::getEnvConfig($allow_key); // Figure out which of these reviewers the viewer has authority to act as. if ($this->needReviewerAuthority && $viewer_phid) { $authority = $this->loadReviewerAuthority( $revisions, $edges, $allow_self); } foreach ($revisions as $revision) { $revision_edges = $edges[$revision->getPHID()][$edge_type]; $reviewers = array(); foreach ($revision_edges as $reviewer_phid => $edge) { $reviewer = new DifferentialReviewer($reviewer_phid, $edge['data']); if ($this->needReviewerAuthority) { if (!$viewer_phid) { // Logged-out users never have authority. $has_authority = false; } else if ((!$allow_self) && ($revision->getAuthorPHID() == $viewer_phid)) { // The author can never have authority unless we allow self-accept. $has_authority = false; } else { // Otherwise, look up whether th viewer has authority. $has_authority = isset($authority[$reviewer_phid]); } $reviewer->attachAuthority($viewer, $has_authority); } $reviewers[$reviewer_phid] = $reviewer; } $revision->attachReviewerStatus($reviewers); } } public static function splitResponsible(array $revisions, array $user_phids) { $blocking = array(); $active = array(); $waiting = array(); $status_review = ArcanistDifferentialRevisionStatus::NEEDS_REVIEW; // Bucket revisions into $blocking (revisions where you are blocking // others), $active (revisions you need to do something about) and $waiting // (revisions you're waiting on someone else to do something about). foreach ($revisions as $revision) { $needs_review = ($revision->getStatus() == $status_review); $filter_is_author = in_array($revision->getAuthorPHID(), $user_phids); if (!$revision->getReviewers()) { $needs_review = false; $author_is_reviewer = false; } else { $author_is_reviewer = in_array( $revision->getAuthorPHID(), $revision->getReviewers()); } // If exactly one of "needs review" and "the user is the author" is // true, the user needs to act on it. Otherwise, they're waiting on // it. if ($needs_review ^ $filter_is_author) { if ($needs_review) { array_unshift($blocking, $revision); } else { $active[] = $revision; } // User is author **and** reviewer. An exotic but configurable workflow. // User needs to act on it double. } else if ($needs_review && $author_is_reviewer) { array_unshift($blocking, $revision); $active[] = $revision; } else { $waiting[] = $revision; } } return array($blocking, $active, $waiting); } private function loadReviewerAuthority( array $revisions, array $edges, $allow_self) { $revision_map = mpull($revisions, null, 'getPHID'); $viewer_phid = $this->getViewer()->getPHID(); // Find all the project reviewers which the user may have authority over. $project_phids = array(); - $project_type = PhabricatorProjectPHIDTypeProject::TYPECONST; + $project_type = PhabricatorProjectProjectPHIDType::TYPECONST; $edge_type = PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER; foreach ($edges as $src => $types) { if (!$allow_self) { if ($revision_map[$src]->getAuthorPHID() == $viewer_phid) { // If self-review isn't permitted, the user will never have // authority over projects on revisions they authored because you // can't accept your own revisions, so we don't need to load any // data about these reviewers. continue; } } $edge_data = idx($types, $edge_type, array()); foreach ($edge_data as $dst => $data) { if (phid_get_type($dst) == $project_type) { $project_phids[] = $dst; } } } // Now, figure out which of these projects the viewer is actually a // member of. $project_authority = array(); if ($project_phids) { $project_authority = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs($project_phids) ->withMemberPHIDs(array($viewer_phid)) ->execute(); $project_authority = mpull($project_authority, 'getPHID'); } // Finally, the viewer has authority over themselves. return array( $viewer_phid => true, ) + array_fuse($project_authority); } public function getQueryApplicationClass() { return 'PhabricatorDifferentialApplication'; } } diff --git a/src/applications/differential/query/DifferentialRevisionSearchEngine.php b/src/applications/differential/query/DifferentialRevisionSearchEngine.php index 0cd7773d5..f4d203b67 100644 --- a/src/applications/differential/query/DifferentialRevisionSearchEngine.php +++ b/src/applications/differential/query/DifferentialRevisionSearchEngine.php @@ -1,321 +1,321 @@ getQueryKey() == 'active') { return 0xFFFF; } return parent::getPageSize($saved); } public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); $saved->setParameter( 'responsiblePHIDs', $this->readUsersFromRequest($request, 'responsibles')); $saved->setParameter( 'authorPHIDs', $this->readUsersFromRequest($request, 'authors')); $saved->setParameter( 'reviewerPHIDs', $this->readUsersFromRequest( $request, 'reviewers', array( - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, ))); $saved->setParameter( 'subscriberPHIDs', $this->readUsersFromRequest($request, 'subscribers')); $saved->setParameter( 'repositoryPHIDs', $request->getArr('repositories')); $saved->setParameter( 'draft', $request->getBool('draft')); $saved->setParameter( 'order', $request->getStr('order')); $saved->setParameter( 'status', $request->getStr('status')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new DifferentialRevisionQuery()) ->needFlags(true) ->needDrafts(true) ->needRelationships(true); $responsible_phids = $saved->getParameter('responsiblePHIDs', array()); if ($responsible_phids) { $query->withResponsibleUsers($responsible_phids); } $author_phids = $saved->getParameter('authorPHIDs', array()); if ($author_phids) { $query->withAuthors($author_phids); } $reviewer_phids = $saved->getParameter('reviewerPHIDs', array()); if ($reviewer_phids) { $query->withReviewers($reviewer_phids); } $subscriber_phids = $saved->getParameter('subscriberPHIDs', array()); if ($subscriber_phids) { $query->withCCs($subscriber_phids); } $repository_phids = $saved->getParameter('repositoryPHIDs', array()); if ($repository_phids) { $query->withRepositoryPHIDs($repository_phids); } $draft = $saved->getParameter('draft', false); if ($draft && $this->requireViewer()->isLoggedIn()) { $query->withDraftRepliesByAuthors( array($this->requireViewer()->getPHID())); } $status = $saved->getParameter('status'); if (idx($this->getStatusOptions(), $status)) { $query->withStatus($status); } $order = $saved->getParameter('order'); if (idx($this->getOrderOptions(), $order)) { $query->setOrder($order); } else { $query->setOrder(DifferentialRevisionQuery::ORDER_CREATED); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $responsible_phids = $saved->getParameter('responsiblePHIDs', array()); $author_phids = $saved->getParameter('authorPHIDs', array()); $reviewer_phids = $saved->getParameter('reviewerPHIDs', array()); $subscriber_phids = $saved->getParameter('subscriberPHIDs', array()); $repository_phids = $saved->getParameter('repositoryPHIDs', array()); $only_draft = $saved->getParameter('draft', false); $all_phids = array_mergev( array( $responsible_phids, $author_phids, $reviewer_phids, $subscriber_phids, $repository_phids, )); $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($all_phids) ->execute(); $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Responsible Users')) ->setName('responsibles') ->setDatasource(new PhabricatorPeopleDatasource()) ->setValue(array_select_keys($handles, $responsible_phids))) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Authors')) ->setName('authors') ->setDatasource(new PhabricatorPeopleDatasource()) ->setValue(array_select_keys($handles, $author_phids))) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Reviewers')) ->setName('reviewers') ->setDatasource(new PhabricatorProjectOrUserDatasource()) ->setValue(array_select_keys($handles, $reviewer_phids))) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Subscribers')) ->setName('subscribers') ->setDatasource(new PhabricatorMetaMTAMailableDatasource()) ->setValue(array_select_keys($handles, $subscriber_phids))) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Repositories')) ->setName('repositories') ->setDatasource(new DiffusionRepositoryDatasource()) ->setValue(array_select_keys($handles, $repository_phids))) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Status')) ->setName('status') ->setOptions($this->getStatusOptions()) ->setValue($saved->getParameter('status'))); if ($this->requireViewer()->isLoggedIn()) { $form ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'draft', 1, pht('Show only revisions with a draft comment.'), $only_draft)); } $form ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Order')) ->setName('order') ->setOptions($this->getOrderOptions()) ->setValue($saved->getParameter('order'))); } protected function getURI($path) { return '/differential/'.$path; } public function getBuiltinQueryNames() { $names = array(); if ($this->requireViewer()->isLoggedIn()) { $names['active'] = pht('Active Revisions'); $names['authored'] = pht('Authored'); } $names['all'] = pht('All Revisions'); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); $viewer = $this->requireViewer(); switch ($query_key) { case 'active': return $query ->setParameter('responsiblePHIDs', array($viewer->getPHID())) ->setParameter('status', DifferentialRevisionQuery::STATUS_OPEN); case 'authored': return $query ->setParameter('authorPHIDs', array($viewer->getPHID())); case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } private function getStatusOptions() { return array( DifferentialRevisionQuery::STATUS_ANY => pht('All'), DifferentialRevisionQuery::STATUS_OPEN => pht('Open'), DifferentialRevisionQuery::STATUS_CLOSED => pht('Closed'), DifferentialRevisionQuery::STATUS_ABANDONED => pht('Abandoned'), ); } private function getOrderOptions() { return array( DifferentialRevisionQuery::ORDER_CREATED => pht('Created'), DifferentialRevisionQuery::ORDER_MODIFIED => pht('Updated'), ); } protected function renderResultList( array $revisions, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($revisions, 'DifferentialRevision'); $viewer = $this->requireViewer(); $template = id(new DifferentialRevisionListView()) ->setUser($viewer); $views = array(); if ($query->getQueryKey() == 'active') { $split = DifferentialRevisionQuery::splitResponsible( $revisions, $query->getParameter('responsiblePHIDs')); list($blocking, $active, $waiting) = $split; $views[] = id(clone $template) ->setHeader(pht('Blocking Others')) ->setNoDataString( pht('No revisions are blocked on your action.')) ->setHighlightAge(true) ->setRevisions($blocking) ->setHandles(array()); $views[] = id(clone $template) ->setHeader(pht('Action Required')) ->setNoDataString( pht('No revisions require your action.')) ->setHighlightAge(true) ->setRevisions($active) ->setHandles(array()); $views[] = id(clone $template) ->setHeader(pht('Waiting on Others')) ->setNoDataString( pht('You have no revisions waiting on others.')) ->setRevisions($waiting) ->setHandles(array()); } else { $views[] = id(clone $template) ->setRevisions($revisions) ->setHandles(array()); } $phids = array_mergev(mpull($views, 'getRequiredHandlePHIDs')); if ($phids) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs($phids) ->execute(); } else { $handles = array(); } foreach ($views as $view) { $view->setHandles($handles); } if (count($views) == 1) { // Reduce this to a PHUIObjectItemListView so we can get the free // support from ApplicationSearch. return head($views)->render(); } else { return $views; } } } diff --git a/src/applications/differential/search/DifferentialSearchIndexer.php b/src/applications/differential/search/DifferentialSearchIndexer.php index 9bc27402f..66a89a6fb 100644 --- a/src/applications/differential/search/DifferentialSearchIndexer.php +++ b/src/applications/differential/search/DifferentialSearchIndexer.php @@ -1,81 +1,81 @@ setViewer($this->getViewer()) ->withPHIDs(array($phid)) ->needReviewerStatus(true) ->executeOne(); if (!$object) { throw new Exception("Unable to load object by phid '{$phid}'!"); } return $object; } protected function buildAbstractDocumentByPHID($phid) { $rev = $this->loadDocumentByPHID($phid); $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($rev->getPHID()); - $doc->setDocumentType(DifferentialPHIDTypeRevision::TYPECONST); + $doc->setDocumentType(DifferentialRevisionPHIDType::TYPECONST); $doc->setDocumentTitle($rev->getTitle()); $doc->setDocumentCreated($rev->getDateCreated()); $doc->setDocumentModified($rev->getDateModified()); $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $rev->getAuthorPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $rev->getDateCreated()); $doc->addRelationship( $rev->isClosed() ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED : PhabricatorSearchRelationship::RELATIONSHIP_OPEN, $rev->getPHID(), - DifferentialPHIDTypeRevision::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST, time()); $this->indexTransactions( $doc, new DifferentialTransactionQuery(), array($rev->getPHID())); // If a revision needs review, the owners are the reviewers. Otherwise, the // owner is the author (e.g., accepted, rejected, closed). if ($rev->getStatus() == ArcanistDifferentialRevisionStatus::NEEDS_REVIEW) { $reviewers = $rev->getReviewerStatus(); $reviewers = mpull($reviewers, 'getReviewerPHID', 'getReviewerPHID'); if ($reviewers) { foreach ($reviewers as $phid) { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $phid, - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $rev->getDateModified()); // Bogus timestamp. } } else { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_UNOWNED, $rev->getPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $rev->getDateModified()); // Bogus timestamp. } } else { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $rev->getAuthorPHID(), PhabricatorPHIDConstants::PHID_TYPE_VOID, $rev->getDateCreated()); } return $doc; } } diff --git a/src/applications/differential/storage/DifferentialDiff.php b/src/applications/differential/storage/DifferentialDiff.php index 5f92f0531..863312520 100644 --- a/src/applications/differential/storage/DifferentialDiff.php +++ b/src/applications/differential/storage/DifferentialDiff.php @@ -1,418 +1,418 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - DifferentialPHIDTypeDiff::TYPECONST); + DifferentialDiffPHIDType::TYPECONST); } public function addUnsavedChangeset(DifferentialChangeset $changeset) { if ($this->changesets === null) { $this->changesets = array(); } $this->unsavedChangesets[] = $changeset; $this->changesets[] = $changeset; return $this; } public function attachChangesets(array $changesets) { assert_instances_of($changesets, 'DifferentialChangeset'); $this->changesets = $changesets; return $this; } public function getChangesets() { return $this->assertAttached($this->changesets); } public function loadChangesets() { if (!$this->getID()) { return array(); } return id(new DifferentialChangeset())->loadAllWhere( 'diffID = %d', $this->getID()); } public function attachArcanistProject( PhabricatorRepositoryArcanistProject $project = null) { $this->arcanistProject = $project; return $this; } public function getArcanistProject() { return $this->assertAttached($this->arcanistProject); } public function getArcanistProjectName() { $name = ''; if ($this->arcanistProject) { $project = $this->getArcanistProject(); $name = $project->getName(); } return $name; } public function save() { $this->openTransaction(); $ret = parent::save(); foreach ($this->unsavedChangesets as $changeset) { $changeset->setDiffID($this->getID()); $changeset->save(); } $this->saveTransaction(); return $ret; } public static function newFromRawChanges(array $changes) { assert_instances_of($changes, 'ArcanistDiffChange'); $diff = new DifferentialDiff(); // There may not be any changes; initialize the changesets list so that // we don't throw later when accessing it. $diff->attachChangesets(array()); $lines = 0; foreach ($changes as $change) { if ($change->getType() == ArcanistDiffChangeType::TYPE_MESSAGE) { // If a user pastes a diff into Differential which includes a commit // message (e.g., they ran `git show` to generate it), discard that // change when constructing a DifferentialDiff. continue; } $changeset = new DifferentialChangeset(); $add_lines = 0; $del_lines = 0; $first_line = PHP_INT_MAX; $hunks = $change->getHunks(); if ($hunks) { foreach ($hunks as $hunk) { $dhunk = new DifferentialHunkModern(); $dhunk->setOldOffset($hunk->getOldOffset()); $dhunk->setOldLen($hunk->getOldLength()); $dhunk->setNewOffset($hunk->getNewOffset()); $dhunk->setNewLen($hunk->getNewLength()); $dhunk->setChanges($hunk->getCorpus()); $changeset->addUnsavedHunk($dhunk); $add_lines += $hunk->getAddLines(); $del_lines += $hunk->getDelLines(); $added_lines = $hunk->getChangedLines('new'); if ($added_lines) { $first_line = min($first_line, head_key($added_lines)); } } $lines += $add_lines + $del_lines; } else { // This happens when you add empty files. $changeset->attachHunks(array()); } $metadata = $change->getAllMetadata(); if ($first_line != PHP_INT_MAX) { $metadata['line:first'] = $first_line; } $changeset->setOldFile($change->getOldPath()); $changeset->setFilename($change->getCurrentPath()); $changeset->setChangeType($change->getType()); $changeset->setFileType($change->getFileType()); $changeset->setMetadata($metadata); $changeset->setOldProperties($change->getOldProperties()); $changeset->setNewProperties($change->getNewProperties()); $changeset->setAwayPaths($change->getAwayPaths()); $changeset->setAddLines($add_lines); $changeset->setDelLines($del_lines); $diff->addUnsavedChangeset($changeset); } $diff->setLineCount($lines); $parser = new DifferentialChangesetParser(); $changesets = $parser->detectCopiedCode( $diff->getChangesets(), $min_width = 30, $min_lines = 3); $diff->attachChangesets($changesets); return $diff; } public function getDiffDict() { $dict = array( 'id' => $this->getID(), 'revisionID' => $this->getRevisionID(), 'dateCreated' => $this->getDateCreated(), 'dateModified' => $this->getDateModified(), 'sourceControlBaseRevision' => $this->getSourceControlBaseRevision(), 'sourceControlPath' => $this->getSourceControlPath(), 'sourceControlSystem' => $this->getSourceControlSystem(), 'branch' => $this->getBranch(), 'bookmark' => $this->getBookmark(), 'creationMethod' => $this->getCreationMethod(), 'description' => $this->getDescription(), 'unitStatus' => $this->getUnitStatus(), 'lintStatus' => $this->getLintStatus(), 'changes' => array(), 'properties' => array(), 'projectName' => $this->getArcanistProjectName() ); $dict['changes'] = $this->buildChangesList(); $properties = id(new DifferentialDiffProperty())->loadAllWhere( 'diffID = %d', $this->getID()); foreach ($properties as $property) { $dict['properties'][$property->getName()] = $property->getData(); if ($property->getName() == 'local:commits') { foreach ($property->getData() as $commit) { $dict['authorName'] = $commit['author']; $dict['authorEmail'] = idx($commit, 'authorEmail'); break; } } } return $dict; } public function buildChangesList() { $changes = array(); foreach ($this->getChangesets() as $changeset) { $hunks = array(); foreach ($changeset->getHunks() as $hunk) { $hunks[] = array( 'oldOffset' => $hunk->getOldOffset(), 'newOffset' => $hunk->getNewOffset(), 'oldLength' => $hunk->getOldLen(), 'newLength' => $hunk->getNewLen(), 'addLines' => null, 'delLines' => null, 'isMissingOldNewline' => null, 'isMissingNewNewline' => null, 'corpus' => $hunk->getChanges(), ); } $change = array( 'id' => $changeset->getID(), 'metadata' => $changeset->getMetadata(), 'oldPath' => $changeset->getOldFile(), 'currentPath' => $changeset->getFilename(), 'awayPaths' => $changeset->getAwayPaths(), 'oldProperties' => $changeset->getOldProperties(), 'newProperties' => $changeset->getNewProperties(), 'type' => $changeset->getChangeType(), 'fileType' => $changeset->getFileType(), 'commitHash' => null, 'addLines' => $changeset->getAddLines(), 'delLines' => $changeset->getDelLines(), 'hunks' => $hunks, ); $changes[] = $change; } return $changes; } public function getRevision() { return $this->assertAttached($this->revision); } public function attachRevision(DifferentialRevision $revision = null) { $this->revision = $revision; return $this; } public function attachProperty($key, $value) { $this->properties[$key] = $value; return $this; } public function getProperty($key) { return $this->assertAttachedKey($this->properties, $key); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { if ($this->getRevision()) { return $this->getRevision()->getPolicy($capability); } return PhabricatorPolicies::POLICY_USER; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { if ($this->getRevision()) { return $this->getRevision()->hasAutomaticCapability($capability, $viewer); } return false; } public function describeAutomaticCapability($capability) { if ($this->getRevision()) { return pht( 'This diff is attached to a revision, and inherits its policies.'); } return null; } /* -( HarbormasterBuildableInterface )------------------------------------- */ public function getHarbormasterBuildablePHID() { return $this->getPHID(); } public function getHarbormasterContainerPHID() { if ($this->getRevisionID()) { $revision = id(new DifferentialRevision())->load($this->getRevisionID()); if ($revision) { return $revision->getPHID(); } } return null; } public function getBuildVariables() { $results = array(); $results['buildable.diff'] = $this->getID(); $revision = $this->getRevision(); $results['buildable.revision'] = $revision->getID(); $repo = $revision->getRepository(); if ($repo) { $results['repository.callsign'] = $repo->getCallsign(); $results['repository.vcs'] = $repo->getVersionControlSystem(); $results['repository.uri'] = $repo->getPublicCloneURI(); } return $results; } public function getAvailableBuildVariables() { return array( 'buildable.diff' => pht('The differential diff ID, if applicable.'), 'buildable.revision' => pht('The differential revision ID, if applicable.'), 'repository.callsign' => pht('The callsign of the repository in Phabricator.'), 'repository.vcs' => pht('The version control system, either "svn", "hg" or "git".'), 'repository.uri' => pht('The URI to clone or checkout the repository from.'), ); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { if (!$this->getRevisionID()) { return null; } return $this->getRevision()->getApplicationTransactionEditor(); } public function getApplicationTransactionObject() { if (!$this->getRevisionID()) { return null; } return $this->getRevision(); } public function getApplicationTransactionTemplate() { if (!$this->getRevisionID()) { return null; } return $this->getRevision()->getApplicationTransactionTemplate(); } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); foreach ($this->loadChangesets() as $changeset) { $changeset->delete(); } $properties = id(new DifferentialDiffProperty())->loadAllWhere( 'diffID = %d', $this->getID()); foreach ($properties as $prop) { $prop->delete(); } $this->saveTransaction(); } } diff --git a/src/applications/differential/storage/DifferentialInlineComment.php b/src/applications/differential/storage/DifferentialInlineComment.php index c2dec0d51..59e555c0f 100644 --- a/src/applications/differential/storage/DifferentialInlineComment.php +++ b/src/applications/differential/storage/DifferentialInlineComment.php @@ -1,217 +1,217 @@ proxy = new DifferentialTransactionComment(); } public function __clone() { $this->proxy = clone $this->proxy; } public function getTransactionCommentForSave() { $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_LEGACY, array()); $this->proxy ->setViewPolicy('public') ->setEditPolicy($this->getAuthorPHID()) ->setContentSource($content_source) ->setCommentVersion(1); return $this->proxy; } public function openTransaction() { $this->proxy->openTransaction(); } public function saveTransaction() { $this->proxy->saveTransaction(); } public function save() { $this->getTransactionCommentForSave()->save(); return $this; } public function delete() { $this->proxy->delete(); return $this; } public function getID() { return $this->proxy->getID(); } public function getPHID() { return $this->proxy->getPHID(); } public static function newFromModernComment( DifferentialTransactionComment $comment) { $obj = new DifferentialInlineComment(); $obj->proxy = $comment; return $obj; } public function setSyntheticAuthor($synthetic_author) { $this->syntheticAuthor = $synthetic_author; return $this; } public function getSyntheticAuthor() { return $this->syntheticAuthor; } public function isCompatible(PhabricatorInlineCommentInterface $comment) { return ($this->getAuthorPHID() === $comment->getAuthorPHID()) && ($this->getSyntheticAuthor() === $comment->getSyntheticAuthor()) && ($this->getContent() === $comment->getContent()); } public function setContent($content) { $this->proxy->setContent($content); return $this; } public function getContent() { return $this->proxy->getContent(); } public function isDraft() { return !$this->proxy->getTransactionPHID(); } public function setChangesetID($id) { $this->proxy->setChangesetID($id); return $this; } public function getChangesetID() { return $this->proxy->getChangesetID(); } public function setIsNewFile($is_new) { $this->proxy->setIsNewFile($is_new); return $this; } public function getIsNewFile() { return $this->proxy->getIsNewFile(); } public function setLineNumber($number) { $this->proxy->setLineNumber($number); return $this; } public function getLineNumber() { return $this->proxy->getLineNumber(); } public function setLineLength($length) { $this->proxy->setLineLength($length); return $this; } public function getLineLength() { return $this->proxy->getLineLength(); } public function setCache($cache) { return $this; } public function getCache() { return null; } public function setAuthorPHID($phid) { $this->proxy->setAuthorPHID($phid); return $this; } public function getAuthorPHID() { return $this->proxy->getAuthorPHID(); } public function setRevision(DifferentialRevision $revision) { $this->proxy->setRevisionPHID($revision->getPHID()); return $this; } public function getRevisionPHID() { return $this->proxy->getRevisionPHID(); } // Although these are purely transitional, they're also *extra* dumb. public function setRevisionID($revision_id) { $revision = id(new DifferentialRevision())->load($revision_id); return $this->setRevision($revision); } public function getRevisionID() { $phid = $this->proxy->getRevisionPHID(); if (!$phid) { return null; } $revision = id(new DifferentialRevision())->loadOneWhere( 'phid = %s', $phid); if (!$revision) { return null; } return $revision->getID(); } // When setting a comment ID, we also generate a phantom transaction PHID for // the future transaction. public function setCommentID($id) { $this->proxy->setTransactionPHID( PhabricatorPHID::generateNewPHID( - PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST, - DifferentialPHIDTypeRevision::TYPECONST)); + PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST)); return $this; } /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ public function getMarkupFieldKey($field) { // We can't use ID because synthetic comments don't have it. return 'DI:'.PhabricatorHash::digest($this->getContent()); } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newDifferentialMarkupEngine(); } public function getMarkupText($field) { return $this->getContent(); } public function didMarkupText($field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { // Only cache submitted comments. return ($this->getID() && !$this->isDraft()); } } diff --git a/src/applications/differential/storage/DifferentialReviewer.php b/src/applications/differential/storage/DifferentialReviewer.php index 6893d7d18..b5a339efb 100644 --- a/src/applications/differential/storage/DifferentialReviewer.php +++ b/src/applications/differential/storage/DifferentialReviewer.php @@ -1,56 +1,56 @@ reviewerPHID = $reviewer_phid; $this->status = idx($edge_data, 'status'); $this->diffID = idx($edge_data, 'diff'); } public function getReviewerPHID() { return $this->reviewerPHID; } public function getStatus() { return $this->status; } public function getDiffID() { return $this->diffID; } public function isUser() { - $user_type = PhabricatorPeoplePHIDTypeUser::TYPECONST; + $user_type = PhabricatorPeopleUserPHIDType::TYPECONST; return (phid_get_type($this->getReviewerPHID()) == $user_type); } public function attachAuthority(PhabricatorUser $user, $has_authority) { $this->authority[$user->getPHID()] = $has_authority; return $this; } public function hasAuthority(PhabricatorUser $viewer) { // It would be nice to use assertAttachedKey() here, but we don't extend // PhabricatorLiskDAO, and faking that seems sketchy. $viewer_phid = $viewer->getPHID(); if (!array_key_exists($viewer_phid, $this->authority)) { throw new Exception('You must attachAuthority() first!'); } return $this->authority[$viewer_phid]; } public function getEdgeData() { return array( 'status' => $this->status, 'diffID' => $this->diffID, ); } } diff --git a/src/applications/differential/storage/DifferentialRevision.php b/src/applications/differential/storage/DifferentialRevision.php index 7544b8e8d..8f549885f 100644 --- a/src/applications/differential/storage/DifferentialRevision.php +++ b/src/applications/differential/storage/DifferentialRevision.php @@ -1,499 +1,499 @@ setViewer($actor) ->withClasses(array('PhabricatorDifferentialApplication')) ->executeOne(); $view_policy = $app->getPolicy( DifferentialCapabilityDefaultView::CAPABILITY); return id(new DifferentialRevision()) ->setViewPolicy($view_policy) ->setAuthorPHID($actor->getPHID()) ->attachRelationships(array()) ->setStatus(ArcanistDifferentialRevisionStatus::NEEDS_REVIEW); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'attached' => self::SERIALIZATION_JSON, 'unsubscribed' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function getMonogram() { $id = $this->getID(); return "D{$id}"; } public function setTitle($title) { $this->title = $title; if (!$this->getID()) { $this->originalTitle = $title; } return $this; } public function loadIDsByCommitPHIDs($phids) { if (!$phids) { return array(); } $revision_ids = queryfx_all( $this->establishConnection('r'), 'SELECT * FROM %T WHERE commitPHID IN (%Ls)', self::TABLE_COMMIT, $phids); return ipull($revision_ids, 'revisionID', 'commitPHID'); } public function loadCommitPHIDs() { if (!$this->getID()) { return ($this->commits = array()); } $commits = queryfx_all( $this->establishConnection('r'), 'SELECT commitPHID FROM %T WHERE revisionID = %d', self::TABLE_COMMIT, $this->getID()); $commits = ipull($commits, 'commitPHID'); return ($this->commits = $commits); } public function getCommitPHIDs() { return $this->assertAttached($this->commits); } public function getActiveDiff() { // TODO: Because it's currently technically possible to create a revision // without an associated diff, we allow an attached-but-null active diff. // It would be good to get rid of this once we make diff-attaching // transactional. return $this->assertAttached($this->activeDiff); } public function attachActiveDiff($diff) { $this->activeDiff = $diff; return $this; } public function getDiffIDs() { return $this->assertAttached($this->diffIDs); } public function attachDiffIDs(array $ids) { rsort($ids); $this->diffIDs = array_values($ids); return $this; } public function attachCommitPHIDs(array $phids) { $this->commits = array_values($phids); return $this; } public function getAttachedPHIDs($type) { return array_keys(idx($this->attached, $type, array())); } public function setAttachedPHIDs($type, array $phids) { $this->attached[$type] = array_fill_keys($phids, array()); return $this; } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - DifferentialPHIDTypeRevision::TYPECONST); + DifferentialRevisionPHIDType::TYPECONST); } public function loadActiveDiff() { return id(new DifferentialDiff())->loadOneWhere( 'revisionID = %d ORDER BY id DESC LIMIT 1', $this->getID()); } public function save() { if (!$this->getMailKey()) { $this->mailKey = Filesystem::readRandomCharacters(40); } return parent::save(); } public function loadRelationships() { if (!$this->getID()) { $this->relationships = array(); return; } $data = array(); $subscriber_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $this->getPHID(), PhabricatorEdgeConfig::TYPE_OBJECT_HAS_SUBSCRIBER); $subscriber_phids = array_reverse($subscriber_phids); foreach ($subscriber_phids as $phid) { $data[] = array( 'relation' => self::RELATION_SUBSCRIBED, 'objectPHID' => $phid, 'reasonPHID' => null, ); } $reviewer_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $this->getPHID(), PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER); $reviewer_phids = array_reverse($reviewer_phids); foreach ($reviewer_phids as $phid) { $data[] = array( 'relation' => self::RELATION_REVIEWER, 'objectPHID' => $phid, 'reasonPHID' => null, ); } return $this->attachRelationships($data); } public function attachRelationships(array $relationships) { $this->relationships = igroup($relationships, 'relation'); return $this; } public function getReviewers() { return $this->getRelatedPHIDs(self::RELATION_REVIEWER); } public function getCCPHIDs() { return $this->getRelatedPHIDs(self::RELATION_SUBSCRIBED); } private function getRelatedPHIDs($relation) { $this->assertAttached($this->relationships); return ipull($this->getRawRelations($relation), 'objectPHID'); } public function getRawRelations($relation) { return idx($this->relationships, $relation, array()); } public function getPrimaryReviewer() { $reviewers = $this->getReviewers(); $last = $this->lastReviewerPHID; if (!$last || !in_array($last, $reviewers)) { return head($this->getReviewers()); } return $last; } public function getHashes() { return $this->assertAttached($this->hashes); } public function attachHashes(array $hashes) { $this->hashes = $hashes; return $this; } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $user) { // A revision's author (which effectively means "owner" after we added // commandeering) can always view and edit it. $author_phid = $this->getAuthorPHID(); if ($author_phid) { if ($user->getPHID() == $author_phid) { return true; } } return false; } public function describeAutomaticCapability($capability) { $description = array( pht('The owner of a revision can always view and edit it.'), ); switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $description[] = pht( "A revision's reviewers can always view it."); $description[] = pht( 'If a revision belongs to a repository, other users must be able '. 'to view the repository in order to view the revision.'); break; } return $description; } public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), ); } public function getReviewerStatus() { return $this->assertAttached($this->reviewerStatus); } public function attachReviewerStatus(array $reviewers) { assert_instances_of($reviewers, 'DifferentialReviewer'); $this->reviewerStatus = $reviewers; return $this; } public function getRepository() { return $this->assertAttached($this->repository); } public function attachRepository(PhabricatorRepository $repository = null) { $this->repository = $repository; return $this; } public function isClosed() { return DifferentialRevisionStatus::isClosedStatus($this->getStatus()); } public function getFlag(PhabricatorUser $viewer) { return $this->assertAttachedKey($this->flags, $viewer->getPHID()); } public function attachFlag( PhabricatorUser $viewer, PhabricatorFlag $flag = null) { $this->flags[$viewer->getPHID()] = $flag; return $this; } public function getDrafts(PhabricatorUser $viewer) { return $this->assertAttachedKey($this->drafts, $viewer->getPHID()); } public function attachDrafts(PhabricatorUser $viewer, array $drafts) { $this->drafts[$viewer->getPHID()] = $drafts; return $this; } /* -( HarbormasterBuildableInterface )------------------------------------- */ public function getHarbormasterBuildablePHID() { return $this->loadActiveDiff()->getPHID(); } public function getHarbormasterContainerPHID() { return $this->getPHID(); } public function getBuildVariables() { return array(); } public function getAvailableBuildVariables() { return array(); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { if ($phid == $this->getAuthorPHID()) { return true; } // TODO: This only happens when adding or removing CCs, and is safe from a // policy perspective, but the subscription pathway should have some // opportunity to load this data properly. For now, this is the only case // where implicit subscription is not an intrinsic property of the object. if ($this->reviewerStatus == self::ATTACHABLE) { $reviewers = id(new DifferentialRevisionQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($this->getPHID())) ->needReviewerStatus(true) ->executeOne() ->getReviewerStatus(); } else { $reviewers = $this->getReviewerStatus(); } foreach ($reviewers as $reviewer) { if ($reviewer->getReviewerPHID() == $phid) { return true; } } return false; } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('differential.fields'); } public function getCustomFieldBaseClass() { return 'DifferentialCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new DifferentialTransactionEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new DifferentialTransaction(); } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $diffs = id(new DifferentialDiffQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withRevisionIDs(array($this->getID())) ->execute(); foreach ($diffs as $diff) { $engine->destroyObject($diff); } $conn_w = $this->establishConnection('w'); queryfx( $conn_w, 'DELETE FROM %T WHERE revisionID = %d', self::TABLE_COMMIT, $this->getID()); try { $inlines = id(new DifferentialInlineCommentQuery()) ->withRevisionIDs(array($this->getID())) ->execute(); foreach ($inlines as $inline) { $inline->delete(); } } catch (PhabricatorEmptyQueryException $ex) { // TODO: There's still some funky legacy wrapping going on here, and // we might catch a raw query exception. } // we have to do paths a little differentally as they do not have // an id or phid column for delete() to act on $dummy_path = new DifferentialAffectedPath(); queryfx( $conn_w, 'DELETE FROM %T WHERE revisionID = %d', $dummy_path->getTableName(), $this->getID()); $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/differential/storage/DifferentialTransaction.php b/src/applications/differential/storage/DifferentialTransaction.php index 25d877f15..5b7fce871 100644 --- a/src/applications/differential/storage/DifferentialTransaction.php +++ b/src/applications/differential/storage/DifferentialTransaction.php @@ -1,512 +1,512 @@ isCommandeerSideEffect = $is_side_effect; return $this; } public function getIsCommandeerSideEffect() { return $this->isCommandeerSideEffect; } const TYPE_INLINE = 'differential:inline'; const TYPE_UPDATE = 'differential:update'; const TYPE_ACTION = 'differential:action'; const TYPE_STATUS = 'differential:status'; public function getApplicationName() { return 'differential'; } public function getApplicationTransactionType() { - return DifferentialPHIDTypeRevision::TYPECONST; + return DifferentialRevisionPHIDType::TYPECONST; } public function getApplicationTransactionCommentObject() { return new DifferentialTransactionComment(); } public function shouldHide() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_UPDATE: // Older versions of this transaction have an ID for the new value, // and/or do not record the old value. Only hide the transaction if // the new value is a PHID, indicating that this is a newer style // transaction. if ($old === null) { - if (phid_get_type($new) == DifferentialPHIDTypeDiff::TYPECONST) { + if (phid_get_type($new) == DifferentialDiffPHIDType::TYPECONST) { return true; } } break; case PhabricatorTransactions::TYPE_EDGE: $add = array_diff_key($new, $old); $rem = array_diff_key($old, $new); // Hide metadata-only edge transactions. These correspond to users // accepting or rejecting revisions, but the change is always explicit // because of the TYPE_ACTION transaction. Rendering these transactions // just creates clutter. if (!$add && !$rem) { return true; } break; } return parent::shouldHide(); } public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { case self::TYPE_INLINE: // Hide inlines when rendering mail transactions if any other // transaction type exists. foreach ($xactions as $xaction) { if ($xaction->getTransactionType() != self::TYPE_INLINE) { return true; } } // If only inline transactions exist, we just render the first one. return ($this !== head($xactions)); } return parent::shouldHideForMail($xactions); } public function getBodyForMail() { switch ($this->getTransactionType()) { case self::TYPE_INLINE: // Don't render inlines into the mail body; they render into a special // section immediately after the body instead. return null; } return parent::getBodyForMail(); } public function getRequiredHandlePHIDs() { $phids = parent::getRequiredHandlePHIDs(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_UPDATE: if ($new) { $phids[] = $new; } break; } return $phids; } public function getActionStrength() { switch ($this->getTransactionType()) { case self::TYPE_ACTION: return 3; case self::TYPE_UPDATE: return 2; case self::TYPE_INLINE: return 0.25; } return parent::getActionStrength(); } public function getActionName() { switch ($this->getTransactionType()) { case self::TYPE_INLINE: return pht('Commented On'); case self::TYPE_UPDATE: $old = $this->getOldValue(); if ($old === null) { return pht('Request'); } else { return pht('Updated'); } case self::TYPE_ACTION: $map = array( DifferentialAction::ACTION_ACCEPT => pht('Accepted'), DifferentialAction::ACTION_REJECT => pht('Requested Changes To'), DifferentialAction::ACTION_RETHINK => pht('Planned Changes To'), DifferentialAction::ACTION_ABANDON => pht('Abandoned'), DifferentialAction::ACTION_CLOSE => pht('Closed'), DifferentialAction::ACTION_REQUEST => pht('Requested A Review Of'), DifferentialAction::ACTION_RESIGN => pht('Resigned From'), DifferentialAction::ACTION_ADDREVIEWERS => pht('Added Reviewers'), DifferentialAction::ACTION_CLAIM => pht('Commandeered'), DifferentialAction::ACTION_REOPEN => pht('Reopened'), ); $name = idx($map, $this->getNewValue()); if ($name !== null) { return $name; } break; } return parent::getActionName(); } public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_SUBSCRIBERS; $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_CC; break; case self::TYPE_ACTION: switch ($this->getNewValue()) { case DifferentialAction::ACTION_CLOSE: $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_CLOSED; break; } break; case self::TYPE_UPDATE: $old = $this->getOldValue(); if ($old === null) { $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_REVIEW_REQUEST; } else { $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_UPDATED; } break; case PhabricatorTransactions::TYPE_EDGE: switch ($this->getMetadataValue('edge:type')) { case PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER: $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_REVIEWERS; break; } break; case PhabricatorTransactions::TYPE_COMMENT: case self::TYPE_INLINE: $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_COMMENT; break; } if (!$tags) { $tags[] = MetaMTANotificationType::TYPE_DIFFERENTIAL_OTHER; } return $tags; } public function getTitle() { $author_phid = $this->getAuthorPHID(); $author_handle = $this->renderHandleLink($author_phid); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_INLINE: return pht( '%s added inline comments.', $author_handle); case self::TYPE_UPDATE: if ($new) { // TODO: Migrate to PHIDs and use handles here? - if (phid_get_type($new) == DifferentialPHIDTypeDiff::TYPECONST) { + if (phid_get_type($new) == DifferentialDiffPHIDType::TYPECONST) { return pht( '%s updated this revision to %s.', $author_handle, $this->renderHandleLink($new)); } else { return pht( '%s updated this revision.', $author_handle); } } else { return pht( '%s updated this revision.', $author_handle); } case self::TYPE_ACTION: return DifferentialAction::getBasicStoryText($new, $author_handle); case self::TYPE_STATUS: switch ($this->getNewValue()) { case ArcanistDifferentialRevisionStatus::ACCEPTED: return pht( 'This revision is now accepted and ready to land.'); case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: return pht( 'This revision now requires changes to proceed.'); case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: return pht( 'This revision now requires review to proceed.'); } } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $author_link = $this->renderHandleLink($author_phid); $object_link = $this->renderHandleLink($object_phid); switch ($this->getTransactionType()) { case self::TYPE_INLINE: return pht( '%s added inline comments to %s.', $author_link, $object_link); case self::TYPE_UPDATE: return pht( '%s updated the diff for %s.', $author_link, $object_link); case self::TYPE_ACTION: switch ($new) { case DifferentialAction::ACTION_ACCEPT: return pht( '%s accepted %s.', $author_link, $object_link); case DifferentialAction::ACTION_REJECT: return pht( '%s requested changes to %s.', $author_link, $object_link); case DifferentialAction::ACTION_RETHINK: return pht( '%s planned changes to %s.', $author_link, $object_link); case DifferentialAction::ACTION_ABANDON: return pht( '%s abandoned %s.', $author_link, $object_link); case DifferentialAction::ACTION_CLOSE: return pht( '%s closed %s.', $author_link, $object_link); case DifferentialAction::ACTION_REQUEST: return pht( '%s requested review of %s.', $author_link, $object_link); case DifferentialAction::ACTION_RECLAIM: return pht( '%s reclaimed %s.', $author_link, $object_link); case DifferentialAction::ACTION_RESIGN: return pht( '%s resigned from %s.', $author_link, $object_link); case DifferentialAction::ACTION_CLAIM: return pht( '%s commandeered %s.', $author_link, $object_link); case DifferentialAction::ACTION_REOPEN: return pht( '%s reopened %s.', $author_link, $object_link); } break; case self::TYPE_STATUS: switch ($this->getNewValue()) { case ArcanistDifferentialRevisionStatus::ACCEPTED: return pht( '%s is now accepted and ready to land.', $object_link); case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: return pht( '%s now requires changes to proceed.', $object_link); case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: return pht( '%s now requires review to proceed.', $object_link); } } return parent::getTitleForFeed($story); } public function getIcon() { switch ($this->getTransactionType()) { case self::TYPE_INLINE: return 'fa-comment'; case self::TYPE_UPDATE: return 'fa-refresh'; case self::TYPE_STATUS: switch ($this->getNewValue()) { case ArcanistDifferentialRevisionStatus::ACCEPTED: return 'fa-check'; case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: return 'fa-times'; case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: return 'fa-undo'; } break; case self::TYPE_ACTION: switch ($this->getNewValue()) { case DifferentialAction::ACTION_CLOSE: return 'fa-check'; case DifferentialAction::ACTION_ACCEPT: return 'fa-check-circle-o'; case DifferentialAction::ACTION_REJECT: return 'fa-times-circle-o'; case DifferentialAction::ACTION_ABANDON: return 'fa-plane'; case DifferentialAction::ACTION_RETHINK: return 'fa-headphones'; case DifferentialAction::ACTION_REQUEST: return 'fa-refresh'; case DifferentialAction::ACTION_RECLAIM: case DifferentialAction::ACTION_REOPEN: return 'fa-bullhorn'; case DifferentialAction::ACTION_RESIGN: return 'fa-flag'; case DifferentialAction::ACTION_CLAIM: return 'fa-flag'; } case PhabricatorTransactions::TYPE_EDGE: switch ($this->getMetadataValue('edge:type')) { case PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER: return 'fa-user'; } } return parent::getIcon(); } public function shouldDisplayGroupWith(array $group) { // Never group status changes with other types of actions, they're indirect // and don't make sense when combined with direct actions. $type_status = self::TYPE_STATUS; if ($this->getTransactionType() == $type_status) { return false; } foreach ($group as $xaction) { if ($xaction->getTransactionType() == $type_status) { return false; } } return parent::shouldDisplayGroupWith($group); } public function getColor() { switch ($this->getTransactionType()) { case self::TYPE_UPDATE: return PhabricatorTransactions::COLOR_SKY; case self::TYPE_STATUS: switch ($this->getNewValue()) { case ArcanistDifferentialRevisionStatus::ACCEPTED: return PhabricatorTransactions::COLOR_GREEN; case ArcanistDifferentialRevisionStatus::NEEDS_REVISION: return PhabricatorTransactions::COLOR_RED; case ArcanistDifferentialRevisionStatus::NEEDS_REVIEW: return PhabricatorTransactions::COLOR_ORANGE; } break; case self::TYPE_ACTION: switch ($this->getNewValue()) { case DifferentialAction::ACTION_CLOSE: return PhabricatorTransactions::COLOR_BLUE; case DifferentialAction::ACTION_ACCEPT: return PhabricatorTransactions::COLOR_GREEN; case DifferentialAction::ACTION_REJECT: return PhabricatorTransactions::COLOR_RED; case DifferentialAction::ACTION_ABANDON: return PhabricatorTransactions::COLOR_BLACK; case DifferentialAction::ACTION_RETHINK: return PhabricatorTransactions::COLOR_RED; case DifferentialAction::ACTION_REQUEST: return PhabricatorTransactions::COLOR_SKY; case DifferentialAction::ACTION_RECLAIM: return PhabricatorTransactions::COLOR_SKY; case DifferentialAction::ACTION_REOPEN: return PhabricatorTransactions::COLOR_SKY; case DifferentialAction::ACTION_RESIGN: return PhabricatorTransactions::COLOR_ORANGE; case DifferentialAction::ACTION_CLAIM: return PhabricatorTransactions::COLOR_YELLOW; } } return parent::getColor(); } public function getNoEffectDescription() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_EDGE: switch ($this->getMetadataValue('edge:type')) { case PhabricatorEdgeConfig::TYPE_DREV_HAS_REVIEWER: return pht( 'The reviewers you are trying to add are already reviewing '. 'this revision.'); } break; case DifferentialTransaction::TYPE_ACTION: switch ($this->getNewValue()) { case DifferentialAction::ACTION_CLOSE: return pht('This revision is already closed.'); case DifferentialAction::ACTION_ABANDON: return pht('This revision has already been abandoned.'); case DifferentialAction::ACTION_RECLAIM: return pht( 'You can not reclaim this revision because his revision is '. 'not abandoned.'); case DifferentialAction::ACTION_REOPEN: return pht( 'You can not reopen this revision because this revision is '. 'not closed.'); case DifferentialAction::ACTION_RETHINK: return pht('This revision already requires changes.'); case DifferentialAction::ACTION_REQUEST: return pht('Review is already requested for this revision.'); case DifferentialAction::ACTION_RESIGN: return pht( 'You can not resign from this revision because you are not '. 'a reviewer.'); case DifferentialAction::ACTION_CLAIM: return pht( 'You can not commandeer this revision because you already own '. 'it.'); case DifferentialAction::ACTION_ACCEPT: return pht( 'You have already accepted this revision.'); case DifferentialAction::ACTION_REJECT: return pht( 'You have already requested changes to this revision.'); } break; } return parent::getNoEffectDescription(); } } diff --git a/src/applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php b/src/applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php index 6169b6e1b..ace1d1888 100644 --- a/src/applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php +++ b/src/applications/diffusion/remarkup/DiffusionCommitRemarkupRule.php @@ -1,30 +1,29 @@ getEngine()->getConfig('viewer'); $query = id(new DiffusionCommitQuery()) ->setViewer($viewer) ->withIdentifiers($ids); $query->execute(); return $query->getIdentifierMap(); } } diff --git a/src/applications/diviner/phid/DivinerPHIDTypeAtom.php b/src/applications/diviner/phid/DivinerAtomPHIDType.php similarity index 90% rename from src/applications/diviner/phid/DivinerPHIDTypeAtom.php rename to src/applications/diviner/phid/DivinerAtomPHIDType.php index a47efb322..21f0b105d 100644 --- a/src/applications/diviner/phid/DivinerPHIDTypeAtom.php +++ b/src/applications/diviner/phid/DivinerAtomPHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $atom = $objects[$phid]; $handle->setName($atom->getTitle()); $handle->setURI($atom->getName()); } } } diff --git a/src/applications/diviner/phid/DivinerPHIDTypeBook.php b/src/applications/diviner/phid/DivinerBookPHIDType.php similarity index 92% rename from src/applications/diviner/phid/DivinerPHIDTypeBook.php rename to src/applications/diviner/phid/DivinerBookPHIDType.php index af2ebb11e..9828b3e98 100644 --- a/src/applications/diviner/phid/DivinerPHIDTypeBook.php +++ b/src/applications/diviner/phid/DivinerBookPHIDType.php @@ -1,39 +1,39 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $book = $objects[$phid]; $name = $book->getName(); $handle->setName($book->getShortTitle()); $handle->setFullName($book->getTitle()); $handle->setURI("/diviner/book/{$name}/"); } } } diff --git a/src/applications/diviner/storage/DivinerLiveBook.php b/src/applications/diviner/storage/DivinerLiveBook.php index 7b8ff7562..dd08ad34c 100644 --- a/src/applications/diviner/storage/DivinerLiveBook.php +++ b/src/applications/diviner/storage/DivinerLiveBook.php @@ -1,71 +1,71 @@ true, self::CONFIG_SERIALIZATION => array( 'configurationData' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function getConfig($key, $default = null) { return idx($this->configurationData, $key, $default); } public function setConfig($key, $value) { $this->configurationData[$key] = $value; return $this; } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - DivinerPHIDTypeBook::TYPECONST); + DivinerBookPHIDType::TYPECONST); } public function getTitle() { return $this->getConfig('title', $this->getName()); } public function getShortTitle() { return $this->getConfig('short', $this->getTitle()); } public function getPreface() { return $this->getConfig('preface'); } public function getGroupName($group) { $groups = $this->getConfig('groups'); $spec = idx($groups, $group, array()); return idx($spec, 'name', $group); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return PhabricatorPolicies::getMostOpenPolicy(); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/diviner/storage/DivinerLiveSymbol.php b/src/applications/diviner/storage/DivinerLiveSymbol.php index 5ed524a58..069f3fc76 100644 --- a/src/applications/diviner/storage/DivinerLiveSymbol.php +++ b/src/applications/diviner/storage/DivinerLiveSymbol.php @@ -1,198 +1,197 @@ true, self::CONFIG_TIMESTAMPS => false, ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - DivinerPHIDTypeAtom::TYPECONST); + return PhabricatorPHID::generateNewPHID(DivinerAtomPHIDType::TYPECONST); } public function getBook() { return $this->assertAttached($this->book); } public function attachBook(DivinerLiveBook $book) { $this->book = $book; return $this; } public function getAtom() { return $this->assertAttached($this->atom); } public function attachAtom(DivinerLiveAtom $atom) { $this->atom = DivinerAtom::newFromDictionary($atom->getAtomData()); return $this; } public function getURI() { $parts = array( 'book', $this->getBook()->getName(), $this->getType(), ); if ($this->getContext()) { $parts[] = $this->getContext(); } $parts[] = $this->getName(); if ($this->getAtomIndex()) { $parts[] = $this->getAtomIndex(); } return '/'.implode('/', $parts).'/'; } public function getSortKey() { // Sort articles before other types of content. Then, sort atoms in a // case-insensitive way. return sprintf( '%c:%s', ($this->getType() == DivinerAtom::TYPE_ARTICLE ? '0' : '1'), phutil_utf8_strtolower($this->getTitle())); } public function save() { // NOTE: The identity hash is just a sanity check because the unique tuple // on this table is way way too long to fit into a normal UNIQUE KEY. We // don't use it directly, but its existence prevents duplicate records. if (!$this->identityHash) { $this->identityHash = PhabricatorHash::digestForIndex( serialize( array( 'bookPHID' => $this->getBookPHID(), 'context' => $this->getContext(), 'type' => $this->getType(), 'name' => $this->getName(), 'index' => $this->getAtomIndex(), ))); } return parent::save(); } public function getTitle() { $title = parent::getTitle(); if (!strlen($title)) { $title = $this->getName(); } return $title; } public function setTitle($value) { $this->writeField('title', $value); if (strlen($value)) { $slug = DivinerAtomRef::normalizeTitleString($value); $hash = PhabricatorHash::digestForIndex($slug); $this->titleSlugHash = $hash; } else { $this->titleSlugHash = null; } return $this; } public function attachExtends(array $extends) { assert_instances_of($extends, 'DivinerLiveSymbol'); $this->extends = $extends; return $this; } public function getExtends() { return $this->assertAttached($this->extends); } public function attachChildren(array $children) { assert_instances_of($children, 'DivinerLiveSymbol'); $this->children = $children; return $this; } public function getChildren() { return $this->assertAttached($this->children); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return $this->getBook()->getCapabilities(); } public function getPolicy($capability) { return $this->getBook()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBook()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('Atoms inherit the policies of the books they are part of.'); } /* -( Markup Interface )--------------------------------------------------- */ public function getMarkupFieldKey($field) { return $this->getPHID().':'.$field.':'.$this->getGraphHash(); } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::getEngine('diviner'); } public function getMarkupText($field) { return $this->getAtom()->getDocblockText(); } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return true; } } diff --git a/src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php b/src/applications/drydock/phid/DrydockBlueprintPHIDType.php similarity index 90% rename from src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php rename to src/applications/drydock/phid/DrydockBlueprintPHIDType.php index 553205cf7..b61eb396b 100644 --- a/src/applications/drydock/phid/DrydockPHIDTypeBlueprint.php +++ b/src/applications/drydock/phid/DrydockBlueprintPHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $blueprint = $objects[$phid]; $id = $blueprint->getID(); $handle->setURI("/drydock/blueprint/{$id}/"); } } } diff --git a/src/applications/drydock/phid/DrydockPHIDTypeLease.php b/src/applications/drydock/phid/DrydockLeasePHIDType.php similarity index 90% rename from src/applications/drydock/phid/DrydockPHIDTypeLease.php rename to src/applications/drydock/phid/DrydockLeasePHIDType.php index 55649c9d9..157bef667 100644 --- a/src/applications/drydock/phid/DrydockPHIDTypeLease.php +++ b/src/applications/drydock/phid/DrydockLeasePHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $lease = $objects[$phid]; $id = $lease->getID(); $handle->setURI("/drydock/lease/{$id}/"); } } } diff --git a/src/applications/drydock/phid/DrydockPHIDTypeResource.php b/src/applications/drydock/phid/DrydockResourcePHIDType.php similarity index 90% rename from src/applications/drydock/phid/DrydockPHIDTypeResource.php rename to src/applications/drydock/phid/DrydockResourcePHIDType.php index ffe76c6e7..36f9a8bbb 100644 --- a/src/applications/drydock/phid/DrydockPHIDTypeResource.php +++ b/src/applications/drydock/phid/DrydockResourcePHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $resource = $objects[$phid]; $id = $resource->getID(); $handle->setURI("/drydock/resource/{$id}/"); } } } diff --git a/src/applications/drydock/storage/DrydockBlueprint.php b/src/applications/drydock/storage/DrydockBlueprint.php index 4fc2e1735..7b6aa095e 100644 --- a/src/applications/drydock/storage/DrydockBlueprint.php +++ b/src/applications/drydock/storage/DrydockBlueprint.php @@ -1,89 +1,89 @@ setViewer($actor) ->withClasses(array('PhabricatorDrydockApplication')) ->executeOne(); $view_policy = $app->getPolicy( DrydockCapabilityDefaultView::CAPABILITY); $edit_policy = $app->getPolicy( DrydockCapabilityDefaultEdit::CAPABILITY); return id(new DrydockBlueprint()) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->setBlueprintName(''); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ) ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - DrydockPHIDTypeBlueprint::TYPECONST); + DrydockBlueprintPHIDType::TYPECONST); } public function getImplementation() { $class = $this->className; $implementations = DrydockBlueprintImplementation::getAllBlueprintImplementations(); if (!isset($implementations[$class])) { throw new Exception( "Invalid class name for blueprint (got '".$class."')"); } return id(new $class())->attachInstance($this); } public function attachImplementation(DrydockBlueprintImplementation $impl) { $this->implementation = $impl; return $this; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/drydock/storage/DrydockBlueprintTransaction.php b/src/applications/drydock/storage/DrydockBlueprintTransaction.php index 6bb46e28e..0e3b2e2e3 100644 --- a/src/applications/drydock/storage/DrydockBlueprintTransaction.php +++ b/src/applications/drydock/storage/DrydockBlueprintTransaction.php @@ -1,39 +1,39 @@ getOldValue(); $new = $this->getNewValue(); $author_handle = $this->renderHandleLink($this->getAuthorPHID()); switch ($this->getTransactionType()) { case self::TYPE_NAME: if (!strlen($old)) { return pht( '%s created this blueprint.', $author_handle); } else { return pht( '%s renamed this blueprint from "%s" to "%s".', $author_handle, $old, $new); } } return parent::getTitle(); } } diff --git a/src/applications/drydock/storage/DrydockLease.php b/src/applications/drydock/storage/DrydockLease.php index 9271d4c4e..fd3d2b0e8 100644 --- a/src/applications/drydock/storage/DrydockLease.php +++ b/src/applications/drydock/storage/DrydockLease.php @@ -1,214 +1,214 @@ releaseOnDestruction = true; return $this; } public function __destruct() { if ($this->releaseOnDestruction) { if ($this->isActive()) { $this->release(); } } } public function getLeaseName() { return pht('Lease %d', $this->getID()); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'attributes' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function setAttribute($key, $value) { $this->attributes[$key] = $value; return $this; } public function getAttribute($key, $default = null) { return idx($this->attributes, $key, $default); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(DrydockPHIDTypeLease::TYPECONST); + return PhabricatorPHID::generateNewPHID(DrydockLeasePHIDType::TYPECONST); } public function getInterface($type) { return $this->getResource()->getInterface($this, $type); } public function getResource() { return $this->assertAttached($this->resource); } public function attachResource(DrydockResource $resource = null) { $this->resource = $resource; return $this; } public function hasAttachedResource() { return ($this->resource !== null); } public function loadResource() { return id(new DrydockResource())->loadOneWhere( 'id = %d', $this->getResourceID()); } public function queueForActivation() { if ($this->getID()) { throw new Exception( 'Only new leases may be queued for activation!'); } $this->setStatus(DrydockLeaseStatus::STATUS_PENDING); $this->save(); $task = PhabricatorWorker::scheduleTask( 'DrydockAllocatorWorker', $this->getID()); // NOTE: Scheduling the task might execute it in-process, if we're running // from a CLI script. Reload the lease to make sure we have the most // up-to-date information. Normally, this has no effect. $this->reload(); $this->setTaskID($task->getID()); $this->save(); return $this; } public function release() { $this->assertActive(); $this->setStatus(DrydockLeaseStatus::STATUS_RELEASED); $this->save(); $this->resource = null; return $this; } public function isActive() { switch ($this->status) { case DrydockLeaseStatus::STATUS_ACTIVE: case DrydockLeaseStatus::STATUS_ACQUIRING: return true; } return false; } private function assertActive() { if (!$this->isActive()) { throw new Exception( 'Lease is not active! You can not interact with resources through '. 'an inactive lease.'); } } public static function waitForLeases(array $leases) { assert_instances_of($leases, 'DrydockLease'); $task_ids = array_filter(mpull($leases, 'getTaskID')); PhabricatorWorker::waitForTasks($task_ids); $unresolved = $leases; while (true) { foreach ($unresolved as $key => $lease) { $lease->reload(); switch ($lease->getStatus()) { case DrydockLeaseStatus::STATUS_ACTIVE: unset($unresolved[$key]); break; case DrydockLeaseStatus::STATUS_RELEASED: throw new Exception('Lease has already been released!'); case DrydockLeaseStatus::STATUS_EXPIRED: throw new Exception('Lease has already expired!'); case DrydockLeaseStatus::STATUS_BROKEN: throw new Exception('Lease has been broken!'); case DrydockLeaseStatus::STATUS_PENDING: case DrydockLeaseStatus::STATUS_ACQUIRING: break; default: throw new Exception('Unknown status??'); } } if ($unresolved) { sleep(1); } else { break; } } foreach ($leases as $lease) { $lease->attachResource($lease->loadResource()); } } public function waitUntilActive() { if (!$this->getID()) { $this->queueForActivation(); } self::waitForLeases(array($this)); return $this; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { if ($this->getResource()) { return $this->getResource()->getPolicy($capability); } return PhabricatorPolicies::getMostOpenPolicy(); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { if ($this->getResource()) { return $this->getResource()->hasAutomaticCapability($capability, $viewer); } return false; } public function describeAutomaticCapability($capability) { return pht('Leases inherit policies from the resources they lease.'); } } diff --git a/src/applications/drydock/storage/DrydockResource.php b/src/applications/drydock/storage/DrydockResource.php index ba2e6a801..6db5c0d5b 100644 --- a/src/applications/drydock/storage/DrydockResource.php +++ b/src/applications/drydock/storage/DrydockResource.php @@ -1,121 +1,121 @@ true, self::CONFIG_SERIALIZATION => array( 'attributes' => self::SERIALIZATION_JSON, 'capabilities' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(DrydockPHIDTypeResource::TYPECONST); + return PhabricatorPHID::generateNewPHID(DrydockResourcePHIDType::TYPECONST); } public function getAttribute($key, $default = null) { return idx($this->attributes, $key, $default); } public function getAttributesForTypeSpec(array $attribute_names) { return array_select_keys($this->attributes, $attribute_names); } public function setAttribute($key, $value) { $this->attributes[$key] = $value; return $this; } public function getCapability($key, $default = null) { return idx($this->capbilities, $key, $default); } public function getInterface(DrydockLease $lease, $type) { return $this->getBlueprint()->getInterface($this, $lease, $type); } public function getBlueprint() { // TODO: Policy stuff. if (empty($this->blueprint)) { $blueprint = id(new DrydockBlueprint()) ->loadOneWhere('phid = %s', $this->blueprintPHID); $this->blueprint = $blueprint->getImplementation(); } return $this->blueprint; } public function closeResource() { $this->openTransaction(); $statuses = array( DrydockLeaseStatus::STATUS_PENDING, DrydockLeaseStatus::STATUS_ACTIVE, ); $leases = id(new DrydockLeaseQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withResourceIDs(array($this->getID())) ->withStatuses($statuses) ->execute(); foreach ($leases as $lease) { switch ($lease->getStatus()) { case DrydockLeaseStatus::STATUS_PENDING: $message = pht('Breaking pending lease (resource closing).'); $lease->setStatus(DrydockLeaseStatus::STATUS_BROKEN); break; case DrydockLeaseStatus::STATUS_ACTIVE: $message = pht('Releasing active lease (resource closing).'); $lease->setStatus(DrydockLeaseStatus::STATUS_RELEASED); break; } DrydockBlueprintImplementation::writeLog($this, $lease, $message); $lease->save(); } $this->setStatus(DrydockResourceStatus::STATUS_CLOSED); $this->save(); $this->saveTransaction(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::getMostOpenPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/feed/story/PhabricatorFeedStory.php b/src/applications/feed/story/PhabricatorFeedStory.php index 40fe2674b..e81031e16 100644 --- a/src/applications/feed/story/PhabricatorFeedStory.php +++ b/src/applications/feed/story/PhabricatorFeedStory.php @@ -1,379 +1,379 @@ List of @{class:PhabricatorFeedStoryData} rows from the * database. * @return list List of @{class:PhabricatorFeedStory} * objects. * @task load */ public static function loadAllFromRows(array $rows, PhabricatorUser $viewer) { $stories = array(); $data = id(new PhabricatorFeedStoryData())->loadAllFromArray($rows); foreach ($data as $story_data) { $class = $story_data->getStoryType(); try { $ok = class_exists($class) && is_subclass_of($class, 'PhabricatorFeedStory'); } catch (PhutilMissingSymbolException $ex) { $ok = false; } // If the story type isn't a valid class or isn't a subclass of // PhabricatorFeedStory, decline to load it. if (!$ok) { continue; } $key = $story_data->getChronologicalKey(); $stories[$key] = newv($class, array($story_data)); } $object_phids = array(); $key_phids = array(); foreach ($stories as $key => $story) { $phids = array(); foreach ($story->getRequiredObjectPHIDs() as $phid) { $phids[$phid] = true; } if ($story->getPrimaryObjectPHID()) { $phids[$story->getPrimaryObjectPHID()] = true; } $key_phids[$key] = $phids; $object_phids += $phids; } $objects = id(new PhabricatorObjectQuery()) ->setViewer($viewer) ->withPHIDs(array_keys($object_phids)) ->execute(); foreach ($key_phids as $key => $phids) { if (!$phids) { continue; } $story_objects = array_select_keys($objects, array_keys($phids)); if (count($story_objects) != count($phids)) { // An object this story requires either does not exist or is not visible // to the user. Decline to render the story. unset($stories[$key]); unset($key_phids[$key]); continue; } $stories[$key]->setObjects($story_objects); } $handle_phids = array(); foreach ($stories as $key => $story) { foreach ($story->getRequiredHandlePHIDs() as $phid) { $key_phids[$key][$phid] = true; } if ($story->getAuthorPHID()) { $key_phids[$key][$story->getAuthorPHID()] = true; } $handle_phids += $key_phids[$key]; } $handles = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs(array_keys($handle_phids)) ->execute(); foreach ($key_phids as $key => $phids) { if (!$phids) { continue; } $story_handles = array_select_keys($handles, array_keys($phids)); $stories[$key]->setHandles($story_handles); } return $stories; } public function setHovercard($hover) { $this->hovercard = $hover; return $this; } public function setRenderingTarget($target) { $this->validateRenderingTarget($target); $this->renderingTarget = $target; return $this; } public function getRenderingTarget() { return $this->renderingTarget; } private function validateRenderingTarget($target) { switch ($target) { case PhabricatorApplicationTransaction::TARGET_HTML: case PhabricatorApplicationTransaction::TARGET_TEXT: break; default: throw new Exception('Unknown rendering target: '.$target); break; } } public function setObjects(array $objects) { $this->objects = $objects; return $this; } public function getObject($phid) { $object = idx($this->objects, $phid); if (!$object) { throw new Exception( "Story is asking for an object it did not request ('{$phid}')!"); } return $object; } public function getPrimaryObject() { $phid = $this->getPrimaryObjectPHID(); if (!$phid) { throw new Exception('Story has no primary object!'); } return $this->getObject($phid); } public function getPrimaryObjectPHID() { return null; } final public function __construct(PhabricatorFeedStoryData $data) { $this->data = $data; } abstract public function renderView(); public function getRequiredHandlePHIDs() { return array(); } public function getRequiredObjectPHIDs() { return array(); } public function setHasViewed($has_viewed) { $this->hasViewed = $has_viewed; return $this; } public function getHasViewed() { return $this->hasViewed; } final public function setFramed($framed) { $this->framed = $framed; return $this; } final public function setHandles(array $handles) { assert_instances_of($handles, 'PhabricatorObjectHandle'); $this->handles = $handles; return $this; } final protected function getObjects() { return $this->objects; } final protected function getHandles() { return $this->handles; } final protected function getHandle($phid) { if (isset($this->handles[$phid])) { if ($this->handles[$phid] instanceof PhabricatorObjectHandle) { return $this->handles[$phid]; } } $handle = new PhabricatorObjectHandle(); $handle->setPHID($phid); $handle->setName("Unloaded Object '{$phid}'"); return $handle; } final public function getStoryData() { return $this->data; } final public function getEpoch() { return $this->getStoryData()->getEpoch(); } final public function getChronologicalKey() { return $this->getStoryData()->getChronologicalKey(); } final public function getValue($key, $default = null) { return $this->getStoryData()->getValue($key, $default); } final public function getAuthorPHID() { return $this->getStoryData()->getAuthorPHID(); } final protected function renderHandleList(array $phids) { $items = array(); foreach ($phids as $phid) { $items[] = $this->linkTo($phid); } $list = null; switch ($this->getRenderingTarget()) { case PhabricatorApplicationTransaction::TARGET_TEXT: $list = implode(', ', $items); break; case PhabricatorApplicationTransaction::TARGET_HTML: $list = phutil_implode_html(', ', $items); break; } return $list; } final protected function linkTo($phid) { $handle = $this->getHandle($phid); switch ($this->getRenderingTarget()) { case PhabricatorApplicationTransaction::TARGET_TEXT: return $handle->getLinkName(); } // NOTE: We render our own link here to customize the styling and add // the '_top' target for framed feeds. $class = null; - if ($handle->getType() == PhabricatorPeoplePHIDTypeUser::TYPECONST) { + if ($handle->getType() == PhabricatorPeopleUserPHIDType::TYPECONST) { $class = 'phui-link-person'; } return javelin_tag( 'a', array( 'href' => $handle->getURI(), 'target' => $this->framed ? '_top' : null, 'sigil' => $this->hovercard ? 'hovercard' : null, 'meta' => $this->hovercard ? array('hoverPHID' => $phid) : null, 'class' => $class, ), $handle->getLinkName()); } final protected function renderString($str) { switch ($this->getRenderingTarget()) { case PhabricatorApplicationTransaction::TARGET_TEXT: return $str; case PhabricatorApplicationTransaction::TARGET_HTML: return phutil_tag('strong', array(), $str); } } final protected function renderSummary($text, $len = 128) { if ($len) { $text = phutil_utf8_shorten($text, $len); } switch ($this->getRenderingTarget()) { case PhabricatorApplicationTransaction::TARGET_HTML: $text = phutil_escape_html_newlines($text); break; } return $text; } public function getNotificationAggregations() { return array(); } protected function newStoryView() { return id(new PHUIFeedStoryView()) ->setChronologicalKey($this->getChronologicalKey()) ->setEpoch($this->getEpoch()) ->setViewed($this->getHasViewed()); } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getPHID() { return null; } /** * @task policy */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } /** * @task policy */ public function getPolicy($capability) { // If this story's primary object is a policy-aware object, use its policy // to control story visiblity. $primary_phid = $this->getPrimaryObjectPHID(); if (isset($this->objects[$primary_phid])) { $object = $this->objects[$primary_phid]; if ($object instanceof PhabricatorPolicyInterface) { return $object->getPolicy($capability); } } // TODO: Remove this once all objects are policy-aware. For now, keep // respecting the `feed.public` setting. return PhabricatorEnv::getEnvConfig('feed.public') ? PhabricatorPolicies::POLICY_PUBLIC : PhabricatorPolicies::POLICY_USER; } /** * @task policy */ public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/files/management/PhabricatorFilesManagementWorkflow.php b/src/applications/files/management/PhabricatorFilesManagementWorkflow.php index 43a8f6df1..400c2ee03 100644 --- a/src/applications/files/management/PhabricatorFilesManagementWorkflow.php +++ b/src/applications/files/management/PhabricatorFilesManagementWorkflow.php @@ -1,40 +1,40 @@ getArg('names'); if ($args->getArg('all')) { if ($names) { throw new PhutilArgumentUsageException( 'Specify either a list of files or `--all`, but not both.'); } return new LiskMigrationIterator(new PhabricatorFile()); } if ($names) { $query = id(new PhabricatorObjectQuery()) ->setViewer($this->getViewer()) ->withNames($names) - ->withTypes(array(PhabricatorFilePHIDTypeFile::TYPECONST)); + ->withTypes(array(PhabricatorFileFilePHIDType::TYPECONST)); $query->execute(); $files = $query->getNamedResults(); foreach ($names as $name) { if (empty($files[$name])) { throw new PhutilArgumentUsageException( "No file '{$name}' exists!"); } } return array_values($files); } return null; } } diff --git a/src/applications/files/phid/PhabricatorFilePHIDTypeFile.php b/src/applications/files/phid/PhabricatorFileFilePHIDType.php similarity index 95% rename from src/applications/files/phid/PhabricatorFilePHIDTypeFile.php rename to src/applications/files/phid/PhabricatorFileFilePHIDType.php index d655511a3..ff44fbd9d 100644 --- a/src/applications/files/phid/PhabricatorFilePHIDTypeFile.php +++ b/src/applications/files/phid/PhabricatorFileFilePHIDType.php @@ -1,70 +1,70 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $file = $objects[$phid]; $id = $file->getID(); $name = $file->getName(); $uri = $file->getBestURI(); $handle->setName("F{$id}"); $handle->setFullName("F{$id}: {$name}"); $handle->setURI($uri); } } public function canLoadNamedObject($name) { return preg_match('/^F\d*[1-9]\d*$/', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PhabricatorFileQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/files/storage/PhabricatorFile.php b/src/applications/files/storage/PhabricatorFile.php index ec33019ec..9153f16ce 100644 --- a/src/applications/files/storage/PhabricatorFile.php +++ b/src/applications/files/storage/PhabricatorFile.php @@ -1,947 +1,947 @@ true, self::CONFIG_SERIALIZATION => array( 'metadata' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorFilePHIDTypeFile::TYPECONST); + PhabricatorFileFilePHIDType::TYPECONST); } public function save() { if (!$this->getSecretKey()) { $this->setSecretKey($this->generateSecretKey()); } if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public static function readUploadedFileData($spec) { if (!$spec) { throw new Exception('No file was uploaded!'); } $err = idx($spec, 'error'); if ($err) { throw new PhabricatorFileUploadException($err); } $tmp_name = idx($spec, 'tmp_name'); $is_valid = @is_uploaded_file($tmp_name); if (!$is_valid) { throw new Exception('File is not an uploaded file.'); } $file_data = Filesystem::readFile($tmp_name); $file_size = idx($spec, 'size'); if (strlen($file_data) != $file_size) { throw new Exception('File size disagrees with uploaded size.'); } self::validateFileSize(strlen($file_data)); return $file_data; } public static function newFromPHPUpload($spec, array $params = array()) { $file_data = self::readUploadedFileData($spec); $file_name = nonempty( idx($params, 'name'), idx($spec, 'name')); $params = array( 'name' => $file_name, ) + $params; return self::newFromFileData($file_data, $params); } public static function newFromXHRUpload($data, array $params = array()) { self::validateFileSize(strlen($data)); return self::newFromFileData($data, $params); } private static function validateFileSize($size) { $limit = PhabricatorEnv::getEnvConfig('storage.upload-size-limit'); if (!$limit) { return; } $limit = phutil_parse_bytes($limit); if ($size > $limit) { throw new PhabricatorFileUploadException(-1000); } } /** * Given a block of data, try to load an existing file with the same content * if one exists. If it does not, build a new file. * * This method is generally used when we have some piece of semi-trusted data * like a diff or a file from a repository that we want to show to the user. * We can't just dump it out because it may be dangerous for any number of * reasons; instead, we need to serve it through the File abstraction so it * ends up on the CDN domain if one is configured and so on. However, if we * simply wrote a new file every time we'd potentially end up with a lot * of redundant data in file storage. * * To solve these problems, we use file storage as a cache and reuse the * same file again if we've previously written it. * * NOTE: This method unguards writes. * * @param string Raw file data. * @param dict Dictionary of file information. */ public static function buildFromFileDataOrHash( $data, array $params = array()) { $file = id(new PhabricatorFile())->loadOneWhere( 'name = %s AND contentHash = %s LIMIT 1', self::normalizeFileName(idx($params, 'name')), self::hashFileContent($data)); if (!$file) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file = PhabricatorFile::newFromFileData($data, $params); unset($unguarded); } return $file; } public static function newFileFromContentHash($hash, $params) { // Check to see if a file with same contentHash exist $file = id(new PhabricatorFile())->loadOneWhere( 'contentHash = %s LIMIT 1', $hash); if ($file) { // copy storageEngine, storageHandle, storageFormat $copy_of_storage_engine = $file->getStorageEngine(); $copy_of_storage_handle = $file->getStorageHandle(); $copy_of_storage_format = $file->getStorageFormat(); $copy_of_byteSize = $file->getByteSize(); $copy_of_mimeType = $file->getMimeType(); $file_name = idx($params, 'name'); $file_name = self::normalizeFileName($file_name); $file_ttl = idx($params, 'ttl'); $authorPHID = idx($params, 'authorPHID'); $new_file = new PhabricatorFile(); $new_file->setName($file_name); $new_file->setByteSize($copy_of_byteSize); $new_file->setAuthorPHID($authorPHID); $new_file->setTtl($file_ttl); if (idx($params, 'viewPolicy')) { $new_file->setViewPolicy($params['viewPolicy']); } $new_file->setContentHash($hash); $new_file->setStorageEngine($copy_of_storage_engine); $new_file->setStorageHandle($copy_of_storage_handle); $new_file->setStorageFormat($copy_of_storage_format); $new_file->setMimeType($copy_of_mimeType); $new_file->copyDimensions($file); $new_file->save(); return $new_file; } return $file; } private static function buildFromFileData($data, array $params = array()) { $selector = PhabricatorEnv::newObjectFromConfig('storage.engine-selector'); if (isset($params['storageEngines'])) { $engines = $params['storageEngines']; } else { $selector = PhabricatorEnv::newObjectFromConfig( 'storage.engine-selector'); $engines = $selector->selectStorageEngines($data, $params); } assert_instances_of($engines, 'PhabricatorFileStorageEngine'); if (!$engines) { throw new Exception('No valid storage engines are available!'); } $file = new PhabricatorFile(); $data_handle = null; $engine_identifier = null; $exceptions = array(); foreach ($engines as $engine) { $engine_class = get_class($engine); try { list($engine_identifier, $data_handle) = $file->writeToEngine( $engine, $data, $params); // We stored the file somewhere so stop trying to write it to other // places. break; } catch (PhabricatorFileStorageConfigurationException $ex) { // If an engine is outright misconfigured (or misimplemented), raise // that immediately since it probably needs attention. throw $ex; } catch (Exception $ex) { phlog($ex); // If an engine doesn't work, keep trying all the other valid engines // in case something else works. $exceptions[$engine_class] = $ex; } } if (!$data_handle) { throw new PhutilAggregateException( 'All storage engines failed to write file:', $exceptions); } $file_name = idx($params, 'name'); $file_name = self::normalizeFileName($file_name); $file_ttl = idx($params, 'ttl'); // If for whatever reason, authorPHID isn't passed as a param // (always the case with newFromFileDownload()), store a '' $authorPHID = idx($params, 'authorPHID'); $file->setName($file_name); $file->setByteSize(strlen($data)); $file->setAuthorPHID($authorPHID); $file->setTtl($file_ttl); $file->setContentHash(self::hashFileContent($data)); if (idx($params, 'viewPolicy')) { $file->setViewPolicy($params['viewPolicy']); } $file->setStorageEngine($engine_identifier); $file->setStorageHandle($data_handle); // TODO: This is probably YAGNI, but allows for us to do encryption or // compression later if we want. $file->setStorageFormat(self::STORAGE_FORMAT_RAW); $file->setIsExplicitUpload(idx($params, 'isExplicitUpload') ? 1 : 0); if (isset($params['mime-type'])) { $file->setMimeType($params['mime-type']); } else { $tmp = new TempFile(); Filesystem::writeFile($tmp, $data); $file->setMimeType(Filesystem::getMimeType($tmp)); } try { $file->updateDimensions(false); } catch (Exception $ex) { // Do nothing } $file->save(); return $file; } public static function newFromFileData($data, array $params = array()) { $hash = self::hashFileContent($data); $file = self::newFileFromContentHash($hash, $params); if ($file) { return $file; } return self::buildFromFileData($data, $params); } public function migrateToEngine(PhabricatorFileStorageEngine $engine) { if (!$this->getID() || !$this->getStorageHandle()) { throw new Exception( "You can not migrate a file which hasn't yet been saved."); } $data = $this->loadFileData(); $params = array( 'name' => $this->getName(), ); list($new_identifier, $new_handle) = $this->writeToEngine( $engine, $data, $params); $old_engine = $this->instantiateStorageEngine(); $old_handle = $this->getStorageHandle(); $this->setStorageEngine($new_identifier); $this->setStorageHandle($new_handle); $this->save(); $old_engine->deleteFile($old_handle); return $this; } private function writeToEngine( PhabricatorFileStorageEngine $engine, $data, array $params) { $engine_class = get_class($engine); $data_handle = $engine->writeFile($data, $params); if (!$data_handle || strlen($data_handle) > 255) { // This indicates an improperly implemented storage engine. throw new PhabricatorFileStorageConfigurationException( "Storage engine '{$engine_class}' executed writeFile() but did ". "not return a valid handle ('{$data_handle}') to the data: it ". "must be nonempty and no longer than 255 characters."); } $engine_identifier = $engine->getEngineIdentifier(); if (!$engine_identifier || strlen($engine_identifier) > 32) { throw new PhabricatorFileStorageConfigurationException( "Storage engine '{$engine_class}' returned an improper engine ". "identifier '{$engine_identifier}': it must be nonempty ". "and no longer than 32 characters."); } return array($engine_identifier, $data_handle); } public static function newFromFileDownload($uri, array $params = array()) { // Make sure we're allowed to make a request first if (!PhabricatorEnv::getEnvConfig('security.allow-outbound-http')) { throw new Exception('Outbound HTTP requests are disabled!'); } $uri = new PhutilURI($uri); $protocol = $uri->getProtocol(); switch ($protocol) { case 'http': case 'https': break; default: // Make sure we are not accessing any file:// URIs or similar. return null; } $timeout = 5; list($file_data) = id(new HTTPSFuture($uri)) ->setTimeout($timeout) ->resolvex(); $params = $params + array( 'name' => basename($uri), ); return self::newFromFileData($file_data, $params); } public static function normalizeFileName($file_name) { $pattern = "@[\\x00-\\x19#%&+!~'\$\"\/=\\\\?<> ]+@"; $file_name = preg_replace($pattern, '_', $file_name); $file_name = preg_replace('@_+@', '_', $file_name); $file_name = trim($file_name, '_'); $disallowed_filenames = array( '.' => 'dot', '..' => 'dotdot', '' => 'file', ); $file_name = idx($disallowed_filenames, $file_name, $file_name); return $file_name; } public function delete() { // We want to delete all the rows which mark this file as the transformation // of some other file (since we're getting rid of it). We also delete all // the transformations of this file, so that a user who deletes an image // doesn't need to separately hunt down and delete a bunch of thumbnails and // resizes of it. $outbound_xforms = id(new PhabricatorFileQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withTransforms( array( array( 'originalPHID' => $this->getPHID(), 'transform' => true, ), )) ->execute(); foreach ($outbound_xforms as $outbound_xform) { $outbound_xform->delete(); } $inbound_xforms = id(new PhabricatorTransformedFile())->loadAllWhere( 'transformedPHID = %s', $this->getPHID()); $this->openTransaction(); foreach ($inbound_xforms as $inbound_xform) { $inbound_xform->delete(); } $ret = parent::delete(); $this->saveTransaction(); // Check to see if other files are using storage $other_file = id(new PhabricatorFile())->loadAllWhere( 'storageEngine = %s AND storageHandle = %s AND storageFormat = %s AND id != %d LIMIT 1', $this->getStorageEngine(), $this->getStorageHandle(), $this->getStorageFormat(), $this->getID()); // If this is the only file using the storage, delete storage if (!$other_file) { $engine = $this->instantiateStorageEngine(); try { $engine->deleteFile($this->getStorageHandle()); } catch (Exception $ex) { // In the worst case, we're leaving some data stranded in a storage // engine, which is fine. phlog($ex); } } return $ret; } public static function hashFileContent($data) { return sha1($data); } public function loadFileData() { $engine = $this->instantiateStorageEngine(); $data = $engine->readFile($this->getStorageHandle()); switch ($this->getStorageFormat()) { case self::STORAGE_FORMAT_RAW: $data = $data; break; default: throw new Exception('Unknown storage format.'); } return $data; } public function getViewURI() { if (!$this->getPHID()) { throw new Exception( 'You must save a file before you can generate a view URI.'); } $name = phutil_escape_uri($this->getName()); $path = '/file/data/'.$this->getSecretKey().'/'.$this->getPHID().'/'.$name; return PhabricatorEnv::getCDNURI($path); } public function getInfoURI() { return '/file/info/'.$this->getPHID().'/'; } public function getBestURI() { if ($this->isViewableInBrowser()) { return $this->getViewURI(); } else { return $this->getInfoURI(); } } public function getDownloadURI() { $uri = id(new PhutilURI($this->getViewURI())) ->setQueryParam('download', true); return (string) $uri; } public function getProfileThumbURI() { $path = '/file/xform/thumb-profile/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function getThumb60x45URI() { $path = '/file/xform/thumb-60x45/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function getThumb160x120URI() { $path = '/file/xform/thumb-160x120/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function getPreview100URI() { $path = '/file/xform/preview-100/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function getPreview220URI() { $path = '/file/xform/preview-220/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function getThumb220x165URI() { $path = '/file/xform/thumb-220x165/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function getThumb280x210URI() { $path = '/file/xform/thumb-280x210/'.$this->getPHID().'/' .$this->getSecretKey().'/'; return PhabricatorEnv::getCDNURI($path); } public function isViewableInBrowser() { return ($this->getViewableMimeType() !== null); } public function isViewableImage() { if (!$this->isViewableInBrowser()) { return false; } $mime_map = PhabricatorEnv::getEnvConfig('files.image-mime-types'); $mime_type = $this->getMimeType(); return idx($mime_map, $mime_type); } public function isAudio() { if (!$this->isViewableInBrowser()) { return false; } $mime_map = PhabricatorEnv::getEnvConfig('files.audio-mime-types'); $mime_type = $this->getMimeType(); return idx($mime_map, $mime_type); } public function isTransformableImage() { // NOTE: The way the 'gd' extension works in PHP is that you can install it // with support for only some file types, so it might be able to handle // PNG but not JPEG. Try to generate thumbnails for whatever we can. Setup // warns you if you don't have complete support. $matches = null; $ok = preg_match( '@^image/(gif|png|jpe?g)@', $this->getViewableMimeType(), $matches); if (!$ok) { return false; } switch ($matches[1]) { case 'jpg'; case 'jpeg': return function_exists('imagejpeg'); break; case 'png': return function_exists('imagepng'); break; case 'gif': return function_exists('imagegif'); break; default: throw new Exception('Unknown type matched as image MIME type.'); } } public static function getTransformableImageFormats() { $supported = array(); if (function_exists('imagejpeg')) { $supported[] = 'jpg'; } if (function_exists('imagepng')) { $supported[] = 'png'; } if (function_exists('imagegif')) { $supported[] = 'gif'; } return $supported; } protected function instantiateStorageEngine() { return self::buildEngine($this->getStorageEngine()); } public static function buildEngine($engine_identifier) { $engines = self::buildAllEngines(); foreach ($engines as $engine) { if ($engine->getEngineIdentifier() == $engine_identifier) { return $engine; } } throw new Exception( "Storage engine '{$engine_identifier}' could not be located!"); } public static function buildAllEngines() { $engines = id(new PhutilSymbolLoader()) ->setType('class') ->setConcreteOnly(true) ->setAncestorClass('PhabricatorFileStorageEngine') ->selectAndLoadSymbols(); $results = array(); foreach ($engines as $engine_class) { $results[] = newv($engine_class['name'], array()); } return $results; } public function getViewableMimeType() { $mime_map = PhabricatorEnv::getEnvConfig('files.viewable-mime-types'); $mime_type = $this->getMimeType(); $mime_parts = explode(';', $mime_type); $mime_type = trim(reset($mime_parts)); return idx($mime_map, $mime_type); } public function getDisplayIconForMimeType() { $mime_map = PhabricatorEnv::getEnvConfig('files.icon-mime-types'); $mime_type = $this->getMimeType(); return idx($mime_map, $mime_type, 'docs_file'); } public function validateSecretKey($key) { return ($key == $this->getSecretKey()); } public function generateSecretKey() { return Filesystem::readRandomCharacters(20); } public function updateDimensions($save = true) { if (!$this->isViewableImage()) { throw new Exception( 'This file is not a viewable image.'); } if (!function_exists('imagecreatefromstring')) { throw new Exception( 'Cannot retrieve image information.'); } $data = $this->loadFileData(); $img = imagecreatefromstring($data); if ($img === false) { throw new Exception( 'Error when decoding image.'); } $this->metadata[self::METADATA_IMAGE_WIDTH] = imagesx($img); $this->metadata[self::METADATA_IMAGE_HEIGHT] = imagesy($img); if ($save) { $this->save(); } return $this; } public function copyDimensions(PhabricatorFile $file) { $metadata = $file->getMetadata(); $width = idx($metadata, self::METADATA_IMAGE_WIDTH); if ($width) { $this->metadata[self::METADATA_IMAGE_WIDTH] = $width; } $height = idx($metadata, self::METADATA_IMAGE_HEIGHT); if ($height) { $this->metadata[self::METADATA_IMAGE_HEIGHT] = $height; } return $this; } /** * Load (or build) the {@class:PhabricatorFile} objects for builtin file * resources. The builtin mechanism allows files shipped with Phabricator * to be treated like normal files so that APIs do not need to special case * things like default images or deleted files. * * Builtins are located in `resources/builtin/` and identified by their * name. * * @param PhabricatorUser Viewing user. * @param list List of builtin file names. * @return dict Dictionary of named builtins. */ public static function loadBuiltins(PhabricatorUser $user, array $names) { $specs = array(); foreach ($names as $name) { $specs[] = array( 'originalPHID' => PhabricatorPHIDConstants::PHID_VOID, 'transform' => 'builtin:'.$name, ); } // NOTE: Anyone is allowed to access builtin files. $files = id(new PhabricatorFileQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withTransforms($specs) ->execute(); $files = mpull($files, null, 'getName'); $root = dirname(phutil_get_library_root('phabricator')); $root = $root.'/resources/builtin/'; $build = array(); foreach ($names as $name) { if (isset($files[$name])) { continue; } // This is just a sanity check to prevent loading arbitrary files. if (basename($name) != $name) { throw new Exception("Invalid builtin name '{$name}'!"); } $path = $root.$name; if (!Filesystem::pathExists($path)) { throw new Exception("Builtin '{$path}' does not exist!"); } $data = Filesystem::readFile($path); $params = array( 'name' => $name, 'ttl' => time() + (60 * 60 * 24 * 7), ); $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); $file = PhabricatorFile::newFromFileData($data, $params); $xform = id(new PhabricatorTransformedFile()) ->setOriginalPHID(PhabricatorPHIDConstants::PHID_VOID) ->setTransform('builtin:'.$name) ->setTransformedPHID($file->getPHID()) ->save(); unset($unguarded); $file->attachObjectPHIDs(array()); $file->attachObjects(array()); $files[$name] = $file; } return $files; } /** * Convenience wrapper for @{method:loadBuiltins}. * * @param PhabricatorUser Viewing user. * @param string Single builtin name to load. * @return PhabricatorFile Corresponding builtin file. */ public static function loadBuiltin(PhabricatorUser $user, $name) { return idx(self::loadBuiltins($user, array($name)), $name); } public function getObjects() { return $this->assertAttached($this->objects); } public function attachObjects(array $objects) { $this->objects = $objects; return $this; } public function getObjectPHIDs() { return $this->assertAttached($this->objectPHIDs); } public function attachObjectPHIDs(array $object_phids) { $this->objectPHIDs = $object_phids; return $this; } public function getImageHeight() { if (!$this->isViewableImage()) { return null; } return idx($this->metadata, self::METADATA_IMAGE_HEIGHT); } public function getImageWidth() { if (!$this->isViewableImage()) { return null; } return idx($this->metadata, self::METADATA_IMAGE_WIDTH); } /** * Write the policy edge between this file and some object. * * @param PhabricatorUser Acting user. * @param phid Object PHID to attach to. * @return this */ public function attachToObject(PhabricatorUser $actor, $phid) { $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_FILE; id(new PhabricatorEdgeEditor()) ->addEdge($phid, $edge_type, $this->getPHID()) ->save(); return $this; } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { $viewer_phid = $viewer->getPHID(); if ($viewer_phid) { if ($this->getAuthorPHID() == $viewer_phid) { return true; } } switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: // If you can see any object this file is attached to, you can see // the file. return (count($this->getObjects()) > 0); } return false; } public function describeAutomaticCapability($capability) { $out = array(); $out[] = pht('The user who uploaded a file can always view and edit it.'); switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $out[] = pht( 'Files attached to objects are visible to users who can view '. 'those objects.'); break; } return $out; } /* -( PhabricatorSubscribableInterface Implementation )-------------------- */ public function isAutomaticallySubscribed($phid) { return ($this->authorPHID == $phid); } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), ); } } diff --git a/src/applications/files/storage/PhabricatorFileTransaction.php b/src/applications/files/storage/PhabricatorFileTransaction.php index 5983d4a00..07ab8df39 100644 --- a/src/applications/files/storage/PhabricatorFileTransaction.php +++ b/src/applications/files/storage/PhabricatorFileTransaction.php @@ -1,18 +1,18 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $build_item = $objects[$phid]; } } } diff --git a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildLog.php b/src/applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php similarity index 89% rename from src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildLog.php rename to src/applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php index 2612d1555..5e2705a40 100644 --- a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildLog.php +++ b/src/applications/harbormaster/phid/HarbormasterBuildLogPHIDType.php @@ -1,33 +1,33 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $build_log = $objects[$phid]; } } } diff --git a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php b/src/applications/harbormaster/phid/HarbormasterBuildPHIDType.php similarity index 92% rename from src/applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php rename to src/applications/harbormaster/phid/HarbormasterBuildPHIDType.php index 0977134c7..5ca684a09 100644 --- a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuild.php +++ b/src/applications/harbormaster/phid/HarbormasterBuildPHIDType.php @@ -1,39 +1,39 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $build = $objects[$phid]; $handles[$phid]->setName(pht( 'Build %d: %s', $build->getID(), $build->getName())); $handles[$phid]->setURI( '/harbormaster/build/'.$build->getID()); } } } diff --git a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildPlan.php b/src/applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php similarity index 92% rename from src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildPlan.php rename to src/applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php index 444997442..d2a733630 100644 --- a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildPlan.php +++ b/src/applications/harbormaster/phid/HarbormasterBuildPlanPHIDType.php @@ -1,40 +1,40 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $build_plan = $objects[$phid]; $id = $build_plan->getID(); $handles[$phid]->setName(pht('Plan %d %s', $id, $build_plan->getName())); $handles[$phid]->setURI('/harbormaster/plan/'.$id.'/'); } } } diff --git a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildStep.php b/src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php similarity index 89% rename from src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildStep.php rename to src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php index 37500a0e7..7c92daf9d 100644 --- a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildStep.php +++ b/src/applications/harbormaster/phid/HarbormasterBuildStepPHIDType.php @@ -1,33 +1,33 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $build_step = $objects[$phid]; } } } diff --git a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildTarget.php b/src/applications/harbormaster/phid/HarbormasterBuildTargetPHIDType.php similarity index 90% rename from src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildTarget.php rename to src/applications/harbormaster/phid/HarbormasterBuildTargetPHIDType.php index fab5a5823..8aa69abad 100644 --- a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildTarget.php +++ b/src/applications/harbormaster/phid/HarbormasterBuildTargetPHIDType.php @@ -1,33 +1,33 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $build_target = $objects[$phid]; } } } diff --git a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildable.php b/src/applications/harbormaster/phid/HarbormasterBuildablePHIDType.php similarity index 95% rename from src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildable.php rename to src/applications/harbormaster/phid/HarbormasterBuildablePHIDType.php index d88dfcfc5..8c854efdf 100644 --- a/src/applications/harbormaster/phid/HarbormasterPHIDTypeBuildable.php +++ b/src/applications/harbormaster/phid/HarbormasterBuildablePHIDType.php @@ -1,70 +1,70 @@ withPHIDs($phids) ->needBuildableHandles(true); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $buildable = $objects[$phid]; $id = $buildable->getID(); $target = $buildable->getBuildableHandle()->getFullName(); $handle->setURI("/B{$id}"); $handle->setName("B{$id}"); $handle->setFullName("B{$id}: ".$target); } } public function canLoadNamedObject($name) { return preg_match('/^B\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new HarbormasterBuildableQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php b/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php index 701fde3de..ef4e0dc6e 100644 --- a/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php +++ b/src/applications/harbormaster/query/HarbormasterBuildableSearchEngine.php @@ -1,221 +1,221 @@ readPHIDsFromRequest( $request, 'revisions', array( - DifferentialPHIDTypeRevision::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST, )); $repositories = $this->readPHIDsFromRequest( $request, 'repositories', array( - PhabricatorRepositoryPHIDTypeRepository::TYPECONST, + PhabricatorRepositoryRepositoryPHIDType::TYPECONST, )); $container_phids = array_merge($revisions, $repositories); $saved->setParameter('containerPHIDs', $container_phids); $commits = $this->readPHIDsFromRequest( $request, 'commits', array( - PhabricatorRepositoryPHIDTypeCommit::TYPECONST, + PhabricatorRepositoryCommitPHIDType::TYPECONST, )); $diffs = $this->readListFromRequest($request, 'diffs'); if ($diffs) { $diffs = id(new DifferentialDiffQuery()) ->setViewer($this->requireViewer()) ->withIDs($diffs) ->execute(); $diffs = mpull($diffs, 'getPHID', 'getPHID'); } $buildable_phids = array_merge($commits, $diffs); $saved->setParameter('buildablePHIDs', $buildable_phids); $saved->setParameter( 'manual', $this->readBoolFromRequest($request, 'manual')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new HarbormasterBuildableQuery()) ->needContainerHandles(true) ->needBuildableHandles(true); $container_phids = $saved->getParameter('containerPHIDs', array()); if ($container_phids) { $query->withContainerPHIDs($container_phids); } $buildable_phids = $saved->getParameter('buildablePHIDs', array()); if ($buildable_phids) { $query->withBuildablePHIDs($buildable_phids); } $manual = $saved->getParameter('manual'); if ($manual !== null) { $query->withManualBuildables($manual); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $container_phids = $saved_query->getParameter('containerPHIDs', array()); $buildable_phids = $saved_query->getParameter('buildablePHIDs', array()); $all_phids = array_merge($container_phids, $buildable_phids); $revision_names = array(); $diff_names = array(); $repository_names = array(); $commit_names = array(); if ($all_phids) { $objects = id(new PhabricatorObjectQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($all_phids) ->execute(); foreach ($all_phids as $phid) { $object = idx($objects, $phid); if (!$object) { continue; } if ($object instanceof DifferentialRevision) { $revision_names[] = 'D'.$object->getID(); } else if ($object instanceof DifferentialDiff) { $diff_names[] = $object->getID(); } else if ($object instanceof PhabricatorRepository) { $repository_names[] = 'r'.$object->getCallsign(); } else if ($object instanceof PhabricatorRepositoryCommit) { $repository = $object->getRepository(); $commit_names[] = $repository->formatCommitName( $object->getCommitIdentifier()); } } } $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Differential Revisions')) ->setName('revisions') ->setValue(implode(', ', $revision_names))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Differential Diffs')) ->setName('diffs') ->setValue(implode(', ', $diff_names))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Repositories')) ->setName('repositories') ->setValue(implode(', ', $repository_names))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Commits')) ->setName('commits') ->setValue(implode(', ', $commit_names))) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Origin')) ->setName('manual') ->setValue($this->getBoolFromQuery($saved_query, 'manual')) ->setOptions( array( '' => pht('(All Origins)'), 'true' => pht('Manual Buildables'), 'false' => pht('Automatic Buildables'), ))); } protected function getURI($path) { return '/harbormaster/'.$path; } public function getBuiltinQueryNames() { return array( 'all' => pht('All Buildables'), ); } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function renderResultList( array $buildables, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($buildables, 'HarbormasterBuildable'); $viewer = $this->requireViewer(); $list = new PHUIObjectItemListView(); foreach ($buildables as $buildable) { $id = $buildable->getID(); $item = id(new PHUIObjectItemView()) ->setHeader(pht('Buildable %d', $buildable->getID())); if ($buildable->getContainerHandle() !== null) { $item->addAttribute($buildable->getContainerHandle()->getName()); } if ($buildable->getBuildableHandle() !== null) { $item->addAttribute($buildable->getBuildableHandle()->getFullName()); } if ($id) { $item->setHref("/B{$id}"); } if ($buildable->getIsManualBuildable()) { $item->addIcon('fa-wrench grey', pht('Manual')); } $item->setBarColor(HarbormasterBuildable::getBuildableStatusColor( $buildable->getBuildableStatus())); $item->addByline(HarbormasterBuildable::getBuildableStatusName( $buildable->getBuildableStatus())); $list->addItem($item); } return $list; } } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php b/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php index be83f8ace..07d81b40c 100644 --- a/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildTransaction.php @@ -1,87 +1,87 @@ getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return pht( '%s created this build.', $this->renderHandleLink($author_phid)); case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_RESTART: return pht( '%s restarted this build.', $this->renderHandleLink($author_phid)); case HarbormasterBuildCommand::COMMAND_RESUME: return pht( '%s resumed this build.', $this->renderHandleLink($author_phid)); case HarbormasterBuildCommand::COMMAND_STOP: return pht( '%s stopped this build.', $this->renderHandleLink($author_phid)); } } return parent::getTitle(); } public function getIcon() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return 'fa-plus'; case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_RESTART: return 'fa-backward'; case HarbormasterBuildCommand::COMMAND_RESUME: return 'fa-play'; case HarbormasterBuildCommand::COMMAND_STOP: return 'fa-stop'; } } return parent::getIcon(); } public function getColor() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return 'green'; case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_STOP: return 'red'; } } return parent::getColor(); } } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildable.php b/src/applications/harbormaster/storage/HarbormasterBuildable.php index ec7a68882..e7e1b4b5e 100644 --- a/src/applications/harbormaster/storage/HarbormasterBuildable.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildable.php @@ -1,262 +1,262 @@ setIsManualBuildable(0) ->setBuildableStatus(self::STATUS_BUILDING); } public function getMonogram() { return 'B'.$this->getID(); } /** * Returns an existing buildable for the object's PHID or creates a * new buildable implicitly if needed. */ public static function createOrLoadExisting( PhabricatorUser $actor, $buildable_object_phid, $container_object_phid) { $buildable = id(new HarbormasterBuildableQuery()) ->setViewer($actor) ->withBuildablePHIDs(array($buildable_object_phid)) ->withManualBuildables(false) ->setLimit(1) ->executeOne(); if ($buildable) { return $buildable; } $buildable = HarbormasterBuildable::initializeNewBuildable($actor) ->setBuildablePHID($buildable_object_phid) ->setContainerPHID($container_object_phid); $buildable->save(); return $buildable; } /** * Looks up the plan PHIDs and applies the plans to the specified * object identified by it's PHID. */ public static function applyBuildPlans( $phid, $container_phid, array $plan_phids) { if (count($plan_phids) === 0) { return; } // Skip all of this logic if the Harbormaster application // isn't currently installed. $harbormaster_app = 'PhabricatorHarbormasterApplication'; if (!PhabricatorApplication::isClassInstalled($harbormaster_app)) { return; } $buildable = HarbormasterBuildable::createOrLoadExisting( PhabricatorUser::getOmnipotentUser(), $phid, $container_phid); $plans = id(new HarbormasterBuildPlanQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs($plan_phids) ->execute(); foreach ($plans as $plan) { if ($plan->isDisabled()) { // TODO: This should be communicated more clearly -- maybe we should // create the build but set the status to "disabled" or "derelict". continue; } $buildable->applyPlan($plan); } } public function applyPlan(HarbormasterBuildPlan $plan) { $viewer = PhabricatorUser::getOmnipotentUser(); $build = HarbormasterBuild::initializeNewBuild($viewer) ->setBuildablePHID($this->getPHID()) ->setBuildPlanPHID($plan->getPHID()) ->setBuildStatus(HarbormasterBuild::STATUS_PENDING) ->save(); PhabricatorWorker::scheduleTask( 'HarbormasterBuildWorker', array( 'buildID' => $build->getID() )); return $build; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuildable::TYPECONST); + HarbormasterBuildablePHIDType::TYPECONST); } public function attachBuildableObject($buildable_object) { $this->buildableObject = $buildable_object; return $this; } public function getBuildableObject() { return $this->assertAttached($this->buildableObject); } public function attachContainerObject($container_object) { $this->containerObject = $container_object; return $this; } public function getContainerObject() { return $this->assertAttached($this->containerObject); } public function attachContainerHandle($container_handle) { $this->containerHandle = $container_handle; return $this; } public function getContainerHandle() { return $this->assertAttached($this->containerHandle); } public function attachBuildableHandle($buildable_handle) { $this->buildableHandle = $buildable_handle; return $this; } public function getBuildableHandle() { return $this->assertAttached($this->buildableHandle); } public function attachBuilds(array $builds) { assert_instances_of($builds, 'HarbormasterBuild'); $this->builds = $builds; return $this; } public function getBuilds() { return $this->assertAttached($this->builds); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getBuildableObject()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBuildableObject()->hasAutomaticCapability( $capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('A buildable inherits policies from the underlying object.'); } /* -( HarbormasterBuildableInterface )------------------------------------- */ public function getHarbormasterBuildablePHID() { // NOTE: This is essentially just for convenience, as it allows you create // a copy of a buildable by specifying `B123` without bothering to go // look up the underlying object. return $this->getBuildablePHID(); } public function getHarbormasterContainerPHID() { return $this->getContainerPHID(); } public function getBuildVariables() { return array(); } public function getAvailableBuildVariables() { return array(); } } diff --git a/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php b/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php index bd802a493..0696edbc1 100644 --- a/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php +++ b/src/applications/harbormaster/storage/HarbormasterBuildableTransaction.php @@ -1,87 +1,87 @@ getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return pht( '%s created this buildable.', $this->renderHandleLink($author_phid)); case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_RESTART: return pht( '%s restarted this buildable.', $this->renderHandleLink($author_phid)); case HarbormasterBuildCommand::COMMAND_RESUME: return pht( '%s resumed this buildable.', $this->renderHandleLink($author_phid)); case HarbormasterBuildCommand::COMMAND_STOP: return pht( '%s stopped this buildable.', $this->renderHandleLink($author_phid)); } } return parent::getTitle(); } public function getIcon() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return 'fa-plus'; case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_RESTART: return 'fa-backward'; case HarbormasterBuildCommand::COMMAND_RESUME: return 'fa-play'; case HarbormasterBuildCommand::COMMAND_STOP: return 'fa-stop'; } } return parent::getIcon(); } public function getColor() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return 'green'; case self::TYPE_COMMAND: switch ($new) { case HarbormasterBuildCommand::COMMAND_STOP: return 'red'; } } return parent::getColor(); } } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuild.php b/src/applications/harbormaster/storage/build/HarbormasterBuild.php index 379e7febc..20ef299e3 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuild.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuild.php @@ -1,396 +1,396 @@ setBuildStatus(self::STATUS_INACTIVE); } public function delete() { $this->openTransaction(); $this->deleteUnprocessedCommands(); $result = parent::delete(); $this->saveTransaction(); return $result; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuild::TYPECONST); + HarbormasterBuildPHIDType::TYPECONST); } public function attachBuildable(HarbormasterBuildable $buildable) { $this->buildable = $buildable; return $this; } public function getBuildable() { return $this->assertAttached($this->buildable); } public function getName() { if ($this->getBuildPlan()) { return $this->getBuildPlan()->getName(); } return pht('Build'); } public function attachBuildPlan( HarbormasterBuildPlan $build_plan = null) { $this->buildPlan = $build_plan; return $this; } public function getBuildPlan() { return $this->assertAttached($this->buildPlan); } public function getBuildTargets() { return $this->assertAttached($this->buildTargets); } public function attachBuildTargets(array $targets) { $this->buildTargets = $targets; return $this; } public function isBuilding() { return $this->getBuildStatus() === self::STATUS_PENDING || $this->getBuildStatus() === self::STATUS_BUILDING; } public function createLog( HarbormasterBuildTarget $build_target, $log_source, $log_type) { $log_source = phutil_utf8_shorten($log_source, 250); $log = HarbormasterBuildLog::initializeNewBuildLog($build_target) ->setLogSource($log_source) ->setLogType($log_type) ->save(); return $log; } public function createArtifact( HarbormasterBuildTarget $build_target, $artifact_key, $artifact_type) { $artifact = HarbormasterBuildArtifact::initializeNewBuildArtifact($build_target); $artifact->setArtifactKey($this->getPHID(), $artifact_key); $artifact->setArtifactType($artifact_type); $artifact->save(); return $artifact; } public function loadArtifact($name) { $artifact = id(new HarbormasterBuildArtifactQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withArtifactKeys( $this->getPHID(), array($name)) ->executeOne(); if ($artifact === null) { throw new Exception('Artifact not found!'); } return $artifact; } public function retrieveVariablesFromBuild() { $results = array( 'buildable.diff' => null, 'buildable.revision' => null, 'buildable.commit' => null, 'repository.callsign' => null, 'repository.vcs' => null, 'repository.uri' => null, 'step.timestamp' => null, 'build.id' => null, ); $buildable = $this->getBuildable(); $object = $buildable->getBuildableObject(); $object_variables = $object->getBuildVariables(); $results = $object_variables + $results; $results['step.timestamp'] = time(); $results['build.id'] = $this->getID(); return $results; } public static function getAvailableBuildVariables() { $objects = id(new PhutilSymbolLoader()) ->setAncestorClass('HarbormasterBuildableInterface') ->loadObjects(); $variables = array(); $variables[] = array( 'step.timestamp' => pht('The current UNIX timestamp.'), 'build.id' => pht('The ID of the current build.'), 'target.phid' => pht('The PHID of the current build target.'), ); foreach ($objects as $object) { $variables[] = $object->getAvailableBuildVariables(); } $variables = array_mergev($variables); return $variables; } public function isComplete() { switch ($this->getBuildStatus()) { case self::STATUS_PASSED: case self::STATUS_FAILED: case self::STATUS_ERROR: case self::STATUS_STOPPED: return true; } return false; } public function isStopped() { return ($this->getBuildStatus() == self::STATUS_STOPPED); } /* -( Build Commands )----------------------------------------------------- */ private function getUnprocessedCommands() { return $this->assertAttached($this->unprocessedCommands); } public function attachUnprocessedCommands(array $commands) { $this->unprocessedCommands = $commands; return $this; } public function canRestartBuild() { return !$this->isRestarting(); } public function canStopBuild() { return !$this->isComplete() && !$this->isStopped() && !$this->isStopping(); } public function canResumeBuild() { return $this->isStopped() && !$this->isResuming(); } public function isStopping() { $is_stopping = false; foreach ($this->getUnprocessedCommands() as $command_object) { $command = $command_object->getCommand(); switch ($command) { case HarbormasterBuildCommand::COMMAND_STOP: $is_stopping = true; break; case HarbormasterBuildCommand::COMMAND_RESUME: case HarbormasterBuildCommand::COMMAND_RESTART: $is_stopping = false; break; } } return $is_stopping; } public function isResuming() { $is_resuming = false; foreach ($this->getUnprocessedCommands() as $command_object) { $command = $command_object->getCommand(); switch ($command) { case HarbormasterBuildCommand::COMMAND_RESTART: case HarbormasterBuildCommand::COMMAND_RESUME: $is_resuming = true; break; case HarbormasterBuildCommand::COMMAND_STOP: $is_resuming = false; break; } } return $is_resuming; } public function isRestarting() { $is_restarting = false; foreach ($this->getUnprocessedCommands() as $command_object) { $command = $command_object->getCommand(); switch ($command) { case HarbormasterBuildCommand::COMMAND_RESTART: $is_restarting = true; break; } } return $is_restarting; } public function deleteUnprocessedCommands() { foreach ($this->getUnprocessedCommands() as $key => $command_object) { $command_object->delete(); unset($this->unprocessedCommands[$key]); } return $this; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getBuildable()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBuildable()->hasAutomaticCapability( $capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('A build inherits policies from its buildable.'); } } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildItem.php b/src/applications/harbormaster/storage/build/HarbormasterBuildItem.php index db1227805..ada416eeb 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuildItem.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildItem.php @@ -1,18 +1,18 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuildItem::TYPECONST); + HarbormasterBuildItemPHIDType::TYPECONST); } } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php b/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php index 8c4a7a11a..ebdf53246 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildLog.php @@ -1,193 +1,193 @@ setBuildTargetPHID($build_target->getPHID()) ->setDuration(null) ->setLive(0); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuildLog::TYPECONST); + HarbormasterBuildLogPHIDType::TYPECONST); } public function attachBuildTarget(HarbormasterBuildTarget $build_target) { $this->buildTarget = $build_target; return $this; } public function getBuildTarget() { return $this->assertAttached($this->buildTarget); } public function getName() { return pht('Build Log'); } public function start() { if ($this->getLive()) { throw new Exception('Live logging has already started for this log.'); } $this->setLive(1); $this->save(); return time(); } public function append($content) { if (!$this->getLive()) { throw new Exception('Start logging before appending data to the log.'); } if (strlen($content) === 0) { return; } // If the length of the content is greater than the chunk size limit, // then we can never fit the content in a single record. We need to // split our content out and call append on it for as many parts as there // are to the content. if (strlen($content) > self::CHUNK_BYTE_LIMIT) { $current = $content; while (strlen($current) > self::CHUNK_BYTE_LIMIT) { $part = substr($current, 0, self::CHUNK_BYTE_LIMIT); $current = substr($current, self::CHUNK_BYTE_LIMIT); $this->append($part); } $this->append($current); return; } // Retrieve the size of last chunk from the DB for this log. If the // chunk is over 500K, then we need to create a new log entry. $conn = $this->establishConnection('w'); $result = queryfx_all( $conn, 'SELECT id, size, encoding '. 'FROM harbormaster_buildlogchunk '. 'WHERE logID = %d '. 'ORDER BY id DESC '. 'LIMIT 1', $this->getID()); if (count($result) === 0 || $result[0]['size'] + strlen($content) > self::CHUNK_BYTE_LIMIT || $result[0]['encoding'] !== self::ENCODING_TEXT) { // We must insert a new chunk because the data we are appending // won't fit into the existing one, or we don't have any existing // chunk data. queryfx( $conn, 'INSERT INTO harbormaster_buildlogchunk '. '(logID, encoding, size, chunk) '. 'VALUES '. '(%d, %s, %d, %s)', $this->getID(), self::ENCODING_TEXT, strlen($content), $content); } else { // We have a resulting record that we can append our content onto. queryfx( $conn, 'UPDATE harbormaster_buildlogchunk '. 'SET chunk = CONCAT(chunk, %s), size = LENGTH(CONCAT(chunk, %s))'. 'WHERE id = %d', $content, $content, $result[0]['id']); } } public function finalize($start = 0) { if (!$this->getLive()) { throw new Exception('Start logging before finalizing it.'); } // TODO: Encode the log contents in a gzipped format. $this->reload(); if ($start > 0) { $this->setDuration(time() - $start); } $this->setLive(0); $this->save(); } public function getLogText() { // TODO: This won't cope very well if we're pulling like a 700MB // log file out of the DB. We should probably implement some sort // of optional limit parameter so that when we're rendering out only // 25 lines in the UI, we don't wastefully read in the whole log. // We have to read our content out of the database and stitch all of // the log data back together. $conn = $this->establishConnection('r'); $result = queryfx_all( $conn, 'SELECT chunk '. 'FROM harbormaster_buildlogchunk '. 'WHERE logID = %d '. 'ORDER BY id ASC', $this->getID()); $content = ''; foreach ($result as $row) { $content .= $row['chunk']; } return $content; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return $this->getBuildTarget()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBuildTarget()->hasAutomaticCapability( $capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'Users must be able to see a build target to view it\'s build log.'); } } diff --git a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php index 0c994701e..624219285 100644 --- a/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php +++ b/src/applications/harbormaster/storage/build/HarbormasterBuildTarget.php @@ -1,190 +1,190 @@ setName($build_step->getName()) ->setBuildPHID($build->getPHID()) ->setBuildStepPHID($build_step->getPHID()) ->setClassName($build_step->getClassName()) ->setDetails($build_step->getDetails()) ->setTargetStatus(self::STATUS_PENDING) ->setVariables($variables); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, 'variables' => self::SERIALIZATION_JSON, ) ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuildTarget::TYPECONST); + HarbormasterBuildTargetPHIDType::TYPECONST); } public function attachBuild(HarbormasterBuild $build) { $this->build = $build; return $this; } public function getBuild() { return $this->assertAttached($this->build); } public function attachBuildStep(HarbormasterBuildStep $step) { $this->buildStep = $step; return $this; } public function getBuildStep() { return $this->assertAttached($this->buildStep); } public function getDetail($key, $default = null) { return idx($this->details, $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } public function getVariables() { return parent::getVariables() + $this->getBuildTargetVariables(); } public function getVariable($key, $default = null) { return idx($this->variables, $key, $default); } public function setVariable($key, $value) { $this->variables[$key] = $value; return $this; } public function getImplementation() { if ($this->implementation === null) { $obj = HarbormasterBuildStepImplementation::requireImplementation( $this->className); $obj->loadSettings($this); $this->implementation = $obj; } return $this->implementation; } public function getName() { if (strlen($this->name)) { return $this->name; } try { return $this->getImplementation()->getName(); } catch (Exception $e) { return $this->getClassName(); } } private function getBuildTargetVariables() { return array( 'target.phid' => $this->getPHID(), ); } /* -( Status )------------------------------------------------------------- */ public function isComplete() { switch ($this->getTargetStatus()) { case self::STATUS_PASSED: case self::STATUS_FAILED: return true; } return false; } public function isFailed() { switch ($this->getTargetStatus()) { case self::STATUS_FAILED: return true; } return false; } public function isWaiting() { switch ($this->getTargetStatus()) { case self::STATUS_WAITING: return true; } return false; } public function isUnderway() { switch ($this->getTargetStatus()) { case self::STATUS_PENDING: case self::STATUS_BUILDING: return true; } return false; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return $this->getBuild()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBuild()->hasAutomaticCapability( $capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('Users must be able to see a build to view its build targets.'); } } diff --git a/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php b/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php index cffcda72e..2a2c22ecb 100644 --- a/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php +++ b/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlan.php @@ -1,99 +1,99 @@ setPlanStatus(self::STATUS_ACTIVE); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuildPlan::TYPECONST); + HarbormasterBuildPlanPHIDType::TYPECONST); } public function attachBuildSteps(array $steps) { assert_instances_of($steps, 'HarbormasterBuildStep'); $this->buildSteps = $steps; return $this; } public function getBuildSteps() { return $this->assertAttached($this->buildSteps); } /** * Returns a standard, ordered list of build steps for this build plan. * * This method should be used to load build steps for a given build plan * so that the ordering is consistent. */ public function loadOrderedBuildSteps() { return id(new HarbormasterBuildStepQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withBuildPlanPHIDs(array($this->getPHID())) ->execute(); } public function isDisabled() { return ($this->getPlanStatus() == self::STATUS_DISABLED); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return false; } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::getMostOpenPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransaction.php b/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransaction.php index 96e6f5d7d..9d48339f3 100644 --- a/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransaction.php +++ b/src/applications/harbormaster/storage/configuration/HarbormasterBuildPlanTransaction.php @@ -1,84 +1,84 @@ getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_NAME: if ($old === null) { return 'fa-plus'; } break; } return parent::getIcon(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_NAME: if ($old === null) { return 'green'; } break; } return parent::getIcon(); } public function getTitle() { $old = $this->getOldValue(); $new = $this->getNewValue(); $author_handle = $this->renderHandleLink($this->getAuthorPHID()); switch ($this->getTransactionType()) { case self::TYPE_NAME: if ($old === null) { return pht( '%s created this build plan.', $author_handle); } else { return pht( '%s renamed this build plan from "%s" to "%s".', $author_handle, $old, $new); } case self::TYPE_STATUS: if ($new == HarbormasterBuildPlan::STATUS_DISABLED) { return pht( '%s disabled this build plan.', $author_handle); } else { return pht( '%s enabled this build plan.', $author_handle); } } return parent::getTitle(); } } diff --git a/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php b/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php index c412e0984..f1ad55c08 100644 --- a/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php +++ b/src/applications/harbormaster/storage/configuration/HarbormasterBuildStep.php @@ -1,117 +1,117 @@ true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ) ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - HarbormasterPHIDTypeBuildStep::TYPECONST); + HarbormasterBuildStepPHIDType::TYPECONST); } public function attachBuildPlan(HarbormasterBuildPlan $plan) { $this->buildPlan = $plan; return $this; } public function getBuildPlan() { return $this->assertAttached($this->buildPlan); } public function getDetail($key, $default = null) { return idx($this->details, $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } public function getName() { if (strlen($this->name)) { return $this->name; } return $this->getStepImplementation()->getName(); } public function getStepImplementation() { if ($this->implementation === null) { $obj = HarbormasterBuildStepImplementation::requireImplementation( $this->className); $obj->loadSettings($this); $this->implementation = $obj; } return $this->implementation; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return $this->getBuildPlan()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBuildPlan()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('A build step has the same policies as its build plan.'); } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return array(); } public function getCustomFieldBaseClass() { return 'HarbormasterBuildStepCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } } diff --git a/src/applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php b/src/applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php index f1e75d1fb..d5f87cd71 100644 --- a/src/applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php +++ b/src/applications/harbormaster/storage/configuration/HarbormasterBuildStepTransaction.php @@ -1,61 +1,61 @@ getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return pht( '%s created this build step.', $this->renderHandleLink($author_phid)); } return parent::getTitle(); } public function getIcon() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return 'fa-plus'; } return parent::getIcon(); } public function getColor() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CREATE: return 'green'; } return parent::getColor(); } } diff --git a/src/applications/herald/controller/HeraldTranscriptController.php b/src/applications/herald/controller/HeraldTranscriptController.php index ff47550bb..0d46421a0 100644 --- a/src/applications/herald/controller/HeraldTranscriptController.php +++ b/src/applications/herald/controller/HeraldTranscriptController.php @@ -1,552 +1,552 @@ id = $data['id']; $map = $this->getFilterMap(); $this->filter = idx($data, 'filter'); if (empty($map[$this->filter])) { $this->filter = self::FILTER_ALL; } } private function getAdapter() { return $this->adapter; } public function processRequest() { $request = $this->getRequest(); $viewer = $request->getUser(); $xscript = id(new HeraldTranscriptQuery()) ->setViewer($viewer) ->withIDs(array($this->id)) ->executeOne(); if (!$xscript) { return new Aphront404Response(); } require_celerity_resource('herald-test-css'); $nav = $this->buildSideNav(); $object_xscript = $xscript->getObjectTranscript(); if (!$object_xscript) { $notice = id(new AphrontErrorView()) ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) ->setTitle(pht('Old Transcript')) ->appendChild(phutil_tag( 'p', array(), pht('Details of this transcript have been garbage collected.'))); $nav->appendChild($notice); } else { $map = HeraldAdapter::getEnabledAdapterMap($viewer); $object_type = $object_xscript->getType(); if (empty($map[$object_type])) { // TODO: We should filter these out in the Query, but we have to load // the objectTranscript right now, which is potentially enormous. We // should denormalize the object type, or move the data into a separate // table, and then filter this earlier (and thus raise a better error). // For now, just block access so we don't violate policies. throw new Exception( pht('This transcript has an invalid or inaccessible adapter.')); } $this->adapter = HeraldAdapter::getAdapterForContentType($object_type); $filter = $this->getFilterPHIDs(); $this->filterTranscript($xscript, $filter); $phids = array_merge($filter, $this->getTranscriptPHIDs($xscript)); $phids = array_unique($phids); $phids = array_filter($phids); $handles = $this->loadViewerHandles($phids); $this->handles = $handles; if ($xscript->getDryRun()) { $notice = new AphrontErrorView(); $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); $notice->setTitle(pht('Dry Run')); $notice->appendChild(pht('This was a dry run to test Herald '. 'rules, no actions were executed.')); $nav->appendChild($notice); } $warning_panel = $this->buildWarningPanel($xscript); $nav->appendChild($warning_panel); $apply_xscript_panel = $this->buildApplyTranscriptPanel( $xscript); $nav->appendChild($apply_xscript_panel); $action_xscript_panel = $this->buildActionTranscriptPanel( $xscript); $nav->appendChild($action_xscript_panel); $object_xscript_panel = $this->buildObjectTranscriptPanel( $xscript); $nav->appendChild($object_xscript_panel); } $crumbs = id($this->buildApplicationCrumbs()) ->addTextCrumb( pht('Transcripts'), $this->getApplicationURI('/transcript/')) ->addTextCrumb($xscript->getID()); $nav->setCrumbs($crumbs); return $this->buildApplicationPage( $nav, array( 'title' => pht('Transcript'), )); } protected function renderConditionTestValue($condition, $handles) { switch ($condition->getFieldName()) { case HeraldAdapter::FIELD_RULE: $value = array($condition->getTestValue()); break; default: $value = $condition->getTestValue(); break; } if (!is_scalar($value) && $value !== null) { foreach ($value as $key => $phid) { $handle = idx($handles, $phid); if ($handle) { $value[$key] = $handle->getName(); } else { // This shouldn't ever really happen as we are supposed to have // grabbed handles for everything, but be super liberal in what // we accept here since we expect all sorts of weird issues as we // version the system. $value[$key] = 'Unknown Object #'.$phid; } } sort($value); $value = implode(', ', $value); } return phutil_tag('span', array('class' => 'condition-test-value'), $value); } private function buildSideNav() { $nav = new AphrontSideNavFilterView(); $nav->setBaseURI(new PhutilURI('/herald/transcript/'.$this->id.'/')); $items = array(); $filters = $this->getFilterMap(); foreach ($filters as $key => $name) { $nav->addFilter($key, $name); } $nav->selectFilter($this->filter, null); return $nav; } protected function getFilterMap() { return array( self::FILTER_ALL => pht('All Rules'), self::FILTER_OWNED => pht('Rules I Own'), self::FILTER_AFFECTED => pht('Rules that Affected Me'), ); } protected function getFilterPHIDs() { return array($this->getRequest()->getUser()->getPHID()); } protected function getTranscriptPHIDs($xscript) { $phids = array(); $object_xscript = $xscript->getObjectTranscript(); if (!$object_xscript) { return array(); } $phids[] = $object_xscript->getPHID(); foreach ($xscript->getApplyTranscripts() as $apply_xscript) { // TODO: This is total hacks. Add another amazing layer of abstraction. $target = (array)$apply_xscript->getTarget(); foreach ($target as $phid) { if ($phid) { $phids[] = $phid; } } } foreach ($xscript->getRuleTranscripts() as $rule_xscript) { $phids[] = $rule_xscript->getRuleOwner(); } $condition_xscripts = $xscript->getConditionTranscripts(); if ($condition_xscripts) { $condition_xscripts = call_user_func_array( 'array_merge', $condition_xscripts); } foreach ($condition_xscripts as $condition_xscript) { switch ($condition_xscript->getFieldName()) { case HeraldAdapter::FIELD_RULE: $phids[] = $condition_xscript->getTestValue(); break; default: $value = $condition_xscript->getTestValue(); // TODO: Also total hacks. if (is_array($value)) { foreach ($value as $phid) { if ($phid) { // TODO: Probably need to make sure this // "looks like" a PHID or decrease the level of hacks here; // this used to be an is_numeric() check in Facebook land. $phids[] = $phid; } } } break; } } return $phids; } protected function filterTranscript($xscript, $filter_phids) { $filter_owned = ($this->filter == self::FILTER_OWNED); $filter_affected = ($this->filter == self::FILTER_AFFECTED); if (!$filter_owned && !$filter_affected) { // No filtering to be done. return; } if (!$xscript->getObjectTranscript()) { return; } $user_phid = $this->getRequest()->getUser()->getPHID(); $keep_apply_xscripts = array(); $keep_rule_xscripts = array(); $filter_phids = array_fill_keys($filter_phids, true); $rule_xscripts = $xscript->getRuleTranscripts(); foreach ($xscript->getApplyTranscripts() as $id => $apply_xscript) { $rule_id = $apply_xscript->getRuleID(); if ($filter_owned) { if (empty($rule_xscripts[$rule_id])) { // No associated rule so you can't own this effect. continue; } if ($rule_xscripts[$rule_id]->getRuleOwner() != $user_phid) { continue; } } else if ($filter_affected) { $targets = (array)$apply_xscript->getTarget(); if (!array_select_keys($filter_phids, $targets)) { continue; } } $keep_apply_xscripts[$id] = true; if ($rule_id) { $keep_rule_xscripts[$rule_id] = true; } } foreach ($rule_xscripts as $rule_id => $rule_xscript) { if ($filter_owned && $rule_xscript->getRuleOwner() == $user_phid) { $keep_rule_xscripts[$rule_id] = true; } } $xscript->setRuleTranscripts( array_intersect_key( $xscript->getRuleTranscripts(), $keep_rule_xscripts)); $xscript->setApplyTranscripts( array_intersect_key( $xscript->getApplyTranscripts(), $keep_apply_xscripts)); $xscript->setConditionTranscripts( array_intersect_key( $xscript->getConditionTranscripts(), $keep_rule_xscripts)); } private function buildWarningPanel(HeraldTranscript $xscript) { $request = $this->getRequest(); $panel = null; if ($xscript->getObjectTranscript()) { $handles = $this->handles; $object_xscript = $xscript->getObjectTranscript(); $handle = $handles[$object_xscript->getPHID()]; if ($handle->getType() == - PhabricatorRepositoryPHIDTypeCommit::TYPECONST) { + PhabricatorRepositoryCommitPHIDType::TYPECONST) { $commit = id(new DiffusionCommitQuery()) ->setViewer($request->getUser()) ->withPHIDs(array($handle->getPHID())) ->executeOne(); if ($commit) { $repository = $commit->getRepository(); if ($repository->isImporting()) { $title = pht( 'The %s repository is still importing.', $repository->getMonogram()); $body = pht( 'Herald rules will not trigger until import completes.'); } else if (!$repository->isTracked()) { $title = pht( 'The %s repository is not tracked.', $repository->getMonogram()); $body = pht( 'Herald rules will not trigger until tracking is enabled.'); } else { return $panel; } $panel = id(new AphrontErrorView()) ->setSeverity(AphrontErrorView::SEVERITY_WARNING) ->setTitle($title) ->appendChild($body); } } } return $panel; } private function buildApplyTranscriptPanel(HeraldTranscript $xscript) { $handles = $this->handles; $adapter = $this->getAdapter(); $rule_type_global = HeraldRuleTypeConfig::RULE_TYPE_GLOBAL; $action_names = $adapter->getActionNameMap($rule_type_global); $list = new PHUIObjectItemListView(); $list->setStates(true); $list->setNoDataString(pht('No actions were taken.')); foreach ($xscript->getApplyTranscripts() as $apply_xscript) { $target = $apply_xscript->getTarget(); switch ($apply_xscript->getAction()) { case HeraldAdapter::ACTION_NOTHING: $target = null; break; case HeraldAdapter::ACTION_FLAG: $target = PhabricatorFlagColor::getColorName($target); break; case HeraldAdapter::ACTION_BLOCK: // Target is a text string. $target = $target; break; default: if (is_array($target) && $target) { foreach ($target as $k => $phid) { if (isset($handles[$phid])) { $target[$k] = $handles[$phid]->getName(); } } $target = implode(', ', $target); } else if (is_string($target)) { $target = $target; } else { $target = ''; } break; } $item = new PHUIObjectItemView(); if ($apply_xscript->getApplied()) { $item->setState(PHUIObjectItemView::STATE_SUCCESS); } else { $item->setState(PHUIObjectItemView::STATE_FAIL); } $rule = idx($action_names, $apply_xscript->getAction(), pht('Unknown')); $item->setHeader(pht('%s: %s', $rule, $target)); $item->addAttribute($apply_xscript->getReason()); $item->addAttribute( pht('Outcome: %s', $apply_xscript->getAppliedReason())); $list->addItem($item); } $box = new PHUIObjectBoxView(); $box->setHeaderText(pht('Actions Taken')); $box->appendChild($list); return $box; } private function buildActionTranscriptPanel(HeraldTranscript $xscript) { $action_xscript = mgroup($xscript->getApplyTranscripts(), 'getRuleID'); $adapter = $this->getAdapter(); $field_names = $adapter->getFieldNameMap(); $condition_names = $adapter->getConditionNameMap(); $handles = $this->handles; $rule_markup = array(); foreach ($xscript->getRuleTranscripts() as $rule_id => $rule) { $cond_markup = array(); foreach ($xscript->getConditionTranscriptsForRule($rule_id) as $cond) { if ($cond->getNote()) { $note = phutil_tag_div('herald-condition-note', $cond->getNote()); } else { $note = null; } if ($cond->getResult()) { $result = phutil_tag( 'span', array('class' => 'herald-outcome condition-pass'), "\xE2\x9C\x93"); } else { $result = phutil_tag( 'span', array('class' => 'herald-outcome condition-fail'), "\xE2\x9C\x98"); } $cond_markup[] = phutil_tag( 'li', array(), pht( '%s Condition: %s %s %s%s', $result, idx($field_names, $cond->getFieldName(), pht('Unknown')), idx($condition_names, $cond->getCondition(), pht('Unknown')), $this->renderConditionTestValue($cond, $handles), $note)); } if ($rule->getResult()) { $result = phutil_tag( 'span', array('class' => 'herald-outcome rule-pass'), pht('PASS')); $class = 'herald-rule-pass'; } else { $result = phutil_tag( 'span', array('class' => 'herald-outcome rule-fail'), pht('FAIL')); $class = 'herald-rule-fail'; } $cond_markup[] = phutil_tag( 'li', array(), array($result, $rule->getReason())); $user_phid = $this->getRequest()->getUser()->getPHID(); $name = $rule->getRuleName(); $rule_markup[] = phutil_tag( 'li', array( 'class' => $class, ), phutil_tag_div('rule-name', array( phutil_tag('strong', array(), $name), ' ', phutil_tag('ul', array(), $cond_markup), ))); } $box = null; if ($rule_markup) { $box = new PHUIObjectBoxView(); $box->setHeaderText(pht('Rule Details')); $box->appendChild(phutil_tag( 'ul', array('class' => 'herald-explain-list'), $rule_markup)); } return $box; } private function buildObjectTranscriptPanel(HeraldTranscript $xscript) { $adapter = $this->getAdapter(); $field_names = $adapter->getFieldNameMap(); $object_xscript = $xscript->getObjectTranscript(); $data = array(); if ($object_xscript) { $phid = $object_xscript->getPHID(); $handles = $this->handles; $data += array( pht('Object Name') => $object_xscript->getName(), pht('Object Type') => $object_xscript->getType(), pht('Object PHID') => $phid, pht('Object Link') => $handles[$phid]->renderLink(), ); } $data += $xscript->getMetadataMap(); if ($object_xscript) { foreach ($object_xscript->getFields() as $field => $value) { $field = idx($field_names, $field, '['.$field.'?]'); $data['Field: '.$field] = $value; } } $rows = array(); foreach ($data as $name => $value) { if (!($value instanceof PhutilSafeHTML)) { if (!is_scalar($value) && !is_null($value)) { $value = implode("\n", $value); } if (strlen($value) > 256) { $value = phutil_tag( 'textarea', array( 'class' => 'herald-field-value-transcript', ), $value); } } $rows[] = array($name, $value); } $property_list = new PHUIPropertyListView(); $property_list->setStacked(true); foreach ($rows as $row) { $property_list->addProperty($row[0], $row[1]); } $box = new PHUIObjectBoxView(); $box->setHeaderText(pht('Object Transcript')); $box->appendChild($property_list); return $box; } } diff --git a/src/applications/herald/phid/HeraldPHIDTypeRule.php b/src/applications/herald/phid/HeraldRulePHIDType.php similarity index 95% rename from src/applications/herald/phid/HeraldPHIDTypeRule.php rename to src/applications/herald/phid/HeraldRulePHIDType.php index 3db09494d..4820eee62 100644 --- a/src/applications/herald/phid/HeraldPHIDTypeRule.php +++ b/src/applications/herald/phid/HeraldRulePHIDType.php @@ -1,69 +1,69 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $rule = $objects[$phid]; $id = $rule->getID(); $name = $rule->getName(); $handle->setName("H{$id}"); $handle->setFullName("H{$id} {$name}"); $handle->setURI("/herald/rule/{$id}/"); } } public function canLoadNamedObject($name) { return preg_match('/^H\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new HeraldRuleQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/herald/storage/HeraldRule.php b/src/applications/herald/storage/HeraldRule.php index 806eaab96..a9753797e 100644 --- a/src/applications/herald/storage/HeraldRule.php +++ b/src/applications/herald/storage/HeraldRule.php @@ -1,265 +1,265 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(HeraldPHIDTypeRule::TYPECONST); + return PhabricatorPHID::generateNewPHID(HeraldRulePHIDType::TYPECONST); } public function getRuleApplied($phid) { return $this->assertAttachedKey($this->ruleApplied, $phid); } public function setRuleApplied($phid, $applied) { if ($this->ruleApplied === self::ATTACHABLE) { $this->ruleApplied = array(); } $this->ruleApplied[$phid] = $applied; return $this; } public function loadConditions() { if (!$this->getID()) { return array(); } return id(new HeraldCondition())->loadAllWhere( 'ruleID = %d', $this->getID()); } public function attachConditions(array $conditions) { assert_instances_of($conditions, 'HeraldCondition'); $this->conditions = $conditions; return $this; } public function getConditions() { // TODO: validate conditions have been attached. return $this->conditions; } public function loadActions() { if (!$this->getID()) { return array(); } return id(new HeraldAction())->loadAllWhere( 'ruleID = %d', $this->getID()); } public function attachActions(array $actions) { // TODO: validate actions have been attached. assert_instances_of($actions, 'HeraldAction'); $this->actions = $actions; return $this; } public function getActions() { return $this->actions; } public function loadEdits() { if (!$this->getID()) { return array(); } $edits = id(new HeraldRuleEdit())->loadAllWhere( 'ruleID = %d ORDER BY dateCreated DESC', $this->getID()); return $edits; } public function logEdit($editor_phid, $action) { id(new HeraldRuleEdit()) ->setRuleID($this->getID()) ->setRuleName($this->getName()) ->setEditorPHID($editor_phid) ->setAction($action) ->save(); } public function saveConditions(array $conditions) { assert_instances_of($conditions, 'HeraldCondition'); return $this->saveChildren( id(new HeraldCondition())->getTableName(), $conditions); } public function saveActions(array $actions) { assert_instances_of($actions, 'HeraldAction'); return $this->saveChildren( id(new HeraldAction())->getTableName(), $actions); } protected function saveChildren($table_name, array $children) { assert_instances_of($children, 'HeraldDAO'); if (!$this->getID()) { throw new Exception('Save rule before saving children.'); } foreach ($children as $child) { $child->setRuleID($this->getID()); } $this->openTransaction(); queryfx( $this->establishConnection('w'), 'DELETE FROM %T WHERE ruleID = %d', $table_name, $this->getID()); foreach ($children as $child) { $child->save(); } $this->saveTransaction(); } public function delete() { $this->openTransaction(); queryfx( $this->establishConnection('w'), 'DELETE FROM %T WHERE ruleID = %d', id(new HeraldCondition())->getTableName(), $this->getID()); queryfx( $this->establishConnection('w'), 'DELETE FROM %T WHERE ruleID = %d', id(new HeraldAction())->getTableName(), $this->getID()); $result = parent::delete(); $this->saveTransaction(); return $result; } public function hasValidAuthor() { return $this->assertAttached($this->validAuthor); } public function attachValidAuthor($valid) { $this->validAuthor = $valid; return $this; } public function getAuthor() { return $this->assertAttached($this->author); } public function attachAuthor(PhabricatorUser $user) { $this->author = $user; return $this; } public function isGlobalRule() { return ($this->getRuleType() === HeraldRuleTypeConfig::RULE_TYPE_GLOBAL); } public function isPersonalRule() { return ($this->getRuleType() === HeraldRuleTypeConfig::RULE_TYPE_PERSONAL); } public function isObjectRule() { return ($this->getRuleType() == HeraldRuleTypeConfig::RULE_TYPE_OBJECT); } public function attachTriggerObject($trigger_object) { $this->triggerObject = $trigger_object; return $this; } public function getTriggerObject() { return $this->assertAttached($this->triggerObject); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { if ($this->isGlobalRule()) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::POLICY_USER; case PhabricatorPolicyCapability::CAN_EDIT: $app = 'PhabricatorHeraldApplication'; $herald = PhabricatorApplication::getByClass($app); $global = HeraldCapabilityManageGlobalRules::CAPABILITY; return $herald->getPolicy($global); } } else if ($this->isObjectRule()) { return $this->getTriggerObject()->getPolicy($capability); } else { return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { if ($this->isPersonalRule()) { return ($viewer->getPHID() == $this->getAuthorPHID()); } else { return false; } } public function describeAutomaticCapability($capability) { if ($this->isPersonalRule()) { return pht("A personal rule's owner can always view and edit it."); } else if ($this->isObjectRule()) { return pht('Object rules inherit the policies of their objects.'); } return null; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/herald/storage/HeraldRuleTransaction.php b/src/applications/herald/storage/HeraldRuleTransaction.php index 11eb4012b..8046eb1c3 100644 --- a/src/applications/herald/storage/HeraldRuleTransaction.php +++ b/src/applications/herald/storage/HeraldRuleTransaction.php @@ -1,92 +1,92 @@ getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_DISABLE: if ($new) { return 'red'; } else { return 'green'; } } return parent::getColor(); } public function getActionName() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_DISABLE: if ($new) { return pht('Disabled'); } else { return pht('Enabled'); } } return parent::getActionName(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_DISABLE: if ($new) { return 'fa-pause'; } else { return 'fa-play'; } } return parent::getIcon(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_DISABLE: if ($new) { return pht( '%s disabled this rule.', $this->renderHandleLink($author_phid)); } else { return pht( '%s enabled this rule.', $this->renderHandleLink($author_phid)); } } return parent::getTitle(); } } diff --git a/src/applications/legalpad/phid/PhabricatorLegalpadPHIDTypeDocument.php b/src/applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php similarity index 95% rename from src/applications/legalpad/phid/PhabricatorLegalpadPHIDTypeDocument.php rename to src/applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php index f187ee335..5b1a4a983 100644 --- a/src/applications/legalpad/phid/PhabricatorLegalpadPHIDTypeDocument.php +++ b/src/applications/legalpad/phid/PhabricatorLegalpadDocumentPHIDType.php @@ -1,70 +1,70 @@ withPHIDs($phids) ->needDocumentBodies(true); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $document = $objects[$phid]; $name = $document->getDocumentBody()->getTitle(); $handle->setName($document->getMonogram().' '.$name); $handle->setURI('/'.$document->getMonogram()); } } public function canLoadNamedObject($name) { return preg_match('/^L\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new LegalpadDocumentQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php b/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php index 4eae91f7b..6feb42bcc 100644 --- a/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php +++ b/src/applications/legalpad/query/LegalpadDocumentSignatureSearchEngine.php @@ -1,327 +1,327 @@ document = $document; return $this; } public function buildSavedQueryFromRequest(AphrontRequest $request) { $saved = new PhabricatorSavedQuery(); $saved->setParameter( 'signerPHIDs', $this->readUsersFromRequest($request, 'signers')); $saved->setParameter( 'documentPHIDs', $this->readPHIDsFromRequest( $request, 'documents', array( - PhabricatorLegalpadPHIDTypeDocument::TYPECONST, + PhabricatorLegalpadDocumentPHIDType::TYPECONST, ))); $saved->setParameter('nameContains', $request->getStr('nameContains')); $saved->setParameter('emailContains', $request->getStr('emailContains')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new LegalpadDocumentSignatureQuery()); $signer_phids = $saved->getParameter('signerPHIDs', array()); if ($signer_phids) { $query->withSignerPHIDs($signer_phids); } if ($this->document) { $query->withDocumentPHIDs(array($this->document->getPHID())); } else { $document_phids = $saved->getParameter('documentPHIDs', array()); if ($document_phids) { $query->withDocumentPHIDs($document_phids); } } $name_contains = $saved->getParameter('nameContains'); if (strlen($name_contains)) { $query->withNameContains($name_contains); } $email_contains = $saved->getParameter('emailContains'); if (strlen($email_contains)) { $query->withEmailContains($email_contains); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $document_phids = $saved_query->getParameter('documentPHIDs', array()); $signer_phids = $saved_query->getParameter('signerPHIDs', array()); $phids = array_merge($document_phids, $signer_phids); $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($phids) ->execute(); if (!$this->document) { $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource('/typeahead/common/legalpaddocuments/') ->setName('documents') ->setLabel(pht('Documents')) ->setValue(array_select_keys($handles, $document_phids))); } $name_contains = $saved_query->getParameter('nameContains', ''); $email_contains = $saved_query->getParameter('emailContains', ''); $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setName('signers') ->setLabel(pht('Signers')) ->setValue(array_select_keys($handles, $signer_phids))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Name Contains')) ->setName('nameContains') ->setValue($name_contains)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel(pht('Email Contains')) ->setName('emailContains') ->setValue($email_contains)); } protected function getURI($path) { if ($this->document) { return '/legalpad/signatures/'.$this->document->getID().'/'.$path; } else { return '/legalpad/signatures/'.$path; } } public function getBuiltinQueryNames() { $names = array( 'all' => pht('All Signatures'), ); return $names; } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function getRequiredHandlePHIDsForResultList( array $signatures, PhabricatorSavedQuery $query) { return array_merge( mpull($signatures, 'getSignerPHID'), mpull($signatures, 'getDocumentPHID')); } protected function renderResultList( array $signatures, PhabricatorSavedQuery $query, array $handles) { assert_instances_of($signatures, 'LegalpadDocumentSignature'); $viewer = $this->requireViewer(); Javelin::initBehavior('phabricator-tooltips'); $sig_good = $this->renderIcon( 'fa-check', null, pht('Verified, Current')); $sig_corp = $this->renderIcon( 'fa-building-o', null, pht('Verified, Corporate')); $sig_old = $this->renderIcon( 'fa-clock-o', 'orange', pht('Signed Older Version')); $sig_unverified = $this->renderIcon( 'fa-envelope', 'red', pht('Unverified Email')); $sig_exemption = $this->renderIcon( 'fa-asterisk', 'indigo', pht('Exemption')); id(new PHUIIconView()) ->setIconFont('fa-envelope', 'red') ->addSigil('has-tooltip') ->setMetadata(array('tip' => pht('Unverified Email'))); $type_corporate = LegalpadDocument::SIGNATURE_TYPE_CORPORATION; $rows = array(); foreach ($signatures as $signature) { $name = $signature->getSignerName(); $email = $signature->getSignerEmail(); $document = $signature->getDocument(); if ($signature->getIsExemption()) { $sig_icon = $sig_exemption; } else if (!$signature->isVerified()) { $sig_icon = $sig_unverified; } else if ($signature->getDocumentVersion() != $document->getVersions()) { $sig_icon = $sig_old; } else if ($signature->getSignatureType() == $type_corporate) { $sig_icon = $sig_corp; } else { $sig_icon = $sig_good; } $signature_href = $this->getApplicationURI( 'signature/'.$signature->getID().'/'); $sig_icon = javelin_tag( 'a', array( 'href' => $signature_href, 'sigil' => 'workflow', ), $sig_icon); $signer_phid = $signature->getSignerPHID(); $rows[] = array( $sig_icon, $handles[$document->getPHID()]->renderLink(), $signer_phid ? $handles[$signer_phid]->renderLink() : null, $name, phutil_tag( 'a', array( 'href' => 'mailto:'.$email, ), $email), phabricator_datetime($signature->getDateCreated(), $viewer), ); } $table = id(new AphrontTableView($rows)) ->setNoDataString(pht('No signatures match the query.')) ->setHeaders( array( '', pht('Document'), pht('Account'), pht('Name'), pht('Email'), pht('Signed'), )) ->setColumnVisibility( array( true, // Only show the "Document" column if we aren't scoped to a // particular document. !$this->document, )) ->setColumnClasses( array( '', '', '', '', 'wide', 'right', )); $header = id(new PHUIHeaderView()) ->setHeader(pht('Signatures')); if ($this->document) { $document_id = $this->document->getID(); $header->addActionLink( id(new PHUIButtonView()) ->setText(pht('Add Signature Exemption')) ->setTag('a') ->setHref($this->getApplicationURI('addsignature/'.$document_id.'/')) ->setWorkflow(true) ->setIcon(id(new PHUIIconView())->setIconFont('fa-pencil'))); } $box = id(new PHUIObjectBoxView()) ->setHeader($header) ->appendChild($table); if (!$this->document) { $policy_notice = id(new AphrontErrorView()) ->setSeverity(AphrontErrorView::SEVERITY_NOTICE) ->setErrors( array( pht( 'NOTE: You can only see your own signatures and signatures on '. 'documents you have permission to edit.'), )); $box->setErrorView($policy_notice); } return $box; } private function renderIcon($icon, $color, $title) { Javelin::initBehavior('phabricator-tooltips'); return array( id(new PHUIIconView()) ->setIconFont($icon, $color) ->addSigil('has-tooltip') ->setMetadata(array('tip' => $title)), javelin_tag( 'span', array( 'aural' => true, ), $title), ); } } diff --git a/src/applications/legalpad/storage/LegalpadDocument.php b/src/applications/legalpad/storage/LegalpadDocument.php index 265731b89..d59f853c0 100644 --- a/src/applications/legalpad/storage/LegalpadDocument.php +++ b/src/applications/legalpad/storage/LegalpadDocument.php @@ -1,230 +1,230 @@ setViewer($actor) ->withClasses(array('PhabricatorLegalpadApplication')) ->executeOne(); $view_policy = $app->getPolicy(LegalpadCapabilityDefaultView::CAPABILITY); $edit_policy = $app->getPolicy(LegalpadCapabilityDefaultEdit::CAPABILITY); return id(new LegalpadDocument()) ->setVersions(0) ->setCreatorPHID($actor->getPHID()) ->setContributorCount(0) ->setRecentContributorPHIDs(array()) ->attachSignatures(array()) ->setSignatureType(self::SIGNATURE_TYPE_INDIVIDUAL) ->setPreamble('') ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'recentContributorPHIDs' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorLegalpadPHIDTypeDocument::TYPECONST); + PhabricatorLegalpadDocumentPHIDType::TYPECONST); } public function getDocumentBody() { return $this->assertAttached($this->documentBody); } public function attachDocumentBody(LegalpadDocumentBody $body) { $this->documentBody = $body; return $this; } public function getContributors() { return $this->assertAttached($this->contributors); } public function attachContributors(array $contributors) { $this->contributors = $contributors; return $this; } public function getSignatures() { return $this->assertAttached($this->signatures); } public function attachSignatures(array $signatures) { $this->signatures = $signatures; return $this; } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getMonogram() { return 'L'.$this->getID(); } public function getUserSignature($phid) { return $this->assertAttachedKey($this->userSignatures, $phid); } public function attachUserSignature( $user_phid, LegalpadDocumentSignature $signature = null) { $this->userSignatures[$user_phid] = $signature; return $this; } public static function getSignatureTypeMap() { return array( self::SIGNATURE_TYPE_INDIVIDUAL => pht('Individuals'), self::SIGNATURE_TYPE_CORPORATION => pht('Corporations'), ); } public function getSignatureTypeName() { $type = $this->getSignatureType(); return idx(self::getSignatureTypeMap(), $type, $type); } public function getSignatureTypeIcon() { $type = $this->getSignatureType(); $map = array( self::SIGNATURE_TYPE_INDIVIDUAL => 'fa-user grey', self::SIGNATURE_TYPE_CORPORATION => 'fa-building-o grey', ); return idx($map, $type, 'fa-user grey'); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($this->creatorPHID == $phid); } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $policy = $this->viewPolicy; break; case PhabricatorPolicyCapability::CAN_EDIT: $policy = $this->editPolicy; break; default: $policy = PhabricatorPolicies::POLICY_NOONE; break; } return $policy; } public function hasAutomaticCapability($capability, PhabricatorUser $user) { return ($user->getPHID() == $this->getCreatorPHID()); } public function describeAutomaticCapability($capability) { return pht( 'The author of a document can always view and edit it.'); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new LegalpadDocumentEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new LegalpadTransaction(); } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $bodies = id(new LegalpadDocumentBody())->loadAllWhere( 'documentPHID = %s', $this->getPHID()); foreach ($bodies as $body) { $body->delete(); } $signatures = id(new LegalpadDocumentSignature())->loadAllWhere( 'documentPHID = %s', $this->getPHID()); foreach ($signatures as $signature) { $signature->delete(); } $this->saveTransaction(); } } diff --git a/src/applications/legalpad/storage/LegalpadTransaction.php b/src/applications/legalpad/storage/LegalpadTransaction.php index 1cd4a1dcb..9c81c9f7e 100644 --- a/src/applications/legalpad/storage/LegalpadTransaction.php +++ b/src/applications/legalpad/storage/LegalpadTransaction.php @@ -1,79 +1,79 @@ getOldValue(); switch ($this->getTransactionType()) { case LegalpadTransactionType::TYPE_TITLE: case LegalpadTransactionType::TYPE_TEXT: return ($old === null); case LegalpadTransactionType::TYPE_SIGNATURE_TYPE: return true; } return parent::shouldHide(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case LegalpadTransactionType::TYPE_TITLE: return pht( '%s renamed this document from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); case LegalpadTransactionType::TYPE_TEXT: return pht( "%s updated the document's text.", $this->renderHandleLink($author_phid)); case LegalpadTransactionType::TYPE_PREAMBLE: return pht( '%s updated the preamble.', $this->renderHandleLink($author_phid)); } return parent::getTitle(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case LegalpadTransactionType::TYPE_TITLE: case LegalpadTransactionType::TYPE_TEXT: case LegalpadTransactionType::TYPE_PREAMBLE: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } } diff --git a/src/applications/macro/phid/PhabricatorMacroPHIDTypeMacro.php b/src/applications/macro/phid/PhabricatorMacroMacroPHIDType.php similarity index 92% rename from src/applications/macro/phid/PhabricatorMacroPHIDTypeMacro.php rename to src/applications/macro/phid/PhabricatorMacroMacroPHIDType.php index 9c883b77a..7d2dcfc9a 100644 --- a/src/applications/macro/phid/PhabricatorMacroPHIDTypeMacro.php +++ b/src/applications/macro/phid/PhabricatorMacroMacroPHIDType.php @@ -1,44 +1,44 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $macro = $objects[$phid]; $id = $macro->getID(); $name = $macro->getName(); $handle->setName($name); $handle->setFullName(pht('Image Macro "%s"', $name)); $handle->setURI("/macro/view/{$id}/"); } } } diff --git a/src/applications/macro/query/PhabricatorMacroQuery.php b/src/applications/macro/query/PhabricatorMacroQuery.php index c769e5c32..f07f30858 100644 --- a/src/applications/macro/query/PhabricatorMacroQuery.php +++ b/src/applications/macro/query/PhabricatorMacroQuery.php @@ -1,227 +1,227 @@ pht('Active Macros'), self::STATUS_DISABLED => pht('Disabled Macros'), self::STATUS_ANY => pht('Active and Disabled Macros'), ); } public static function getFlagColorsOptions() { $options = array( '-1' => pht('(No Filtering)'), '-2' => pht('(Marked With Any Flag)'), ); foreach (PhabricatorFlagColor::getColorNameMap() as $color => $name) { $options[$color] = $name; } return $options; } public function withIDs(array $ids) { $this->ids = $ids; return $this; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function withAuthorPHIDs(array $authors) { $this->authors = $authors; return $this; } public function withNameLike($name) { $this->nameLike = $name; return $this; } public function withNames(array $names) { $this->names = $names; return $this; } public function withStatus($status) { $this->status = $status; return $this; } public function withDateCreatedBefore($date_created_before) { $this->dateCreatedBefore = $date_created_before; return $this; } public function withDateCreatedAfter($date_created_after) { $this->dateCreatedAfter = $date_created_after; return $this; } public function withFlagColor($flag_color) { $this->flagColor = $flag_color; return $this; } protected function loadPage() { $macro_table = new PhabricatorFileImageMacro(); $conn = $macro_table->establishConnection('r'); $rows = queryfx_all( $conn, 'SELECT m.* FROM %T m %Q %Q %Q', $macro_table->getTableName(), $this->buildWhereClause($conn), $this->buildOrderClause($conn), $this->buildLimitClause($conn)); return $macro_table->loadAllFromArray($rows); } protected function buildWhereClause(AphrontDatabaseConnection $conn) { $where = array(); if ($this->ids) { $where[] = qsprintf( $conn, 'm.id IN (%Ld)', $this->ids); } if ($this->phids) { $where[] = qsprintf( $conn, 'm.phid IN (%Ls)', $this->phids); } if ($this->authors) { $where[] = qsprintf( $conn, 'm.authorPHID IN (%Ls)', $this->authors); } if ($this->nameLike) { $where[] = qsprintf( $conn, 'm.name LIKE %~', $this->nameLike); } if ($this->names) { $where[] = qsprintf( $conn, 'm.name IN (%Ls)', $this->names); } switch ($this->status) { case self::STATUS_ACTIVE: $where[] = qsprintf( $conn, 'm.isDisabled = 0'); break; case self::STATUS_DISABLED: $where[] = qsprintf( $conn, 'm.isDisabled = 1'); break; case self::STATUS_ANY: break; default: throw new Exception("Unknown status '{$this->status}'!"); } if ($this->dateCreatedAfter) { $where[] = qsprintf( $conn, 'm.dateCreated >= %d', $this->dateCreatedAfter); } if ($this->dateCreatedBefore) { $where[] = qsprintf( $conn, 'm.dateCreated <= %d', $this->dateCreatedBefore); } if ($this->flagColor != '-1' && $this->flagColor !== null) { if ($this->flagColor == '-2') { $flag_colors = array_keys(PhabricatorFlagColor::getColorNameMap()); } else { $flag_colors = array($this->flagColor); } $flags = id(new PhabricatorFlagQuery()) ->withOwnerPHIDs(array($this->getViewer()->getPHID())) - ->withTypes(array(PhabricatorMacroPHIDTypeMacro::TYPECONST)) + ->withTypes(array(PhabricatorMacroMacroPHIDType::TYPECONST)) ->withColors($flag_colors) ->setViewer($this->getViewer()) ->execute(); if (empty($flags)) { throw new PhabricatorEmptyQueryException('No matching flags.'); } else { $where[] = qsprintf( $conn, 'm.phid IN (%Ls)', mpull($flags, 'getObjectPHID')); } } $where[] = $this->buildPagingClause($conn); return $this->formatWhereClause($where); } protected function didFilterPage(array $macros) { $file_phids = mpull($macros, 'getFilePHID'); $files = id(new PhabricatorFileQuery()) ->setViewer($this->getViewer()) ->setParentQuery($this) ->withPHIDs($file_phids) ->execute(); $files = mpull($files, null, 'getPHID'); foreach ($macros as $key => $macro) { $file = idx($files, $macro->getFilePHID()); if (!$file) { unset($macros[$key]); continue; } $macro->attachFile($file); } return $macros; } protected function getPagingColumn() { return 'm.id'; } public function getQueryApplicationClass() { return 'PhabricatorMacroApplication'; } } diff --git a/src/applications/macro/storage/PhabricatorFileImageMacro.php b/src/applications/macro/storage/PhabricatorFileImageMacro.php index 0318c025b..df244a69c 100644 --- a/src/applications/macro/storage/PhabricatorFileImageMacro.php +++ b/src/applications/macro/storage/PhabricatorFileImageMacro.php @@ -1,116 +1,116 @@ file = $file; return $this; } public function getFile() { return $this->assertAttached($this->file); } public function attachAudio(PhabricatorFile $audio = null) { $this->audio = $audio; return $this; } public function getAudio() { return $this->assertAttached($this->audio); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorMacroPHIDTypeMacro::TYPECONST); + PhabricatorMacroMacroPHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new PhabricatorMacroEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new PhabricatorMacroTransaction(); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return false; } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return PhabricatorPolicies::getMostOpenPolicy(); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/macro/storage/PhabricatorMacroTransaction.php b/src/applications/macro/storage/PhabricatorMacroTransaction.php index c2bd27950..11a1f7a32 100644 --- a/src/applications/macro/storage/PhabricatorMacroTransaction.php +++ b/src/applications/macro/storage/PhabricatorMacroTransaction.php @@ -1,303 +1,303 @@ getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_FILE: case PhabricatorMacroTransactionType::TYPE_AUDIO: if ($old !== null) { $phids[] = $old; } $phids[] = $new; break; } return $phids; } public function shouldHide() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_NAME: return ($old === null); } return parent::shouldHide(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_NAME: return pht( '%s renamed this macro from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); break; case PhabricatorMacroTransactionType::TYPE_DISABLED: if ($new) { return pht( '%s disabled this macro.', $this->renderHandleLink($author_phid)); } else { return pht( '%s restored this macro.', $this->renderHandleLink($author_phid)); } break; case PhabricatorMacroTransactionType::TYPE_AUDIO: if (!$old) { return pht( '%s attached audio: %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($new)); } else { return pht( '%s changed the audio for this macro from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($old), $this->renderHandleLink($new)); } case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: switch ($new) { case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: return pht( '%s set the audio to play once.', $this->renderHandleLink($author_phid)); case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: return pht( '%s set the audio to loop.', $this->renderHandleLink($author_phid)); default: return pht( '%s disabled the audio for this macro.', $this->renderHandleLink($author_phid)); } case PhabricatorMacroTransactionType::TYPE_FILE: if ($old === null) { return pht( '%s created this macro.', $this->renderHandleLink($author_phid)); } else { return pht( '%s changed the image for this macro from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($old), $this->renderHandleLink($new)); } break; } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_NAME: return pht( '%s renamed %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); case PhabricatorMacroTransactionType::TYPE_DISABLED: if ($new) { return pht( '%s disabled %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s restored %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } case PhabricatorMacroTransactionType::TYPE_FILE: if ($old === null) { return pht( '%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s updated the image for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } case PhabricatorMacroTransactionType::TYPE_AUDIO: if (!$old) { return pht( '%s attached audio to %s: %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($new)); } else { return pht( '%s changed the audio for %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($old), $this->renderHandleLink($new)); } case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: switch ($new) { case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_ONCE: return pht( '%s set the audio for %s to play once.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorFileImageMacro::AUDIO_BEHAVIOR_LOOP: return pht( '%s set the audio for %s to loop.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); default: return pht( '%s disabled the audio for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } } return parent::getTitleForFeed($story); } public function getActionName() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_NAME: if ($old === null) { return pht('Created'); } else { return pht('Renamed'); } case PhabricatorMacroTransactionType::TYPE_DISABLED: if ($new) { return pht('Disabled'); } else { return pht('Restored'); } case PhabricatorMacroTransactionType::TYPE_FILE: if ($old === null) { return pht('Created'); } else { return pht('Edited Image'); } case PhabricatorMacroTransactionType::TYPE_AUDIO: return pht('Audio'); case PhabricatorMacroTransactionType::TYPE_AUDIO_BEHAVIOR: return pht('Audio Behavior'); } return parent::getActionName(); } public function getActionStrength() { switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_DISABLED: return 2.0; case PhabricatorMacroTransactionType::TYPE_FILE: return 1.5; } return parent::getActionStrength(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_NAME: return 'fa-pencil'; case PhabricatorMacroTransactionType::TYPE_FILE: if ($old === null) { return 'fa-plus'; } else { return 'fa-pencil'; } case PhabricatorMacroTransactionType::TYPE_DISABLED: if ($new) { return 'fa-times'; } else { return 'fa-undo'; } case PhabricatorMacroTransactionType::TYPE_AUDIO: return 'fa-headphones'; } return parent::getIcon(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorMacroTransactionType::TYPE_NAME: return PhabricatorTransactions::COLOR_BLUE; case PhabricatorMacroTransactionType::TYPE_FILE: if ($old === null) { return PhabricatorTransactions::COLOR_GREEN; } else { return PhabricatorTransactions::COLOR_BLUE; } case PhabricatorMacroTransactionType::TYPE_DISABLED: if ($new) { return PhabricatorTransactions::COLOR_BLACK; } else { return PhabricatorTransactions::COLOR_SKY; } } return parent::getColor(); } } diff --git a/src/applications/mailinglists/phid/PhabricatorMailingListPHIDTypeList.php b/src/applications/mailinglists/phid/PhabricatorMailingListListPHIDType.php similarity index 95% rename from src/applications/mailinglists/phid/PhabricatorMailingListPHIDTypeList.php rename to src/applications/mailinglists/phid/PhabricatorMailingListListPHIDType.php index 6f0c0de0f..367a77114 100644 --- a/src/applications/mailinglists/phid/PhabricatorMailingListPHIDTypeList.php +++ b/src/applications/mailinglists/phid/PhabricatorMailingListListPHIDType.php @@ -1,71 +1,71 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $list = $objects[$phid]; $handle->setName($list->getName()); $handle->setURI($list->getURI()); } } public function canLoadNamedObject($name) { return preg_match('/^.+@.+/', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { // Maybe normalize these some day? $id = $name; $id_map[$id][] = $name; } $objects = id(new PhabricatorMailingListQuery()) ->setViewer($query->getViewer()) ->withEmails(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { $email = $object->getEmail(); foreach (idx($id_map, $email, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php b/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php index e506815a0..794560e72 100644 --- a/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php +++ b/src/applications/mailinglists/storage/PhabricatorMetaMTAMailingList.php @@ -1,57 +1,57 @@ true, ) + parent::getConfiguration(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return PhabricatorPolicies::POLICY_USER; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/maniphest/conduit/ConduitAPI_maniphest_Method.php b/src/applications/maniphest/conduit/ConduitAPI_maniphest_Method.php index 19a6963bc..5aed0c3bd 100644 --- a/src/applications/maniphest/conduit/ConduitAPI_maniphest_Method.php +++ b/src/applications/maniphest/conduit/ConduitAPI_maniphest_Method.php @@ -1,299 +1,299 @@ 'Missing or malformed parameter.', ); } protected function buildTaskInfoDictionary(ManiphestTask $task) { $results = $this->buildTaskInfoDictionaries(array($task)); return idx($results, $task->getPHID()); } protected function getTaskFields($is_new) { $fields = array(); if (!$is_new) { $fields += array( 'id' => 'optional int', 'phid' => 'optional int', ); } $fields += array( 'title' => $is_new ? 'required string' : 'optional string', 'description' => 'optional string', 'ownerPHID' => 'optional phid', 'ccPHIDs' => 'optional list', 'priority' => 'optional int', 'projectPHIDs' => 'optional list', 'auxiliary' => 'optional dict', ); if (!$is_new) { $fields += array( 'status' => 'optional int', 'comments' => 'optional string', ); } return $fields; } protected function applyRequest( ManiphestTask $task, ConduitAPIRequest $request, $is_new) { $changes = array(); if ($is_new) { $task->setTitle((string)$request->getValue('title')); $task->setDescription((string)$request->getValue('description')); $changes[ManiphestTransaction::TYPE_STATUS] = ManiphestTaskStatus::getDefaultStatus(); } else { $comments = $request->getValue('comments'); if (!$is_new && $comments !== null) { $changes[PhabricatorTransactions::TYPE_COMMENT] = null; } $title = $request->getValue('title'); if ($title !== null) { $changes[ManiphestTransaction::TYPE_TITLE] = $title; } $desc = $request->getValue('description'); if ($desc !== null) { $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $desc; } $status = $request->getValue('status'); if ($status !== null) { $valid_statuses = ManiphestTaskStatus::getTaskStatusMap(); if (!isset($valid_statuses[$status])) { throw id(new ConduitException('ERR-INVALID-PARAMETER')) ->setErrorDescription('Status set to invalid value.'); } $changes[ManiphestTransaction::TYPE_STATUS] = $status; } } $priority = $request->getValue('priority'); if ($priority !== null) { $valid_priorities = ManiphestTaskPriority::getTaskPriorityMap(); if (!isset($valid_priorities[$priority])) { throw id(new ConduitException('ERR-INVALID-PARAMETER')) ->setErrorDescription('Priority set to invalid value.'); } $changes[ManiphestTransaction::TYPE_PRIORITY] = $priority; } $owner_phid = $request->getValue('ownerPHID'); if ($owner_phid !== null) { $this->validatePHIDList( array($owner_phid), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, 'ownerPHID'); $changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid; } $ccs = $request->getValue('ccPHIDs'); if ($ccs !== null) { $this->validatePHIDList( $ccs, - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, 'ccPHIDS'); $changes[ManiphestTransaction::TYPE_CCS] = $ccs; } $transactions = array(); $project_phids = $request->getValue('projectPHIDs'); if ($project_phids !== null) { $this->validatePHIDList( $project_phids, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, 'projectPHIDS'); $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transactions[] = id(new ManiphestTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $project_type) ->setNewValue( array( '=' => array_fuse($project_phids), )); } $template = new ManiphestTransaction(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); if ($type == PhabricatorTransactions::TYPE_COMMENT) { $transaction->attachComment( id(new ManiphestTransactionComment()) ->setContent($comments)); } else { $transaction->setNewValue($value); } $transactions[] = $transaction; } $field_list = PhabricatorCustomField::getObjectFields( $task, PhabricatorCustomField::ROLE_EDIT); $field_list->readFieldsFromStorage($task); $auxiliary = $request->getValue('auxiliary'); if ($auxiliary) { foreach ($field_list->getFields() as $key => $field) { if (!array_key_exists($key, $auxiliary)) { continue; } $transaction = clone $template; $transaction->setTransactionType( PhabricatorTransactions::TYPE_CUSTOMFIELD); $transaction->setMetadataValue('customfield:key', $key); $transaction->setOldValue( $field->getOldValueForApplicationTransactions()); $transaction->setNewValue($auxiliary[$key]); $transactions[] = $transaction; } } if (!$transactions) { return; } $event = new PhabricatorEvent( PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array( 'task' => $task, 'new' => $is_new, 'transactions' => $transactions, )); $event->setUser($request->getUser()); $event->setConduitRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_CONDUIT, array()); $editor = id(new ManiphestTransactionEditor()) ->setActor($request->getUser()) ->setContentSource($content_source) ->setContinueOnNoEffect(true); if (!$is_new) { $editor->setContinueOnMissingFields(true); } $editor->applyTransactions($task, $transactions); $event = new PhabricatorEvent( PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array( 'task' => $task, 'new' => $is_new, 'transactions' => $transactions, )); $event->setUser($request->getUser()); $event->setConduitRequest($request); PhutilEventEngine::dispatchEvent($event); } protected function buildTaskInfoDictionaries(array $tasks) { assert_instances_of($tasks, 'ManiphestTask'); if (!$tasks) { return array(); } $task_phids = mpull($tasks, 'getPHID'); $all_deps = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($task_phids) ->withEdgeTypes(array(PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK)); $all_deps->execute(); $result = array(); foreach ($tasks as $task) { // TODO: Batch this get as CustomField gets cleaned up. $field_list = PhabricatorCustomField::getObjectFields( $task, PhabricatorCustomField::ROLE_EDIT); $field_list->readFieldsFromStorage($task); $auxiliary = mpull( $field_list->getFields(), 'getValueForStorage', 'getFieldKey'); $task_deps = $all_deps->getDestinationPHIDs( array($task->getPHID()), array(PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK)); $result[$task->getPHID()] = array( 'id' => $task->getID(), 'phid' => $task->getPHID(), 'authorPHID' => $task->getAuthorPHID(), 'ownerPHID' => $task->getOwnerPHID(), 'ccPHIDs' => $task->getCCPHIDs(), 'status' => $task->getStatus(), 'statusName' => ManiphestTaskStatus::getTaskStatusName( $task->getStatus()), 'isClosed' => $task->isClosed(), 'priority' => ManiphestTaskPriority::getTaskPriorityName( $task->getPriority()), 'priorityColor' => ManiphestTaskPriority::getTaskPriorityColor( $task->getPriority()), 'title' => $task->getTitle(), 'description' => $task->getDescription(), 'projectPHIDs' => $task->getProjectPHIDs(), 'uri' => PhabricatorEnv::getProductionURI('/T'.$task->getID()), 'auxiliary' => $auxiliary, 'objectName' => 'T'.$task->getID(), 'dateCreated' => $task->getDateCreated(), 'dateModified' => $task->getDateModified(), 'dependsOnTaskPHIDs' => $task_deps, ); } return $result; } /** * NOTE: This is a temporary stop gap since its easy to make malformed tasks. * Long-term, the values set in @{method:defineParamTypes} will be used to * validate data implicitly within the larger Conduit application. * * TODO: Remove this in favor of generalized Conduit hotness. */ private function validatePHIDList(array $phid_list, $phid_type, $field) { $phid_groups = phid_group_by_type($phid_list); unset($phid_groups[$phid_type]); if (!empty($phid_groups)) { throw id(new ConduitException('ERR-INVALID-PARAMETER')) ->setErrorDescription('One or more PHIDs were invalid for '.$field.'.'); } return true; } } diff --git a/src/applications/maniphest/controller/ManiphestTaskDetailController.php b/src/applications/maniphest/controller/ManiphestTaskDetailController.php index 60a8fe5e7..6a62e314a 100644 --- a/src/applications/maniphest/controller/ManiphestTaskDetailController.php +++ b/src/applications/maniphest/controller/ManiphestTaskDetailController.php @@ -1,701 +1,701 @@ id = $data['id']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $e_title = null; $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); $task = id(new ManiphestTaskQuery()) ->setViewer($user) ->withIDs(array($this->id)) ->executeOne(); if (!$task) { return new Aphront404Response(); } $workflow = $request->getStr('workflow'); $parent_task = null; if ($workflow && is_numeric($workflow)) { $parent_task = id(new ManiphestTaskQuery()) ->setViewer($user) ->withIDs(array($workflow)) ->executeOne(); } $transactions = id(new ManiphestTransactionQuery()) ->setViewer($user) ->withObjectPHIDs(array($task->getPHID())) ->needComments(true) ->execute(); $field_list = PhabricatorCustomField::getObjectFields( $task, PhabricatorCustomField::ROLE_VIEW); $field_list ->setViewer($user) ->readFieldsFromStorage($task); $e_commit = ManiphestTaskHasCommitEdgeType::EDGECONST; $e_dep_on = PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK; $e_dep_by = PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK; $e_rev = ManiphestTaskHasRevisionEdgeType::EDGECONST; $e_mock = PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK; $phid = $task->getPHID(); $query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(array($phid)) ->withEdgeTypes( array( $e_commit, $e_dep_on, $e_dep_by, $e_rev, $e_mock, )); $edges = idx($query->execute(), $phid); $phids = array_fill_keys($query->getDestinationPHIDs(), true); foreach ($task->getCCPHIDs() as $phid) { $phids[$phid] = true; } foreach ($task->getProjectPHIDs() as $phid) { $phids[$phid] = true; } if ($task->getOwnerPHID()) { $phids[$task->getOwnerPHID()] = true; } $phids[$task->getAuthorPHID()] = true; $attached = $task->getAttached(); foreach ($attached as $type => $list) { foreach ($list as $phid => $info) { $phids[$phid] = true; } } if ($parent_task) { $phids[$parent_task->getPHID()] = true; } $phids = array_keys($phids); $this->loadHandles($phids); $handles = $this->getLoadedHandles(); $context_bar = null; if ($parent_task) { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/?parent='.$parent_task->getID(), 'class' => 'green button', ), pht('Create Another Subtask'))); $context_bar->appendChild(hsprintf( 'Created a subtask of %s', $this->getHandle($parent_task->getPHID())->renderLink())); } else if ($workflow == 'create') { $context_bar = new AphrontContextBarView(); $context_bar->addButton(phutil_tag('label', array(), 'Create Another')); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/?template='.$task->getID(), 'class' => 'green button', ), pht('Similar Task'))); $context_bar->addButton(phutil_tag( 'a', array( 'href' => '/maniphest/task/create/', 'class' => 'green button', ), pht('Empty Task'))); $context_bar->appendChild(pht('New task created.')); } $engine = new PhabricatorMarkupEngine(); $engine->setViewer($user); $engine->addObject($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION); foreach ($transactions as $modern_xaction) { if ($modern_xaction->getComment()) { $engine->addObject( $modern_xaction->getComment(), PhabricatorApplicationTransactionComment::MARKUP_FIELD_COMMENT); } } $engine->process(); $resolution_types = ManiphestTaskStatus::getTaskStatusMap(); $transaction_types = array( PhabricatorTransactions::TYPE_COMMENT => pht('Comment'), ManiphestTransaction::TYPE_STATUS => pht('Change Status'), ManiphestTransaction::TYPE_OWNER => pht('Reassign / Claim'), ManiphestTransaction::TYPE_CCS => pht('Add CCs'), ManiphestTransaction::TYPE_PRIORITY => pht('Change Priority'), ManiphestTransaction::TYPE_PROJECTS => pht('Associate Projects'), ); // Remove actions the user doesn't have permission to take. $requires = array( ManiphestTransaction::TYPE_OWNER => ManiphestCapabilityEditAssign::CAPABILITY, ManiphestTransaction::TYPE_PRIORITY => ManiphestCapabilityEditPriority::CAPABILITY, ManiphestTransaction::TYPE_PROJECTS => ManiphestCapabilityEditProjects::CAPABILITY, ManiphestTransaction::TYPE_STATUS => ManiphestCapabilityEditStatus::CAPABILITY, ); foreach ($transaction_types as $type => $name) { if (isset($requires[$type])) { if (!$this->hasApplicationCapability($requires[$type])) { unset($transaction_types[$type]); } } } // Don't show an option to change to the current status, or to change to // the duplicate status explicitly. unset($resolution_types[$task->getStatus()]); unset($resolution_types[ManiphestTaskStatus::getDuplicateStatus()]); // Don't show owner/priority changes for closed tasks, as they don't make // much sense. if ($task->isClosed()) { unset($transaction_types[ManiphestTransaction::TYPE_PRIORITY]); unset($transaction_types[ManiphestTransaction::TYPE_OWNER]); } $default_claim = array( $user->getPHID() => $user->getUsername().' ('.$user->getRealName().')', ); $draft = id(new PhabricatorDraft())->loadOneWhere( 'authorPHID = %s AND draftKey = %s', $user->getPHID(), $task->getPHID()); if ($draft) { $draft_text = $draft->getDraft(); } else { $draft_text = null; } $comment_form = new AphrontFormView(); $comment_form ->setUser($user) ->setWorkflow(true) ->setAction('/maniphest/transaction/save/') ->setEncType('multipart/form-data') ->addHiddenInput('taskID', $task->getID()) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Action')) ->setName('action') ->setOptions($transaction_types) ->setID('transaction-action')) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Status')) ->setName('resolution') ->setControlID('resolution') ->setControlStyle('display: none') ->setOptions($resolution_types)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Assign To')) ->setName('assign_to') ->setControlID('assign_to') ->setControlStyle('display: none') ->setID('assign-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('CCs')) ->setName('ccs') ->setControlID('ccs') ->setControlStyle('display: none') ->setID('cc-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Priority')) ->setName('priority') ->setOptions($priority_map) ->setControlID('priority') ->setControlStyle('display: none') ->setValue($task->getPriority())) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setControlID('projects') ->setControlStyle('display: none') ->setID('projects-tokenizer') ->setDisableBehavior(true)) ->appendChild( id(new AphrontFormFileControl()) ->setLabel(pht('File')) ->setName('file') ->setControlID('file') ->setControlStyle('display: none')) ->appendChild( id(new PhabricatorRemarkupControl()) ->setLabel(pht('Comments')) ->setName('comments') ->setValue($draft_text) ->setID('transaction-comments') ->setUser($user)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue(pht('Submit'))); $control_map = array( ManiphestTransaction::TYPE_STATUS => 'resolution', ManiphestTransaction::TYPE_OWNER => 'assign_to', ManiphestTransaction::TYPE_CCS => 'ccs', ManiphestTransaction::TYPE_PRIORITY => 'priority', ManiphestTransaction::TYPE_PROJECTS => 'projects', ); $projects_source = new PhabricatorProjectDatasource(); $users_source = new PhabricatorPeopleDatasource(); $mailable_source = new PhabricatorMetaMTAMailableDatasource(); $tokenizer_map = array( ManiphestTransaction::TYPE_PROJECTS => array( 'id' => 'projects-tokenizer', 'src' => $projects_source->getDatasourceURI(), 'placeholder' => $projects_source->getPlaceholderText(), ), ManiphestTransaction::TYPE_OWNER => array( 'id' => 'assign-tokenizer', 'src' => $users_source->getDatasourceURI(), 'value' => $default_claim, 'limit' => 1, 'placeholder' => $users_source->getPlaceholderText(), ), ManiphestTransaction::TYPE_CCS => array( 'id' => 'cc-tokenizer', 'src' => $mailable_source->getDatasourceURI(), 'placeholder' => $mailable_source->getPlaceholderText(), ), ); // TODO: Initializing these behaviors for logged out users fatals things. if ($user->isLoggedIn()) { Javelin::initBehavior('maniphest-transaction-controls', array( 'select' => 'transaction-action', 'controlMap' => $control_map, 'tokenizers' => $tokenizer_map, )); Javelin::initBehavior('maniphest-transaction-preview', array( 'uri' => '/maniphest/transaction/preview/'.$task->getID().'/', 'preview' => 'transaction-preview', 'comments' => 'transaction-comments', 'action' => 'transaction-action', 'map' => $control_map, 'tokenizers' => $tokenizer_map, )); } $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $comment_header = $is_serious ? pht('Add Comment') : pht('Weigh In'); $preview_panel = phutil_tag_div( 'aphront-panel-preview', phutil_tag( 'div', array('id' => 'transaction-preview'), phutil_tag_div( 'aphront-panel-preview-loading-text', pht('Loading preview...')))); $timeline = id(new PhabricatorApplicationTransactionView()) ->setUser($user) ->setObjectPHID($task->getPHID()) ->setTransactions($transactions) ->setMarkupEngine($engine); $object_name = 'T'.$task->getID(); $actions = $this->buildActionView($task); $crumbs = $this->buildApplicationCrumbs() ->addTextCrumb($object_name, '/'.$object_name) ->setActionList($actions); $header = $this->buildHeaderView($task); $properties = $this->buildPropertyView( $task, $field_list, $edges, $actions); $description = $this->buildDescriptionView($task, $engine); if (!$user->isLoggedIn()) { // TODO: Eventually, everything should run through this. For now, we're // only using it to get a consistent "Login to Comment" button. $comment_box = id(new PhabricatorApplicationTransactionCommentView()) ->setUser($user) ->setRequestURI($request->getRequestURI()); $preview_panel = null; } else { $comment_box = id(new PHUIObjectBoxView()) ->setFlush(true) ->setHeaderText($comment_header) ->appendChild($comment_form); $timeline->setQuoteTargetID('transaction-comments'); $timeline->setQuoteRef($object_name); } $object_box = id(new PHUIObjectBoxView()) ->setHeader($header) ->addPropertyList($properties); if ($description) { $object_box->addPropertyList($description); } return $this->buildApplicationPage( array( $crumbs, $context_bar, $object_box, $timeline, $comment_box, $preview_panel, ), array( 'title' => 'T'.$task->getID().' '.$task->getTitle(), 'pageObjects' => array($task->getPHID()), )); } private function buildHeaderView(ManiphestTask $task) { $view = id(new PHUIHeaderView()) ->setHeader($task->getTitle()) ->setUser($this->getRequest()->getUser()) ->setPolicyObject($task); $status = $task->getStatus(); $status_name = ManiphestTaskStatus::renderFullDescription($status); $view->addProperty(PHUIHeaderView::PROPERTY_STATUS, $status_name); return $view; } private function buildActionView(ManiphestTask $task) { $viewer = $this->getRequest()->getUser(); $viewer_phid = $viewer->getPHID(); $viewer_is_cc = in_array($viewer_phid, $task->getCCPHIDs()); $id = $task->getID(); $phid = $task->getPHID(); $can_edit = PhabricatorPolicyFilter::hasCapability( $viewer, $task, PhabricatorPolicyCapability::CAN_EDIT); $view = id(new PhabricatorActionListView()) ->setUser($viewer) ->setObject($task) ->setObjectURI($this->getRequest()->getRequestURI()); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Task')) ->setIcon('fa-pencil') ->setHref($this->getApplicationURI("/task/edit/{$id}/")) ->setDisabled(!$can_edit) ->setWorkflow(!$can_edit)); if ($task->getOwnerPHID() === $viewer_phid) { $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Automatically Subscribed')) ->setDisabled(true) ->setIcon('fa-check-circle')); } else { $action = $viewer_is_cc ? 'rem' : 'add'; $name = $viewer_is_cc ? pht('Unsubscribe') : pht('Subscribe'); $icon = $viewer_is_cc ? 'fa-minus-circle' : 'fa-plus-circle'; $view->addAction( id(new PhabricatorActionView()) ->setName($name) ->setHref("/maniphest/subscribe/{$action}/{$id}/") ->setRenderAsForm(true) ->setUser($viewer) ->setIcon($icon)); } $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Merge Duplicates In')) ->setHref("/search/attach/{$phid}/TASK/merge/") ->setWorkflow(true) ->setIcon('fa-compress') ->setDisabled(!$can_edit) ->setWorkflow(true)); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Create Subtask')) ->setHref($this->getApplicationURI("/task/create/?parent={$id}")) ->setIcon('fa-level-down')); $view->addAction( id(new PhabricatorActionView()) ->setName(pht('Edit Blocking Tasks')) ->setHref("/search/attach/{$phid}/TASK/blocks/") ->setWorkflow(true) ->setIcon('fa-link') ->setDisabled(!$can_edit) ->setWorkflow(true)); return $view; } private function buildPropertyView( ManiphestTask $task, PhabricatorCustomFieldList $field_list, array $edges, PhabricatorActionListView $actions) { $viewer = $this->getRequest()->getUser(); $view = id(new PHUIPropertyListView()) ->setUser($viewer) ->setObject($task) ->setActionList($actions); $view->addProperty( pht('Assigned To'), $task->getOwnerPHID() ? $this->getHandle($task->getOwnerPHID())->renderLink() : phutil_tag('em', array(), pht('None'))); $view->addProperty( pht('Priority'), ManiphestTaskPriority::getTaskPriorityName($task->getPriority())); $handles = $this->getLoadedHandles(); $cc_handles = array_select_keys($handles, $task->getCCPHIDs()); $subscriber_html = id(new SubscriptionListStringBuilder()) ->setObjectPHID($task->getPHID()) ->setHandles($cc_handles) ->buildPropertyString(); $view->addProperty(pht('Subscribers'), $subscriber_html); $view->addProperty( pht('Author'), $this->getHandle($task->getAuthorPHID())->renderLink()); $source = $task->getOriginalEmailSource(); if ($source) { $subject = '[T'.$task->getID().'] '.$task->getTitle(); $view->addProperty( pht('From Email'), phutil_tag( 'a', array( 'href' => 'mailto:'.$source.'?subject='.$subject ), $source)); } $project_phids = $task->getProjectPHIDs(); if ($project_phids) { require_celerity_resource('maniphest-task-summary-css'); // If we end up with real-world projects with many hundreds of columns, it // might be better to just load all the edges, then load those columns and // work backward that way, or denormalize this data more. $columns = id(new PhabricatorProjectColumnQuery()) ->setViewer($viewer) ->withProjectPHIDs($project_phids) ->execute(); $columns = mpull($columns, null, 'getPHID'); $column_edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN; $all_column_phids = array_keys($columns); $column_edge_query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(array($task->getPHID())) ->withEdgeTypes(array($column_edge_type)) ->withDestinationPHIDs($all_column_phids); $column_edge_query->execute(); $in_column_phids = array_fuse($column_edge_query->getDestinationPHIDs()); $column_groups = mgroup($columns, 'getProjectPHID'); $project_handles = array(); $project_annotations = array(); foreach ($project_phids as $project_phid) { $handle = $this->getHandle($project_phid); $project_handles[] = $handle; $columns = idx($column_groups, $project_phid, array()); $column = head(array_intersect_key($columns, $in_column_phids)); if ($column) { $column_name = pht('(%s)', $column->getDisplayName()); $column_link = phutil_tag( 'a', array( 'href' => $handle->getURI().'board/', 'class' => 'maniphest-board-link', ), $column_name); $project_annotations[$project_phid] = array( ' ', $column_link); } } $project_rows = id(new PHUIHandleTagListView()) ->setHandles($project_handles) ->setAnnotations($project_annotations); } else { $project_rows = phutil_tag('em', array(), pht('None')); } $view->addProperty(pht('Projects'), $project_rows); $edge_types = array( PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK => pht('Blocks'), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK => pht('Blocked By'), ManiphestTaskHasRevisionEdgeType::EDGECONST => pht('Differential Revisions'), PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK => pht('Pholio Mocks'), ); $revisions_commits = array(); $handles = $this->getLoadedHandles(); $commit_phids = array_keys( $edges[ManiphestTaskHasCommitEdgeType::EDGECONST]); if ($commit_phids) { $commit_drev = PhabricatorEdgeConfig::TYPE_COMMIT_HAS_DREV; $drev_edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($commit_phids) ->withEdgeTypes(array($commit_drev)) ->execute(); foreach ($commit_phids as $phid) { $revisions_commits[$phid] = $handles[$phid]->renderLink(); $revision_phid = key($drev_edges[$phid][$commit_drev]); $revision_handle = idx($handles, $revision_phid); if ($revision_handle) { $task_drev = ManiphestTaskHasRevisionEdgeType::EDGECONST; unset($edges[$task_drev][$revision_phid]); $revisions_commits[$phid] = hsprintf( '%s / %s', $revision_handle->renderLink($revision_handle->getName()), $revisions_commits[$phid]); } } } foreach ($edge_types as $edge_type => $edge_name) { if ($edges[$edge_type]) { $view->addProperty( $edge_name, $this->renderHandlesForPHIDs(array_keys($edges[$edge_type]))); } } if ($revisions_commits) { $view->addProperty( pht('Commits'), phutil_implode_html(phutil_tag('br'), $revisions_commits)); } $attached = $task->getAttached(); if (!is_array($attached)) { $attached = array(); } - $file_infos = idx($attached, PhabricatorFilePHIDTypeFile::TYPECONST); + $file_infos = idx($attached, PhabricatorFileFilePHIDType::TYPECONST); if ($file_infos) { $file_phids = array_keys($file_infos); // TODO: These should probably be handles or something; clean this up // as we sort out file attachments. $files = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs($file_phids) ->execute(); $file_view = new PhabricatorFileLinkListView(); $file_view->setFiles($files); $view->addProperty( pht('Files'), $file_view->render()); } $field_list->appendFieldsToPropertyList( $task, $viewer, $view); $view->invokeWillRenderEvent(); return $view; } private function buildDescriptionView( ManiphestTask $task, PhabricatorMarkupEngine $engine) { $section = null; if (strlen($task->getDescription())) { $section = new PHUIPropertyListView(); $section->addSectionHeader( pht('Description'), PHUIPropertyListView::ICON_SUMMARY); $section->addTextContent( phutil_tag( 'div', array( 'class' => 'phabricator-remarkup', ), $engine->getOutput($task, ManiphestTask::MARKUP_FIELD_DESCRIPTION))); } return $section; } } diff --git a/src/applications/maniphest/controller/ManiphestTaskEditController.php b/src/applications/maniphest/controller/ManiphestTaskEditController.php index b8bf1a701..79ad18b2b 100644 --- a/src/applications/maniphest/controller/ManiphestTaskEditController.php +++ b/src/applications/maniphest/controller/ManiphestTaskEditController.php @@ -1,753 +1,753 @@ id = idx($data, 'id'); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $response_type = $request->getStr('responseType', 'task'); $can_edit_assign = $this->hasApplicationCapability( ManiphestCapabilityEditAssign::CAPABILITY); $can_edit_policies = $this->hasApplicationCapability( ManiphestCapabilityEditPolicies::CAPABILITY); $can_edit_priority = $this->hasApplicationCapability( ManiphestCapabilityEditPriority::CAPABILITY); $can_edit_projects = $this->hasApplicationCapability( ManiphestCapabilityEditProjects::CAPABILITY); $can_edit_status = $this->hasApplicationCapability( ManiphestCapabilityEditStatus::CAPABILITY); $parent_task = null; $template_id = null; if ($this->id) { $task = id(new ManiphestTaskQuery()) ->setViewer($user) ->requireCapabilities( array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, )) ->withIDs(array($this->id)) ->executeOne(); if (!$task) { return new Aphront404Response(); } } else { $task = ManiphestTask::initializeNewTask($user); // We currently do not allow you to set the task status when creating // a new task, although now that statuses are custom it might make // sense. $can_edit_status = false; // These allow task creation with defaults. if (!$request->isFormPost()) { $task->setTitle($request->getStr('title')); if ($can_edit_projects) { $projects = $request->getStr('projects'); if ($projects) { $tokens = $request->getStrList('projects'); - $type_project = PhabricatorProjectPHIDTypeProject::TYPECONST; + $type_project = PhabricatorProjectProjectPHIDType::TYPECONST; foreach ($tokens as $key => $token) { if (phid_get_type($token) == $type_project) { // If this is formatted like a PHID, leave it as-is. continue; } if (preg_match('/^#/', $token)) { // If this already has a "#", leave it as-is. continue; } // Add a "#" prefix. $tokens[$key] = '#'.$token; } $default_projects = id(new PhabricatorObjectQuery()) ->setViewer($user) ->withNames($tokens) ->execute(); $default_projects = mpull($default_projects, 'getPHID'); if ($default_projects) { $task->attachProjectPHIDs($default_projects); } } } if ($can_edit_priority) { $priority = $request->getInt('priority'); if ($priority !== null) { $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if (isset($priority_map[$priority])) { $task->setPriority($priority); } } } $task->setDescription($request->getStr('description')); if ($can_edit_assign) { $assign = $request->getStr('assign'); if (strlen($assign)) { $assign_user = id(new PhabricatorPeopleQuery()) ->setViewer($user) ->withUsernames(array($assign)) ->executeOne(); if (!$assign_user) { $assign_user = id(new PhabricatorPeopleQuery()) ->setViewer($user) ->withPHIDs(array($assign)) ->executeOne(); } if ($assign_user) { $task->setOwnerPHID($assign_user->getPHID()); } } } } $template_id = $request->getInt('template'); // You can only have a parent task if you're creating a new task. $parent_id = $request->getInt('parent'); if ($parent_id) { $parent_task = id(new ManiphestTaskQuery()) ->setViewer($user) ->withIDs(array($parent_id)) ->executeOne(); if (!$template_id) { $template_id = $parent_id; } } } $errors = array(); $e_title = true; $field_list = PhabricatorCustomField::getObjectFields( $task, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($user); $field_list->readFieldsFromStorage($task); $aux_fields = $field_list->getFields(); if ($request->isFormPost()) { $changes = array(); $new_title = $request->getStr('title'); $new_desc = $request->getStr('description'); $new_status = $request->getStr('status'); if (!$task->getID()) { $workflow = 'create'; } else { $workflow = ''; } $changes[ManiphestTransaction::TYPE_TITLE] = $new_title; $changes[ManiphestTransaction::TYPE_DESCRIPTION] = $new_desc; if ($can_edit_status) { $changes[ManiphestTransaction::TYPE_STATUS] = $new_status; } else if (!$task->getID()) { // Create an initial status transaction for the burndown chart. // TODO: We can probably remove this once Facts comes online. $changes[ManiphestTransaction::TYPE_STATUS] = $task->getStatus(); } $owner_tokenizer = $request->getArr('assigned_to'); $owner_phid = reset($owner_tokenizer); if (!strlen($new_title)) { $e_title = pht('Required'); $errors[] = pht('Title is required.'); } $old_values = array(); foreach ($aux_fields as $aux_arr_key => $aux_field) { // TODO: This should be buildFieldTransactionsFromRequest() once we // switch to ApplicationTransactions properly. $aux_old_value = $aux_field->getOldValueForApplicationTransactions(); $aux_field->readValueFromRequest($request); $aux_new_value = $aux_field->getNewValueForApplicationTransactions(); // TODO: We're faking a call to the ApplicaitonTransaction validation // logic here. We need valid objects to pass, but they aren't used // in a meaningful way. For now, build User objects. Once the Maniphest // objects exist, this will switch over automatically. This is a big // hack but shouldn't be long for this world. $placeholder_editor = new PhabricatorUserProfileEditor(); $field_errors = $aux_field->validateApplicationTransactions( $placeholder_editor, PhabricatorTransactions::TYPE_CUSTOMFIELD, array( id(new ManiphestTransaction()) ->setOldValue($aux_old_value) ->setNewValue($aux_new_value), )); foreach ($field_errors as $error) { $errors[] = $error->getMessage(); } $old_values[$aux_field->getFieldKey()] = $aux_old_value; } if ($errors) { $task->setTitle($new_title); $task->setDescription($new_desc); $task->setPriority($request->getInt('priority')); $task->setOwnerPHID($owner_phid); $task->setCCPHIDs($request->getArr('cc')); $task->attachProjectPHIDs($request->getArr('projects')); } else { if ($can_edit_priority) { $changes[ManiphestTransaction::TYPE_PRIORITY] = $request->getInt('priority'); } if ($can_edit_assign) { $changes[ManiphestTransaction::TYPE_OWNER] = $owner_phid; } $changes[ManiphestTransaction::TYPE_CCS] = $request->getArr('cc'); if ($can_edit_projects) { $projects = $request->getArr('projects'); $changes[ManiphestTransaction::TYPE_PROJECTS] = $projects; $column_phid = $request->getStr('columnPHID'); // allow for putting a task in a project column at creation -only- if (!$task->getID() && $column_phid && $projects) { $column = id(new PhabricatorProjectColumnQuery()) ->setViewer($user) ->withProjectPHIDs($projects) ->withPHIDs(array($column_phid)) ->executeOne(); if ($column) { $changes[ManiphestTransaction::TYPE_PROJECT_COLUMN] = array( 'new' => array( 'projectPHID' => $column->getProjectPHID(), 'columnPHIDs' => array($column_phid)), 'old' => array( 'projectPHID' => $column->getProjectPHID(), 'columnPHIDs' => array())); } } } if ($can_edit_policies) { $changes[PhabricatorTransactions::TYPE_VIEW_POLICY] = $request->getStr('viewPolicy'); $changes[PhabricatorTransactions::TYPE_EDIT_POLICY] = $request->getStr('editPolicy'); } $template = new ManiphestTransaction(); $transactions = array(); foreach ($changes as $type => $value) { $transaction = clone $template; $transaction->setTransactionType($type); if ($type == ManiphestTransaction::TYPE_PROJECT_COLUMN) { $transaction->setNewValue($value['new']); $transaction->setOldValue($value['old']); } else if ($type == ManiphestTransaction::TYPE_PROJECTS) { // TODO: Gross. $project_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $transaction ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $project_type) ->setNewValue( array( '=' => array_fuse($value), )); } else { $transaction->setNewValue($value); } $transactions[] = $transaction; } if ($aux_fields) { foreach ($aux_fields as $aux_field) { $transaction = clone $template; $transaction->setTransactionType( PhabricatorTransactions::TYPE_CUSTOMFIELD); $aux_key = $aux_field->getFieldKey(); $transaction->setMetadataValue('customfield:key', $aux_key); $old = idx($old_values, $aux_key); $new = $aux_field->getNewValueForApplicationTransactions(); $transaction->setOldValue($old); $transaction->setNewValue($new); $transactions[] = $transaction; } } if ($transactions) { $is_new = !$task->getID(); $event = new PhabricatorEvent( PhabricatorEventType::TYPE_MANIPHEST_WILLEDITTASK, array( 'task' => $task, 'new' => $is_new, 'transactions' => $transactions, )); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); $task = $event->getValue('task'); $transactions = $event->getValue('transactions'); $editor = id(new ManiphestTransactionEditor()) ->setActor($user) ->setContentSourceFromRequest($request) ->setContinueOnNoEffect(true) ->applyTransactions($task, $transactions); $event = new PhabricatorEvent( PhabricatorEventType::TYPE_MANIPHEST_DIDEDITTASK, array( 'task' => $task, 'new' => $is_new, 'transactions' => $transactions, )); $event->setUser($user); $event->setAphrontRequest($request); PhutilEventEngine::dispatchEvent($event); } if ($parent_task) { id(new PhabricatorEdgeEditor()) ->addEdge( $parent_task->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK, $task->getPHID()) ->save(); $workflow = $parent_task->getID(); } if ($request->isAjax()) { switch ($response_type) { case 'card': $owner = null; if ($task->getOwnerPHID()) { $owner = id(new PhabricatorHandleQuery()) ->setViewer($user) ->withPHIDs(array($task->getOwnerPHID())) ->executeOne(); } $tasks = id(new ProjectBoardTaskCard()) ->setViewer($user) ->setTask($task) ->setOwner($owner) ->setCanEdit(true) ->getItem(); $column_phid = $request->getStr('columnPHID'); $column = id(new PhabricatorProjectColumnQuery()) ->setViewer($user) ->withPHIDs(array($column_phid)) ->executeOne(); if ($column->isDefaultColumn()) { $column_tasks = array(); $potential_col_tasks = id(new ManiphestTaskQuery()) ->setViewer($user) ->withAllProjects(array($column->getProjectPHID())) ->execute(); $potential_col_tasks = mpull( $potential_col_tasks, null, 'getPHID'); $potential_task_phids = array_keys($potential_col_tasks); if ($potential_task_phids) { $edge_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_COLUMN; $edge_query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($potential_task_phids) ->withEdgeTypes(array($edge_type)); $edges = $edge_query->execute(); foreach ($potential_col_tasks as $task_phid => $curr_task) { $curr_column_phids = $edges[$task_phid][$edge_type]; $curr_column_phid = head_key($curr_column_phids); if (!$curr_column_phid || $curr_column_phid == $column_phid) { $column_tasks[] = $curr_task; } } } } else { $column_task_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $column_phid, PhabricatorEdgeConfig::TYPE_COLUMN_HAS_OBJECT); $column_tasks = id(new ManiphestTaskQuery()) ->setViewer($user) ->withPHIDs($column_task_phids) ->execute(); } $sort_map = mpull( $column_tasks, 'getPrioritySortVector', 'getPHID'); $data = array( 'sortMap' => $sort_map, ); break; case 'task': default: $tasks = $this->renderSingleTask($task); $data = array(); break; } return id(new AphrontAjaxResponse())->setContent( array( 'tasks' => $tasks, 'data' => $data, )); } $redirect_uri = '/T'.$task->getID(); if ($workflow) { $redirect_uri .= '?workflow='.$workflow; } return id(new AphrontRedirectResponse()) ->setURI($redirect_uri); } } else { if (!$task->getID()) { $task->setCCPHIDs(array( $user->getPHID(), )); if ($template_id) { $template_task = id(new ManiphestTaskQuery()) ->setViewer($user) ->withIDs(array($template_id)) ->executeOne(); if ($template_task) { $task->setCCPHIDs($template_task->getCCPHIDs()); $task->attachProjectPHIDs($template_task->getProjectPHIDs()); $task->setOwnerPHID($template_task->getOwnerPHID()); $task->setPriority($template_task->getPriority()); $task->setViewPolicy($template_task->getViewPolicy()); $task->setEditPolicy($template_task->getEditPolicy()); $template_fields = PhabricatorCustomField::getObjectFields( $template_task, PhabricatorCustomField::ROLE_EDIT); $fields = $template_fields->getFields(); foreach ($fields as $key => $field) { if (!$field->shouldCopyWhenCreatingSimilarTask()) { unset($fields[$key]); } if (empty($aux_fields[$key])) { unset($fields[$key]); } } if ($fields) { id(new PhabricatorCustomFieldList($fields)) ->setViewer($user) ->readFieldsFromStorage($template_task); foreach ($fields as $key => $field) { $aux_fields[$key]->setValueFromStorage( $field->getValueForStorage()); } } } } } } $phids = array_merge( array($task->getOwnerPHID()), $task->getCCPHIDs(), $task->getProjectPHIDs()); if ($parent_task) { $phids[] = $parent_task->getPHID(); } $phids = array_filter($phids); $phids = array_unique($phids); $handles = $this->loadViewerHandles($phids); $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setErrors($errors); } $priority_map = ManiphestTaskPriority::getTaskPriorityMap(); if ($task->getOwnerPHID()) { $assigned_value = array($handles[$task->getOwnerPHID()]); } else { $assigned_value = array(); } if ($task->getCCPHIDs()) { $cc_value = array_select_keys($handles, $task->getCCPHIDs()); } else { $cc_value = array(); } if ($task->getProjectPHIDs()) { $projects_value = array_select_keys($handles, $task->getProjectPHIDs()); } else { $projects_value = array(); } $cancel_id = nonempty($task->getID(), $template_id); if ($cancel_id) { $cancel_uri = '/T'.$cancel_id; } else { $cancel_uri = '/maniphest/'; } if ($task->getID()) { $button_name = pht('Save Task'); $header_name = pht('Edit Task'); } else if ($parent_task) { $cancel_uri = '/T'.$parent_task->getID(); $button_name = pht('Create Task'); $header_name = pht('Create New Subtask'); } else { $button_name = pht('Create Task'); $header_name = pht('Create New Task'); } require_celerity_resource('maniphest-task-edit-css'); $project_tokenizer_id = celerity_generate_unique_node_id(); $form = new AphrontFormView(); $form ->setUser($user) ->addHiddenInput('template', $template_id) ->addHiddenInput('responseType', $response_type) ->addHiddenInput('columnPHID', $request->getStr('columnPHID')); if ($parent_task) { $form ->appendChild( id(new AphrontFormStaticControl()) ->setLabel(pht('Parent Task')) ->setValue($handles[$parent_task->getPHID()]->getFullName())) ->addHiddenInput('parent', $parent_task->getID()); } $form ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel(pht('Title')) ->setName('title') ->setError($e_title) ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) ->setValue($task->getTitle())); if ($can_edit_status) { // See T4819. $status_map = ManiphestTaskStatus::getTaskStatusMap(); $dup_status = ManiphestTaskStatus::getDuplicateStatus(); if ($task->getStatus() != $dup_status) { unset($status_map[$dup_status]); } $form ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Status')) ->setName('status') ->setValue($task->getStatus()) ->setOptions($status_map)); } $policies = id(new PhabricatorPolicyQuery()) ->setViewer($user) ->setObject($task) ->execute(); if ($can_edit_assign) { $form->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Assigned To')) ->setName('assigned_to') ->setValue($assigned_value) ->setUser($user) ->setDatasource(new PhabricatorPeopleDatasource()) ->setLimit(1)); } $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('CC')) ->setName('cc') ->setValue($cc_value) ->setUser($user) ->setDatasource(new PhabricatorMetaMTAMailableDatasource())); if ($can_edit_priority) { $form ->appendChild( id(new AphrontFormSelectControl()) ->setLabel(pht('Priority')) ->setName('priority') ->setOptions($priority_map) ->setValue($task->getPriority())); } if ($can_edit_policies) { $form ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) ->setPolicyObject($task) ->setPolicies($policies) ->setName('viewPolicy')) ->appendChild( id(new AphrontFormPolicyControl()) ->setUser($user) ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) ->setPolicyObject($task) ->setPolicies($policies) ->setName('editPolicy')); } if ($can_edit_projects) { $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel(pht('Projects')) ->setName('projects') ->setValue($projects_value) ->setID($project_tokenizer_id) ->setCaption( javelin_tag( 'a', array( 'href' => '/project/create/', 'mustcapture' => true, 'sigil' => 'project-create', ), pht('Create New Project'))) ->setDatasource(new PhabricatorProjectDatasource())); } $field_list->appendFieldsToForm($form); require_celerity_resource('aphront-error-view-css'); Javelin::initBehavior('project-create', array( 'tokenizerID' => $project_tokenizer_id, )); $description_control = new PhabricatorRemarkupControl(); // "Upsell" creating tasks via email in create flows if the instance is // configured for this awesomeness. $email_create = PhabricatorEnv::getEnvConfig( 'metamta.maniphest.public-create-email'); if (!$task->getID() && $email_create) { $email_hint = pht( 'You can also create tasks by sending an email to: %s', phutil_tag('tt', array(), $email_create)); $description_control->setCaption($email_hint); } $description_control ->setLabel(pht('Description')) ->setName('description') ->setID('description-textarea') ->setValue($task->getDescription()) ->setUser($user); $form ->appendChild($description_control); if ($request->isAjax()) { $dialog = id(new AphrontDialogView()) ->setUser($user) ->setWidth(AphrontDialogView::WIDTH_FULL) ->setTitle($header_name) ->appendChild( array( $error_view, $form->buildLayoutView(), )) ->addCancelButton($cancel_uri) ->addSubmitButton($button_name); return id(new AphrontDialogResponse())->setDialog($dialog); } $form ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton($cancel_uri) ->setValue($button_name)); $form_box = id(new PHUIObjectBoxView()) ->setHeaderText($header_name) ->setFormErrors($errors) ->setForm($form); $preview = id(new PHUIRemarkupPreviewPanel()) ->setHeader(pht('Description Preview')) ->setControlID('description-textarea') ->setPreviewURI($this->getApplicationURI('task/descriptionpreview/')); if ($task->getID()) { $page_objects = array($task->getPHID()); } else { $page_objects = array(); } $crumbs = $this->buildApplicationCrumbs(); if ($task->getID()) { $crumbs->addTextCrumb('T'.$task->getID(), '/T'.$task->getID()); } $crumbs->addTextCrumb($header_name); return $this->buildApplicationPage( array( $crumbs, $form_box, $preview, ), array( 'title' => $header_name, 'pageObjects' => $page_objects, )); } } diff --git a/src/applications/maniphest/event/ManiphestNameIndexEventListener.php b/src/applications/maniphest/event/ManiphestNameIndexEventListener.php index 089178b9a..15cb072f0 100644 --- a/src/applications/maniphest/event/ManiphestNameIndexEventListener.php +++ b/src/applications/maniphest/event/ManiphestNameIndexEventListener.php @@ -1,25 +1,25 @@ listen(PhabricatorEventType::TYPE_SEARCH_DIDUPDATEINDEX); } public function handleEvent(PhutilEvent $event) { $phid = $event->getValue('phid'); $type = phid_get_type($phid); // For now, we only index projects. - if ($type != PhabricatorProjectPHIDTypeProject::TYPECONST) { + if ($type != PhabricatorProjectProjectPHIDType::TYPECONST) { return; } $document = $event->getValue('document'); ManiphestNameIndex::updateIndex( $phid, $document->getDocumentTitle()); } } diff --git a/src/applications/maniphest/phid/ManiphestPHIDTypeTask.php b/src/applications/maniphest/phid/ManiphestTaskPHIDType.php similarity index 96% rename from src/applications/maniphest/phid/ManiphestPHIDTypeTask.php rename to src/applications/maniphest/phid/ManiphestTaskPHIDType.php index 2f09bd22c..d1a78adc0 100644 --- a/src/applications/maniphest/phid/ManiphestPHIDTypeTask.php +++ b/src/applications/maniphest/phid/ManiphestTaskPHIDType.php @@ -1,76 +1,76 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $task = $objects[$phid]; $id = $task->getID(); $title = $task->getTitle(); $handle->setName("T{$id}"); $handle->setFullName("T{$id}: {$title}"); $handle->setURI("/T{$id}"); if ($task->isClosed()) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } public function canLoadNamedObject($name) { return preg_match('/^T\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new ManiphestTaskQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/maniphest/query/ManiphestTaskQuery.php b/src/applications/maniphest/query/ManiphestTaskQuery.php index b6884723e..7afbd4e0f 100644 --- a/src/applications/maniphest/query/ManiphestTaskQuery.php +++ b/src/applications/maniphest/query/ManiphestTaskQuery.php @@ -1,973 +1,973 @@ authorPHIDs = $authors; return $this; } public function withIDs(array $ids) { $this->taskIDs = $ids; return $this; } public function withPHIDs(array $phids) { $this->taskPHIDs = $phids; return $this; } public function withOwners(array $owners) { $this->includeUnowned = false; foreach ($owners as $k => $phid) { if ($phid == ManiphestTaskOwner::OWNER_UP_FOR_GRABS || $phid === null) { $this->includeUnowned = true; unset($owners[$k]); break; } } $this->ownerPHIDs = $owners; return $this; } public function withAllProjects(array $projects) { $this->includeNoProject = false; foreach ($projects as $k => $phid) { if ($phid == ManiphestTaskOwner::PROJECT_NO_PROJECT) { $this->includeNoProject = true; unset($projects[$k]); } } $this->projectPHIDs = $projects; return $this; } /** * Add an additional "all projects" constraint to existing filters. * * This is used by boards to supplement queries. * * @param list List of project PHIDs to add to any existing constraint. * @return this */ public function addWithAllProjects(array $projects) { if ($this->projectPHIDs === null) { $this->projectPHIDs = array(); } return $this->withAllProjects(array_merge($this->projectPHIDs, $projects)); } public function withoutProjects(array $projects) { $this->xprojectPHIDs = $projects; return $this; } public function withStatus($status) { $this->status = $status; return $this; } public function withStatuses(array $statuses) { $this->statuses = $statuses; return $this; } public function withPriorities(array $priorities) { $this->priorities = $priorities; return $this; } public function withSubscribers(array $subscribers) { $this->subscriberPHIDs = $subscribers; return $this; } public function withFullTextSearch($fulltext_search) { $this->fullTextSearch = $fulltext_search; return $this; } public function setGroupBy($group) { $this->groupBy = $group; return $this; } public function setOrderBy($order) { $this->orderBy = $order; return $this; } public function withAnyProjects(array $projects) { $this->anyProjectPHIDs = $projects; return $this; } public function withAnyUserProjects(array $users) { $this->anyUserProjectPHIDs = $users; return $this; } public function withDateCreatedBefore($date_created_before) { $this->dateCreatedBefore = $date_created_before; return $this; } public function withDateCreatedAfter($date_created_after) { $this->dateCreatedAfter = $date_created_after; return $this; } public function withDateModifiedBefore($date_modified_before) { $this->dateModifiedBefore = $date_modified_before; return $this; } public function withDateModifiedAfter($date_modified_after) { $this->dateModifiedAfter = $date_modified_after; return $this; } public function loadPage() { // TODO: (T603) It is possible for a user to find the PHID of a project // they can't see, then query for tasks in that project and deduce the // identity of unknown/invisible projects. Before we allow the user to // execute a project-based PHID query, we should verify that they // can see the project. $task_dao = new ManiphestTask(); $conn = $task_dao->establishConnection('r'); $where = array(); $where[] = $this->buildTaskIDsWhereClause($conn); $where[] = $this->buildTaskPHIDsWhereClause($conn); $where[] = $this->buildStatusWhereClause($conn); $where[] = $this->buildStatusesWhereClause($conn); $where[] = $this->buildPrioritiesWhereClause($conn); $where[] = $this->buildAuthorWhereClause($conn); $where[] = $this->buildOwnerWhereClause($conn); $where[] = $this->buildSubscriberWhereClause($conn); $where[] = $this->buildProjectWhereClause($conn); $where[] = $this->buildAnyProjectWhereClause($conn); $where[] = $this->buildAnyUserProjectWhereClause($conn); $where[] = $this->buildXProjectWhereClause($conn); $where[] = $this->buildFullTextWhereClause($conn); if ($this->dateCreatedAfter) { $where[] = qsprintf( $conn, 'task.dateCreated >= %d', $this->dateCreatedAfter); } if ($this->dateCreatedBefore) { $where[] = qsprintf( $conn, 'task.dateCreated <= %d', $this->dateCreatedBefore); } if ($this->dateModifiedAfter) { $where[] = qsprintf( $conn, 'task.dateModified >= %d', $this->dateModifiedAfter); } if ($this->dateModifiedBefore) { $where[] = qsprintf( $conn, 'task.dateModified <= %d', $this->dateModifiedBefore); } $where[] = $this->buildPagingClause($conn); $where = $this->formatWhereClause($where); $having = ''; $count = ''; if (count($this->projectPHIDs) > 1) { // We want to treat the query as an intersection query, not a union // query. We sum the project count and require it be the same as the // number of projects we're searching for. $count = ', COUNT(project.dst) projectCount'; $having = qsprintf( $conn, 'HAVING projectCount = %d', count($this->projectPHIDs)); } $order = $this->buildCustomOrderClause($conn); // TODO: Clean up this nonstandardness. if (!$this->getLimit()) { $this->setLimit(self::DEFAULT_PAGE_SIZE); } $group_column = ''; switch ($this->groupBy) { case self::GROUP_PROJECT: $group_column = qsprintf( $conn, ', projectGroupName.indexedObjectPHID projectGroupPHID'); break; } $rows = queryfx_all( $conn, 'SELECT task.* %Q %Q FROM %T task %Q %Q %Q %Q %Q %Q', $count, $group_column, $task_dao->getTableName(), $this->buildJoinsClause($conn), $where, $this->buildGroupClause($conn), $having, $order, $this->buildLimitClause($conn)); switch ($this->groupBy) { case self::GROUP_PROJECT: $data = ipull($rows, null, 'id'); break; default: $data = $rows; break; } $tasks = $task_dao->loadAllFromArray($data); switch ($this->groupBy) { case self::GROUP_PROJECT: $results = array(); foreach ($rows as $row) { $task = clone $tasks[$row['id']]; $task->attachGroupByProjectPHID($row['projectGroupPHID']); $results[] = $task; } $tasks = $results; break; } return $tasks; } protected function willFilterPage(array $tasks) { if ($this->groupBy == self::GROUP_PROJECT) { // We should only return project groups which the user can actually see. $project_phids = mpull($tasks, 'getGroupByProjectPHID'); $projects = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs($project_phids) ->execute(); $projects = mpull($projects, null, 'getPHID'); foreach ($tasks as $key => $task) { if (!$task->getGroupByProjectPHID()) { // This task is either not in any projects, or only in projects // which we're ignoring because they're being queried for explicitly. continue; } if (empty($projects[$task->getGroupByProjectPHID()])) { unset($tasks[$key]); } } } return $tasks; } protected function didFilterPage(array $tasks) { // TODO: Eventually, we should make this optional and introduce a // needProjectPHIDs() method, but for now there's a lot of code which // assumes the data is always populated. $edge_query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(mpull($tasks, 'getPHID')) ->withEdgeTypes( array( PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, )); $edge_query->execute(); foreach ($tasks as $task) { $phids = $edge_query->getDestinationPHIDs(array($task->getPHID())); $task->attachProjectPHIDs($phids); } return $tasks; } private function buildTaskIDsWhereClause(AphrontDatabaseConnection $conn) { if (!$this->taskIDs) { return null; } return qsprintf( $conn, 'id in (%Ld)', $this->taskIDs); } private function buildTaskPHIDsWhereClause(AphrontDatabaseConnection $conn) { if (!$this->taskPHIDs) { return null; } return qsprintf( $conn, 'phid in (%Ls)', $this->taskPHIDs); } private function buildStatusWhereClause(AphrontDatabaseConnection $conn) { static $map = array( self::STATUS_RESOLVED => ManiphestTaskStatus::STATUS_CLOSED_RESOLVED, self::STATUS_WONTFIX => ManiphestTaskStatus::STATUS_CLOSED_WONTFIX, self::STATUS_INVALID => ManiphestTaskStatus::STATUS_CLOSED_INVALID, self::STATUS_SPITE => ManiphestTaskStatus::STATUS_CLOSED_SPITE, self::STATUS_DUPLICATE => ManiphestTaskStatus::STATUS_CLOSED_DUPLICATE, ); switch ($this->status) { case self::STATUS_ANY: return null; case self::STATUS_OPEN: return qsprintf( $conn, 'status IN (%Ls)', ManiphestTaskStatus::getOpenStatusConstants()); case self::STATUS_CLOSED: return qsprintf( $conn, 'status IN (%Ls)', ManiphestTaskStatus::getClosedStatusConstants()); default: $constant = idx($map, $this->status); if (!$constant) { throw new Exception("Unknown status query '{$this->status}'!"); } return qsprintf( $conn, 'status = %s', $constant); } } private function buildStatusesWhereClause(AphrontDatabaseConnection $conn) { if ($this->statuses) { return qsprintf( $conn, 'status IN (%Ls)', $this->statuses); } return null; } private function buildPrioritiesWhereClause(AphrontDatabaseConnection $conn) { if ($this->priorities) { return qsprintf( $conn, 'priority IN (%Ld)', $this->priorities); } return null; } private function buildAuthorWhereClause(AphrontDatabaseConnection $conn) { if (!$this->authorPHIDs) { return null; } return qsprintf( $conn, 'authorPHID in (%Ls)', $this->authorPHIDs); } private function buildOwnerWhereClause(AphrontDatabaseConnection $conn) { if (!$this->ownerPHIDs) { if ($this->includeUnowned === null) { return null; } else if ($this->includeUnowned) { return qsprintf( $conn, 'ownerPHID IS NULL'); } else { return qsprintf( $conn, 'ownerPHID IS NOT NULL'); } } if ($this->includeUnowned) { return qsprintf( $conn, 'ownerPHID IN (%Ls) OR ownerPHID IS NULL', $this->ownerPHIDs); } else { return qsprintf( $conn, 'ownerPHID IN (%Ls)', $this->ownerPHIDs); } } private function buildFullTextWhereClause(AphrontDatabaseConnection $conn) { if (!strlen($this->fullTextSearch)) { return null; } // In doing a fulltext search, we first find all the PHIDs that match the // fulltext search, and then use that to limit the rest of the search $fulltext_query = id(new PhabricatorSavedQuery()) ->setEngineClassName('PhabricatorSearchApplicationSearchEngine') ->setParameter('query', $this->fullTextSearch); // NOTE: Setting this to something larger than 2^53 will raise errors in // ElasticSearch, and billions of results won't fit in memory anyway. $fulltext_query->setParameter('limit', 100000); - $fulltext_query->setParameter('type', ManiphestPHIDTypeTask::TYPECONST); + $fulltext_query->setParameter('type', ManiphestTaskPHIDType::TYPECONST); $engine = PhabricatorSearchEngineSelector::newSelector()->newEngine(); $fulltext_results = $engine->executeSearch($fulltext_query); if (empty($fulltext_results)) { $fulltext_results = array(null); } return qsprintf( $conn, 'phid IN (%Ls)', $fulltext_results); } private function buildSubscriberWhereClause(AphrontDatabaseConnection $conn) { if (!$this->subscriberPHIDs) { return null; } return qsprintf( $conn, 'subscriber.subscriberPHID IN (%Ls)', $this->subscriberPHIDs); } private function buildProjectWhereClause(AphrontDatabaseConnection $conn) { if (!$this->projectPHIDs && !$this->includeNoProject) { return null; } $parts = array(); if ($this->projectPHIDs) { $parts[] = qsprintf( $conn, 'project.dst in (%Ls)', $this->projectPHIDs); } if ($this->includeNoProject) { $parts[] = qsprintf( $conn, 'project.dst IS NULL'); } return '('.implode(') OR (', $parts).')'; } private function buildAnyProjectWhereClause(AphrontDatabaseConnection $conn) { if (!$this->anyProjectPHIDs) { return null; } return qsprintf( $conn, 'anyproject.dst IN (%Ls)', $this->anyProjectPHIDs); } private function buildAnyUserProjectWhereClause( AphrontDatabaseConnection $conn) { if (!$this->anyUserProjectPHIDs) { return null; } $projects = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withMemberPHIDs($this->anyUserProjectPHIDs) ->execute(); $any_user_project_phids = mpull($projects, 'getPHID'); if (!$any_user_project_phids) { throw new PhabricatorEmptyQueryException(); } return qsprintf( $conn, 'anyproject.dst IN (%Ls)', $any_user_project_phids); } private function buildXProjectWhereClause(AphrontDatabaseConnection $conn) { if (!$this->xprojectPHIDs) { return null; } return qsprintf( $conn, 'xproject.dst IS NULL'); } private function buildCustomOrderClause(AphrontDatabaseConnection $conn) { $order = array(); switch ($this->groupBy) { case self::GROUP_NONE: break; case self::GROUP_PRIORITY: $order[] = 'priority'; break; case self::GROUP_OWNER: $order[] = 'ownerOrdering'; break; case self::GROUP_STATUS: $order[] = 'status'; break; case self::GROUP_PROJECT: $order[] = ''; break; default: throw new Exception("Unknown group query '{$this->groupBy}'!"); } switch ($this->orderBy) { case self::ORDER_PRIORITY: $order[] = 'priority'; $order[] = 'subpriority'; $order[] = 'dateModified'; break; case self::ORDER_CREATED: $order[] = 'id'; break; case self::ORDER_MODIFIED: $order[] = 'dateModified'; break; case self::ORDER_TITLE: $order[] = 'title'; break; default: throw new Exception("Unknown order query '{$this->orderBy}'!"); } $order = array_unique($order); if (empty($order)) { return null; } $reverse = ($this->getBeforeID() xor $this->getReversePaging()); foreach ($order as $k => $column) { switch ($column) { case 'subpriority': case 'ownerOrdering': case 'title': if ($reverse) { $order[$k] = "task.{$column} DESC"; } else { $order[$k] = "task.{$column} ASC"; } break; case '': // Put "No Project" at the end of the list. if ($reverse) { $order[$k] = 'projectGroupName.indexedObjectName IS NULL DESC, '. 'projectGroupName.indexedObjectName DESC'; } else { $order[$k] = 'projectGroupName.indexedObjectName IS NULL ASC, '. 'projectGroupName.indexedObjectName ASC'; } break; default: if ($reverse) { $order[$k] = "task.{$column} ASC"; } else { $order[$k] = "task.{$column} DESC"; } break; } } return 'ORDER BY '.implode(', ', $order); } private function buildJoinsClause(AphrontDatabaseConnection $conn_r) { $edge_table = PhabricatorEdgeConfig::TABLE_NAME_EDGE; $joins = array(); if ($this->projectPHIDs || $this->includeNoProject) { $joins[] = qsprintf( $conn_r, '%Q JOIN %T project ON project.src = task.phid AND project.type = %d', ($this->includeNoProject ? 'LEFT' : ''), $edge_table, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); } if ($this->anyProjectPHIDs || $this->anyUserProjectPHIDs) { $joins[] = qsprintf( $conn_r, 'JOIN %T anyproject ON anyproject.src = task.phid AND anyproject.type = %d', $edge_table, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); } if ($this->xprojectPHIDs) { $joins[] = qsprintf( $conn_r, 'LEFT JOIN %T xproject ON xproject.src = task.phid AND xproject.type = %d AND xproject.dst IN (%Ls)', $edge_table, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, $this->xprojectPHIDs); } if ($this->subscriberPHIDs) { $subscriber_dao = new ManiphestTaskSubscriber(); $joins[] = qsprintf( $conn_r, 'JOIN %T subscriber ON subscriber.taskPHID = task.phid', $subscriber_dao->getTableName()); } switch ($this->groupBy) { case self::GROUP_PROJECT: $ignore_group_phids = $this->getIgnoreGroupedProjectPHIDs(); if ($ignore_group_phids) { $joins[] = qsprintf( $conn_r, 'LEFT JOIN %T projectGroup ON task.phid = projectGroup.src AND projectGroup.type = %d AND projectGroup.dst NOT IN (%Ls)', $edge_table, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, $ignore_group_phids); } else { $joins[] = qsprintf( $conn_r, 'LEFT JOIN %T projectGroup ON task.phid = projectGroup.src AND projectGroup.type = %d', $edge_table, PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); } $joins[] = qsprintf( $conn_r, 'LEFT JOIN %T projectGroupName ON projectGroup.dst = projectGroupName.indexedObjectPHID', id(new ManiphestNameIndex())->getTableName()); break; } $joins[] = $this->buildApplicationSearchJoinClause($conn_r); return implode(' ', $joins); } private function buildGroupClause(AphrontDatabaseConnection $conn_r) { $joined_multiple_rows = (count($this->projectPHIDs) > 1) || (count($this->anyProjectPHIDs) > 1) || ($this->getApplicationSearchMayJoinMultipleRows()); $joined_project_name = ($this->groupBy == self::GROUP_PROJECT); // If we're joining multiple rows, we need to group the results by the // task IDs. if ($joined_multiple_rows) { if ($joined_project_name) { return 'GROUP BY task.phid, projectGroup.dst'; } else { return 'GROUP BY task.phid'; } } else { return ''; } } /** * Return project PHIDs which we should ignore when grouping tasks by * project. For example, if a user issues a query like: * * Tasks in all projects: Frontend, Bugs * * ...then we don't show "Frontend" or "Bugs" groups in the result set, since * they're meaningless as all results are in both groups. * * Similarly, for queries like: * * Tasks in any projects: Public Relations * * ...we ignore the single project, as every result is in that project. (In * the case that there are several "any" projects, we do not ignore them.) * * @return list Project PHIDs which should be ignored in query * construction. */ private function getIgnoreGroupedProjectPHIDs() { $phids = array(); if ($this->projectPHIDs) { $phids[] = $this->projectPHIDs; } if (count($this->anyProjectPHIDs) == 1) { $phids[] = $this->anyProjectPHIDs; } // Maybe we should also exclude the "excludeProjectPHIDs"? It won't // impact the results, but we might end up with a better query plan. // Investigate this on real data? This is likely very rare. return array_mergev($phids); } private function loadCursorObject($id) { $results = id(new ManiphestTaskQuery()) ->setViewer($this->getPagingViewer()) ->withIDs(array((int)$id)) ->execute(); return head($results); } protected function getPagingValue($result) { $id = $result->getID(); switch ($this->groupBy) { case self::GROUP_NONE: return $id; case self::GROUP_PRIORITY: return $id.'.'.$result->getPriority(); case self::GROUP_OWNER: return rtrim($id.'.'.$result->getOwnerPHID(), '.'); case self::GROUP_STATUS: return $id.'.'.$result->getStatus(); case self::GROUP_PROJECT: return rtrim($id.'.'.$result->getGroupByProjectPHID(), '.'); default: throw new Exception("Unknown group query '{$this->groupBy}'!"); } } protected function buildPagingClause(AphrontDatabaseConnection $conn_r) { $default = parent::buildPagingClause($conn_r); $before_id = $this->getBeforeID(); $after_id = $this->getAfterID(); if (!$before_id && !$after_id) { return $default; } $cursor_id = nonempty($before_id, $after_id); $cursor_parts = explode('.', $cursor_id, 2); $task_id = $cursor_parts[0]; $group_id = idx($cursor_parts, 1); $cursor = $this->loadCursorObject($task_id); if (!$cursor) { return null; } $columns = array(); switch ($this->groupBy) { case self::GROUP_NONE: break; case self::GROUP_PRIORITY: $columns[] = array( 'name' => 'task.priority', 'value' => (int)$group_id, 'type' => 'int', ); break; case self::GROUP_OWNER: $columns[] = array( 'name' => '(task.ownerOrdering IS NULL)', 'value' => (int)(strlen($group_id) ? 0 : 1), 'type' => 'int', ); if ($group_id) { $paging_users = id(new PhabricatorPeopleQuery()) ->setViewer($this->getViewer()) ->withPHIDs(array($group_id)) ->execute(); if (!$paging_users) { return null; } $columns[] = array( 'name' => 'task.ownerOrdering', 'value' => head($paging_users)->getUsername(), 'type' => 'string', 'reverse' => true, ); } break; case self::GROUP_STATUS: $columns[] = array( 'name' => 'task.status', 'value' => $group_id, 'type' => 'string', ); break; case self::GROUP_PROJECT: $columns[] = array( 'name' => '(projectGroupName.indexedObjectName IS NULL)', 'value' => (int)(strlen($group_id) ? 0 : 1), 'type' => 'int', ); if ($group_id) { $paging_projects = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs(array($group_id)) ->execute(); if (!$paging_projects) { return null; } $columns[] = array( 'name' => 'projectGroupName.indexedObjectName', 'value' => head($paging_projects)->getName(), 'type' => 'string', 'reverse' => true, ); } break; default: throw new Exception("Unknown group query '{$this->groupBy}'!"); } switch ($this->orderBy) { case self::ORDER_PRIORITY: if ($this->groupBy != self::GROUP_PRIORITY) { $columns[] = array( 'name' => 'task.priority', 'value' => (int)$cursor->getPriority(), 'type' => 'int', ); } $columns[] = array( 'name' => 'task.subpriority', 'value' => (int)$cursor->getSubpriority(), 'type' => 'int', 'reverse' => true, ); $columns[] = array( 'name' => 'task.dateModified', 'value' => (int)$cursor->getDateModified(), 'type' => 'int', ); break; case self::ORDER_CREATED: $columns[] = array( 'name' => 'task.id', 'value' => (int)$cursor->getID(), 'type' => 'int', ); break; case self::ORDER_MODIFIED: $columns[] = array( 'name' => 'task.dateModified', 'value' => (int)$cursor->getDateModified(), 'type' => 'int', ); break; case self::ORDER_TITLE: $columns[] = array( 'name' => 'task.title', 'value' => $cursor->getTitle(), 'type' => 'string', ); $columns[] = array( 'name' => 'task.id', 'value' => $cursor->getID(), 'type' => 'int', ); break; default: throw new Exception("Unknown order query '{$this->orderBy}'!"); } return $this->buildPagingClauseFromMultipleColumns( $conn_r, $columns, array( 'reversed' => (bool)($before_id xor $this->getReversePaging()), )); } protected function getApplicationSearchObjectPHIDColumn() { return 'task.phid'; } public function getQueryApplicationClass() { return 'PhabricatorManiphestApplication'; } } diff --git a/src/applications/maniphest/search/ManiphestSearchIndexer.php b/src/applications/maniphest/search/ManiphestSearchIndexer.php index 67befa46b..290d7c92d 100644 --- a/src/applications/maniphest/search/ManiphestSearchIndexer.php +++ b/src/applications/maniphest/search/ManiphestSearchIndexer.php @@ -1,83 +1,83 @@ loadDocumentByPHID($phid); $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($task->getPHID()); - $doc->setDocumentType(ManiphestPHIDTypeTask::TYPECONST); + $doc->setDocumentType(ManiphestTaskPHIDType::TYPECONST); $doc->setDocumentTitle($task->getTitle()); $doc->setDocumentCreated($task->getDateCreated()); $doc->setDocumentModified($task->getDateModified()); $doc->addField( PhabricatorSearchField::FIELD_BODY, $task->getDescription()); $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $task->getAuthorPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $task->getDateCreated()); $doc->addRelationship( $task->isClosed() ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED : PhabricatorSearchRelationship::RELATIONSHIP_OPEN, $task->getPHID(), - ManiphestPHIDTypeTask::TYPECONST, + ManiphestTaskPHIDType::TYPECONST, time()); $this->indexTransactions( $doc, new ManiphestTransactionQuery(), array($phid)); foreach ($task->getProjectPHIDs() as $phid) { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_PROJECT, $phid, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, $task->getDateModified()); // Bogus. } $owner = $task->getOwnerPHID(); if ($owner) { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_OWNER, $owner, - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, time()); } else { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_UNOWNED, $task->getPHID(), PhabricatorPHIDConstants::PHID_TYPE_VOID, $task->getDateCreated()); } // We need to load handles here since non-users may subscribe (mailing // lists, e.g.) $ccs = $task->getCCPHIDs(); $handles = id(new PhabricatorHandleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs($ccs) ->execute(); foreach ($ccs as $cc) { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_SUBSCRIBER, $handles[$cc]->getPHID(), $handles[$cc]->getType(), time()); } return $doc; } } diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php index b6444d435..b518629a4 100644 --- a/src/applications/maniphest/storage/ManiphestTask.php +++ b/src/applications/maniphest/storage/ManiphestTask.php @@ -1,323 +1,323 @@ setViewer($actor) ->withClasses(array('PhabricatorManiphestApplication')) ->executeOne(); $view_policy = $app->getPolicy(ManiphestCapabilityDefaultView::CAPABILITY); $edit_policy = $app->getPolicy(ManiphestCapabilityDefaultEdit::CAPABILITY); return id(new ManiphestTask()) ->setStatus(ManiphestTaskStatus::getDefaultStatus()) ->setPriority(ManiphestTaskPriority::getDefaultPriority()) ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->attachProjectPHIDs(array()); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'ccPHIDs' => self::SERIALIZATION_JSON, 'attached' => self::SERIALIZATION_JSON, 'projectPHIDs' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function loadDependsOnTaskPHIDs() { return PhabricatorEdgeQuery::loadDestinationPHIDs( $this->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK); } public function loadDependedOnByTaskPHIDs() { return PhabricatorEdgeQuery::loadDestinationPHIDs( $this->getPHID(), PhabricatorEdgeConfig::TYPE_TASK_DEPENDED_ON_BY_TASK); } public function getAttachedPHIDs($type) { return array_keys(idx($this->attached, $type, array())); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(ManiphestPHIDTypeTask::TYPECONST); + return PhabricatorPHID::generateNewPHID(ManiphestTaskPHIDType::TYPECONST); } public function getCCPHIDs() { return array_values(nonempty($this->ccPHIDs, array())); } public function getProjectPHIDs() { return $this->assertAttached($this->edgeProjectPHIDs); } public function attachProjectPHIDs(array $phids) { $this->edgeProjectPHIDs = $phids; return $this; } public function setCCPHIDs(array $phids) { $this->ccPHIDs = array_values($phids); $this->subscribersNeedUpdate = true; return $this; } public function setOwnerPHID($phid) { $this->ownerPHID = nonempty($phid, null); $this->subscribersNeedUpdate = true; return $this; } public function setTitle($title) { $this->title = $title; if (!$this->getID()) { $this->originalTitle = $title; } return $this; } public function getMonogram() { return 'T'.$this->getID(); } public function attachGroupByProjectPHID($phid) { $this->groupByProjectPHID = $phid; return $this; } public function getGroupByProjectPHID() { return $this->assertAttached($this->groupByProjectPHID); } public function save() { if (!$this->mailKey) { $this->mailKey = Filesystem::readRandomCharacters(20); } $result = parent::save(); if ($this->subscribersNeedUpdate) { // If we've changed the subscriber PHIDs for this task, update the link // table. ManiphestTaskSubscriber::updateTaskSubscribers($this); $this->subscribersNeedUpdate = false; } return $result; } public function isClosed() { return ManiphestTaskStatus::isClosedStatus($this->getStatus()); } public function getPrioritySortVector() { return array( $this->getPriority(), -$this->getSubpriority(), ); } /* -( Markup Interface )--------------------------------------------------- */ /** * @task markup */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); $id = $this->getID(); return "maniphest:T{$id}:{$field}:{$hash}"; } /** * @task markup */ public function getMarkupText($field) { return $this->getDescription(); } /** * @task markup */ public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newManiphestMarkupEngine(); } /** * @task markup */ public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } /** * @task markup */ public function shouldUseMarkupCache($field) { return (bool)$this->getID(); } /* -( Policy Interface )--------------------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $user) { // The owner of a task can always view and edit it. $owner_phid = $this->getOwnerPHID(); if ($owner_phid) { $user_phid = $user->getPHID(); if ($user_phid == $owner_phid) { return true; } } return false; } public function describeAutomaticCapability($capability) { return pht('The owner of a task can always view and edit it.'); } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { // Sort of ambiguous who this was intended for; just let them both know. return array_filter( array_unique( array( $this->getAuthorPHID(), $this->getOwnerPHID(), ))); } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('maniphest.fields'); } public function getCustomFieldBaseClass() { return 'ManiphestCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); // TODO: Once this implements PhabricatorTransactionInterface, this // will be handled automatically and can be removed. $xactions = id(new ManiphestTransaction())->loadAllWhere( 'objectPHID = %s', $this->getPHID()); foreach ($xactions as $xaction) { $engine->destroyObject($xaction); } $this->delete(); $this->saveTransaction(); } /* -( PhabricatorApplicationTransactionInterface )------------------------- */ public function getApplicationTransactionEditor() { return new ManiphestTransactionEditor(); } public function getApplicationTransactionObject() { return $this; } public function getApplicationTransactionTemplate() { return new ManiphestTransaction(); } } diff --git a/src/applications/maniphest/storage/ManiphestTransaction.php b/src/applications/maniphest/storage/ManiphestTransaction.php index d3185d661..e663a17c7 100644 --- a/src/applications/maniphest/storage/ManiphestTransaction.php +++ b/src/applications/maniphest/storage/ManiphestTransaction.php @@ -1,830 +1,830 @@ getTransactionType()) { case self::TYPE_PROJECT_COLUMN: case self::TYPE_EDGE: case self::TYPE_UNBLOCK: return false; } return parent::shouldGenerateOldValue(); } public function getRequiredHandlePHIDs() { $phids = parent::getRequiredHandlePHIDs(); $new = $this->getNewValue(); $old = $this->getOldValue(); switch ($this->getTransactionType()) { case self::TYPE_OWNER: if ($new) { $phids[] = $new; } if ($old) { $phids[] = $old; } break; case self::TYPE_CCS: case self::TYPE_PROJECTS: $phids = array_mergev( array( $phids, nonempty($old, array()), nonempty($new, array()), )); break; case self::TYPE_PROJECT_COLUMN: $phids[] = $new['projectPHID']; $phids[] = head($new['columnPHIDs']); break; case self::TYPE_EDGE: $phids = array_mergev( array( $phids, array_keys(nonempty($old, array())), array_keys(nonempty($new, array())), )); break; case self::TYPE_ATTACH: $old = nonempty($old, array()); $new = nonempty($new, array()); $phids = array_mergev( array( $phids, array_keys(idx($new, 'FILE', array())), array_keys(idx($old, 'FILE', array())), )); break; case self::TYPE_UNBLOCK: foreach (array_keys($new) as $phid) { $phids[] = $phid; } break; } return $phids; } public function shouldHide() { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: case self::TYPE_PRIORITY: case self::TYPE_STATUS: if ($this->getOldValue() === null) { return true; } else { return false; } break; case self::TYPE_SUBPRIORITY: return true; } return parent::shouldHide(); } public function getActionStrength() { switch ($this->getTransactionType()) { case self::TYPE_TITLE: return 1.4; case self::TYPE_STATUS: return 1.3; case self::TYPE_OWNER: return 1.2; case self::TYPE_PRIORITY: return 1.1; } return parent::getActionStrength(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_OWNER: if ($this->getAuthorPHID() == $new) { return 'green'; } else if (!$new) { return 'black'; } else if (!$old) { return 'green'; } else { return 'green'; } case self::TYPE_STATUS: $color = ManiphestTaskStatus::getStatusColor($new); if ($color !== null) { return $color; } if (ManiphestTaskStatus::isOpenStatus($new)) { return 'green'; } else { return 'black'; } case self::TYPE_PRIORITY: if ($old == ManiphestTaskPriority::getDefaultPriority()) { return 'green'; } else if ($old > $new) { return 'grey'; } else { return 'yellow'; } } return parent::getColor(); } public function getActionName() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht('Created'); } return pht('Retitled'); case self::TYPE_STATUS: $action = ManiphestTaskStatus::getStatusActionName($new); if ($action) { return $action; } $old_closed = ManiphestTaskStatus::isClosedStatus($old); $new_closed = ManiphestTaskStatus::isClosedStatus($new); if ($new_closed && !$old_closed) { return pht('Closed'); } else if (!$new_closed && $old_closed) { return pht('Reopened'); } else { return pht('Changed Status'); } case self::TYPE_DESCRIPTION: return pht('Edited'); case self::TYPE_OWNER: if ($this->getAuthorPHID() == $new) { return pht('Claimed'); } else if (!$new) { return pht('Up For Grabs'); } else if (!$old) { return pht('Assigned'); } else { return pht('Reassigned'); } case self::TYPE_CCS: return pht('Changed CC'); case self::TYPE_PROJECTS: return pht('Changed Projects'); case self::TYPE_PROJECT_COLUMN: return pht('Changed Project Column'); case self::TYPE_PRIORITY: if ($old == ManiphestTaskPriority::getDefaultPriority()) { return pht('Triaged'); } else if ($old > $new) { return pht('Lowered Priority'); } else { return pht('Raised Priority'); } case self::TYPE_EDGE: case self::TYPE_ATTACH: return pht('Attached'); case self::TYPE_UNBLOCK: $old_status = head($old); $new_status = head($new); $old_closed = ManiphestTaskStatus::isClosedStatus($old_status); $new_closed = ManiphestTaskStatus::isClosedStatus($new_status); if ($old_closed && !$new_closed) { return pht('Block'); } else if (!$old_closed && $new_closed) { return pht('Unblock'); } else { return pht('Blocker'); } } return parent::getActionName(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_OWNER: return 'fa-user'; case self::TYPE_CCS: return 'fa-envelope'; case self::TYPE_TITLE: if ($old === null) { return 'fa-pencil'; } return 'fa-pencil'; case self::TYPE_STATUS: $action = ManiphestTaskStatus::getStatusIcon($new); if ($action !== null) { return $action; } if (ManiphestTaskStatus::isClosedStatus($new)) { return 'fa-check'; } else { return 'fa-pencil'; } case self::TYPE_DESCRIPTION: return 'fa-pencil'; case self::TYPE_PROJECTS: return 'fa-briefcase'; case self::TYPE_PROJECT_COLUMN: return 'fa-columns'; case self::TYPE_PRIORITY: if ($old == ManiphestTaskPriority::getDefaultPriority()) { return 'fa-arrow-right'; } else if ($old > $new) { return 'fa-arrow-down'; } else { return 'fa-arrow-up'; } case self::TYPE_EDGE: case self::TYPE_ATTACH: return 'fa-thumb-tack'; case self::TYPE_UNBLOCK: return 'fa-shield'; } return parent::getIcon(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht( '%s created this task.', $this->renderHandleLink($author_phid)); } return pht( '%s changed the title from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); case self::TYPE_DESCRIPTION: return pht( '%s edited the task description.', $this->renderHandleLink($author_phid)); case self::TYPE_STATUS: $old_closed = ManiphestTaskStatus::isClosedStatus($old); $new_closed = ManiphestTaskStatus::isClosedStatus($new); $old_name = ManiphestTaskStatus::getTaskStatusName($old); $new_name = ManiphestTaskStatus::getTaskStatusName($new); if ($new_closed && !$old_closed) { if ($new == ManiphestTaskStatus::getDuplicateStatus()) { return pht( '%s closed this task as a duplicate.', $this->renderHandleLink($author_phid)); } else { return pht( '%s closed this task as "%s".', $this->renderHandleLink($author_phid), $new_name); } } else if (!$new_closed && $old_closed) { return pht( '%s reopened this task as "%s".', $this->renderHandleLink($author_phid), $new_name); } else { return pht( '%s changed the task status from "%s" to "%s".', $this->renderHandleLink($author_phid), $old_name, $new_name); } case self::TYPE_UNBLOCK: $blocker_phid = key($new); $old_status = head($old); $new_status = head($new); $old_closed = ManiphestTaskStatus::isClosedStatus($old_status); $new_closed = ManiphestTaskStatus::isClosedStatus($new_status); $old_name = ManiphestTaskStatus::getTaskStatusName($old_status); $new_name = ManiphestTaskStatus::getTaskStatusName($new_status); if ($old_closed && !$new_closed) { return pht( '%s reopened blocking task %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $new_name); } else if (!$old_closed && $new_closed) { return pht( '%s closed blocking task %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $new_name); } else { return pht( '%s changed the status of blocking task %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($blocker_phid), $old_name, $new_name); } case self::TYPE_OWNER: if ($author_phid == $new) { return pht( '%s claimed this task.', $this->renderHandleLink($author_phid)); } else if (!$new) { return pht( '%s placed this task up for grabs.', $this->renderHandleLink($author_phid)); } else if (!$old) { return pht( '%s assigned this task to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($new)); } else { return pht( '%s reassigned this task from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($old), $this->renderHandleLink($new)); } case self::TYPE_PROJECTS: $added = array_diff($new, $old); $removed = array_diff($old, $new); if ($added && !$removed) { return pht( '%s added %d project(s): %s', $this->renderHandleLink($author_phid), count($added), $this->renderHandleList($added)); } else if ($removed && !$added) { return pht( '%s removed %d project(s): %s', $this->renderHandleLink($author_phid), count($removed), $this->renderHandleList($removed)); } else if ($removed && $added) { return pht( '%s changed project(s), added %d: %s; removed %d: %s', $this->renderHandleLink($author_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed)); } else { // This is hit when rendering previews. return pht( '%s changed projects...', $this->renderHandleLink($author_phid)); } case self::TYPE_PRIORITY: $old_name = ManiphestTaskPriority::getTaskPriorityName($old); $new_name = ManiphestTaskPriority::getTaskPriorityName($new); if ($old == ManiphestTaskPriority::getDefaultPriority()) { return pht( '%s triaged this task as "%s" priority.', $this->renderHandleLink($author_phid), $new_name); } else if ($old > $new) { return pht( '%s lowered the priority of this task from "%s" to "%s".', $this->renderHandleLink($author_phid), $old_name, $new_name); } else { return pht( '%s raised the priority of this task from "%s" to "%s".', $this->renderHandleLink($author_phid), $old_name, $new_name); } case self::TYPE_CCS: // TODO: Remove this when we switch to subscribers. Just reuse the // code in the parent. $clone = clone $this; $clone->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS); return $clone->getTitle(); case self::TYPE_EDGE: // TODO: Remove this when we switch to real edges. Just reuse the // code in the parent; $clone = clone $this; $clone->setTransactionType(PhabricatorTransactions::TYPE_EDGE); return $clone->getTitle(); case self::TYPE_ATTACH: $old = nonempty($old, array()); $new = nonempty($new, array()); $new = array_keys(idx($new, 'FILE', array())); $old = array_keys(idx($old, 'FILE', array())); $added = array_diff($new, $old); $removed = array_diff($old, $new); if ($added && !$removed) { return pht( '%s attached %d file(s): %s', $this->renderHandleLink($author_phid), count($added), $this->renderHandleList($added)); } else if ($removed && !$added) { return pht( '%s detached %d file(s): %s', $this->renderHandleLink($author_phid), count($removed), $this->renderHandleList($removed)); } else { return pht( '%s changed file(s), attached %d: %s; detached %d: %s', $this->renderHandleLink($author_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed)); } case self::TYPE_PROJECT_COLUMN: $project_phid = $new['projectPHID']; $column_phid = head($new['columnPHIDs']); return pht( '%s moved this task to %s on the %s workboard.', $this->renderHandleLink($author_phid), $this->renderHandleLink($column_phid), $this->renderHandleLink($project_phid)); break; } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht( '%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } return pht( '%s renamed %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); case self::TYPE_DESCRIPTION: return pht( '%s edited the description of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case self::TYPE_STATUS: $old_closed = ManiphestTaskStatus::isClosedStatus($old); $new_closed = ManiphestTaskStatus::isClosedStatus($new); $old_name = ManiphestTaskStatus::getTaskStatusName($old); $new_name = ManiphestTaskStatus::getTaskStatusName($new); if ($new_closed && !$old_closed) { if ($new == ManiphestTaskStatus::getDuplicateStatus()) { return pht( '%s closed %s as a duplicate.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s closed %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name); } } else if (!$new_closed && $old_closed) { return pht( '%s reopened %s as "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name); } else { return pht( '%s changed the status of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name); } case self::TYPE_UNBLOCK: // TODO: We should probably not show these in feed; they're highly // redundant. For now, just use the normal titles. Right now, we can't // publish something to noficiations without also publishing it to feed. // Fix that, then stop these from rendering in feed only. break; case self::TYPE_OWNER: if ($author_phid == $new) { return pht( '%s claimed %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else if (!$new) { return pht( '%s placed %s up for grabs.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else if (!$old) { return pht( '%s assigned %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($new)); } else { return pht( '%s reassigned %s from %s to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($old), $this->renderHandleLink($new)); } case self::TYPE_PROJECTS: $added = array_diff($new, $old); $removed = array_diff($old, $new); if ($added && !$removed) { return pht( '%s added %d project(s) to %s: %s', $this->renderHandleLink($author_phid), count($added), $this->renderHandleLink($object_phid), $this->renderHandleList($added)); } else if ($removed && !$added) { return pht( '%s removed %d project(s) from %s: %s', $this->renderHandleLink($author_phid), count($removed), $this->renderHandleLink($object_phid), $this->renderHandleList($removed)); } else if ($removed && $added) { return pht( '%s changed project(s) of %s, added %d: %s; removed %d: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed)); } case self::TYPE_PRIORITY: $old_name = ManiphestTaskPriority::getTaskPriorityName($old); $new_name = ManiphestTaskPriority::getTaskPriorityName($new); if ($old == ManiphestTaskPriority::getDefaultPriority()) { return pht( '%s triaged %s as "%s" priority.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $new_name); } else if ($old > $new) { return pht( '%s lowered the priority of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name); } else { return pht( '%s raised the priority of %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old_name, $new_name); } case self::TYPE_CCS: // TODO: Remove this when we switch to subscribers. Just reuse the // code in the parent. $clone = clone $this; $clone->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS); return $clone->getTitleForFeed($story); case self::TYPE_EDGE: // TODO: Remove this when we switch to real edges. Just reuse the // code in the parent; $clone = clone $this; $clone->setTransactionType(PhabricatorTransactions::TYPE_EDGE); return $clone->getTitleForFeed($story); case self::TYPE_ATTACH: $old = nonempty($old, array()); $new = nonempty($new, array()); $new = array_keys(idx($new, 'FILE', array())); $old = array_keys(idx($old, 'FILE', array())); $added = array_diff($new, $old); $removed = array_diff($old, $new); if ($added && !$removed) { return pht( '%s attached %d file(s) of %s: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added)); } else if ($removed && !$added) { return pht( '%s detached %d file(s) of %s: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($removed), $this->renderHandleList($removed)); } else { return pht( '%s changed file(s) for %s, attached %d: %s; detached %d: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), count($added), $this->renderHandleList($added), count($removed), $this->renderHandleList($removed)); } case self::TYPE_PROJECT_COLUMN: $project_phid = $new['projectPHID']; $column_phid = head($new['columnPHIDs']); return pht( '%s moved %s to %s on the %s workboard.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $this->renderHandleLink($column_phid), $this->renderHandleLink($project_phid)); break; } return parent::getTitleForFeed($story); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { case self::TYPE_STATUS: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_STATUS; break; case self::TYPE_OWNER: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OWNER; break; case self::TYPE_CCS: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_CC; break; case PhabricatorTransactions::TYPE_EDGE: switch ($this->getMetadataValue('edge:type')) { case PhabricatorProjectObjectHasProjectEdgeType::EDGECONST: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_PROJECTS; break; default: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OTHER; break; } break; case self::TYPE_PRIORITY: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_PRIORITY; break; case PhabricatorTransactions::TYPE_COMMENT: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_COMMENT; break; default: $tags[] = MetaMTANotificationType::TYPE_MANIPHEST_OTHER; break; } return $tags; } public function getNoEffectDescription() { switch ($this->getTransactionType()) { case self::TYPE_STATUS: return pht('The task already has the selected status.'); case self::TYPE_OWNER: return pht('The task already has the selected owner.'); case self::TYPE_PROJECTS: return pht('The task is already associated with those projects.'); case self::TYPE_PRIORITY: return pht('The task already has the selected priority.'); } return parent::getNoEffectDescription(); } } diff --git a/src/applications/meta/phid/PhabricatorApplicationPHIDTypeApplication.php b/src/applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php similarity index 92% rename from src/applications/meta/phid/PhabricatorApplicationPHIDTypeApplication.php rename to src/applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php index d35e43e6e..ffffd112f 100644 --- a/src/applications/meta/phid/PhabricatorApplicationPHIDTypeApplication.php +++ b/src/applications/meta/phid/PhabricatorApplicationApplicationPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $application = $objects[$phid]; $handle->setName($application->getName()); $handle->setURI($application->getApplicationURI()); } } } diff --git a/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php index ff5689d44..58178edb1 100644 --- a/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php +++ b/src/applications/metamta/query/PhabricatorMetaMTAActorQuery.php @@ -1,192 +1,192 @@ viewer = $viewer; return $this; } public function getViewer() { return $this->viewer; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function execute() { $phids = array_fuse($this->phids); $actors = array(); $type_map = array(); foreach ($phids as $phid) { $type_map[phid_get_type($phid)][] = $phid; $actors[$phid] = id(new PhabricatorMetaMTAActor())->setPHID($phid); } // TODO: Move this to PhabricatorPHIDType, or the objects, or some // interface. foreach ($type_map as $type => $phids) { switch ($type) { - case PhabricatorPeoplePHIDTypeUser::TYPECONST: + case PhabricatorPeopleUserPHIDType::TYPECONST: $this->loadUserActors($actors, $phids); break; - case PhabricatorPeoplePHIDTypeExternal::TYPECONST: + case PhabricatorPeopleExternalPHIDType::TYPECONST: $this->loadExternalUserActors($actors, $phids); break; - case PhabricatorMailingListPHIDTypeList::TYPECONST: + case PhabricatorMailingListListPHIDType::TYPECONST: $this->loadMailingListActors($actors, $phids); break; default: $this->loadUnknownActors($actors, $phids); break; } } return $actors; } private function loadUserActors(array $actors, array $phids) { assert_instances_of($actors, 'PhabricatorMetaMTAActor'); $emails = id(new PhabricatorUserEmail())->loadAllWhere( 'userPHID IN (%Ls) AND isPrimary = 1', $phids); $emails = mpull($emails, null, 'getUserPHID'); $users = id(new PhabricatorPeopleQuery()) ->setViewer($this->getViewer()) ->withPHIDs($phids) ->execute(); $users = mpull($users, null, 'getPHID'); foreach ($phids as $phid) { $actor = $actors[$phid]; $user = idx($users, $phid); if (!$user) { $actor->setUndeliverable( pht('Unable to load user record for this PHID.')); } else { $actor->setName($this->getUserName($user)); if ($user->getIsDisabled()) { $actor->setUndeliverable( pht('This user is disabled; disabled users do not receive mail.')); } if ($user->getIsSystemAgent()) { $actor->setUndeliverable( pht('This user is a bot; bot accounts do not receive mail.')); } // NOTE: We do send email to unapproved users, and to unverified users, // because it would otherwise be impossible to get them to verify their // email addresses. Possibly we should white-list this kind of mail and // deny all other types of mail. } $email = idx($emails, $phid); if (!$email) { $actor->setUndeliverable( pht('Unable to load email record for this PHID.')); } else { $actor->setEmailAddress($email->getAddress()); } } } private function loadExternalUserActors(array $actors, array $phids) { assert_instances_of($actors, 'PhabricatorMetaMTAActor'); $xusers = id(new PhabricatorExternalAccountQuery()) ->setViewer($this->getViewer()) ->withPHIDs($phids) ->execute(); $xusers = mpull($xusers, null, 'getPHID'); foreach ($phids as $phid) { $actor = $actors[$phid]; $xuser = idx($xusers, $phid); if (!$xuser) { $actor->setUndeliverable( pht('Unable to load external user record for this PHID.')); continue; } $actor->setName($xuser->getDisplayName()); if ($xuser->getAccountType() != 'email') { $actor->setUndeliverable( pht( 'Only external accounts of type "email" are deliverable; this '. 'account has a different type.')); continue; } $actor->setEmailAddress($xuser->getAccountID()); } } private function loadMailingListActors(array $actors, array $phids) { assert_instances_of($actors, 'PhabricatorMetaMTAActor'); $lists = id(new PhabricatorMailingListQuery()) ->setViewer($this->getViewer()) ->withPHIDs($phids) ->execute(); $lists = mpull($lists, null, 'getPHID'); foreach ($phids as $phid) { $actor = $actors[$phid]; $list = idx($lists, $phid); if (!$list) { $actor->setUndeliverable( pht( 'Unable to load mailing list record for this PHID.')); continue; } $actor->setName($list->getName()); $actor->setEmailAddress($list->getEmail()); } } private function loadUnknownActors(array $actors, array $phids) { foreach ($phids as $phid) { $actor = $actors[$phid]; $actor->setUndeliverable(pht('This PHID type is not mailable.')); } } /** * Small helper function to make sure we format the username properly as * specified by the `metamta.user-address-format` configuration value. */ private function getUserName(PhabricatorUser $user) { $format = PhabricatorEnv::getEnvConfig('metamta.user-address-format'); switch ($format) { case 'short': $name = $user->getUserName(); break; case 'real': $name = strlen($user->getRealName()) ? $user->getRealName() : $user->getUserName(); break; case 'full': default: $name = $user->getFullName(); break; } return $name; } } diff --git a/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php b/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php index f270f0089..34a156964 100644 --- a/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php +++ b/src/applications/metamta/query/PhabricatorMetaMTAMemberQuery.php @@ -1,69 +1,69 @@ viewer = $viewer; return $this; } public function getViewer() { return $this->viewer; } public function withPHIDs(array $phids) { $this->phids = $phids; return $this; } public function execute() { $phids = array_fuse($this->phids); $actors = array(); $type_map = array(); foreach ($phids as $phid) { $type_map[phid_get_type($phid)][] = $phid; } // TODO: Generalize this somewhere else. $results = array(); foreach ($type_map as $type => $phids) { switch ($type) { - case PhabricatorProjectPHIDTypeProject::TYPECONST: + case PhabricatorProjectProjectPHIDType::TYPECONST: // NOTE: We're loading the projects here in order to respect policies. $projects = id(new PhabricatorProjectQuery()) ->setViewer($this->getViewer()) ->withPHIDs($phids) ->execute(); $subscribers = id(new PhabricatorSubscribersQuery()) ->withObjectPHIDs($phids) ->execute(); $projects = mpull($projects, null, 'getPHID'); foreach ($phids as $phid) { $project = idx($projects, $phid); if (!$project) { $results[$phid] = array(); } else { $results[$phid] = idx($subscribers, $phid, array()); } } break; default: break; } } return $results; } } diff --git a/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php b/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php index 64784a196..8ac1c2c9b 100644 --- a/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php +++ b/src/applications/metamta/replyhandler/PhabricatorMailReplyHandler.php @@ -1,331 +1,331 @@ validateMailReceiver($mail_receiver); $this->mailReceiver = $mail_receiver; return $this; } final public function getMailReceiver() { return $this->mailReceiver; } final public function setActor(PhabricatorUser $actor) { $this->actor = $actor; return $this; } final public function getActor() { return $this->actor; } final public function setExcludeMailRecipientPHIDs(array $exclude) { $this->excludePHIDs = $exclude; return $this; } final public function getExcludeMailRecipientPHIDs() { return $this->excludePHIDs; } abstract public function validateMailReceiver($mail_receiver); abstract public function getPrivateReplyHandlerEmailAddress( PhabricatorObjectHandle $handle); public function getReplyHandlerDomain() { return PhabricatorEnv::getEnvConfig( 'metamta.reply-handler-domain'); } abstract public function getReplyHandlerInstructions(); abstract protected function receiveEmail( PhabricatorMetaMTAReceivedMail $mail); public function processEmail(PhabricatorMetaMTAReceivedMail $mail) { $this->dropEmptyMail($mail); return $this->receiveEmail($mail); } private function dropEmptyMail(PhabricatorMetaMTAReceivedMail $mail) { $body = $mail->getCleanTextBody(); $attachments = $mail->getAttachments(); if (strlen($body) || $attachments) { return; } // Only send an error email if the user is talking to just Phabricator. // We can assume if there is only one "To" address it is a Phabricator // address since this code is running and everything. $is_direct_mail = (count($mail->getToAddresses()) == 1) && (count($mail->getCCAddresses()) == 0); if ($is_direct_mail) { $status_code = MetaMTAReceivedMailStatus::STATUS_EMPTY; } else { $status_code = MetaMTAReceivedMailStatus::STATUS_EMPTY_IGNORED; } throw new PhabricatorMetaMTAReceivedMailProcessingException( $status_code, pht( 'Your message does not contain any body text or attachments, so '. 'Phabricator can not do anything useful with it. Make sure comment '. 'text appears at the top of your message: quoted replies, inline '. 'text, and signatures are discarded and ignored.')); } public function supportsPrivateReplies() { return (bool)$this->getReplyHandlerDomain() && !$this->supportsPublicReplies(); } public function supportsPublicReplies() { if (!PhabricatorEnv::getEnvConfig('metamta.public-replies')) { return false; } if (!$this->getReplyHandlerDomain()) { return false; } return (bool)$this->getPublicReplyHandlerEmailAddress(); } final public function supportsReplies() { return $this->supportsPrivateReplies() || $this->supportsPublicReplies(); } public function getPublicReplyHandlerEmailAddress() { return null; } final public function getRecipientsSummary( array $to_handles, array $cc_handles) { assert_instances_of($to_handles, 'PhabricatorObjectHandle'); assert_instances_of($cc_handles, 'PhabricatorObjectHandle'); $body = ''; if (PhabricatorEnv::getEnvConfig('metamta.recipients.show-hints')) { if ($to_handles) { $body .= "To: ".implode(', ', mpull($to_handles, 'getName'))."\n"; } if ($cc_handles) { $body .= "Cc: ".implode(', ', mpull($cc_handles, 'getName'))."\n"; } } return $body; } final public function multiplexMail( PhabricatorMetaMTAMail $mail_template, array $to_handles, array $cc_handles) { assert_instances_of($to_handles, 'PhabricatorObjectHandle'); assert_instances_of($cc_handles, 'PhabricatorObjectHandle'); $result = array(); // If MetaMTA is configured to always multiplex, skip the single-email // case. if (!PhabricatorMetaMTAMail::shouldMultiplexAllMail()) { // If private replies are not supported, simply send one email to all // recipients and CCs. This covers cases where we have no reply handler, // or we have a public reply handler. if (!$this->supportsPrivateReplies()) { $mail = clone $mail_template; $mail->addTos(mpull($to_handles, 'getPHID')); $mail->addCCs(mpull($cc_handles, 'getPHID')); if ($this->supportsPublicReplies()) { $reply_to = $this->getPublicReplyHandlerEmailAddress(); $mail->setReplyTo($reply_to); } $result[] = $mail; return $result; } } // TODO: This is pretty messy. We should really be doing all of this // multiplexing in the task queue, but that requires significant rewriting // in the general case. ApplicationTransactions can do it fairly easily, // but other mail sites currently can not, so we need to support this // junky version until they catch up and we can swap things over. $to_handles = $this->expandRecipientHandles($to_handles); $cc_handles = $this->expandRecipientHandles($cc_handles); $tos = mpull($to_handles, null, 'getPHID'); $ccs = mpull($cc_handles, null, 'getPHID'); // Merge all the recipients together. TODO: We could keep the CCs as real // CCs and send to a "noreply@domain.com" type address, but keep it simple // for now. $recipients = $tos + $ccs; // When multiplexing mail, explicitly include To/Cc information in the // message body and headers. $mail_template = clone $mail_template; $mail_template->addPHIDHeaders('X-Phabricator-To', array_keys($tos)); $mail_template->addPHIDHeaders('X-Phabricator-Cc', array_keys($ccs)); $body = $mail_template->getBody(); $body .= "\n"; $body .= $this->getRecipientsSummary($to_handles, $cc_handles); foreach ($recipients as $phid => $recipient) { $mail = clone $mail_template; if (isset($to_handles[$phid])) { $mail->addTos(array($phid)); } else if (isset($cc_handles[$phid])) { $mail->addCCs(array($phid)); } else { // not good - they should be a to or a cc continue; } $mail->setBody($body); $reply_to = null; if (!$reply_to && $this->supportsPrivateReplies()) { $reply_to = $this->getPrivateReplyHandlerEmailAddress($recipient); } if (!$reply_to && $this->supportsPublicReplies()) { $reply_to = $this->getPublicReplyHandlerEmailAddress(); } if ($reply_to) { $mail->setReplyTo($reply_to); } $result[] = $mail; } return $result; } protected function getDefaultPublicReplyHandlerEmailAddress($prefix) { $receiver = $this->getMailReceiver(); $receiver_id = $receiver->getID(); $domain = $this->getReplyHandlerDomain(); // We compute a hash using the object's own PHID to prevent an attacker // from blindly interacting with objects that they haven't ever received // mail about by just sending to D1@, D2@, etc... $hash = PhabricatorObjectMailReceiver::computeMailHash( $receiver->getMailKey(), $receiver->getPHID()); $address = "{$prefix}{$receiver_id}+public+{$hash}@{$domain}"; return $this->getSingleReplyHandlerPrefix($address); } protected function getSingleReplyHandlerPrefix($address) { $single_handle_prefix = PhabricatorEnv::getEnvConfig( 'metamta.single-reply-handler-prefix'); return ($single_handle_prefix) ? $single_handle_prefix.'+'.$address : $address; } protected function getDefaultPrivateReplyHandlerEmailAddress( PhabricatorObjectHandle $handle, $prefix) { - if ($handle->getType() != PhabricatorPeoplePHIDTypeUser::TYPECONST) { + if ($handle->getType() != PhabricatorPeopleUserPHIDType::TYPECONST) { // You must be a real user to get a private reply handler address. return null; } $user = id(new PhabricatorPeopleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs(array($handle->getPHID())) ->executeOne(); if (!$user) { // This may happen if a user was subscribed to something, and was then // deleted. return null; } $receiver = $this->getMailReceiver(); $receiver_id = $receiver->getID(); $user_id = $user->getID(); $hash = PhabricatorObjectMailReceiver::computeMailHash( $receiver->getMailKey(), $handle->getPHID()); $domain = $this->getReplyHandlerDomain(); $address = "{$prefix}{$receiver_id}+{$user_id}+{$hash}@{$domain}"; return $this->getSingleReplyHandlerPrefix($address); } final protected function enhanceBodyWithAttachments( $body, array $attachments, $format = '- {F%d, layout=link}') { if (!$attachments) { return $body; } // TODO: (T603) What's the policy here? $files = id(new PhabricatorFile()) ->loadAllWhere('phid in (%Ls)', $attachments); // if we have some text then double return before adding our file list if ($body) { $body .= "\n\n"; } foreach ($files as $file) { $file_str = sprintf($format, $file->getID()); $body .= $file_str."\n"; } return rtrim($body); } private function expandRecipientHandles(array $handles) { if (!$handles) { return array(); } $phids = mpull($handles, 'getPHID'); $map = id(new PhabricatorMetaMTAMemberQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs($phids) ->execute(); $results = array(); foreach ($phids as $phid) { if (isset($map[$phid])) { foreach ($map[$phid] as $expanded_phid) { $results[$expanded_phid] = $expanded_phid; } } else { $results[$phid] = $phid; } } return id(new PhabricatorHandleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs($results) ->execute(); } } diff --git a/src/applications/nuance/phid/NuancePHIDTypeItem.php b/src/applications/nuance/phid/NuanceItemPHIDType.php similarity index 91% rename from src/applications/nuance/phid/NuancePHIDTypeItem.php rename to src/applications/nuance/phid/NuanceItemPHIDType.php index 79238343c..e1068cc50 100644 --- a/src/applications/nuance/phid/NuancePHIDTypeItem.php +++ b/src/applications/nuance/phid/NuanceItemPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $item = $objects[$phid]; $handle->setName($item->getLabel($viewer)); $handle->setURI($item->getURI()); } } } diff --git a/src/applications/nuance/phid/NuancePHIDTypeQueue.php b/src/applications/nuance/phid/NuanceQueuePHIDType.php similarity index 91% rename from src/applications/nuance/phid/NuancePHIDTypeQueue.php rename to src/applications/nuance/phid/NuanceQueuePHIDType.php index 3f914e33a..13bcfa5d2 100644 --- a/src/applications/nuance/phid/NuancePHIDTypeQueue.php +++ b/src/applications/nuance/phid/NuanceQueuePHIDType.php @@ -1,38 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $queue = $objects[$phid]; $handle->setName($queue->getName()); $handle->setURI($queue->getURI()); } } } diff --git a/src/applications/nuance/phid/NuancePHIDTypeRequestor.php b/src/applications/nuance/phid/NuanceRequestorPHIDType.php similarity index 91% rename from src/applications/nuance/phid/NuancePHIDTypeRequestor.php rename to src/applications/nuance/phid/NuanceRequestorPHIDType.php index 018c3581c..0e08322a8 100644 --- a/src/applications/nuance/phid/NuancePHIDTypeRequestor.php +++ b/src/applications/nuance/phid/NuanceRequestorPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $requestor = $objects[$phid]; $handle->setName($requestor->getBestName()); $handle->setURI($requestor->getURI()); } } } diff --git a/src/applications/nuance/phid/NuancePHIDTypeSource.php b/src/applications/nuance/phid/NuanceSourcePHIDType.php similarity index 91% rename from src/applications/nuance/phid/NuancePHIDTypeSource.php rename to src/applications/nuance/phid/NuanceSourcePHIDType.php index 2d43d7ef8..d259fe48a 100644 --- a/src/applications/nuance/phid/NuancePHIDTypeSource.php +++ b/src/applications/nuance/phid/NuanceSourcePHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $source = $objects[$phid]; $handle->setName($source->getName()); $handle->setURI($source->getURI()); } } } diff --git a/src/applications/nuance/storage/NuanceItem.php b/src/applications/nuance/storage/NuanceItem.php index 3f32681b4..5f6193d1b 100644 --- a/src/applications/nuance/storage/NuanceItem.php +++ b/src/applications/nuance/storage/NuanceItem.php @@ -1,118 +1,118 @@ setDateNuanced(time()) ->setStatus(NuanceItem::STATUS_OPEN); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'data' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - NuancePHIDTypeItem::TYPECONST); + NuanceItemPHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getURI() { return '/nuance/item/view/'.$this->getID().'/'; } public function getLabel(PhabricatorUser $viewer) { // this is generated at the time the item is created based on // the configuration from the item source. It is typically // something like 'Twitter'. $source_label = $this->getSourceLabel(); return pht( 'Item via %s @ %s.', $source_label, phabricator_datetime($this->getDateCreated(), $viewer)); } public function getRequestor() { return $this->assertAttached($this->requestor); } public function attachRequestor(NuanceRequestor $requestor) { return $this->requestor = $requestor; } public function getSource() { return $this->assertAttached($this->source); } public function attachSource(NuanceSource $source) { $this->source = $source; } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { // TODO - this should be based on the queues the item currently resides in return PhabricatorPolicies::POLICY_USER; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { // TODO - requestors should get auto access too! return $viewer->getPHID() == $this->ownerPHID; } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht('Owners of an item can always view it.'); case PhabricatorPolicyCapability::CAN_EDIT: return pht('Owners of an item can always edit it.'); } return null; } public function toDictionary() { return array( 'id' => $this->getID(), 'phid' => $this->getPHID(), 'ownerPHID' => $this->getOwnerPHID(), 'requestorPHID' => $this->getRequestorPHID(), 'sourcePHID' => $this->getSourcePHID(), 'sourceLabel' => $this->getSourceLabel(), 'dateCreated' => $this->getDateCreated(), 'dateModified' => $this->getDateModified(), 'dateNuanced' => $this->getDateNuanced(), ); } } diff --git a/src/applications/nuance/storage/NuanceItemTransaction.php b/src/applications/nuance/storage/NuanceItemTransaction.php index 6be69da6e..08eef5c68 100644 --- a/src/applications/nuance/storage/NuanceItemTransaction.php +++ b/src/applications/nuance/storage/NuanceItemTransaction.php @@ -1,18 +1,18 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - NuancePHIDTypeQueue::TYPECONST); + NuanceQueuePHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getURI() { return '/nuance/queue/view/'.$this->getID().'/'; } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/nuance/storage/NuanceQueueTransaction.php b/src/applications/nuance/storage/NuanceQueueTransaction.php index b99caec03..0e8ffcfde 100644 --- a/src/applications/nuance/storage/NuanceQueueTransaction.php +++ b/src/applications/nuance/storage/NuanceQueueTransaction.php @@ -1,14 +1,13 @@ true, self::CONFIG_SERIALIZATION => array( 'data' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - NuancePHIDTypeRequestor::TYPECONST); + NuanceRequestorPHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getURI() { return '/nuance/requestor/view/'.$this->getID().'/'; } public function getPhabricatorUserPHID() { return idx($this->getData(), 'phabricatorUserPHID'); } } diff --git a/src/applications/nuance/storage/NuanceRequestorTransaction.php b/src/applications/nuance/storage/NuanceRequestorTransaction.php index 9ed39edaf..d1035cd76 100644 --- a/src/applications/nuance/storage/NuanceRequestorTransaction.php +++ b/src/applications/nuance/storage/NuanceRequestorTransaction.php @@ -1,13 +1,13 @@ true, self::CONFIG_SERIALIZATION => array( 'data' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(NuancePHIDTypeSource::TYPECONST); + return PhabricatorPHID::generateNewPHID(NuanceSourcePHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getURI() { return '/nuance/source/view/'.$this->getID().'/'; } public static function initializeNewSource(PhabricatorUser $actor) { $app = id(new PhabricatorApplicationQuery()) ->setViewer($actor) ->withClasses(array('PhabricatorNuanceApplication')) ->executeOne(); $view_policy = $app->getPolicy( NuanceCapabilitySourceDefaultView::CAPABILITY); $edit_policy = $app->getPolicy( NuanceCapabilitySourceDefaultEdit::CAPABILITY); $definitions = NuanceSourceDefinition::getAllDefinitions(); $lucky_definition = head($definitions); return id(new NuanceSource()) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->setType($lucky_definition->getSourceTypeConstant()); } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/nuance/storage/NuanceSourceTransaction.php b/src/applications/nuance/storage/NuanceSourceTransaction.php index ba7d8e8f0..86f52104d 100644 --- a/src/applications/nuance/storage/NuanceSourceTransaction.php +++ b/src/applications/nuance/storage/NuanceSourceTransaction.php @@ -1,39 +1,39 @@ getOldValue(); $new = $this->getNewValue(); $author_phid = $this->getAuthorPHID(); switch ($this->getTransactionType()) { case self::TYPE_NAME: if ($old === null) { return pht( '%s created this source.', $this->renderHandleLink($author_phid)); } else { return pht( '%s renamed this source from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; } } } diff --git a/src/applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClientAuthorization.php b/src/applications/oauthserver/phid/PhabricatorOAuthServerClientAuthorizationPHIDType.php similarity index 91% rename from src/applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClientAuthorization.php rename to src/applications/oauthserver/phid/PhabricatorOAuthServerClientAuthorizationPHIDType.php index 9618ec1f8..e3ff50a6f 100644 --- a/src/applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClientAuthorization.php +++ b/src/applications/oauthserver/phid/PhabricatorOAuthServerClientAuthorizationPHIDType.php @@ -1,35 +1,35 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $authorization = $objects[$phid]; $handle->setName(pht('Authorization %d', $authorization->getID())); } } } diff --git a/src/applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClient.php b/src/applications/oauthserver/phid/PhabricatorOAuthServerClientPHIDType.php similarity index 88% rename from src/applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClient.php rename to src/applications/oauthserver/phid/PhabricatorOAuthServerClientPHIDType.php index a1776af81..81b8fdacd 100644 --- a/src/applications/oauthserver/phid/PhabricatorOAuthServerPHIDTypeClient.php +++ b/src/applications/oauthserver/phid/PhabricatorOAuthServerClientPHIDType.php @@ -1,36 +1,35 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $client = $objects[$phid]; $handle->setName($client->getName()); } } } diff --git a/src/applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php b/src/applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php index f477bddf2..c29c06eda 100644 --- a/src/applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php +++ b/src/applications/oauthserver/storage/PhabricatorOAuthClientAuthorization.php @@ -1,67 +1,67 @@ getScope(); $scopes = array_keys($scope); sort($scopes); return implode(' ', $scopes); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'scope' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorOAuthServerPHIDTypeClientAuthorization::TYPECONST); + PhabricatorOAuthServerClientAuthorizationPHIDType::TYPECONST); } public function getClient() { return $this->assertAttached($this->client); } public function attachClient(PhabricatorOAuthServerClient $client) { $this->client = $client; return $this; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getUserPHID()); } public function describeAutomaticCapability($capability) { return pht('Authorizations can only be viewed by the authorizing user.'); } } diff --git a/src/applications/oauthserver/storage/PhabricatorOAuthServerClient.php b/src/applications/oauthserver/storage/PhabricatorOAuthServerClient.php index 04958c160..1483ca5ce 100644 --- a/src/applications/oauthserver/storage/PhabricatorOAuthServerClient.php +++ b/src/applications/oauthserver/storage/PhabricatorOAuthServerClient.php @@ -1,77 +1,77 @@ getPHID().'/'; } public function getViewURI() { return '/oauthserver/client/view/'.$this->getPHID().'/'; } public function getDeleteURI() { return '/oauthserver/client/delete/'.$this->getPHID().'/'; } public static function initializeNewClient(PhabricatorUser $actor) { return id(new PhabricatorOAuthServerClient()) ->setCreatorPHID($actor->getPHID()) ->setSecret(Filesystem::readRandomCharacters(32)); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorOAuthServerPHIDTypeClient::TYPECONST); + PhabricatorOAuthServerClientPHIDType::TYPECONST); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::POLICY_USER; case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { switch ($capability) { case PhabricatorPolicyCapability::CAN_EDIT: return ($viewer->getPHID() == $this->getCreatorPHID()); } return false; } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_EDIT: return pht("Only an application's creator can edit it."); } return null; } } diff --git a/src/applications/owners/conduit/ConduitAPI_owners_query_Method.php b/src/applications/owners/conduit/ConduitAPI_owners_query_Method.php index 479a0aa51..f7cd3cdd7 100644 --- a/src/applications/owners/conduit/ConduitAPI_owners_query_Method.php +++ b/src/applications/owners/conduit/ConduitAPI_owners_query_Method.php @@ -1,153 +1,153 @@ 'optional string', 'projectOwner' => 'optional string', 'userAffiliated' => 'optional string', 'repositoryCallsign' => 'optional string', 'path' => 'optional string', ); } public function defineReturnType() { return 'dict dict of package info>'; } public function defineErrorTypes() { return array( 'ERR-INVALID-USAGE' => 'Provide one of a single owner phid (user/project), a single '. 'affiliated user phid (user), or a repository/path.', 'ERR-INVALID-PARAMETER' => 'parameter should be a phid', 'ERR_REP_NOT_FOUND' => 'The repository callsign is not recognized', ); } protected static function queryAll() { return id(new PhabricatorOwnersPackage())->loadAll(); } protected static function queryByOwner($owner) { $is_valid_phid = - phid_get_type($owner) == PhabricatorPeoplePHIDTypeUser::TYPECONST || - phid_get_type($owner) == PhabricatorProjectPHIDTypeProject::TYPECONST; + phid_get_type($owner) == PhabricatorPeopleUserPHIDType::TYPECONST || + phid_get_type($owner) == PhabricatorProjectProjectPHIDType::TYPECONST; if (!$is_valid_phid) { throw id(new ConduitException('ERR-INVALID-PARAMETER')) ->setErrorDescription( 'Expected user/project PHID for owner, got '.$owner); } $owners = id(new PhabricatorOwnersOwner())->loadAllWhere( 'userPHID = %s', $owner); $package_ids = mpull($owners, 'getPackageID'); $packages = array(); foreach ($package_ids as $id) { $packages[] = id(new PhabricatorOwnersPackage())->load($id); } return $packages; } private static function queryByPath( PhabricatorUser $viewer, $repo_callsign, $path) { $repository = id(new PhabricatorRepositoryQuery()) ->setViewer($viewer) ->withCallsigns(array($repo_callsign)) ->executeOne(); if (!$repository) { throw id(new ConduitException('ERR_REP_NOT_FOUND')) ->setErrorDescription( 'Repository callsign '.$repo_callsign.' not recognized'); } if ($path == null) { return PhabricatorOwnersPackage::loadPackagesForRepository($repository); } else { return PhabricatorOwnersPackage::loadOwningPackages( $repository, $path); } } public static function buildPackageInformationDictionaries($packages) { assert_instances_of($packages, 'PhabricatorOwnersPackage'); $result = array(); foreach ($packages as $package) { $p_owners = $package->loadOwners(); $p_paths = $package->loadPaths(); $owners = array_values(mpull($p_owners, 'getUserPHID')); $paths = array(); foreach ($p_paths as $p) { $paths[] = array($p->getRepositoryPHID(), $p->getPath()); } $result[$package->getPHID()] = array( 'phid' => $package->getPHID(), 'name' => $package->getName(), 'description' => $package->getDescription(), 'primaryOwner' => $package->getPrimaryOwnerPHID(), 'owners' => $owners, 'paths' => $paths ); } return $result; } protected function execute(ConduitAPIRequest $request) { $is_owner_query = ($request->getValue('userOwner') || $request->getValue('projectOwner')) ? 1 : 0; $is_affiliated_query = $request->getValue('userAffiliated') ? 1 : 0; $repo = $request->getValue('repositoryCallsign'); $path = $request->getValue('path'); $is_path_query = $repo ? 1 : 0; if ($is_owner_query + $is_path_query + $is_affiliated_query === 0) { // if no search terms are provided, return everything $packages = self::queryAll(); } else if ($is_owner_query + $is_path_query + $is_affiliated_query > 1) { // otherwise, exactly one of these should be provided throw new ConduitException('ERR-INVALID-USAGE'); } if ($is_affiliated_query) { $query = id(new PhabricatorOwnersPackageQuery()) ->setViewer($request->getUser()); $query->withOwnerPHIDs(array($request->getValue('userAffiliated'))); $packages = $query->execute(); } else if ($is_owner_query) { $owner = nonempty( $request->getValue('userOwner'), $request->getValue('projectOwner')); $packages = self::queryByOwner($owner); } else if ($is_path_query) { $packages = self::queryByPath($request->getUser(), $repo, $path); } return self::buildPackageInformationDictionaries($packages); } } diff --git a/src/applications/owners/phid/PhabricatorOwnersPHIDTypePackage.php b/src/applications/owners/phid/PhabricatorOwnersPackagePHIDType.php similarity index 92% rename from src/applications/owners/phid/PhabricatorOwnersPHIDTypePackage.php rename to src/applications/owners/phid/PhabricatorOwnersPackagePHIDType.php index 8c7a25511..b2492b0be 100644 --- a/src/applications/owners/phid/PhabricatorOwnersPHIDTypePackage.php +++ b/src/applications/owners/phid/PhabricatorOwnersPackagePHIDType.php @@ -1,43 +1,43 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $package = $objects[$phid]; $name = $package->getName(); $id = $package->getID(); $handle->setName($name); $handle->setURI("/owners/package/{$id}/"); } } } diff --git a/src/applications/owners/storage/PhabricatorOwnersOwner.php b/src/applications/owners/storage/PhabricatorOwnersOwner.php index 5a3c4f35f..1f0b82b6f 100644 --- a/src/applications/owners/storage/PhabricatorOwnersOwner.php +++ b/src/applications/owners/storage/PhabricatorOwnersOwner.php @@ -1,58 +1,58 @@ false, ) + parent::getConfiguration(); } public static function loadAllForPackages(array $packages) { assert_instances_of($packages, 'PhabricatorOwnersPackage'); if (!$packages) { return array(); } return id(new PhabricatorOwnersOwner())->loadAllWhere( 'packageID IN (%Ls)', mpull($packages, 'getID')); } // Loads all user phids affiliated with a set of packages. This includes both // user owners and all members of any project owners public static function loadAffiliatedUserPHIDs(array $package_ids) { if (!$package_ids) { return array(); } $owners = id(new PhabricatorOwnersOwner())->loadAllWhere( 'packageID IN (%Ls)', $package_ids); $all_phids = phid_group_by_type(mpull($owners, 'getUserPHID')); $user_phids = idx($all_phids, - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, array()); $users_in_project_phids = array(); $project_phids = idx( $all_phids, - PhabricatorProjectPHIDTypeProject::TYPECONST); + PhabricatorProjectProjectPHIDType::TYPECONST); if ($project_phids) { $query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($project_phids) ->withEdgeTypes(array(PhabricatorEdgeConfig::TYPE_PROJ_MEMBER)); $query->execute(); $users_in_project_phids = $query->getDestinationPHIDs(); } return array_unique(array_merge($users_in_project_phids, $user_phids)); } } diff --git a/src/applications/passphrase/phid/PassphrasePHIDTypeCredential.php b/src/applications/passphrase/phid/PassphraseCredentialPHIDType.php similarity index 96% rename from src/applications/passphrase/phid/PassphrasePHIDTypeCredential.php rename to src/applications/passphrase/phid/PassphraseCredentialPHIDType.php index cfd994f9b..e4d6e4104 100644 --- a/src/applications/passphrase/phid/PassphrasePHIDTypeCredential.php +++ b/src/applications/passphrase/phid/PassphraseCredentialPHIDType.php @@ -1,72 +1,72 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $credential = $objects[$phid]; $id = $credential->getID(); $name = $credential->getName(); $handle->setName("K{$id}"); $handle->setFullName("K{$id} {$name}"); $handle->setURI("/K{$id}"); if ($credential->getIsDestroyed()) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } public function canLoadNamedObject($name) { return preg_match('/^K\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PassphraseCredentialQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/passphrase/storage/PassphraseCredential.php b/src/applications/passphrase/storage/PassphraseCredential.php index 574fb8364..8dc8de2fe 100644 --- a/src/applications/passphrase/storage/PassphraseCredential.php +++ b/src/applications/passphrase/storage/PassphraseCredential.php @@ -1,86 +1,86 @@ setName('') ->setUsername('') ->setDescription('') ->setIsDestroyed(0) ->setViewPolicy($actor->getPHID()) ->setEditPolicy($actor->getPHID()); } public function getMonogram() { return 'K'.$this->getID(); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PassphrasePHIDTypeCredential::TYPECONST); + PassphraseCredentialPHIDType::TYPECONST); } public function attachSecret(PhutilOpaqueEnvelope $secret = null) { $this->secret = $secret; return $this; } public function getSecret() { return $this->assertAttached($this->secret); } public function getCredentialTypeImplementation() { $type = $this->getCredentialType(); return PassphraseCredentialType::getTypeByConstant($type); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/passphrase/storage/PassphraseCredentialTransaction.php b/src/applications/passphrase/storage/PassphraseCredentialTransaction.php index fb1aced06..a8d918c78 100644 --- a/src/applications/passphrase/storage/PassphraseCredentialTransaction.php +++ b/src/applications/passphrase/storage/PassphraseCredentialTransaction.php @@ -1,114 +1,114 @@ getOldValue(); switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: return ($old === null); case self::TYPE_LOCK: return ($old === null); case self::TYPE_USERNAME: return !strlen($old); case self::TYPE_LOOKEDATSECRET: return false; } return parent::shouldHide(); } public function getTitle() { $old = $this->getOldValue(); $new = $this->getNewValue(); $author_phid = $this->getAuthorPHID(); switch ($this->getTransactionType()) { case self::TYPE_NAME: if ($old === null) { return pht( '%s created this credential.', $this->renderHandleLink($author_phid)); } else { return pht( '%s renamed this credential from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case self::TYPE_DESCRIPTION: return pht( '%s updated the description for this credential.', $this->renderHandleLink($author_phid)); case self::TYPE_USERNAME: if (strlen($old)) { return pht( '%s changed the username for this credential from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } else { return pht( '%s set the username for this credential to "%s".', $this->renderHandleLink($author_phid), $new); } break; case self::TYPE_SECRET_ID: return pht( '%s updated the secret for this credential.', $this->renderHandleLink($author_phid)); case self::TYPE_DESTROY: return pht( '%s destroyed this credential.', $this->renderHandleLink($author_phid)); case self::TYPE_LOOKEDATSECRET: return pht( '%s examined the secret plaintext for this credential.', $this->renderHandleLink($author_phid)); case self::TYPE_LOCK: return pht( '%s locked this credential.', $this->renderHandleLink($author_phid)); } return parent::getTitle(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, json_encode($this->getOldValue()), json_encode($this->getNewValue())); } } diff --git a/src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php b/src/applications/paste/phid/PhabricatorPastePastePHIDType.php similarity index 95% rename from src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php rename to src/applications/paste/phid/PhabricatorPastePastePHIDType.php index 6256e2892..c07f90231 100644 --- a/src/applications/paste/phid/PhabricatorPastePHIDTypePaste.php +++ b/src/applications/paste/phid/PhabricatorPastePastePHIDType.php @@ -1,69 +1,69 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $paste = $objects[$phid]; $id = $paste->getID(); $name = $paste->getFullName(); $handle->setName("P{$id}"); $handle->setFullName($name); $handle->setURI("/P{$id}"); } } public function canLoadNamedObject($name) { return preg_match('/^P\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PhabricatorPasteQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/paste/storage/PhabricatorPaste.php b/src/applications/paste/storage/PhabricatorPaste.php index 139177b11..9a5dcab65 100644 --- a/src/applications/paste/storage/PhabricatorPaste.php +++ b/src/applications/paste/storage/PhabricatorPaste.php @@ -1,134 +1,134 @@ setViewer($actor) ->withClasses(array('PhabricatorPasteApplication')) ->executeOne(); $view_policy = $app->getPolicy(PasteCapabilityDefaultView::CAPABILITY); return id(new PhabricatorPaste()) ->setTitle('') ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy); } public function getURI() { return '/P'.$this->getID(); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorPastePHIDTypePaste::TYPECONST); + PhabricatorPastePastePHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getFullName() { $title = $this->getTitle(); if (!$title) { $title = pht('(An Untitled Masterwork)'); } return 'P'.$this->getID().' '.$title; } public function getContent() { return $this->assertAttached($this->content); } public function attachContent($content) { $this->content = $content; return $this; } public function getRawContent() { return $this->assertAttached($this->rawContent); } public function attachRawContent($raw_content) { $this->rawContent = $raw_content; return $this; } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($this->authorPHID == $phid); } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), ); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { if ($capability == PhabricatorPolicyCapability::CAN_VIEW) { return $this->viewPolicy; } return PhabricatorPolicies::POLICY_NOONE; } public function hasAutomaticCapability($capability, PhabricatorUser $user) { return ($user->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { return pht('The author of a paste can always view and edit it.'); } } diff --git a/src/applications/paste/storage/PhabricatorPasteTransaction.php b/src/applications/paste/storage/PhabricatorPasteTransaction.php index acb06b22a..397354fda 100644 --- a/src/applications/paste/storage/PhabricatorPasteTransaction.php +++ b/src/applications/paste/storage/PhabricatorPasteTransaction.php @@ -1,185 +1,185 @@ getTransactionType()) { case self::TYPE_CONTENT: $phids[] = $this->getObjectPHID(); break; } return $phids; } public function shouldHide() { $old = $this->getOldValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: case self::TYPE_LANGUAGE: return ($old === null); } return parent::shouldHide(); } public function getIcon() { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return 'fa-plus'; break; case self::TYPE_TITLE: case self::TYPE_LANGUAGE: return 'fa-pencil'; break; } return parent::getIcon(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case PhabricatorPasteTransaction::TYPE_CONTENT: if ($old === null) { return pht( '%s created this paste.', $this->renderHandleLink($author_phid)); } else { return pht( '%s edited the content of this paste.', $this->renderHandleLink($author_phid)); } break; case PhabricatorPasteTransaction::TYPE_TITLE: return pht( '%s updated the paste\'s title to "%s".', $this->renderHandleLink($author_phid), $new); break; case PhabricatorPasteTransaction::TYPE_LANGUAGE: return pht( "%s updated the paste's language.", $this->renderHandleLink($author_phid)); break; } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case PhabricatorPasteTransaction::TYPE_CONTENT: if ($old === null) { return pht( '%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s edited %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } break; case PhabricatorPasteTransaction::TYPE_TITLE: return pht( '%s updated the title for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PhabricatorPasteTransaction::TYPE_LANGUAGE: return pht( '%s update the language for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; } return parent::getTitleForFeed($story); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return PhabricatorTransactions::COLOR_GREEN; } return parent::getColor(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return ($this->getOldValue() !== null); } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: $old = $this->getOldValue(); $new = $this->getNewValue(); $files = id(new PhabricatorFileQuery()) ->setViewer($viewer) ->withPHIDs(array_filter(array($old, $new))) ->execute(); $files = mpull($files, null, 'getPHID'); $old_text = ''; if (idx($files, $old)) { $old_text = $files[$old]->loadFileData(); } $new_text = ''; if (idx($files, $new)) { $new_text = $files[$new]->loadFileData(); } return $this->renderTextCorpusChangeDetails( $viewer, $old_text, $new_text); } return parent::renderChangeDetails($viewer); } } diff --git a/src/applications/people/phid/PhabricatorPeoplePHIDTypeExternal.php b/src/applications/people/phid/PhabricatorPeopleExternalPHIDType.php similarity index 91% rename from src/applications/people/phid/PhabricatorPeoplePHIDTypeExternal.php rename to src/applications/people/phid/PhabricatorPeopleExternalPHIDType.php index 96ac3f601..9fd565700 100644 --- a/src/applications/people/phid/PhabricatorPeoplePHIDTypeExternal.php +++ b/src/applications/people/phid/PhabricatorPeopleExternalPHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $account = $objects[$phid]; $display_name = $account->getDisplayName(); $handle->setName($display_name); } } } diff --git a/src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php similarity index 96% rename from src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php rename to src/applications/people/phid/PhabricatorPeopleUserPHIDType.php index eac4231f8..ad6c10b5f 100644 --- a/src/applications/people/phid/PhabricatorPeoplePHIDTypeUser.php +++ b/src/applications/people/phid/PhabricatorPeopleUserPHIDType.php @@ -1,88 +1,87 @@ withPHIDs($phids) ->needProfileImage(true) ->needStatus(true); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $user = $objects[$phid]; $realname = $user->getRealName(); $handle->setName($user->getUsername()); $handle->setURI('/p/'.$user->getUsername().'/'); $handle->setFullName($user->getFullName()); $handle->setImageURI($user->loadProfileImageURI()); $handle->setDisabled(!$user->isUserActivated()); if ($user->hasStatus()) { $status = $user->getStatus(); $handle->setStatus($status->getTextStatus()); $handle->setTitle($status->getTerseSummary($query->getViewer())); } } - } public function canLoadNamedObject($name) { return preg_match('/^@.+/', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = substr($name, 1); $id = phutil_utf8_strtolower($id); $id_map[$id][] = $name; } $objects = id(new PhabricatorPeopleQuery()) ->setViewer($query->getViewer()) ->withUsernames(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { $user_key = $object->getUsername(); $user_key = phutil_utf8_strtolower($user_key); foreach (idx($id_map, $user_key, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/people/search/PhabricatorUserSearchIndexer.php b/src/applications/people/search/PhabricatorUserSearchIndexer.php index da591d7f7..17c74ad4f 100644 --- a/src/applications/people/search/PhabricatorUserSearchIndexer.php +++ b/src/applications/people/search/PhabricatorUserSearchIndexer.php @@ -1,30 +1,30 @@ loadDocumentByPHID($phid); $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($user->getPHID()); - $doc->setDocumentType(PhabricatorPeoplePHIDTypeUser::TYPECONST); + $doc->setDocumentType(PhabricatorPeopleUserPHIDType::TYPECONST); $doc->setDocumentTitle($user->getFullName()); $doc->setDocumentCreated($user->getDateCreated()); $doc->setDocumentModified($user->getDateModified()); $doc->addRelationship( $user->isUserActivated() ? PhabricatorSearchRelationship::RELATIONSHIP_OPEN : PhabricatorSearchRelationship::RELATIONSHIP_CLOSED, $user->getPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, time()); return $doc; } } diff --git a/src/applications/people/storage/PhabricatorExternalAccount.php b/src/applications/people/storage/PhabricatorExternalAccount.php index 92a22d0c7..ba57f2424 100644 --- a/src/applications/people/storage/PhabricatorExternalAccount.php +++ b/src/applications/people/storage/PhabricatorExternalAccount.php @@ -1,140 +1,140 @@ assertAttached($this->profileImageFile); } public function attachProfileImageFile(PhabricatorFile $file) { $this->profileImageFile = $file; return $this; } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorPeoplePHIDTypeExternal::TYPECONST); + PhabricatorPeopleExternalPHIDType::TYPECONST); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'properties' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function getPhabricatorUser() { $tmp_usr = id(new PhabricatorUser()) ->makeEphemeral() ->setPHID($this->getPHID()); return $tmp_usr; } public function getProviderKey() { return $this->getAccountType().':'.$this->getAccountDomain(); } public function save() { if (!$this->getAccountSecret()) { $this->setAccountSecret(Filesystem::readRandomCharacters(32)); } return parent::save(); } public function setProperty($key, $value) { $this->properties[$key] = $value; return $this; } public function getProperty($key, $default = null) { return idx($this->properties, $key, $default); } public function isUsableForLogin() { $key = $this->getProviderKey(); $provider = PhabricatorAuthProvider::getEnabledProviderByKey($key); if (!$provider) { return false; } if (!$provider->shouldAllowLogin()) { return false; } return true; } public function getDisplayName() { if (strlen($this->displayName)) { return $this->displayName; } // TODO: Figure out how much identifying information we're going to show // to users about external accounts. For now, just show a string which is // clearly not an error, but don't disclose any identifying information. $map = array( 'email' => pht('Email User'), ); $type = $this->getAccountType(); return idx($map, $type, pht('"%s" User', $type)); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::getMostOpenPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getUserPHID()); } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return null; case PhabricatorPolicyCapability::CAN_EDIT: return pht( 'External accounts can only be edited by the account owner.'); } } } diff --git a/src/applications/people/storage/PhabricatorUser.php b/src/applications/people/storage/PhabricatorUser.php index bef873c09..bbdc9dbdf 100644 --- a/src/applications/people/storage/PhabricatorUser.php +++ b/src/applications/people/storage/PhabricatorUser.php @@ -1,886 +1,886 @@ timezoneIdentifier, date_default_timezone_get()); // Make sure these return booleans. case 'isAdmin': return (bool)$this->isAdmin; case 'isDisabled': return (bool)$this->isDisabled; case 'isSystemAgent': return (bool)$this->isSystemAgent; case 'isEmailVerified': return (bool)$this->isEmailVerified; case 'isApproved': return (bool)$this->isApproved; default: return parent::readField($field); } } /** * Is this a live account which has passed required approvals? Returns true * if this is an enabled, verified (if required), approved (if required) * account, and false otherwise. * * @return bool True if this is a standard, usable account. */ public function isUserActivated() { if ($this->getIsDisabled()) { return false; } if (!$this->getIsApproved()) { return false; } if (PhabricatorUserEmail::isEmailVerificationRequired()) { if (!$this->getIsEmailVerified()) { return false; } } return true; } /** * Returns `true` if this is a standard user who is logged in. Returns `false` * for logged out, anonymous, or external users. * * @return bool `true` if the user is a standard user who is logged in with * a normal session. */ public function getIsStandardUser() { - $type_user = PhabricatorPeoplePHIDTypeUser::TYPECONST; + $type_user = PhabricatorPeopleUserPHIDType::TYPECONST; return $this->getPHID() && (phid_get_type($this->getPHID()) == $type_user); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorPeoplePHIDTypeUser::TYPECONST); + PhabricatorPeopleUserPHIDType::TYPECONST); } public function setPassword(PhutilOpaqueEnvelope $envelope) { if (!$this->getPHID()) { throw new Exception( 'You can not set a password for an unsaved user because their PHID '. 'is a salt component in the password hash.'); } if (!strlen($envelope->openEnvelope())) { $this->setPasswordHash(''); } else { $this->setPasswordSalt(md5(Filesystem::readRandomBytes(32))); $hash = $this->hashPassword($envelope); $this->setPasswordHash($hash->openEnvelope()); } return $this; } // To satisfy PhutilPerson. public function getSex() { return $this->sex; } public function getMonogram() { return '@'.$this->getUsername(); } public function getTranslation() { try { if ($this->translation && class_exists($this->translation) && is_subclass_of($this->translation, 'PhabricatorTranslation')) { return $this->translation; } } catch (PhutilMissingSymbolException $ex) { return null; } return null; } public function isLoggedIn() { return !($this->getPHID() === null); } public function save() { if (!$this->getConduitCertificate()) { $this->setConduitCertificate($this->generateConduitCertificate()); } if (!strlen($this->getAccountSecret())) { $this->setAccountSecret(Filesystem::readRandomCharacters(64)); } $result = parent::save(); if ($this->profile) { $this->profile->save(); } $this->updateNameTokens(); id(new PhabricatorSearchIndexer()) ->queueDocumentForIndexing($this->getPHID()); return $result; } public function attachSession(PhabricatorAuthSession $session) { $this->session = $session; return $this; } public function getSession() { return $this->assertAttached($this->session); } public function hasSession() { return ($this->session !== self::ATTACHABLE); } private function generateConduitCertificate() { return Filesystem::readRandomCharacters(255); } public function comparePassword(PhutilOpaqueEnvelope $envelope) { if (!strlen($envelope->openEnvelope())) { return false; } if (!strlen($this->getPasswordHash())) { return false; } return PhabricatorPasswordHasher::comparePassword( $this->getPasswordHashInput($envelope), new PhutilOpaqueEnvelope($this->getPasswordHash())); } private function getPasswordHashInput(PhutilOpaqueEnvelope $password) { $input = $this->getUsername(). $password->openEnvelope(). $this->getPHID(). $this->getPasswordSalt(); return new PhutilOpaqueEnvelope($input); } private function hashPassword(PhutilOpaqueEnvelope $password) { $hasher = PhabricatorPasswordHasher::getBestHasher(); $input_envelope = $this->getPasswordHashInput($password); return $hasher->getPasswordHashForStorage($input_envelope); } const CSRF_CYCLE_FREQUENCY = 3600; const CSRF_SALT_LENGTH = 8; const CSRF_TOKEN_LENGTH = 16; const CSRF_BREACH_PREFIX = 'B@'; const EMAIL_CYCLE_FREQUENCY = 86400; const EMAIL_TOKEN_LENGTH = 24; private function getRawCSRFToken($offset = 0) { return $this->generateToken( time() + (self::CSRF_CYCLE_FREQUENCY * $offset), self::CSRF_CYCLE_FREQUENCY, PhabricatorEnv::getEnvConfig('phabricator.csrf-key'), self::CSRF_TOKEN_LENGTH); } /** * @phutil-external-symbol class PhabricatorStartup */ public function getCSRFToken() { $salt = PhabricatorStartup::getGlobal('csrf.salt'); if (!$salt) { $salt = Filesystem::readRandomCharacters(self::CSRF_SALT_LENGTH); PhabricatorStartup::setGlobal('csrf.salt', $salt); } // Generate a token hash to mitigate BREACH attacks against SSL. See // discussion in T3684. $token = $this->getRawCSRFToken(); $hash = PhabricatorHash::digest($token, $salt); return 'B@'.$salt.substr($hash, 0, self::CSRF_TOKEN_LENGTH); } public function validateCSRFToken($token) { $salt = null; $version = 'plain'; // This is a BREACH-mitigating token. See T3684. $breach_prefix = self::CSRF_BREACH_PREFIX; $breach_prelen = strlen($breach_prefix); if (!strncmp($token, $breach_prefix, $breach_prelen)) { $version = 'breach'; $salt = substr($token, $breach_prelen, self::CSRF_SALT_LENGTH); $token = substr($token, $breach_prelen + self::CSRF_SALT_LENGTH); } // When the user posts a form, we check that it contains a valid CSRF token. // Tokens cycle each hour (every CSRF_CYLCE_FREQUENCY seconds) and we accept // either the current token, the next token (users can submit a "future" // token if you have two web frontends that have some clock skew) or any of // the last 6 tokens. This means that pages are valid for up to 7 hours. // There is also some Javascript which periodically refreshes the CSRF // tokens on each page, so theoretically pages should be valid indefinitely. // However, this code may fail to run (if the user loses their internet // connection, or there's a JS problem, or they don't have JS enabled). // Choosing the size of the window in which we accept old CSRF tokens is // an issue of balancing concerns between security and usability. We could // choose a very narrow (e.g., 1-hour) window to reduce vulnerability to // attacks using captured CSRF tokens, but it's also more likely that real // users will be affected by this, e.g. if they close their laptop for an // hour, open it back up, and try to submit a form before the CSRF refresh // can kick in. Since the user experience of submitting a form with expired // CSRF is often quite bad (you basically lose data, or it's a big pain to // recover at least) and I believe we gain little additional protection // by keeping the window very short (the overwhelming value here is in // preventing blind attacks, and most attacks which can capture CSRF tokens // can also just capture authentication information [sniffing networks] // or act as the user [xss]) the 7 hour default seems like a reasonable // balance. Other major platforms have much longer CSRF token lifetimes, // like Rails (session duration) and Django (forever), which suggests this // is a reasonable analysis. $csrf_window = 6; for ($ii = -$csrf_window; $ii <= 1; $ii++) { $valid = $this->getRawCSRFToken($ii); switch ($version) { // TODO: We can remove this after the BREACH version has been in the // wild for a while. case 'plain': if ($token == $valid) { return true; } break; case 'breach': $digest = PhabricatorHash::digest($valid, $salt); if (substr($digest, 0, self::CSRF_TOKEN_LENGTH) == $token) { return true; } break; default: throw new Exception('Unknown CSRF token format!'); } } return false; } private function generateToken($epoch, $frequency, $key, $len) { if ($this->getPHID()) { $vec = $this->getPHID().$this->getAccountSecret(); } else { $vec = $this->getAlternateCSRFString(); } $time_block = floor($epoch / $frequency); $vec = $vec.$key.$time_block; return substr(PhabricatorHash::digest($vec), 0, $len); } public function attachUserProfile(PhabricatorUserProfile $profile) { $this->profile = $profile; return $this; } public function loadUserProfile() { if ($this->profile) { return $this->profile; } $profile_dao = new PhabricatorUserProfile(); $this->profile = $profile_dao->loadOneWhere('userPHID = %s', $this->getPHID()); if (!$this->profile) { $profile_dao->setUserPHID($this->getPHID()); $this->profile = $profile_dao; } return $this->profile; } public function loadPrimaryEmailAddress() { $email = $this->loadPrimaryEmail(); if (!$email) { throw new Exception('User has no primary email address!'); } return $email->getAddress(); } public function loadPrimaryEmail() { return $this->loadOneRelative( new PhabricatorUserEmail(), 'userPHID', 'getPHID', '(isPrimary = 1)'); } public function loadPreferences() { if ($this->preferences) { return $this->preferences; } $preferences = null; if ($this->getPHID()) { $preferences = id(new PhabricatorUserPreferences())->loadOneWhere( 'userPHID = %s', $this->getPHID()); } if (!$preferences) { $preferences = new PhabricatorUserPreferences(); $preferences->setUserPHID($this->getPHID()); $default_dict = array( PhabricatorUserPreferences::PREFERENCE_TITLES => 'glyph', PhabricatorUserPreferences::PREFERENCE_EDITOR => '', PhabricatorUserPreferences::PREFERENCE_MONOSPACED => '', PhabricatorUserPreferences::PREFERENCE_DARK_CONSOLE => 0); $preferences->setPreferences($default_dict); } $this->preferences = $preferences; return $preferences; } public function loadEditorLink($path, $line, $callsign) { $editor = $this->loadPreferences()->getPreference( PhabricatorUserPreferences::PREFERENCE_EDITOR); if (is_array($path)) { $multiedit = $this->loadPreferences()->getPreference( PhabricatorUserPreferences::PREFERENCE_MULTIEDIT); switch ($multiedit) { case '': $path = implode(' ', $path); break; case 'disable': return null; } } if (!strlen($editor)) { return null; } $uri = strtr($editor, array( '%%' => '%', '%f' => phutil_escape_uri($path), '%l' => phutil_escape_uri($line), '%r' => phutil_escape_uri($callsign), )); // The resulting URI must have an allowed protocol. Otherwise, we'll return // a link to an error page explaining the misconfiguration. $ok = PhabricatorHelpEditorProtocolController::hasAllowedProtocol($uri); if (!$ok) { return '/help/editorprotocol/'; } return (string)$uri; } public function getAlternateCSRFString() { return $this->assertAttached($this->alternateCSRFString); } public function attachAlternateCSRFString($string) { $this->alternateCSRFString = $string; return $this; } /** * Populate the nametoken table, which used to fetch typeahead results. When * a user types "linc", we want to match "Abraham Lincoln" from on-demand * typeahead sources. To do this, we need a separate table of name fragments. */ public function updateNameTokens() { $table = self::NAMETOKEN_TABLE; $conn_w = $this->establishConnection('w'); $tokens = PhabricatorTypeaheadDatasource::tokenizeString( $this->getUserName().' '.$this->getRealName()); $sql = array(); foreach ($tokens as $token) { $sql[] = qsprintf( $conn_w, '(%d, %s)', $this->getID(), $token); } queryfx( $conn_w, 'DELETE FROM %T WHERE userID = %d', $table, $this->getID()); if ($sql) { queryfx( $conn_w, 'INSERT INTO %T (userID, token) VALUES %Q', $table, implode(', ', $sql)); } } public function sendWelcomeEmail(PhabricatorUser $admin) { $admin_username = $admin->getUserName(); $admin_realname = $admin->getRealName(); $user_username = $this->getUserName(); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); $base_uri = PhabricatorEnv::getProductionURI('/'); $engine = new PhabricatorAuthSessionEngine(); $uri = $engine->getOneTimeLoginURI( $this, $this->loadPrimaryEmail(), PhabricatorAuthSessionEngine::ONETIME_WELCOME); $body = <<addTos(array($this->getPHID())) ->setSubject('[Phabricator] Welcome to Phabricator') ->setBody($body) ->saveAndSend(); } public function sendUsernameChangeEmail( PhabricatorUser $admin, $old_username) { $admin_username = $admin->getUserName(); $admin_realname = $admin->getRealName(); $new_username = $this->getUserName(); $password_instructions = null; if (PhabricatorPasswordAuthProvider::getPasswordProvider()) { $engine = new PhabricatorAuthSessionEngine(); $uri = $engine->getOneTimeLoginURI( $this, null, PhabricatorAuthSessionEngine::ONETIME_USERNAME); $password_instructions = <<addTos(array($this->getPHID())) ->setSubject('[Phabricator] Username Changed') ->setBody($body) ->saveAndSend(); } public static function describeValidUsername() { return pht( 'Usernames must contain only numbers, letters, period, underscore and '. 'hyphen, and can not end with a period. They must have no more than %d '. 'characters.', new PhutilNumber(self::MAXIMUM_USERNAME_LENGTH)); } public static function validateUsername($username) { // NOTE: If you update this, make sure to update: // // - Remarkup rule for @mentions. // - Routing rule for "/p/username/". // - Unit tests, obviously. // - describeValidUsername() method, above. if (strlen($username) > self::MAXIMUM_USERNAME_LENGTH) { return false; } return (bool)preg_match('/^[a-zA-Z0-9._-]*[a-zA-Z0-9_-]\z/', $username); } public static function getDefaultProfileImageURI() { return celerity_get_resource_uri('/rsrc/image/avatar.png'); } public function attachStatus(PhabricatorCalendarEvent $status) { $this->status = $status; return $this; } public function getStatus() { return $this->assertAttached($this->status); } public function hasStatus() { return $this->status !== self::ATTACHABLE; } public function attachProfileImageURI($uri) { $this->profileImage = $uri; return $this; } public function getProfileImageURI() { return $this->assertAttached($this->profileImage); } public function loadProfileImageURI() { if ($this->profileImage && ($this->profileImage !== self::ATTACHABLE)) { return $this->profileImage; } $src_phid = $this->getProfileImagePHID(); if ($src_phid) { // TODO: (T603) Can we get rid of this entirely and move it to // PeopleQuery with attach/attachable? $file = id(new PhabricatorFile())->loadOneWhere('phid = %s', $src_phid); if ($file) { $this->profileImage = $file->getBestURI(); return $this->profileImage; } } $this->profileImage = self::getDefaultProfileImageURI(); return $this->profileImage; } public function getFullName() { if (strlen($this->getRealName())) { return $this->getUsername().' ('.$this->getRealName().')'; } else { return $this->getUsername(); } } public function __toString() { return $this->getUsername(); } public static function loadOneWithEmailAddress($address) { $email = id(new PhabricatorUserEmail())->loadOneWhere( 'address = %s', $address); if (!$email) { return null; } return id(new PhabricatorUser())->loadOneWhere( 'phid = %s', $email->getUserPHID()); } /* -( Multi-Factor Authentication )---------------------------------------- */ /** * Update the flag storing this user's enrollment in multi-factor auth. * * With certain settings, we need to check if a user has MFA on every page, * so we cache MFA enrollment on the user object for performance. Calling this * method synchronizes the cache by examining enrollment records. After * updating the cache, use @{method:getIsEnrolledInMultiFactor} to check if * the user is enrolled. * * This method should be called after any changes are made to a given user's * multi-factor configuration. * * @return void * @task factors */ public function updateMultiFactorEnrollment() { $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere( 'userPHID = %s', $this->getPHID()); $enrolled = count($factors) ? 1 : 0; if ($enrolled !== $this->isEnrolledInMultiFactor) { $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites(); queryfx( $this->establishConnection('w'), 'UPDATE %T SET isEnrolledInMultiFactor = %d WHERE id = %d', $this->getTableName(), $enrolled, $this->getID()); unset($unguarded); $this->isEnrolledInMultiFactor = $enrolled; } } /** * Check if the user is enrolled in multi-factor authentication. * * Enrolled users have one or more multi-factor authentication sources * attached to their account. For performance, this value is cached. You * can use @{method:updateMultiFactorEnrollment} to update the cache. * * @return bool True if the user is enrolled. * @task factors */ public function getIsEnrolledInMultiFactor() { return $this->isEnrolledInMultiFactor; } /* -( Omnipotence )-------------------------------------------------------- */ /** * Returns true if this user is omnipotent. Omnipotent users bypass all policy * checks. * * @return bool True if the user bypasses policy checks. */ public function isOmnipotent() { return $this->omnipotent; } /** * Get an omnipotent user object for use in contexts where there is no acting * user, notably daemons. * * @return PhabricatorUser An omnipotent user. */ public static function getOmnipotentUser() { static $user = null; if (!$user) { $user = new PhabricatorUser(); $user->omnipotent = true; $user->makeEphemeral(); } return $user; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::POLICY_PUBLIC; case PhabricatorPolicyCapability::CAN_EDIT: if ($this->getIsSystemAgent()) { return PhabricatorPolicies::POLICY_ADMIN; } else { return PhabricatorPolicies::POLICY_NOONE; } } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getPHID() && ($viewer->getPHID() === $this->getPHID()); } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_EDIT: return pht('Only you can edit your information.'); default: return null; } } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('user.fields'); } public function getCustomFieldBaseClass() { return 'PhabricatorUserCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $externals = id(new PhabricatorExternalAccount())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($externals as $external) { $external->delete(); } $prefs = id(new PhabricatorUserPreferences())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($prefs as $pref) { $pref->delete(); } $profiles = id(new PhabricatorUserProfile())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($profiles as $profile) { $profile->delete(); } $keys = id(new PhabricatorUserSSHKey())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($keys as $key) { $key->delete(); } $emails = id(new PhabricatorUserEmail())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($emails as $email) { $email->delete(); } $sessions = id(new PhabricatorAuthSession())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($sessions as $session) { $session->delete(); } $factors = id(new PhabricatorAuthFactorConfig())->loadAllWhere( 'userPHID = %s', $this->getPHID()); foreach ($factors as $factor) { $factor->delete(); } $this->saveTransaction(); } } diff --git a/src/applications/people/storage/PhabricatorUserTransaction.php b/src/applications/people/storage/PhabricatorUserTransaction.php index 86551be42..b4bd1c986 100644 --- a/src/applications/people/storage/PhabricatorUserTransaction.php +++ b/src/applications/people/storage/PhabricatorUserTransaction.php @@ -1,18 +1,18 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $blog = $objects[$phid]; $handle->setName($blog->getName()); $handle->setFullName($blog->getName()); $handle->setURI('/phame/blog/view/'.$blog->getID().'/'); } } } diff --git a/src/applications/phame/phid/PhabricatorPhamePHIDTypePost.php b/src/applications/phame/phid/PhabricatorPhamePostPHIDType.php similarity index 91% rename from src/applications/phame/phid/PhabricatorPhamePHIDTypePost.php rename to src/applications/phame/phid/PhabricatorPhamePostPHIDType.php index 09080708d..e5eeef371 100644 --- a/src/applications/phame/phid/PhabricatorPhamePHIDTypePost.php +++ b/src/applications/phame/phid/PhabricatorPhamePostPHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $post = $objects[$phid]; $handle->setName($post->getTitle()); $handle->setFullName($post->getTitle()); $handle->setURI('/phame/post/view/'.$post->getID().'/'); } } } diff --git a/src/applications/phame/storage/PhameBlog.php b/src/applications/phame/storage/PhameBlog.php index 3d752fc72..b4c2d5a88 100644 --- a/src/applications/phame/storage/PhameBlog.php +++ b/src/applications/phame/storage/PhameBlog.php @@ -1,281 +1,281 @@ true, self::CONFIG_SERIALIZATION => array( 'configData' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorPhamePHIDTypeBlog::TYPECONST); + PhabricatorPhameBlogPHIDType::TYPECONST); } public function getSkinRenderer(AphrontRequest $request) { $spec = PhameSkinSpecification::loadOneSkinSpecification( $this->getSkin()); if (!$spec) { $spec = PhameSkinSpecification::loadOneSkinSpecification( self::SKIN_DEFAULT); } if (!$spec) { throw new Exception( 'This blog has an invalid skin, and the default skin failed to '. 'load.'); } $skin = newv($spec->getSkinClass(), array($request)); $skin->setSpecification($spec); return $skin; } /** * Makes sure a given custom blog uri is properly configured in DNS * to point at this Phabricator instance. If there is an error in * the configuration, return a string describing the error and how * to fix it. If there is no error, return an empty string. * * @return string */ public function validateCustomDomain($custom_domain) { $example_domain = 'blog.example.com'; $label = pht('Invalid'); // note this "uri" should be pretty busted given the desired input // so just use it to test if there's a protocol specified $uri = new PhutilURI($custom_domain); if ($uri->getProtocol()) { return array($label, pht( 'The custom domain should not include a protocol. Just provide '. 'the bare domain name (for example, "%s").', $example_domain)); } if ($uri->getPort()) { return array($label, pht( 'The custom domain should not include a port number. Just provide '. 'the bare domain name (for example, "%s").', $example_domain)); } if (strpos($custom_domain, '/') !== false) { return array($label, pht( 'The custom domain should not specify a path (hosting a Phame '. 'blog at a path is currently not supported). Instead, just provide '. 'the bare domain name (for example, "%s").', $example_domain)); } if (strpos($custom_domain, '.') === false) { return array($label, pht( 'The custom domain should contain at least one dot (.) because '. 'some browsers fail to set cookies on domains without a dot. '. 'Instead, use a normal looking domain name like "%s".', $example_domain)); } if (!PhabricatorEnv::getEnvConfig('policy.allow-public')) { $href = PhabricatorEnv::getProductionURI( '/config/edit/policy.allow-public/'); return array(pht('Fix Configuration'), pht( 'For custom domains to work, this Phabricator instance must be '. 'configured to allow the public access policy. Configure this '. 'setting %s, or ask an administrator to configure this setting. '. 'The domain can be specified later once this setting has been '. 'changed.', phutil_tag( 'a', array('href' => $href), pht('here')))); } return null; } public function getBloggerPHIDs() { return $this->assertAttached($this->bloggerPHIDs); } public function attachBloggers(array $bloggers) { assert_instances_of($bloggers, 'PhabricatorObjectHandle'); $this->bloggers = $bloggers; return $this; } public function getBloggers() { return $this->assertAttached($this->bloggers); } public function getSkin() { $config = coalesce($this->getConfigData(), array()); return idx($config, 'skin', self::SKIN_DEFAULT); } public function setSkin($skin) { $config = coalesce($this->getConfigData(), array()); $config['skin'] = $skin; return $this->setConfigData($config); } static public function getSkinOptionsForSelect() { $classes = id(new PhutilSymbolLoader()) ->setAncestorClass('PhameBlogSkin') ->setType('class') ->setConcreteOnly(true) ->selectSymbolsWithoutLoading(); return ipull($classes, 'name', 'name'); } public static function setRequestBlog(PhameBlog $blog) { self::$requestBlog = $blog; } public static function getRequestBlog() { return self::$requestBlog; } public function getLiveURI(PhamePost $post = null) { if ($this->getDomain()) { $base = new PhutilURI('http://'.$this->getDomain().'/'); } else { $base = '/phame/live/'.$this->getID().'/'; $base = PhabricatorEnv::getURI($base); } if ($post) { $base .= '/post/'.$post->getPhameTitle(); } return $base; } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_JOIN, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); case PhabricatorPolicyCapability::CAN_JOIN: return $this->getJoinPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $user) { $can_edit = PhabricatorPolicyCapability::CAN_EDIT; $can_join = PhabricatorPolicyCapability::CAN_JOIN; switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: // Users who can edit or post to a blog can always view it. if (PhabricatorPolicyFilter::hasCapability($user, $this, $can_edit)) { return true; } if (PhabricatorPolicyFilter::hasCapability($user, $this, $can_join)) { return true; } break; case PhabricatorPolicyCapability::CAN_JOIN: // Users who can edit a blog can always post to it. if (PhabricatorPolicyFilter::hasCapability($user, $this, $can_edit)) { return true; } break; } return false; } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht( 'Users who can edit or post on a blog can always view it.'); case PhabricatorPolicyCapability::CAN_JOIN: return pht( 'Users who can edit a blog can always post on it.'); } return null; } /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); return $this->getPHID().':'.$field.':'.$hash; } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newPhameMarkupEngine(); } public function getMarkupText($field) { return $this->getDescription(); } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getPHID(); } } diff --git a/src/applications/phame/storage/PhamePost.php b/src/applications/phame/storage/PhamePost.php index cb497c61b..a60b9d361 100644 --- a/src/applications/phame/storage/PhamePost.php +++ b/src/applications/phame/storage/PhamePost.php @@ -1,230 +1,230 @@ setBloggerPHID($blogger->getPHID()) ->setBlogPHID($blog->getPHID()) ->setBlog($blog) ->setDatePublished(0) ->setVisibility(self::VISIBILITY_DRAFT); return $post; } public function setBlog(PhameBlog $blog) { $this->blog = $blog; return $this; } public function getBlog() { return $this->blog; } public function getViewURI() { // go for the pretty uri if we can $domain = ($this->blog ? $this->blog->getDomain() : ''); if ($domain) { $phame_title = PhabricatorSlug::normalize($this->getPhameTitle()); return 'http://'.$domain.'/post/'.$phame_title; } $uri = '/phame/post/view/'.$this->getID().'/'; return PhabricatorEnv::getProductionURI($uri); } public function getEditURI() { return '/phame/post/edit/'.$this->getID().'/'; } public function isDraft() { return $this->getVisibility() == self::VISIBILITY_DRAFT; } public function getHumanName() { if ($this->isDraft()) { $name = 'draft'; } else { $name = 'post'; } return $name; } public function getCommentsWidget() { $config_data = $this->getConfigData(); if (empty($config_data)) { return 'none'; } return idx($config_data, 'comments_widget', 'none'); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'configData' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorPhamePHIDTypePost::TYPECONST); + PhabricatorPhamePostPHIDType::TYPECONST); } public function toDictionary() { return array( 'id' => $this->getID(), 'phid' => $this->getPHID(), 'blogPHID' => $this->getBlogPHID(), 'bloggerPHID' => $this->getBloggerPHID(), 'viewURI' => $this->getViewURI(), 'title' => $this->getTitle(), 'phameTitle' => $this->getPhameTitle(), 'body' => $this->getBody(), 'summary' => PhabricatorMarkupEngine::summarize($this->getBody()), 'datePublished' => $this->getDatePublished(), 'published' => !$this->isDraft(), ); } public static function getVisibilityOptionsForSelect() { return array( self::VISIBILITY_DRAFT => 'Draft: visible only to me.', self::VISIBILITY_PUBLISHED => 'Published: visible to the whole world.', ); } public function getCommentsWidgetOptionsForSelect() { $current = $this->getCommentsWidget(); $options = array(); if ($current == 'facebook' || PhabricatorFacebookAuthProvider::getFacebookApplicationID()) { $options['facebook'] = 'Facebook'; } if ($current == 'disqus' || PhabricatorEnv::getEnvConfig('disqus.shortname')) { $options['disqus'] = 'Disqus'; } $options['none'] = 'None'; return $options; } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { // Draft posts are visible only to the author. Published posts are visible // to whoever the blog is visible to. switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: if (!$this->isDraft() && $this->getBlog()) { return $this->getBlog()->getViewPolicy(); } else { return PhabricatorPolicies::POLICY_NOONE; } break; case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $user) { // A blog post's author can always view it, and is the only user allowed // to edit it. switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: case PhabricatorPolicyCapability::CAN_EDIT: return ($user->getPHID() == $this->getBloggerPHID()); } } public function describeAutomaticCapability($capability) { return pht( 'The author of a blog post can always view and edit it.'); } /* -( PhabricatorMarkupInterface Implementation )-------------------------- */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); return $this->getPHID().':'.$field.':'.$hash; } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newPhameMarkupEngine(); } public function getMarkupText($field) { switch ($field) { case self::MARKUP_FIELD_BODY: return $this->getBody(); case self::MARKUP_FIELD_SUMMARY: return PhabricatorMarkupEngine::summarize($this->getBody()); } } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getPHID(); } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getBloggerPHID(), ); } } diff --git a/src/applications/phid/PhabricatorObjectHandle.php b/src/applications/phid/PhabricatorObjectHandle.php index aa7b17ac1..8b596f68f 100644 --- a/src/applications/phid/PhabricatorObjectHandle.php +++ b/src/applications/phid/PhabricatorObjectHandle.php @@ -1,337 +1,337 @@ icon = $icon; return $this; } public function getIcon() { if ($this->getPolicyFiltered()) { return 'fa-lock'; } if ($this->icon) { return $this->icon; } return $this->getTypeIcon(); } public function setTagColor($color) { static $colors; if (!$colors) { $colors = array_fuse(array_keys(PHUITagView::getShadeMap())); } if (isset($colors[$color])) { $this->tagColor = $color; } return $this; } public function getTagColor() { if ($this->getPolicyFiltered()) { return 'disabled'; } if ($this->tagColor) { return $this->tagColor; } return 'blue'; } public function getTypeIcon() { if ($this->getPHIDType()) { return $this->getPHIDType()->getTypeIcon(); } return null; } public function setPolicyFiltered($policy_filered) { $this->policyFiltered = $policy_filered; return $this; } public function getPolicyFiltered() { return $this->policyFiltered; } public function setObjectName($object_name) { $this->objectName = $object_name; return $this; } public function getObjectName() { if (!$this->objectName) { return $this->getName(); } return $this->objectName; } public function setURI($uri) { $this->uri = $uri; return $this; } public function getURI() { return $this->uri; } public function setPHID($phid) { $this->phid = $phid; return $this; } public function getPHID() { return $this->phid; } public function setName($name) { $this->name = $name; return $this; } public function getName() { if ($this->name === null) { if ($this->getPolicyFiltered()) { return pht('Restricted %s', $this->getTypeName()); } else { return pht('Unknown Object (%s)', $this->getTypeName()); } } return $this->name; } public function setStatus($status) { $this->status = $status; return $this; } public function getStatus() { return $this->status; } public function setFullName($full_name) { $this->fullName = $full_name; return $this; } public function getFullName() { if ($this->fullName !== null) { return $this->fullName; } return $this->getName(); } public function setTitle($title) { $this->title = $title; return $this; } public function getTitle() { return $this->title; } public function setType($type) { $this->type = $type; return $this; } public function getType() { return $this->type; } public function setImageURI($uri) { $this->imageURI = $uri; return $this; } public function getImageURI() { return $this->imageURI; } public function setTimestamp($timestamp) { $this->timestamp = $timestamp; return $this; } public function getTimestamp() { return $this->timestamp; } public function getTypeName() { if ($this->getPHIDType()) { return $this->getPHIDType()->getTypeName(); } return $this->getType(); } /** * Set whether or not the underlying object is complete. See * @{method:isComplete} for an explanation of what it means to be complete. * * @param bool True if the handle represents a complete object. * @return this */ public function setComplete($complete) { $this->complete = $complete; return $this; } /** * Determine if the handle represents an object which was completely loaded * (i.e., the underlying object exists) vs an object which could not be * completely loaded (e.g., the type or data for the PHID could not be * identified or located). * * Basically, @{class:PhabricatorHandleQuery} gives you back a handle for * any PHID you give it, but it gives you a complete handle only for valid * PHIDs. * * @return bool True if the handle represents a complete object. */ public function isComplete() { return $this->complete; } /** * Set whether or not the underlying object is disabled. See * @{method:isDisabled} for an explanation of what it means to be disabled. * * @param bool True if the handle represents a disabled object. * @return this */ public function setDisabled($disabled) { $this->disabled = $disabled; return $this; } /** * Determine if the handle represents an object which has been disabled -- * for example, disabled users, archived projects, etc. These objects are * complete and exist, but should be excluded from some system interactions * (for instance, they usually should not appear in typeaheads, and should * not have mail/notifications delivered to or about them). * * @return bool True if the handle represents a disabled object. */ public function isDisabled() { return $this->disabled; } public function renderLink($name = null) { if ($name === null) { $name = $this->getLinkName(); } $classes = array(); $classes[] = 'phui-handle'; $title = $this->title; if ($this->status != PhabricatorObjectHandleStatus::STATUS_OPEN) { $classes[] = 'handle-status-'.$this->status; $title = $title ? $title : $this->status; } if ($this->disabled) { $classes[] = 'handle-disabled'; $title = pht('Disabled'); // Overwrite status. } - if ($this->getType() == PhabricatorPeoplePHIDTypeUser::TYPECONST) { + if ($this->getType() == PhabricatorPeopleUserPHIDType::TYPECONST) { $classes[] = 'phui-link-person'; } $uri = $this->getURI(); $icon = null; if ($this->getPolicyFiltered()) { $icon = id(new PHUIIconView()) ->setIconFont('fa-lock lightgreytext'); } return phutil_tag( $uri ? 'a' : 'span', array( 'href' => $uri, 'class' => implode(' ', $classes), 'title' => $title, ), array($icon, $name)); } public function renderTag() { return id(new PHUITagView()) ->setType(PHUITagView::TYPE_OBJECT) ->setShade($this->getTagColor()) ->setIcon($this->getIcon()) ->setHref($this->getURI()) ->setName($this->getLinkName()); } public function getLinkName() { switch ($this->getType()) { - case PhabricatorPeoplePHIDTypeUser::TYPECONST: + case PhabricatorPeopleUserPHIDType::TYPECONST: $name = $this->getName(); break; default: $name = $this->getFullName(); break; } return $name; } protected function getPHIDType() { $types = PhabricatorPHIDType::getAllTypes(); return idx($types, $this->getType()); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return PhabricatorPolicies::POLICY_PUBLIC; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { // NOTE: Handles are always visible, they just don't get populated with // data if the user can't see the underlying object. return true; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/phlux/phid/PhluxPHIDTypeVariable.php b/src/applications/phlux/phid/PhluxVariablePHIDType.php similarity index 91% rename from src/applications/phlux/phid/PhluxPHIDTypeVariable.php rename to src/applications/phlux/phid/PhluxVariablePHIDType.php index dc61151b8..643025fd9 100644 --- a/src/applications/phlux/phid/PhluxPHIDTypeVariable.php +++ b/src/applications/phlux/phid/PhluxVariablePHIDType.php @@ -1,39 +1,39 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $variable = $objects[$phid]; $key = $variable->getVariableKey(); $handle->setName($key); $handle->setFullName(pht('Variable "%s"', $key)); $handle->setURI("/phlux/view/{$key}/"); } } } diff --git a/src/applications/phlux/storage/PhluxTransaction.php b/src/applications/phlux/storage/PhluxTransaction.php index 9cac59fbe..1224caf20 100644 --- a/src/applications/phlux/storage/PhluxTransaction.php +++ b/src/applications/phlux/storage/PhluxTransaction.php @@ -1,53 +1,53 @@ getAuthorPHID(); switch ($this->getTransactionType()) { case self::TYPE_EDIT_KEY: return pht( '%s created this variable.', $this->renderHandleLink($author_phid)); case self::TYPE_EDIT_VALUE: return pht( '%s updated this variable.', $this->renderHandleLink($author_phid)); } return parent::getTitle(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_EDIT_VALUE: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, json_encode($this->getOldValue()), json_encode($this->getNewValue())); } } diff --git a/src/applications/phlux/storage/PhluxVariable.php b/src/applications/phlux/storage/PhluxVariable.php index 5da5d9396..88aa3ac22 100644 --- a/src/applications/phlux/storage/PhluxVariable.php +++ b/src/applications/phlux/storage/PhluxVariable.php @@ -1,54 +1,54 @@ true, self::CONFIG_SERIALIZATION => array( 'variableValue' => self::SERIALIZATION_JSON ), ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(PhluxPHIDTypeVariable::TYPECONST); + return PhabricatorPHID::generateNewPHID(PhluxVariablePHIDType::TYPECONST); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->viewPolicy; case PhabricatorPolicyCapability::CAN_EDIT: return $this->editPolicy; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/pholio/phid/PholioPHIDTypeImage.php b/src/applications/pholio/phid/PholioImagePHIDType.php similarity index 92% rename from src/applications/pholio/phid/PholioPHIDTypeImage.php rename to src/applications/pholio/phid/PholioImagePHIDType.php index 0df43956f..9278977b7 100644 --- a/src/applications/pholio/phid/PholioPHIDTypeImage.php +++ b/src/applications/pholio/phid/PholioImagePHIDType.php @@ -1,41 +1,41 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $image = $objects[$phid]; $id = $image->getID(); $mock_id = $image->getMockID(); $name = $image->getName(); $handle->setURI("/M{$mock_id}/{$id}/"); $handle->setName($name); $handle->setFullName($name); } } } diff --git a/src/applications/pholio/phid/PholioPHIDTypeMock.php b/src/applications/pholio/phid/PholioMockPHIDType.php similarity index 96% rename from src/applications/pholio/phid/PholioPHIDTypeMock.php rename to src/applications/pholio/phid/PholioMockPHIDType.php index b11acbafe..a75c9938d 100644 --- a/src/applications/pholio/phid/PholioPHIDTypeMock.php +++ b/src/applications/pholio/phid/PholioMockPHIDType.php @@ -1,77 +1,77 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $mock = $objects[$phid]; $id = $mock->getID(); $name = $mock->getName(); $handle->setURI("/M{$id}"); $handle->setName("M{$id}"); $handle->setFullName("M{$id}: {$name}"); if ($mock->isClosed()) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } public function canLoadNamedObject($name) { return preg_match('/^M\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PholioMockQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/pholio/search/PholioSearchIndexer.php b/src/applications/pholio/search/PholioSearchIndexer.php index 7081743c9..d0c0c47a7 100644 --- a/src/applications/pholio/search/PholioSearchIndexer.php +++ b/src/applications/pholio/search/PholioSearchIndexer.php @@ -1,35 +1,35 @@ loadDocumentByPHID($phid); $doc = $this->newDocument($phid) ->setDocumentTitle($mock->getName()) ->setDocumentCreated($mock->getDateCreated()) ->setDocumentModified($mock->getDateModified()); $doc->addField( PhabricatorSearchField::FIELD_BODY, $mock->getDescription()); $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $mock->getAuthorPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $mock->getDateCreated()); $this->indexTransactions( $doc, new PholioTransactionQuery(), array($phid)); return $doc; } } diff --git a/src/applications/pholio/storage/PholioImage.php b/src/applications/pholio/storage/PholioImage.php index e5baf563f..ccb17246b 100644 --- a/src/applications/pholio/storage/PholioImage.php +++ b/src/applications/pholio/storage/PholioImage.php @@ -1,108 +1,108 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(PholioPHIDTypeImage::TYPECONST); + return PhabricatorPHID::generateNewPHID(PholioImagePHIDType::TYPECONST); } public function attachFile(PhabricatorFile $file) { $this->file = $file; return $this; } public function getFile() { $this->assertAttached($this->file); return $this->file; } public function attachMock(PholioMock $mock) { $this->mock = $mock; return $this; } public function getMock() { $this->assertAttached($this->mock); return $this->mock; } public function attachInlineComments(array $inline_comments) { assert_instances_of($inline_comments, 'PholioTransactionComment'); $this->inlineComments = $inline_comments; return $this; } public function getInlineComments() { $this->assertAttached($this->inlineComments); return $this->inlineComments; } /* -( PhabricatorMarkupInterface )----------------------------------------- */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); return 'M:'.$hash; } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newMarkupEngine(array()); } public function getMarkupText($field) { return $this->getDescription(); } public function didMarkupText($field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getID(); } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return $this->getMock()->getCapabilities(); } public function getPolicy($capability) { return $this->getMock()->getPolicy($capability); } // really the *mock* controls who can see an image public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getMock()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/pholio/storage/PholioTransaction.php b/src/applications/pholio/storage/PholioTransaction.php index 1a7534a17..fa3735a45 100644 --- a/src/applications/pholio/storage/PholioTransaction.php +++ b/src/applications/pholio/storage/PholioTransaction.php @@ -1,374 +1,374 @@ getObjectPHID(); $new = $this->getNewValue(); $old = $this->getOldValue(); switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_IMAGE_FILE: $phids = array_merge($phids, $new, $old); break; case PholioTransactionType::TYPE_IMAGE_REPLACE: $phids[] = $new; $phids[] = $old; break; case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: case PholioTransactionType::TYPE_IMAGE_NAME: case PholioTransactionType::TYPE_IMAGE_SEQUENCE: $phids[] = key($new); break; } return $phids; } public function shouldHide() { $old = $this->getOldValue(); switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_DESCRIPTION: return ($old === null); case PholioTransactionType::TYPE_IMAGE_NAME: case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: return ($old === array(null => null)); // this is boring / silly to surface; changing sequence is NBD case PholioTransactionType::TYPE_IMAGE_SEQUENCE: return true; } return parent::shouldHide(); } public function getIcon() { switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_INLINE: return 'fa-comment'; case PholioTransactionType::TYPE_NAME: case PholioTransactionType::TYPE_DESCRIPTION: case PholioTransactionType::TYPE_STATUS: case PholioTransactionType::TYPE_IMAGE_NAME: case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: case PholioTransactionType::TYPE_IMAGE_SEQUENCE: return 'fa-pencil'; case PholioTransactionType::TYPE_IMAGE_FILE: case PholioTransactionType::TYPE_IMAGE_REPLACE: return 'fa-picture-o'; } return parent::getIcon(); } public function getMailTags() { $tags = array(); switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_INLINE: case PhabricatorTransactions::TYPE_COMMENT: $tags[] = MetaMTANotificationType::TYPE_PHOLIO_COMMENT; break; case PholioTransactionType::TYPE_STATUS: $tags[] = MetaMTANotificationType::TYPE_PHOLIO_STATUS; break; case PholioTransactionType::TYPE_NAME: case PholioTransactionType::TYPE_DESCRIPTION: case PholioTransactionType::TYPE_IMAGE_NAME: case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: case PholioTransactionType::TYPE_IMAGE_SEQUENCE: case PholioTransactionType::TYPE_IMAGE_FILE: case PholioTransactionType::TYPE_IMAGE_REPLACE: $tags[] = MetaMTANotificationType::TYPE_PHOLIO_UPDATED; break; default: $tags[] = MetaMTANotificationType::TYPE_PHOLIO_OTHER; break; } return $tags; } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case PholioTransactionType::TYPE_NAME: if ($old === null) { return pht( '%s created "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s renamed this mock from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case PholioTransactionType::TYPE_DESCRIPTION: return pht( "%s updated the mock's description.", $this->renderHandleLink($author_phid)); break; case PholioTransactionType::TYPE_STATUS: return pht( "%s updated the mock's status.", $this->renderHandleLink($author_phid)); break; case PholioTransactionType::TYPE_INLINE: $count = 1; foreach ($this->getTransactionGroup() as $xaction) { if ($xaction->getTransactionType() == $type) { $count++; } } return pht( '%s added %d inline comment(s).', $this->renderHandleLink($author_phid), $count); break; case PholioTransactionType::TYPE_IMAGE_REPLACE: return pht( '%s replaced %s with %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($old), $this->renderHandleLink($new)); break; case PholioTransactionType::TYPE_IMAGE_FILE: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { return pht( '%s edited image(s), added %d: %s; removed %d: %s.', $this->renderHandleLink($author_phid), count($add), $this->renderHandleList($add), count($rem), $this->renderHandleList($rem)); } else if ($add) { return pht( '%s added %d image(s): %s.', $this->renderHandleLink($author_phid), count($add), $this->renderHandleList($add)); } else { return pht( '%s removed %d image(s): %s.', $this->renderHandleLink($author_phid), count($rem), $this->renderHandleList($rem)); } break; case PholioTransactionType::TYPE_IMAGE_NAME: return pht( '%s renamed an image (%s) from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink(key($new)), reset($old), reset($new)); break; case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: return pht( '%s updated an image\'s (%s) description.', $this->renderHandleLink($author_phid), $this->renderHandleLink(key($new))); break; case PholioTransactionType::TYPE_IMAGE_SEQUENCE: return pht( '%s updated an image\'s (%s) sequence.', $this->renderHandleLink($author_phid), $this->renderHandleLink(key($new))); break; } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); $type = $this->getTransactionType(); switch ($type) { case PholioTransactionType::TYPE_NAME: if ($old === null) { return pht( '%s created %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s renamed %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old, $new); } break; case PholioTransactionType::TYPE_DESCRIPTION: return pht( '%s updated the description for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PholioTransactionType::TYPE_STATUS: return pht( '%s updated the status for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PholioTransactionType::TYPE_INLINE: return pht( '%s added an inline comment to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PholioTransactionType::TYPE_IMAGE_REPLACE: case PholioTransactionType::TYPE_IMAGE_FILE: return pht( '%s updated images of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PholioTransactionType::TYPE_IMAGE_NAME: return pht( '%s updated the image names of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: return pht( '%s updated image descriptions of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; case PholioTransactionType::TYPE_IMAGE_SEQUENCE: return pht( '%s updated image sequence of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); break; } return parent::getTitleForFeed($story); } public function getBodyForFeed(PhabricatorFeedStory $story) { $text = null; switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_NAME: if ($this->getOldValue() === null) { $mock = $story->getPrimaryObject(); $text = $mock->getDescription(); } break; case PholioTransactionType::TYPE_INLINE: $text = $this->getComment()->getContent(); break; } if ($text) { return phutil_escape_html_newlines( phutil_utf8_shorten($text, 128)); } return parent::getBodyForFeed($story); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_DESCRIPTION: case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { $old = $this->getOldValue(); $new = $this->getNewValue(); if ($this->getTransactionType() == PholioTransactionType::TYPE_IMAGE_DESCRIPTION) { $old = reset($old); $new = reset($new); } return $this->renderTextCorpusChangeDetails( $viewer, $old, $new); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_NAME: if ($old === null) { return PhabricatorTransactions::COLOR_GREEN; } case PholioTransactionType::TYPE_DESCRIPTION: case PholioTransactionType::TYPE_STATUS: case PholioTransactionType::TYPE_IMAGE_NAME: case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: case PholioTransactionType::TYPE_IMAGE_SEQUENCE: return PhabricatorTransactions::COLOR_BLUE; case PholioTransactionType::TYPE_IMAGE_REPLACE: return PhabricatorTransactions::COLOR_YELLOW; case PholioTransactionType::TYPE_IMAGE_FILE: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { return PhabricatorTransactions::COLOR_YELLOW; } else if ($add) { return PhabricatorTransactions::COLOR_GREEN; } else { return PhabricatorTransactions::COLOR_RED; } } return parent::getColor(); } public function getNoEffectDescription() { switch ($this->getTransactionType()) { case PholioTransactionType::TYPE_IMAGE_NAME: return pht('The image title was not updated.'); case PholioTransactionType::TYPE_IMAGE_DESCRIPTION: return pht('The image description was not updated.'); case PholioTransactionType::TYPE_IMAGE_SEQUENCE: return pht('The image sequence was not updated.'); } return parent::getNoEffectDescription(); } } diff --git a/src/applications/phragment/phid/PhragmentPHIDTypeFragment.php b/src/applications/phragment/phid/PhragmentFragmentPHIDType.php similarity index 92% rename from src/applications/phragment/phid/PhragmentPHIDTypeFragment.php rename to src/applications/phragment/phid/PhragmentFragmentPHIDType.php index 2b26e6717..3722b2fd6 100644 --- a/src/applications/phragment/phid/PhragmentPHIDTypeFragment.php +++ b/src/applications/phragment/phid/PhragmentFragmentPHIDType.php @@ -1,40 +1,40 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $fragment = $objects[$phid]; $handle->setName(pht( 'Fragment %s: %s', $fragment->getID(), $fragment->getName())); $handle->setURI($fragment->getURI()); } } } diff --git a/src/applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php b/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php similarity index 92% rename from src/applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php rename to src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php index 3811bd49e..2ab0240b5 100644 --- a/src/applications/phragment/phid/PhragmentPHIDTypeFragmentVersion.php +++ b/src/applications/phragment/phid/PhragmentFragmentVersionPHIDType.php @@ -1,40 +1,40 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $version = $objects[$phid]; $handle->setName(pht( 'Fragment Version %d: %s', $version->getSequence(), $version->getFragment()->getName())); $handle->setURI($version->getURI()); } } } diff --git a/src/applications/phragment/phid/PhragmentPHIDTypeSnapshot.php b/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php similarity index 91% rename from src/applications/phragment/phid/PhragmentPHIDTypeSnapshot.php rename to src/applications/phragment/phid/PhragmentSnapshotPHIDType.php index 235aaa34a..060b37963 100644 --- a/src/applications/phragment/phid/PhragmentPHIDTypeSnapshot.php +++ b/src/applications/phragment/phid/PhragmentSnapshotPHIDType.php @@ -1,39 +1,39 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { $viewer = $query->getViewer(); foreach ($handles as $phid => $handle) { $snapshot = $objects[$phid]; $handle->setName(pht( 'Snapshot: %s', $snapshot->getName())); $handle->setURI($snapshot->getURI()); } } } diff --git a/src/applications/phragment/storage/PhragmentFragment.php b/src/applications/phragment/storage/PhragmentFragment.php index e4480b64e..8ea1ae240 100644 --- a/src/applications/phragment/storage/PhragmentFragment.php +++ b/src/applications/phragment/storage/PhragmentFragment.php @@ -1,340 +1,340 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhragmentPHIDTypeFragment::TYPECONST); + PhragmentFragmentPHIDType::TYPECONST); } public function getURI() { return '/phragment/browse/'.$this->getPath(); } public function getName() { return basename($this->path); } public function getFile() { return $this->assertAttached($this->file); } public function attachFile(PhabricatorFile $file) { return $this->file = $file; } public function isDirectory() { return $this->latestVersionPHID === null; } public function isDeleted() { return $this->getLatestVersion()->getFilePHID() === null; } public function getLatestVersion() { if ($this->latestVersionPHID === null) { return null; } return $this->assertAttached($this->latestVersion); } public function attachLatestVersion(PhragmentFragmentVersion $version) { return $this->latestVersion = $version; } /* -( Updating ) --------------------------------------------------------- */ /** * Create a new fragment from a file. */ public static function createFromFile( PhabricatorUser $viewer, PhabricatorFile $file = null, $path, $view_policy, $edit_policy) { $fragment = id(new PhragmentFragment()); $fragment->setPath($path); $fragment->setDepth(count(explode('/', $path))); $fragment->setLatestVersionPHID(null); $fragment->setViewPolicy($view_policy); $fragment->setEditPolicy($edit_policy); $fragment->save(); // Directory fragments have no versions associated with them, so we // just return the fragment at this point. if ($file === null) { return $fragment; } if ($file->getMimeType() === 'application/zip') { $fragment->updateFromZIP($viewer, $file); } else { $fragment->updateFromFile($viewer, $file); } return $fragment; } /** * Set the specified file as the next version for the fragment. */ public function updateFromFile( PhabricatorUser $viewer, PhabricatorFile $file) { $existing = id(new PhragmentFragmentVersionQuery()) ->setViewer($viewer) ->withFragmentPHIDs(array($this->getPHID())) ->execute(); $sequence = count($existing); $this->openTransaction(); $version = id(new PhragmentFragmentVersion()); $version->setSequence($sequence); $version->setFragmentPHID($this->getPHID()); $version->setFilePHID($file->getPHID()); $version->save(); $this->setLatestVersionPHID($version->getPHID()); $this->save(); $this->saveTransaction(); $file->attachToObject($viewer, $version->getPHID()); } /** * Apply the specified ZIP archive onto the fragment, removing * and creating fragments as needed. */ public function updateFromZIP( PhabricatorUser $viewer, PhabricatorFile $file) { if ($file->getMimeType() !== 'application/zip') { throw new Exception("File must have mimetype 'application/zip'"); } // First apply the ZIP as normal. $this->updateFromFile($viewer, $file); // Ensure we have ZIP support. $zip = null; try { $zip = new ZipArchive(); } catch (Exception $e) { // The server doesn't have php5-zip, so we can't do recursive updates. return; } $temp = new TempFile(); Filesystem::writeFile($temp, $file->loadFileData()); if (!$zip->open($temp)) { throw new Exception('Unable to open ZIP'); } // Get all of the paths and their data from the ZIP. $mappings = array(); for ($i = 0; $i < $zip->numFiles; $i++) { $path = trim($zip->getNameIndex($i), '/'); $stream = $zip->getStream($path); $data = null; // If the stream is false, then it is a directory entry. We leave // $data set to null for directories so we know not to create a // version entry for them. if ($stream !== false) { $data = stream_get_contents($stream); fclose($stream); } $mappings[$path] = $data; } // We need to detect any directories that are in the ZIP folder that // aren't explicitly noted in the ZIP. This can happen if the file // entries in the ZIP look like: // // * something/blah.png // * something/other.png // * test.png // // Where there is no explicit "something/" entry. foreach ($mappings as $path_key => $data) { if ($data === null) { continue; } $directory = dirname($path_key); while ($directory !== '.') { if (!array_key_exists($directory, $mappings)) { $mappings[$directory] = null; } if (dirname($directory) === $directory) { // dirname() will not reduce this directory any further; to // prevent infinite loop we just break out here. break; } $directory = dirname($directory); } } // Adjust the paths relative to this fragment so we can look existing // fragments up in the DB. $base_path = $this->getPath(); $paths = array(); foreach ($mappings as $p => $data) { $paths[] = $base_path.'/'.$p; } // FIXME: What happens when a child exists, but the current user // can't see it. We're going to create a new child with the exact // same path and then bad things will happen. $children = id(new PhragmentFragmentQuery()) ->setViewer($viewer) ->needLatestVersion(true) ->withLeadingPath($this->getPath().'/') ->execute(); $children = mpull($children, null, 'getPath'); // Iterate over the existing fragments. foreach ($children as $full_path => $child) { $path = substr($full_path, strlen($base_path) + 1); if (array_key_exists($path, $mappings)) { if ($child->isDirectory() && $mappings[$path] === null) { // Don't create a version entry for a directory // (unless it's been converted into a file). continue; } // The file is being updated. $file = PhabricatorFile::newFromFileData( $mappings[$path], array('name' => basename($path))); $child->updateFromFile($viewer, $file); } else { // The file is being deleted. $child->deleteFile($viewer); } } // Iterate over the mappings to find new files. foreach ($mappings as $path => $data) { if (!array_key_exists($base_path.'/'.$path, $children)) { // The file is being created. If the data is null, // then this is explicitly a directory being created. $file = null; if ($mappings[$path] !== null) { $file = PhabricatorFile::newFromFileData( $mappings[$path], array('name' => basename($path))); } PhragmentFragment::createFromFile( $viewer, $file, $base_path.'/'.$path, $this->getViewPolicy(), $this->getEditPolicy()); } } } /** * Delete the contents of the specified fragment. */ public function deleteFile(PhabricatorUser $viewer) { $existing = id(new PhragmentFragmentVersionQuery()) ->setViewer($viewer) ->withFragmentPHIDs(array($this->getPHID())) ->execute(); $sequence = count($existing); $this->openTransaction(); $version = id(new PhragmentFragmentVersion()); $version->setSequence($sequence); $version->setFragmentPHID($this->getPHID()); $version->setFilePHID(null); $version->save(); $this->setLatestVersionPHID($version->getPHID()); $this->save(); $this->saveTransaction(); } /* -( Utility ) ---------------------------------------------------------- */ public function getFragmentMappings( PhabricatorUser $viewer, $base_path) { $children = id(new PhragmentFragmentQuery()) ->setViewer($viewer) ->needLatestVersion(true) ->withLeadingPath($this->getPath().'/') ->withDepths(array($this->getDepth() + 1)) ->execute(); if (count($children) === 0) { $path = substr($this->getPath(), strlen($base_path) + 1); return array($path => $this); } else { $mappings = array(); foreach ($children as $child) { $child_mappings = $child->getFragmentMappings( $viewer, $base_path); foreach ($child_mappings as $key => $value) { $mappings[$key] = $value; } } return $mappings; } } /* -( Policy Interface )--------------------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/phragment/storage/PhragmentFragmentVersion.php b/src/applications/phragment/storage/PhragmentFragmentVersion.php index ff848e327..79a8a6eee 100644 --- a/src/applications/phragment/storage/PhragmentFragmentVersion.php +++ b/src/applications/phragment/storage/PhragmentFragmentVersion.php @@ -1,62 +1,62 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhragmentPHIDTypeFragmentVersion::TYPECONST); + PhragmentFragmentVersionPHIDType::TYPECONST); } public function getURI() { return '/phragment/version/'.$this->getID().'/'; } public function getFragment() { return $this->assertAttached($this->fragment); } public function attachFragment(PhragmentFragment $fragment) { return $this->fragment = $fragment; } public function getFile() { return $this->assertAttached($this->file); } public function attachFile(PhabricatorFile $file) { return $this->file = $file; } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW ); } public function getPolicy($capability) { return $this->getFragment()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getFragment()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return $this->getFragment()->describeAutomaticCapability($capability); } } diff --git a/src/applications/phragment/storage/PhragmentSnapshot.php b/src/applications/phragment/storage/PhragmentSnapshot.php index 59d0a04b2..a228341ce 100644 --- a/src/applications/phragment/storage/PhragmentSnapshot.php +++ b/src/applications/phragment/storage/PhragmentSnapshot.php @@ -1,67 +1,67 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhragmentPHIDTypeSnapshot::TYPECONST); + PhragmentSnapshotPHIDType::TYPECONST); } public function getURI() { return '/phragment/snapshot/view/'.$this->getID().'/'; } public function getPrimaryFragment() { return $this->assertAttached($this->primaryFragment); } public function attachPrimaryFragment(PhragmentFragment $fragment) { return $this->primaryFragment = $fragment; } public function delete() { $children = id(new PhragmentSnapshotChild()) ->loadAllWhere('snapshotPHID = %s', $this->getPHID()); $this->openTransaction(); foreach ($children as $child) { $child->delete(); } $result = parent::delete(); $this->saveTransaction(); return $result; } /* -( Policy Interface )--------------------------------------------------- */ public function getCapabilities() { return $this->getPrimaryFragment()->getCapabilities(); } public function getPolicy($capability) { return $this->getPrimaryFragment()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getPrimaryFragment() ->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return $this->getPrimaryFragment() ->describeAutomaticCapability($capability); } } diff --git a/src/applications/phriction/phid/PhrictionPHIDTypeDocument.php b/src/applications/phriction/phid/PhrictionDocumentPHIDType.php similarity index 94% rename from src/applications/phriction/phid/PhrictionPHIDTypeDocument.php rename to src/applications/phriction/phid/PhrictionDocumentPHIDType.php index 88522233e..877b1fa55 100644 --- a/src/applications/phriction/phid/PhrictionPHIDTypeDocument.php +++ b/src/applications/phriction/phid/PhrictionDocumentPHIDType.php @@ -1,50 +1,50 @@ withPHIDs($phids) ->needContent(true); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $document = $objects[$phid]; $content = $document->getContent(); $title = $content->getTitle(); $slug = $document->getSlug(); $status = $document->getStatus(); $handle->setName($title); $handle->setURI(PhrictionDocument::getSlugURI($slug)); if ($status != PhrictionDocumentStatus::STATUS_EXISTS) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } } diff --git a/src/applications/phriction/search/PhrictionSearchIndexer.php b/src/applications/phriction/search/PhrictionSearchIndexer.php index 996002d04..7fdc54e7f 100644 --- a/src/applications/phriction/search/PhrictionSearchIndexer.php +++ b/src/applications/phriction/search/PhrictionSearchIndexer.php @@ -1,47 +1,47 @@ loadDocumentByPHID($phid); $content = id(new PhrictionContent())->load($document->getContentID()); $document->attachContent($content); $content = $document->getContent(); $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($document->getPHID()); - $doc->setDocumentType(PhrictionPHIDTypeDocument::TYPECONST); + $doc->setDocumentType(PhrictionDocumentPHIDType::TYPECONST); $doc->setDocumentTitle($content->getTitle()); // TODO: This isn't precisely correct, denormalize into the Document table? $doc->setDocumentCreated($content->getDateCreated()); $doc->setDocumentModified($content->getDateModified()); $doc->addField( PhabricatorSearchField::FIELD_BODY, $content->getContent()); $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $content->getAuthorPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $content->getDateCreated()); $doc->addRelationship( ($document->getStatus() == PhrictionDocumentStatus::STATUS_EXISTS) ? PhabricatorSearchRelationship::RELATIONSHIP_OPEN : PhabricatorSearchRelationship::RELATIONSHIP_CLOSED, $document->getPHID(), - PhrictionPHIDTypeDocument::TYPECONST, + PhrictionDocumentPHIDType::TYPECONST, time()); return $doc; } } diff --git a/src/applications/phriction/storage/PhrictionDocument.php b/src/applications/phriction/storage/PhrictionDocument.php index 9ba8fbccf..45fdf6d0a 100644 --- a/src/applications/phriction/storage/PhrictionDocument.php +++ b/src/applications/phriction/storage/PhrictionDocument.php @@ -1,206 +1,206 @@ true, self::CONFIG_TIMESTAMPS => false, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhrictionPHIDTypeDocument::TYPECONST); + PhrictionDocumentPHIDType::TYPECONST); } public static function getSlugURI($slug, $type = 'document') { static $types = array( 'document' => '/w/', 'history' => '/phriction/history/', ); if (empty($types[$type])) { throw new Exception("Unknown URI type '{$type}'!"); } $prefix = $types[$type]; if ($slug == '/') { return $prefix; } else { // NOTE: The effect here is to escape non-latin characters, since modern // browsers deal with escaped UTF8 characters in a reasonable way (showing // the user a readable URI) but older programs may not. $slug = phutil_escape_uri($slug); return $prefix.$slug; } } public function setSlug($slug) { $this->slug = PhabricatorSlug::normalize($slug); $this->depth = PhabricatorSlug::getDepth($slug); return $this; } public function attachContent(PhrictionContent $content) { $this->contentObject = $content; return $this; } public function getContent() { return $this->assertAttached($this->contentObject); } public function getProject() { return $this->assertAttached($this->project); } public function attachProject(PhabricatorProject $project = null) { $this->project = $project; return $this; } public function hasProject() { return (bool)$this->getProject(); } public function getAncestors() { return $this->ancestors; } public function getAncestor($slug) { return $this->assertAttachedKey($this->ancestors, $slug); } public function attachAncestor($slug, $ancestor) { $this->ancestors[$slug] = $ancestor; return $this; } public static function isProjectSlug($slug) { $slug = PhabricatorSlug::normalize($slug); $prefix = 'projects/'; if ($slug == $prefix) { // The 'projects/' document is not itself a project slug. return false; } return !strncmp($slug, $prefix, strlen($prefix)); } public static function getProjectSlugIdentifier($slug) { if (!self::isProjectSlug($slug)) { throw new Exception("Slug '{$slug}' is not a project slug!"); } $slug = PhabricatorSlug::normalize($slug); $parts = explode('/', $slug); return $parts[1].'/'; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { if ($this->hasProject()) { return $this->getProject()->getPolicy($capability); } return PhabricatorPolicies::POLICY_USER; } public function hasAutomaticCapability($capability, PhabricatorUser $user) { if ($this->hasProject()) { return $this->getProject()->hasAutomaticCapability($capability, $user); } return false; } public function describeAutomaticCapability($capability) { if ($this->hasProject()) { return pht( "This is a project wiki page, and inherits the project's policies."); } switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht( 'To view a wiki document, you must also be able to view all '. 'of its parents.'); } return null; } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return false; } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return PhabricatorSubscribersQuery::loadSubscribersForPHID($this->phid); } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $contents = id(new PhrictionContent())->loadAllWhere( 'documentID = %d', $this->getID()); foreach ($contents as $content) { $content->delete(); } $this->saveTransaction(); } } diff --git a/src/applications/policy/filter/PhabricatorPolicyFilter.php b/src/applications/policy/filter/PhabricatorPolicyFilter.php index f2b84d6bb..869aab7f9 100644 --- a/src/applications/policy/filter/PhabricatorPolicyFilter.php +++ b/src/applications/policy/filter/PhabricatorPolicyFilter.php @@ -1,459 +1,459 @@ setViewer($user) ->requireCapabilities(array($capability)) ->raisePolicyExceptions(true) ->apply(array($object)); } /** * Perform a capability check, acting as though an object had a specific * policy. This is primarily used to check if a policy is valid (for example, * to prevent users from editing away their ability to edit an object). * * Specifically, a check like this: * * PhabricatorPolicyFilter::requireCapabilityWithForcedPolicy( * $viewer, * $object, * PhabricatorPolicyCapability::CAN_EDIT, * $potential_new_policy); * * ...will throw a @{class:PhabricatorPolicyException} if the new policy would * remove the user's ability to edit the object. * * @param PhabricatorUser The viewer to perform a policy check for. * @param PhabricatorPolicyInterface The object to perform a policy check on. * @param string Capability to test. * @param string Perform the test as though the object has this * policy instead of the policy it actually has. * @return void */ public static function requireCapabilityWithForcedPolicy( PhabricatorUser $viewer, PhabricatorPolicyInterface $object, $capability, $forced_policy) { id(new PhabricatorPolicyFilter()) ->setViewer($viewer) ->requireCapabilities(array($capability)) ->raisePolicyExceptions(true) ->forcePolicy($forced_policy) ->apply(array($object)); } public static function hasCapability( PhabricatorUser $user, PhabricatorPolicyInterface $object, $capability) { $filter = new PhabricatorPolicyFilter(); $filter->setViewer($user); $filter->requireCapabilities(array($capability)); $result = $filter->apply(array($object)); return (count($result) == 1); } public function setViewer(PhabricatorUser $user) { $this->viewer = $user; return $this; } public function requireCapabilities(array $capabilities) { $this->capabilities = $capabilities; return $this; } public function raisePolicyExceptions($raise) { $this->raisePolicyExceptions = $raise; return $this; } public function forcePolicy($forced_policy) { $this->forcedPolicy = $forced_policy; return $this; } public function apply(array $objects) { assert_instances_of($objects, 'PhabricatorPolicyInterface'); $viewer = $this->viewer; $capabilities = $this->capabilities; if (!$viewer || !$capabilities) { throw new Exception( 'Call setViewer() and requireCapabilities() before apply()!'); } // If the viewer is omnipotent, short circuit all the checks and just // return the input unmodified. This is an optimization; we know the // result already. if ($viewer->isOmnipotent()) { return $objects; } $filtered = array(); $viewer_phid = $viewer->getPHID(); if (empty($this->userProjects[$viewer_phid])) { $this->userProjects[$viewer_phid] = array(); } $need_projects = array(); $need_policies = array(); foreach ($objects as $key => $object) { $object_capabilities = $object->getCapabilities(); foreach ($capabilities as $capability) { if (!in_array($capability, $object_capabilities)) { throw new Exception( "Testing for capability '{$capability}' on an object which does ". "not have that capability!"); } $policy = $this->getObjectPolicy($object, $capability); $type = phid_get_type($policy); - if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) { + if ($type == PhabricatorProjectProjectPHIDType::TYPECONST) { $need_projects[$policy] = $policy; } if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) { $need_policies[$policy] = $policy; } } } if ($need_policies) { $this->loadCustomPolicies(array_keys($need_policies)); } // If we need projects, check if any of the projects we need are also the // objects we're filtering. Because of how project rules work, this is a // common case. if ($need_projects) { foreach ($objects as $object) { if ($object instanceof PhabricatorProject) { $project_phid = $object->getPHID(); if (isset($need_projects[$project_phid])) { $is_member = $object->isUserMember($viewer_phid); $this->userProjects[$viewer_phid][$project_phid] = $is_member; unset($need_projects[$project_phid]); } } } } if ($need_projects) { $need_projects = array_unique($need_projects); // NOTE: We're using the omnipotent user here to avoid a recursive // descent into madness. We don't actually need to know if the user can // see these projects or not, since: the check is "user is member of // project", not "user can see project"; and membership implies // visibility anyway. Without this, we may load other projects and // re-enter the policy filter and generally create a huge mess. $projects = id(new PhabricatorProjectQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withMemberPHIDs(array($viewer->getPHID())) ->withPHIDs($need_projects) ->execute(); foreach ($projects as $project) { $this->userProjects[$viewer_phid][$project->getPHID()] = true; } } foreach ($objects as $key => $object) { $object_capabilities = $object->getCapabilities(); foreach ($capabilities as $capability) { if (!$this->checkCapability($object, $capability)) { // If we're missing any capability, move on to the next object. continue 2; } } // If we make it here, we have all of the required capabilities. $filtered[$key] = $object; } return $filtered; } private function checkCapability( PhabricatorPolicyInterface $object, $capability) { $policy = $this->getObjectPolicy($object, $capability); if (!$policy) { // TODO: Formalize this somehow? $policy = PhabricatorPolicies::POLICY_USER; } if ($policy == PhabricatorPolicies::POLICY_PUBLIC) { // If the object is set to "public" but that policy is disabled for this // install, restrict the policy to "user". if (!PhabricatorEnv::getEnvConfig('policy.allow-public')) { $policy = PhabricatorPolicies::POLICY_USER; } // If the object is set to "public" but the capability is not a public // capability, restrict the policy to "user". $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); if (!$capobj || !$capobj->shouldAllowPublicPolicySetting()) { $policy = PhabricatorPolicies::POLICY_USER; } } $viewer = $this->viewer; if ($viewer->isOmnipotent()) { return true; } if ($object->hasAutomaticCapability($capability, $viewer)) { return true; } switch ($policy) { case PhabricatorPolicies::POLICY_PUBLIC: return true; case PhabricatorPolicies::POLICY_USER: if ($viewer->getPHID()) { return true; } else { $this->rejectObject($object, $policy, $capability); } break; case PhabricatorPolicies::POLICY_ADMIN: if ($viewer->getIsAdmin()) { return true; } else { $this->rejectObject($object, $policy, $capability); } break; case PhabricatorPolicies::POLICY_NOONE: $this->rejectObject($object, $policy, $capability); break; default: $type = phid_get_type($policy); - if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) { + if ($type == PhabricatorProjectProjectPHIDType::TYPECONST) { if (!empty($this->userProjects[$viewer->getPHID()][$policy])) { return true; } else { $this->rejectObject($object, $policy, $capability); } - } else if ($type == PhabricatorPeoplePHIDTypeUser::TYPECONST) { + } else if ($type == PhabricatorPeopleUserPHIDType::TYPECONST) { if ($viewer->getPHID() == $policy) { return true; } else { $this->rejectObject($object, $policy, $capability); } } else if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) { if ($this->checkCustomPolicy($policy)) { return true; } else { $this->rejectObject($object, $policy, $capability); } } else { // Reject objects with unknown policies. $this->rejectObject($object, false, $capability); } } return false; } public function rejectObject( PhabricatorPolicyInterface $object, $policy, $capability) { if (!$this->raisePolicyExceptions) { return; } if ($this->viewer->isOmnipotent()) { // Never raise policy exceptions for the omnipotent viewer. Although we // will never normally issue a policy rejection for the omnipotent // viewer, we can end up here when queries blanket reject objects that // have failed to load, without distinguishing between nonexistent and // nonvisible objects. return; } $capobj = PhabricatorPolicyCapability::getCapabilityByKey($capability); $rejection = null; if ($capobj) { $rejection = $capobj->describeCapabilityRejection(); $capability_name = $capobj->getCapabilityName(); } else { $capability_name = $capability; } if (!$rejection) { // We couldn't find the capability object, or it doesn't provide a // tailored rejection string. $rejection = pht( 'You do not have the required capability ("%s") to do whatever you '. 'are trying to do.', $capability); } $more = PhabricatorPolicy::getPolicyExplanation($this->viewer, $policy); $exceptions = $object->describeAutomaticCapability($capability); $details = array_filter(array_merge(array($more), (array)$exceptions)); // NOTE: Not every type of policy object has a real PHID; just load an // empty handle if a real PHID isn't available. $phid = nonempty($object->getPHID(), PhabricatorPHIDConstants::PHID_VOID); $handle = id(new PhabricatorHandleQuery()) ->setViewer($this->viewer) ->withPHIDs(array($phid)) ->executeOne(); $object_name = pht( '%s %s', $handle->getTypeName(), $handle->getObjectName()); $is_serious = PhabricatorEnv::getEnvConfig('phabricator.serious-business'); if ($is_serious) { $title = pht( 'Access Denied: %s', $object_name); } else { $title = pht( 'You Shall Not Pass: %s', $object_name); } $full_message = pht( '[%s] (%s) %s // %s', $title, $capability_name, $rejection, implode(' ', $details)); $exception = id(new PhabricatorPolicyException($full_message)) ->setTitle($title) ->setRejection($rejection) ->setCapabilityName($capability_name) ->setMoreInfo($details); throw $exception; } private function loadCustomPolicies(array $phids) { $viewer = $this->viewer; $viewer_phid = $viewer->getPHID(); $custom_policies = id(new PhabricatorPolicyQuery()) ->setViewer($viewer) ->withPHIDs($phids) ->execute(); $custom_policies = mpull($custom_policies, null, 'getPHID'); $classes = array(); $values = array(); foreach ($custom_policies as $policy) { foreach ($policy->getCustomRuleClasses() as $class) { $classes[$class] = $class; $values[$class][] = $policy->getCustomRuleValues($class); } } foreach ($classes as $class => $ignored) { $object = newv($class, array()); $object->willApplyRules($viewer, array_mergev($values[$class])); $classes[$class] = $object; } foreach ($custom_policies as $policy) { $policy->attachRuleObjects($classes); } if (empty($this->customPolicies[$viewer_phid])) { $this->customPolicies[$viewer_phid] = array(); } $this->customPolicies[$viewer->getPHID()] += $custom_policies; } private function checkCustomPolicy($policy_phid) { $viewer = $this->viewer; $viewer_phid = $viewer->getPHID(); $policy = $this->customPolicies[$viewer_phid][$policy_phid]; $objects = $policy->getRuleObjects(); $action = null; foreach ($policy->getRules() as $rule) { $object = idx($objects, idx($rule, 'rule')); if (!$object) { // Reject, this policy has a bogus rule. return false; } // If the user matches this rule, use this action. if ($object->applyRule($viewer, idx($rule, 'value'))) { $action = idx($rule, 'action'); break; } } if ($action === null) { $action = $policy->getDefaultAction(); } if ($action === PhabricatorPolicy::ACTION_ALLOW) { return true; } return false; } private function getObjectPolicy( PhabricatorPolicyInterface $object, $capability) { if ($this->forcedPolicy) { return $this->forcedPolicy; } else { return $object->getPolicy($capability); } } } diff --git a/src/applications/policy/storage/PhabricatorPolicy.php b/src/applications/policy/storage/PhabricatorPolicy.php index 5240a64c8..3840b51f0 100644 --- a/src/applications/policy/storage/PhabricatorPolicy.php +++ b/src/applications/policy/storage/PhabricatorPolicy.php @@ -1,354 +1,354 @@ true, self::CONFIG_SERIALIZATION => array( 'rules' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( PhabricatorPolicyPHIDTypePolicy::TYPECONST); } public static function newFromPolicyAndHandle( $policy_identifier, PhabricatorObjectHandle $handle = null) { $is_global = PhabricatorPolicyQuery::isGlobalPolicy($policy_identifier); if ($is_global) { return PhabricatorPolicyQuery::getGlobalPolicy($policy_identifier); } if (!$handle) { throw new Exception( "Policy identifier is an object PHID ('{$policy_identifier}'), but no ". "object handle was provided. A handle must be provided for object ". "policies."); } $handle_phid = $handle->getPHID(); if ($policy_identifier != $handle_phid) { throw new Exception( "Policy identifier is an object PHID ('{$policy_identifier}'), but ". "the provided handle has a different PHID ('{$handle_phid}'). The ". "handle must correspond to the policy identifier."); } $policy = id(new PhabricatorPolicy()) ->setPHID($policy_identifier) ->setHref($handle->getURI()); $phid_type = phid_get_type($policy_identifier); switch ($phid_type) { - case PhabricatorProjectPHIDTypeProject::TYPECONST: + case PhabricatorProjectProjectPHIDType::TYPECONST: $policy->setType(PhabricatorPolicyType::TYPE_PROJECT); $policy->setName($handle->getName()); break; - case PhabricatorPeoplePHIDTypeUser::TYPECONST: + case PhabricatorPeopleUserPHIDType::TYPECONST: $policy->setType(PhabricatorPolicyType::TYPE_USER); $policy->setName($handle->getFullName()); break; case PhabricatorPolicyPHIDTypePolicy::TYPECONST: // TODO: This creates a weird handle-based version of a rule policy. // It behaves correctly, but can't be applied since it doesn't have // any rules. It is used to render transactions, and might need some // cleanup. break; default: $policy->setType(PhabricatorPolicyType::TYPE_MASKED); $policy->setName($handle->getFullName()); break; } $policy->makeEphemeral(); return $policy; } public function setType($type) { $this->type = $type; return $this; } public function getType() { if (!$this->type) { return PhabricatorPolicyType::TYPE_CUSTOM; } return $this->type; } public function setName($name) { $this->name = $name; return $this; } public function getName() { if (!$this->name) { return pht('Custom Policy'); } return $this->name; } public function setShortName($short_name) { $this->shortName = $short_name; return $this; } public function getShortName() { if ($this->shortName) { return $this->shortName; } return $this->getName(); } public function setHref($href) { $this->href = $href; return $this; } public function getHref() { return $this->href; } public function setWorkflow($workflow) { $this->workflow = $workflow; return $this; } public function getWorkflow() { return $this->workflow; } public function getIcon() { switch ($this->getType()) { case PhabricatorPolicyType::TYPE_GLOBAL: static $map = array( PhabricatorPolicies::POLICY_PUBLIC => 'fa-globe', PhabricatorPolicies::POLICY_USER => 'fa-users', PhabricatorPolicies::POLICY_ADMIN => 'fa-eye', PhabricatorPolicies::POLICY_NOONE => 'fa-ban', ); return idx($map, $this->getPHID(), 'fa-question-circle'); case PhabricatorPolicyType::TYPE_USER: return 'fa-user'; case PhabricatorPolicyType::TYPE_PROJECT: return 'fa-briefcase'; case PhabricatorPolicyType::TYPE_CUSTOM: case PhabricatorPolicyType::TYPE_MASKED: return 'fa-certificate'; default: return 'fa-question-circle'; } } public function getSortKey() { return sprintf( '%02d%s', PhabricatorPolicyType::getPolicyTypeOrder($this->getType()), $this->getSortName()); } private function getSortName() { if ($this->getType() == PhabricatorPolicyType::TYPE_GLOBAL) { static $map = array( PhabricatorPolicies::POLICY_PUBLIC => 0, PhabricatorPolicies::POLICY_USER => 1, PhabricatorPolicies::POLICY_ADMIN => 2, PhabricatorPolicies::POLICY_NOONE => 3, ); return idx($map, $this->getPHID()); } return $this->getName(); } public static function getPolicyExplanation( PhabricatorUser $viewer, $policy) { switch ($policy) { case PhabricatorPolicies::POLICY_PUBLIC: return pht('This object is public.'); case PhabricatorPolicies::POLICY_USER: return pht('Logged in users can take this action.'); case PhabricatorPolicies::POLICY_ADMIN: return pht('Administrators can take this action.'); case PhabricatorPolicies::POLICY_NOONE: return pht('By default, no one can take this action.'); default: $handle = id(new PhabricatorHandleQuery()) ->setViewer($viewer) ->withPHIDs(array($policy)) ->executeOne(); $type = phid_get_type($policy); - if ($type == PhabricatorProjectPHIDTypeProject::TYPECONST) { + if ($type == PhabricatorProjectProjectPHIDType::TYPECONST) { return pht( 'Members of the project "%s" can take this action.', $handle->getFullName()); - } else if ($type == PhabricatorPeoplePHIDTypeUser::TYPECONST) { + } else if ($type == PhabricatorPeopleUserPHIDType::TYPECONST) { return pht( '%s can take this action.', $handle->getFullName()); } else if ($type == PhabricatorPolicyPHIDTypePolicy::TYPECONST) { return pht( 'This object has a custom policy controlling who can take this '. 'action.'); } else { return pht( 'This object has an unknown or invalid policy setting ("%s").', $policy); } } } public function getFullName() { switch ($this->getType()) { case PhabricatorPolicyType::TYPE_PROJECT: return pht('Project: %s', $this->getName()); case PhabricatorPolicyType::TYPE_MASKED: return pht('Other: %s', $this->getName()); default: return $this->getName(); } } public function renderDescription($icon=false) { $img = null; if ($icon) { $img = id(new PHUIIconView()) ->setIconFont($this->getIcon()); } if ($this->getHref()) { $desc = javelin_tag( 'a', array( 'href' => $this->getHref(), 'class' => 'policy-link', 'sigil' => $this->getWorkflow() ? 'workflow' : null, ), array( $img, $this->getName(), )); } else { if ($img) { $desc = array($img, $this->getName()); } else { $desc = $this->getName(); } } switch ($this->getType()) { case PhabricatorPolicyType::TYPE_PROJECT: return pht('%s (Project)', $desc); case PhabricatorPolicyType::TYPE_CUSTOM: return $desc; case PhabricatorPolicyType::TYPE_MASKED: return pht( '%s (You do not have permission to view policy details.)', $desc); default: return $desc; } } /** * Return a list of custom rule classes (concrete subclasses of * @{class:PhabricatorPolicyRule}) this policy uses. * * @return list List of class names. */ public function getCustomRuleClasses() { $classes = array(); foreach ($this->getRules() as $rule) { $class = idx($rule, 'rule'); try { if (class_exists($class)) { $classes[$class] = $class; } } catch (Exception $ex) { continue; } } return array_keys($classes); } /** * Return a list of all values used by a given rule class to implement this * policy. This is used to bulk load data (like project memberships) in order * to apply policy filters efficiently. * * @param string Policy rule classname. * @return list List of values used in this policy. */ public function getCustomRuleValues($rule_class) { $values = array(); foreach ($this->getRules() as $rule) { if ($rule['rule'] == $rule_class) { $values[] = $rule['value']; } } return $values; } public function attachRuleObjects(array $objects) { $this->ruleObjects = $objects; return $this; } public function getRuleObjects() { return $this->assertAttached($this->ruleObjects); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { // NOTE: We implement policies only so we can comply with the interface. // The actual query skips them, as enforcing policies on policies seems // perilous and isn't currently required by the application. return PhabricatorPolicies::POLICY_PUBLIC; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/ponder/phid/PonderPHIDTypeAnswer.php b/src/applications/ponder/phid/PonderAnswerPHIDType.php similarity index 91% rename from src/applications/ponder/phid/PonderPHIDTypeAnswer.php rename to src/applications/ponder/phid/PonderAnswerPHIDType.php index c4a6a7477..24564f6a6 100644 --- a/src/applications/ponder/phid/PonderPHIDTypeAnswer.php +++ b/src/applications/ponder/phid/PonderAnswerPHIDType.php @@ -1,38 +1,38 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $answer = $objects[$phid]; $id = $answer->getID(); $handle->setName("Answer {$id}"); $handle->setURI($answer->getURI()); } } } diff --git a/src/applications/ponder/phid/PonderPHIDTypeQuestion.php b/src/applications/ponder/phid/PonderQuestionPHIDType.php similarity index 95% rename from src/applications/ponder/phid/PonderPHIDTypeQuestion.php rename to src/applications/ponder/phid/PonderQuestionPHIDType.php index e70f5f3d7..97812f673 100644 --- a/src/applications/ponder/phid/PonderPHIDTypeQuestion.php +++ b/src/applications/ponder/phid/PonderQuestionPHIDType.php @@ -1,72 +1,72 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $question = $objects[$phid]; $id = $question->getID(); $handle->setName("Q{$id}"); $handle->setURI("/Q{$id}"); $handle->setFullName($question->getFullTitle()); } } public function canLoadNamedObject($name) { return preg_match('/^Q\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PonderQuestionQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/ponder/search/PonderSearchIndexer.php b/src/applications/ponder/search/PonderSearchIndexer.php index 82cc13dc9..a762ade57 100644 --- a/src/applications/ponder/search/PonderSearchIndexer.php +++ b/src/applications/ponder/search/PonderSearchIndexer.php @@ -1,51 +1,51 @@ loadDocumentByPHID($phid); $doc = $this->newDocument($phid) ->setDocumentTitle($question->getTitle()) ->setDocumentCreated($question->getDateCreated()) ->setDocumentModified($question->getDateModified()); $doc->addField( PhabricatorSearchField::FIELD_BODY, $question->getContent()); $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $question->getAuthorPHID(), - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $question->getDateCreated()); $answers = id(new PonderAnswerQuery()) ->setViewer($this->getViewer()) ->withQuestionIDs(array($question->getID())) ->execute(); foreach ($answers as $answer) { if (strlen($answer->getContent())) { $doc->addField( PhabricatorSearchField::FIELD_COMMENT, $answer->getContent()); } } $this->indexTransactions( $doc, new PonderQuestionTransactionQuery(), array($phid)); $this->indexTransactions( $doc, new PonderAnswerTransactionQuery(), mpull($answers, 'getPHID')); return $doc; } } diff --git a/src/applications/ponder/storage/PonderAnswer.php b/src/applications/ponder/storage/PonderAnswer.php index b281961c3..08f66b29d 100644 --- a/src/applications/ponder/storage/PonderAnswer.php +++ b/src/applications/ponder/storage/PonderAnswer.php @@ -1,199 +1,198 @@ question = $question; return $this; } public function getQuestion() { return $this->assertAttached($this->question); } public function getURI() { return '/Q'.$this->getQuestionID().'#A'.$this->getID(); } public function setUserVote($vote) { $this->vote = $vote['data']; if (!$this->vote) { $this->vote = PonderVote::VOTE_NONE; } return $this; } public function attachUserVote($user_phid, $vote) { $this->vote = $vote; return $this; } public function getUserVote() { return $this->vote; } public function setComments($comments) { $this->comments = $comments; return $this; } public function getComments() { return $this->comments; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID( - PonderPHIDTypeAnswer::TYPECONST); + return PhabricatorPHID::generateNewPHID(PonderAnswerPHIDType::TYPECONST); } public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source->serialize(); return $this; } public function getContentSource() { return PhabricatorContentSource::newFromSerialized($this->contentSource); } public function getMarkupField() { return self::MARKUP_FIELD_CONTENT; } // Markup interface public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); $id = $this->getID(); return "ponder:A{$id}:{$field}:{$hash}"; } public function getMarkupText($field) { return $this->getContent(); } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::getEngine(); } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getID(); } // votable interface public function getUserVoteEdgeType() { return PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER; } public function getVotablePHID() { return $this->getPHID(); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getQuestion()->getPolicy($capability); case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: if ($this->getAuthorPHID() == $viewer->getPHID()) { return true; } return $this->getQuestion()->hasAutomaticCapability( $capability, $viewer); case PhabricatorPolicyCapability::CAN_EDIT: return ($this->getAuthorPHID() == $viewer->getPHID()); } } public function describeAutomaticCapability($capability) { $out = array(); $out[] = pht('The author of an answer can always view and edit it.'); switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $out[] = pht( 'The user who asks a question can always view the answers.'); break; } return $out; } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), ); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($phid == $this->getAuthorPHID()); } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } } diff --git a/src/applications/ponder/storage/PonderAnswerTransaction.php b/src/applications/ponder/storage/PonderAnswerTransaction.php index 24a8a86ba..7b70dcadc 100644 --- a/src/applications/ponder/storage/PonderAnswerTransaction.php +++ b/src/applications/ponder/storage/PonderAnswerTransaction.php @@ -1,104 +1,104 @@ getTransactionType()) { case self::TYPE_CONTENT: $phids[] = $this->getObjectPHID(); break; } return $phids; } public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return pht( '%s edited %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); switch ($this->getTransactionType()) { case self::TYPE_CONTENT: $answer = $story->getObject($object_phid); $question = $answer->getQuestion(); $answer_handle = $this->getHandle($object_phid); $link = $answer_handle->renderLink( $question->getFullTitle()); return pht( '%s updated their answer to %s', $this->renderHandleLink($author_phid), $link); } return parent::getTitleForFeed($story); } public function getBodyForFeed(PhabricatorFeedStory $story) { $new = $this->getNewValue(); $body = null; switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return phutil_escape_html_newlines( phutil_utf8_shorten($new, 128)); break; } return parent::getBodyForFeed($story); } public function hasChangeDetails() { $old = $this->getOldValue(); switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return $old !== null; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } } diff --git a/src/applications/ponder/storage/PonderQuestion.php b/src/applications/ponder/storage/PonderQuestion.php index 6b7856871..1de5dea29 100644 --- a/src/applications/ponder/storage/PonderQuestion.php +++ b/src/applications/ponder/storage/PonderQuestion.php @@ -1,250 +1,250 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(PonderPHIDTypeQuestion::TYPECONST); + return PhabricatorPHID::generateNewPHID(PonderQuestionPHIDType::TYPECONST); } public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source->serialize(); return $this; } public function getContentSource() { return PhabricatorContentSource::newFromSerialized($this->contentSource); } public function attachRelated() { $this->answers = $this->loadRelatives(new PonderAnswer(), 'questionID'); $qa_phids = mpull($this->answers, 'getPHID') + array($this->getPHID()); if ($qa_phids) { $comments = id(new PonderCommentQuery()) ->withTargetPHIDs($qa_phids) ->execute(); $comments = mgroup($comments, 'getTargetPHID'); } else { $comments = array(); } $this->setComments(idx($comments, $this->getPHID(), array())); foreach ($this->answers as $answer) { $answer->attachQuestion($this); $answer->setComments(idx($comments, $answer->getPHID(), array())); } } public function attachVotes($user_phid) { $qa_phids = mpull($this->answers, 'getPHID') + array($this->getPHID()); $edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(array($user_phid)) ->withDestinationPHIDs($qa_phids) ->withEdgeTypes( array( PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION, PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER )) ->needEdgeData(true) ->execute(); $question_edge = $edges[$user_phid][PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION]; $answer_edges = $edges[$user_phid][PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_ANSWER]; $edges = null; $this->setUserVote(idx($question_edge, $this->getPHID())); foreach ($this->answers as $answer) { $answer->setUserVote(idx($answer_edges, $answer->getPHID())); } } public function setUserVote($vote) { $this->vote = $vote['data']; if (!$this->vote) { $this->vote = PonderVote::VOTE_NONE; } return $this; } public function attachUserVote($user_phid, $vote) { $this->vote = $vote; return $this; } public function getUserVote() { return $this->vote; } public function setComments($comments) { $this->comments = $comments; return $this; } public function getComments() { return $this->comments; } public function attachAnswers(array $answers) { assert_instances_of($answers, 'PonderAnswer'); $this->answers = $answers; return $this; } public function getAnswers() { return $this->answers; } public function getMarkupField() { return self::MARKUP_FIELD_CONTENT; } // Markup interface public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digest($this->getMarkupText($field)); $id = $this->getID(); return "ponder:Q{$id}:{$field}:{$hash}"; } public function getMarkupText($field) { return $this->getContent(); } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::getEngine(); } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { return $output; } public function shouldUseMarkupCache($field) { return (bool)$this->getID(); } // votable interface public function getUserVoteEdgeType() { return PhabricatorEdgeConfig::TYPE_VOTING_USER_HAS_QUESTION; } public function getVotablePHID() { return $this->getPHID(); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } public function getOriginalTitle() { // TODO: Make this actually save/return the original title. return $this->getTitle(); } public function getFullTitle() { $id = $this->getID(); $title = $this->getTitle(); return "Q{$id}: {$title}"; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { $policy = PhabricatorPolicies::POLICY_NOONE; switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: $policy = PhabricatorPolicies::POLICY_USER; break; } return $policy; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { return pht( 'The user who asked a question can always view and edit it.'); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($phid == $this->getAuthorPHID()); } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), ); } } diff --git a/src/applications/ponder/storage/PonderQuestionTransaction.php b/src/applications/ponder/storage/PonderQuestionTransaction.php index 67d89201a..eb7aa03e8 100644 --- a/src/applications/ponder/storage/PonderQuestionTransaction.php +++ b/src/applications/ponder/storage/PonderQuestionTransaction.php @@ -1,306 +1,306 @@ getTransactionType()) { case self::TYPE_ANSWERS: $phids[] = $this->getNewAnswerPHID(); $phids[] = $this->getObjectPHID(); break; } return $phids; } public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht( '%s asked this question.', $this->renderHandleLink($author_phid)); } else { return pht( '%s edited the question title from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } case self::TYPE_CONTENT: return pht( '%s edited the question description.', $this->renderHandleLink($author_phid)); case self::TYPE_ANSWERS: $answer_handle = $this->getHandle($this->getNewAnswerPHID()); $question_handle = $this->getHandle($object_phid); return pht( '%s answered %s', $this->renderHandleLink($author_phid), $answer_handle->renderLink($question_handle->getFullName())); case self::TYPE_STATUS: switch ($new) { case PonderQuestionStatus::STATUS_OPEN: return pht( '%s reopened this question.', $this->renderHandleLink($author_phid)); case PonderQuestionStatus::STATUS_CLOSED: return pht( '%s closed this question.', $this->renderHandleLink($author_phid)); } } return parent::getTitle(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: case self::TYPE_CONTENT: return 'fa-pencil'; case self::TYPE_STATUS: switch ($new) { case PonderQuestionStatus::STATUS_OPEN: return 'fa-check-circle'; case PonderQuestionStatus::STATUS_CLOSED: return 'fa-minus-circle'; } case self::TYPE_ANSWERS: return 'fa-plus'; } return parent::getIcon(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: case self::TYPE_CONTENT: return PhabricatorTransactions::COLOR_BLUE; case self::TYPE_ANSWERS: return PhabricatorTransactions::COLOR_GREEN; case self::TYPE_STATUS: switch ($new) { case PonderQuestionStatus::STATUS_OPEN: return PhabricatorTransactions::COLOR_GREEN; case PonderQuestionStatus::STATUS_CLOSED: return PhabricatorTransactions::COLOR_BLACK; } } } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } public function getActionStrength() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return 3; } break; case self::TYPE_ANSWERS: return 2; } return parent::getActionStrength(); } public function getActionName() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht('Asked'); } break; case self::TYPE_ANSWERS: return pht('Answered'); } return parent::getActionName(); } public function shouldHide() { switch ($this->getTransactionType()) { case self::TYPE_CONTENT: if ($this->getOldValue() === null) { return true; } else { return false; } break; } return parent::shouldHide(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { return pht( '%s asked a question: %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s edited the title of %s (was "%s")', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), $old); } case self::TYPE_CONTENT: return pht( '%s edited the description of %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case self::TYPE_ANSWERS: $answer_handle = $this->getHandle($this->getNewAnswerPHID()); $question_handle = $this->getHandle($object_phid); return pht( '%s answered %s', $this->renderHandleLink($author_phid), $answer_handle->renderLink($question_handle->getFullName())); case self::TYPE_STATUS: switch ($new) { case PonderQuestionStatus::STATUS_OPEN: return pht( '%s reopened %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PonderQuestionStatus::STATUS_CLOSED: return pht( '%s closed %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } } return parent::getTitleForFeed($story); } public function getBodyForFeed(PhabricatorFeedStory $story) { $new = $this->getNewValue(); $old = $this->getOldValue(); $body = null; switch ($this->getTransactionType()) { case self::TYPE_TITLE: if ($old === null) { $question = $story->getObject($this->getObjectPHID()); return phutil_escape_html_newlines( phutil_utf8_shorten($question->getContent(), 128)); } break; case self::TYPE_ANSWERS: $answer = $this->getNewAnswerObject($story); if ($answer) { return phutil_escape_html_newlines( phutil_utf8_shorten($answer->getContent(), 128)); } break; } return parent::getBodyForFeed($story); } /** * Currently the application only supports adding answers one at a time. * This data is stored as a list of phids. Use this function to get the * new phid. */ private function getNewAnswerPHID() { $new = $this->getNewValue(); $old = $this->getOldValue(); $add = array_diff($new, $old); if (count($add) != 1) { throw new Exception( 'There should be only one answer added at a time.'); } return reset($add); } /** * Generally, the answer object is only available if the transaction * type is self::TYPE_ANSWERS. * * Some stories - notably ones made before D7027 - will be of the more * generic @{class:PhabricatorApplicationTransactionFeedStory}. These * poor stories won't have the PonderAnswer loaded, and thus will have * less cool information. */ private function getNewAnswerObject(PhabricatorFeedStory $story) { if ($story instanceof PonderTransactionFeedStory) { $answer_phid = $this->getNewAnswerPHID(); if ($answer_phid) { return $story->getObject($answer_phid); } } return null; } } diff --git a/src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php b/src/applications/project/phid/PhabricatorProjectColumnPHIDType.php similarity index 92% rename from src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php rename to src/applications/project/phid/PhabricatorProjectColumnPHIDType.php index eb22f2ce7..a78939e4f 100644 --- a/src/applications/project/phid/PhabricatorProjectPHIDTypeColumn.php +++ b/src/applications/project/phid/PhabricatorProjectColumnPHIDType.php @@ -1,41 +1,41 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $column = $objects[$phid]; $handle->setName($column->getDisplayName()); $handle->setURI('/project/board/'.$column->getProject()->getID().'/'); $handle->setDisabled($column->isHidden()); } } } diff --git a/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php b/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php similarity index 97% rename from src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php rename to src/applications/project/phid/PhabricatorProjectProjectPHIDType.php index 73df5dad8..ae74610dc 100644 --- a/src/applications/project/phid/PhabricatorProjectPHIDTypeProject.php +++ b/src/applications/project/phid/PhabricatorProjectProjectPHIDType.php @@ -1,110 +1,110 @@ withPHIDs($phids) ->needImages(true); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $project = $objects[$phid]; $name = $project->getName(); $id = $project->getID(); $slug = $project->getPrimarySlug(); $handle->setName($name); $handle->setObjectName('#'.$slug); $handle->setURI("/tag/{$slug}/"); $handle->setImageURI($project->getProfileImageURI()); $handle->setIcon($project->getIcon()); $handle->setTagColor($project->getColor()); if ($project->isArchived()) { $handle->setStatus(PhabricatorObjectHandleStatus::STATUS_CLOSED); } } } public static function getProjectMonogramPatternFragment() { // NOTE: See some discussion in ProjectRemarkupRule. return '[^\s,#]+'; } public function canLoadNamedObject($name) { $fragment = self::getProjectMonogramPatternFragment(); return preg_match('/^#'.$fragment.'$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { // If the user types "#YoloSwag", we still want to match "#yoloswag", so // we normalize, query, and then map back to the original inputs. $map = array(); foreach ($names as $key => $slug) { $map[$this->normalizeSlug(substr($slug, 1))][] = $slug; } $projects = id(new PhabricatorProjectQuery()) ->setViewer($query->getViewer()) ->withSlugs(array_keys($map)) ->needSlugs(true) ->execute(); $result = array(); foreach ($projects as $project) { $slugs = $project->getSlugs(); $slug_strs = mpull($slugs, 'getSlug'); foreach ($slug_strs as $slug) { $slug_map = idx($map, $slug, array()); foreach ($slug_map as $original) { $result[$original] = $project; } } } return $result; } private function normalizeSlug($slug) { // NOTE: We're using phutil_utf8_strtolower() (and not PhabricatorSlug's // normalize() method) because this normalization should be only somewhat // liberal. We want "#YOLO" to match against "#yolo", but "#\\yo!!lo" // should not. normalize() strips out most punctuation and leads to // excessively aggressive matches. return phutil_utf8_strtolower($slug); } } diff --git a/src/applications/project/remarkup/ProjectRemarkupRule.php b/src/applications/project/remarkup/ProjectRemarkupRule.php index 883751df8..8ed96034a 100644 --- a/src/applications/project/remarkup/ProjectRemarkupRule.php +++ b/src/applications/project/remarkup/ProjectRemarkupRule.php @@ -1,63 +1,63 @@ getEngine()->isTextMode()) { return '#'.$id; } return $handle->renderTag(); } protected function getObjectIDPattern() { // NOTE: This explicitly does not match strings which contain only // digits, because digit strings like "#123" are used to reference tasks at // Facebook and are somewhat conventional in general. // The latter half of this rule matches monograms with internal periods, // like `#domain.com`, but does not match monograms with terminal periods, // because they're probably just puncutation. // Broadly, this will not match every possible project monogram, and we // accept some false negatives -- like `#1` or `#dot.` -- in order to avoid // a bunch of false positives on general use of the `#` character. - // In other contexts, the PhabricatorProjectPHIDTypeProject pattern is + // In other contexts, the PhabricatorProjectProjectPHIDType pattern is // controlling and these names should parse correctly. return '[^\s.!,:;{}#]*[^\s\d!,:;{}#]+(?:[^\s.!,:;{}#][^\s!,:;{}#]*)*'; } protected function loadObjects(array $ids) { $viewer = $this->getEngine()->getConfig('viewer'); // Put the "#" back on the front of these IDs. $names = array(); foreach ($ids as $id) { $names[] = '#'.$id; } // Issue a query by object name. $query = id(new PhabricatorObjectQuery()) ->setViewer($viewer) ->withNames($names); $query->execute(); $projects = $query->getNamedResults(); // Slice the "#" off again. $result = array(); foreach ($projects as $name => $project) { $result[substr($name, 1)] = $project; } return $result; } } diff --git a/src/applications/project/search/PhabricatorProjectSearchIndexer.php b/src/applications/project/search/PhabricatorProjectSearchIndexer.php index 17a0ac7be..2b046297a 100644 --- a/src/applications/project/search/PhabricatorProjectSearchIndexer.php +++ b/src/applications/project/search/PhabricatorProjectSearchIndexer.php @@ -1,33 +1,34 @@ loadDocumentByPHID($phid); $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($project->getPHID()); - $doc->setDocumentType(PhabricatorProjectPHIDTypeProject::TYPECONST); + $doc->setDocumentType(PhabricatorProjectProjectPHIDType::TYPECONST); $doc->setDocumentTitle($project->getName()); $doc->setDocumentCreated($project->getDateCreated()); $doc->setDocumentModified($project->getDateModified()); $doc->addRelationship( $project->isArchived() ? PhabricatorSearchRelationship::RELATIONSHIP_CLOSED : PhabricatorSearchRelationship::RELATIONSHIP_OPEN, $project->getPHID(), - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, time()); // NOTE: This could be more full-featured, but for now we're mostly // interested in the side effects of indexing. return $doc; } + } diff --git a/src/applications/project/storage/PhabricatorProject.php b/src/applications/project/storage/PhabricatorProject.php index 498f3bf2a..999c988fd 100644 --- a/src/applications/project/storage/PhabricatorProject.php +++ b/src/applications/project/storage/PhabricatorProject.php @@ -1,334 +1,334 @@ setName('') ->setAuthorPHID($actor->getPHID()) ->setIcon(self::DEFAULT_ICON) ->setColor(self::DEFAULT_COLOR) ->setViewPolicy(PhabricatorPolicies::POLICY_USER) ->setEditPolicy(PhabricatorPolicies::POLICY_USER) ->setJoinPolicy(PhabricatorPolicies::POLICY_USER) ->attachMemberPHIDs(array()); } public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, PhabricatorPolicyCapability::CAN_JOIN, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); case PhabricatorPolicyCapability::CAN_JOIN: return $this->getJoinPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: if ($this->isUserMember($viewer->getPHID())) { // Project members can always view a project. return true; } break; case PhabricatorPolicyCapability::CAN_EDIT: break; case PhabricatorPolicyCapability::CAN_JOIN: $can_edit = PhabricatorPolicyCapability::CAN_EDIT; if (PhabricatorPolicyFilter::hasCapability($viewer, $this, $can_edit)) { // Project editors can always join a project. return true; } break; } return false; } public function describeAutomaticCapability($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return pht('Members of a project can always view it.'); case PhabricatorPolicyCapability::CAN_JOIN: return pht('Users who can edit a project can always join it.'); } return null; } public function isUserMember($user_phid) { if ($this->memberPHIDs !== self::ATTACHABLE) { return in_array($user_phid, $this->memberPHIDs); } return $this->assertAttachedKey($this->sparseMembers, $user_phid); } public function setIsUserMember($user_phid, $is_member) { if ($this->sparseMembers === self::ATTACHABLE) { $this->sparseMembers = array(); } $this->sparseMembers[$user_phid] = $is_member; return $this; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'subprojectPHIDs' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorProjectPHIDTypeProject::TYPECONST); + PhabricatorProjectProjectPHIDType::TYPECONST); } public function attachMemberPHIDs(array $phids) { $this->memberPHIDs = $phids; return $this; } public function getMemberPHIDs() { return $this->assertAttached($this->memberPHIDs); } public function setPhrictionSlug($slug) { // NOTE: We're doing a little magic here and stripping out '/' so that // project pages always appear at top level under projects/ even if the // display name is "Hack / Slash" or similar (it will become // 'hack_slash' instead of 'hack/slash'). $slug = str_replace('/', ' ', $slug); $slug = PhabricatorSlug::normalize($slug); $this->phrictionSlug = $slug; return $this; } public function getFullPhrictionSlug() { $slug = $this->getPhrictionSlug(); return 'projects/'.$slug; } // TODO - once we sever project => phriction automagicalness, // migrate getPhrictionSlug to have no trailing slash and be called // getPrimarySlug public function getPrimarySlug() { $slug = $this->getPhrictionSlug(); return rtrim($slug, '/'); } public function isArchived() { return ($this->getStatus() == PhabricatorProjectStatus::STATUS_ARCHIVED); } public function getProfileImageURI() { return $this->getProfileImageFile()->getBestURI(); } public function attachProfileImageFile(PhabricatorFile $file) { $this->profileImageFile = $file; return $this; } public function getProfileImageFile() { return $this->assertAttached($this->profileImageFile); } public function isUserWatcher($user_phid) { if ($this->watcherPHIDs !== self::ATTACHABLE) { return in_array($user_phid, $this->watcherPHIDs); } return $this->assertAttachedKey($this->sparseWatchers, $user_phid); } public function setIsUserWatcher($user_phid, $is_watcher) { if ($this->sparseWatchers === self::ATTACHABLE) { $this->sparseWatchers = array(); } $this->sparseWatchers[$user_phid] = $is_watcher; return $this; } public function attachWatcherPHIDs(array $phids) { $this->watcherPHIDs = $phids; return $this; } public function getWatcherPHIDs() { return $this->assertAttached($this->watcherPHIDs); } public function attachSlugs(array $slugs) { $this->slugs = $slugs; return $this; } public function getSlugs() { return $this->assertAttached($this->slugs); } public function getColor() { if ($this->isArchived()) { return PHUITagView::COLOR_DISABLED; } return $this->color; } public function save() { $this->openTransaction(); $result = parent::save(); $this->updateDatasourceTokens(); $this->saveTransaction(); return $result; } public function updateDatasourceTokens() { $table = self::TABLE_DATASOURCE_TOKEN; $conn_w = $this->establishConnection('w'); $id = $this->getID(); $slugs = queryfx_all( $conn_w, 'SELECT * FROM %T WHERE projectPHID = %s', id(new PhabricatorProjectSlug())->getTableName(), $this->getPHID()); $all_strings = ipull($slugs, 'slug'); $all_strings[] = $this->getName(); $all_strings = implode(' ', $all_strings); $tokens = PhabricatorTypeaheadDatasource::tokenizeString($all_strings); $sql = array(); foreach ($tokens as $token) { $sql[] = qsprintf($conn_w, '(%d, %s)', $id, $token); } $this->openTransaction(); queryfx( $conn_w, 'DELETE FROM %T WHERE projectID = %d', $table, $id); foreach (PhabricatorLiskDAO::chunkSQL($sql) as $chunk) { queryfx( $conn_w, 'INSERT INTO %T (projectID, token) VALUES %Q', $table, $chunk); } $this->saveTransaction(); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return false; } public function shouldShowSubscribersProperty() { return false; } public function shouldAllowSubscription($phid) { return $this->isUserMember($phid) && !$this->isUserWatcher($phid); } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('projects.fields'); } public function getCustomFieldBaseClass() { return 'PhabricatorProjectCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $columns = id(new PhabricatorProjectColumn()) ->loadAllWhere('projectPHID = %s', $this->getPHID()); foreach ($columns as $column) { $engine->destroyObject($column); } $slugs = id(new PhabricatorProjectSlug()) ->loadAllWhere('projectPHID = %s', $this->getPHID()); foreach ($slugs as $slug) { $slug->delete(); } $this->saveTransaction(); } } diff --git a/src/applications/project/storage/PhabricatorProjectColumn.php b/src/applications/project/storage/PhabricatorProjectColumn.php index 54f70a671..10b444154 100644 --- a/src/applications/project/storage/PhabricatorProjectColumn.php +++ b/src/applications/project/storage/PhabricatorProjectColumn.php @@ -1,113 +1,113 @@ setName('') ->setStatus(self::STATUS_ACTIVE); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorProjectPHIDTypeColumn::TYPECONST); + PhabricatorProjectColumnPHIDType::TYPECONST); } public function attachProject(PhabricatorProject $project) { $this->project = $project; return $this; } public function getProject() { return $this->assertAttached($this->project); } public function isDefaultColumn() { return ($this->getSequence() == 0); } public function isHidden() { return ($this->getStatus() == self::STATUS_HIDDEN); } public function getDisplayName() { $name = $this->getName(); if (strlen($name)) { return $name; } if ($this->isDefaultColumn()) { return pht('Backlog'); } return pht('Unnamed Column'); } public function getHeaderColor() { if ($this->isHidden()) { return PHUIActionHeaderView::HEADER_LIGHTRED; } if ($this->isDefaultColumn()) { return PHUIActionHeaderView::HEADER_DARK_GREY; } return PHUIActionHeaderView::HEADER_GREY; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getProject()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getProject()->hasAutomaticCapability( $capability, $viewer); } public function describeAutomaticCapability($capability) { return pht('Users must be able to see a project to see its board.'); } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/project/storage/PhabricatorProjectColumnTransaction.php b/src/applications/project/storage/PhabricatorProjectColumnTransaction.php index 71fc47279..e89672c07 100644 --- a/src/applications/project/storage/PhabricatorProjectColumnTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectColumnTransaction.php @@ -1,63 +1,63 @@ getOldValue(); $new = $this->getNewValue(); $author_handle = $this->renderHandleLink($this->getAuthorPHID()); switch ($this->getTransactionType()) { case PhabricatorProjectColumnTransaction::TYPE_NAME: if ($old === null) { return pht( '%s created this column.', $author_handle); } else { if (!strlen($old)) { return pht( '%s named this column "%s".', $author_handle, $new); } else if (strlen($new)) { return pht( '%s renamed this column from "%s" to "%s".', $author_handle, $old, $new); } else { return pht( '%s removed the custom name of this column.', $author_handle); } } case PhabricatorProjectColumnTransaction::TYPE_STATUS: switch ($new) { case PhabricatorProjectColumn::STATUS_ACTIVE: return pht( '%s marked this column visible.', $author_handle); case PhabricatorProjectColumn::STATUS_HIDDEN: return pht( '%s marked this column hidden.', $author_handle); } break; } return parent::getTitle(); } } diff --git a/src/applications/project/storage/PhabricatorProjectTransaction.php b/src/applications/project/storage/PhabricatorProjectTransaction.php index 3fc3fa3c6..b68966341 100644 --- a/src/applications/project/storage/PhabricatorProjectTransaction.php +++ b/src/applications/project/storage/PhabricatorProjectTransaction.php @@ -1,175 +1,175 @@ getOldValue(); $new = $this->getNewValue(); $req_phids = array(); switch ($this->getTransactionType()) { case PhabricatorProjectTransaction::TYPE_MEMBERS: $add = array_diff($new, $old); $rem = array_diff($old, $new); $req_phids = array_merge($add, $rem); break; case PhabricatorProjectTransaction::TYPE_IMAGE: $req_phids[] = $old; $req_phids[] = $new; break; } return array_merge($req_phids, parent::getRequiredHandlePHIDs()); } public function getTitle() { $old = $this->getOldValue(); $new = $this->getNewValue(); $author_handle = $this->renderHandleLink($this->getAuthorPHID()); switch ($this->getTransactionType()) { case PhabricatorProjectTransaction::TYPE_NAME: if ($old === null) { return pht( '%s created this project.', $author_handle); } else { return pht( '%s renamed this project from "%s" to "%s".', $author_handle, $old, $new); } case PhabricatorProjectTransaction::TYPE_STATUS: if ($old == 0) { return pht( '%s closed this project.', $author_handle); } else { return pht( '%s reopened this project.', $author_handle); } case PhabricatorProjectTransaction::TYPE_IMAGE: // TODO: Some day, it would be nice to show the images. if (!$old) { return pht( '%s set this project\'s image to %s.', $author_handle, $this->renderHandleLink($new)); } else if (!$new) { return pht( '%s removed this project\'s image.', $author_handle); } else { return pht( '%s updated this project\'s image from %s to %s.', $author_handle, $this->renderHandleLink($old), $this->renderHandleLink($new)); } case PhabricatorProjectTransaction::TYPE_ICON: return pht( '%s set this project\'s icon to %s.', $author_handle, PhabricatorProjectIcon::getLabel($new)); case PhabricatorProjectTransaction::TYPE_COLOR: return pht( '%s set this project\'s color to %s.', $author_handle, PHUITagView::getShadeName($new)); case PhabricatorProjectTransaction::TYPE_SLUGS: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { return pht( '%s changed project hashtag(s), added %d: %s; removed %d: %s', $author_handle, count($add), $this->renderSlugList($add), count($rem), $this->renderSlugList($rem)); } else if ($add) { return pht( '%s added %d project hashtag(s): %s', $author_handle, count($add), $this->renderSlugList($add)); } else if ($rem) { return pht( '%s removed %d project hashtag(s): %s', $author_handle, count($rem), $this->renderSlugList($rem)); } case PhabricatorProjectTransaction::TYPE_MEMBERS: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { return pht( '%s changed project member(s), added %d: %s; removed %d: %s', $author_handle, count($add), $this->renderHandleList($add), count($rem), $this->renderHandleList($rem)); } else if ($add) { if (count($add) == 1 && (head($add) == $this->getAuthorPHID())) { return pht( '%s joined this project.', $author_handle); } else { return pht( '%s added %d project member(s): %s', $author_handle, count($add), $this->renderHandleList($add)); } } else if ($rem) { if (count($rem) == 1 && (head($rem) == $this->getAuthorPHID())) { return pht( '%s left this project.', $author_handle); } else { return pht( '%s removed %d project member(s): %s', $author_handle, count($rem), $this->renderHandleList($rem)); } } } return parent::getTitle(); } private function renderSlugList($slugs) { return implode(', ', $slugs); } } diff --git a/src/applications/releeph/phid/ReleephPHIDTypeBranch.php b/src/applications/releeph/phid/ReleephBranchPHIDType.php similarity index 91% rename from src/applications/releeph/phid/ReleephPHIDTypeBranch.php rename to src/applications/releeph/phid/ReleephBranchPHIDType.php index 926021ef1..487f5eebb 100644 --- a/src/applications/releeph/phid/ReleephPHIDTypeBranch.php +++ b/src/applications/releeph/phid/ReleephBranchPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $branch = $objects[$phid]; $handle->setURI($branch->getURI()); $handle->setName($branch->getBasename()); $handle->setFullName($branch->getName()); } } } diff --git a/src/applications/releeph/phid/ReleephPHIDTypeProduct.php b/src/applications/releeph/phid/ReleephProductPHIDType.php similarity index 90% rename from src/applications/releeph/phid/ReleephPHIDTypeProduct.php rename to src/applications/releeph/phid/ReleephProductPHIDType.php index 61bc5c536..7e8079b30 100644 --- a/src/applications/releeph/phid/ReleephPHIDTypeProduct.php +++ b/src/applications/releeph/phid/ReleephProductPHIDType.php @@ -1,36 +1,36 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $product = $objects[$phid]; $handle->setName($product->getName()); $handle->setURI($product->getURI()); } } } diff --git a/src/applications/releeph/phid/ReleephPHIDTypeRequest.php b/src/applications/releeph/phid/ReleephRequestPHIDType.php similarity index 92% rename from src/applications/releeph/phid/ReleephPHIDTypeRequest.php rename to src/applications/releeph/phid/ReleephRequestPHIDType.php index f5352350c..202b146fe 100644 --- a/src/applications/releeph/phid/ReleephPHIDTypeRequest.php +++ b/src/applications/releeph/phid/ReleephRequestPHIDType.php @@ -1,40 +1,40 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $request = $objects[$phid]; $id = $request->getID(); $title = $request->getSummaryForDisplay(); $handle->setURI("/RQ{$id}"); $handle->setName($title); $handle->setFullName("RQ{$id}: {$title}"); } } } diff --git a/src/applications/releeph/storage/ReleephBranch.php b/src/applications/releeph/storage/ReleephBranch.php index f3a2b3738..647406f1a 100644 --- a/src/applications/releeph/storage/ReleephBranch.php +++ b/src/applications/releeph/storage/ReleephBranch.php @@ -1,154 +1,154 @@ true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(ReleephPHIDTypeBranch::TYPECONST); + return PhabricatorPHID::generateNewPHID(ReleephBranchPHIDType::TYPECONST); } public function getDetail($key, $default = null) { return idx($this->getDetails(), $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } public function willWriteData(array &$data) { // If symbolicName is omitted, set it to the basename. // // This means that we can enforce symbolicName as a UNIQUE column in the // DB. We'll interpret symbolicName === basename as meaning "no symbolic // name". // // SYMBOLIC_NAME_NOTE if (!$data['symbolicName']) { $data['symbolicName'] = $data['basename']; } parent::willWriteData($data); } public function getSymbolicName() { // See SYMBOLIC_NAME_NOTE above for why this is needed if ($this->symbolicName == $this->getBasename()) { return ''; } return $this->symbolicName; } public function setSymbolicName($name) { if ($name) { parent::setSymbolicName($name); } else { parent::setSymbolicName($this->getBasename()); } return $this; } public function getDisplayName() { if ($sn = $this->getSymbolicName()) { return $sn; } return $this->getBasename(); } public function getDisplayNameWithDetail() { $n = $this->getBasename(); if ($sn = $this->getSymbolicName()) { return "{$sn} ({$n})"; } else { return $n; } } public function getURI($path = null) { $components = array( '/releeph/branch', $this->getID(), $path, ); return implode('/', $components); } public function isActive() { return $this->getIsActive(); } public function attachProject(ReleephProject $project) { $this->project = $project; return $this; } public function getProject() { return $this->assertAttached($this->project); } public function getProduct() { return $this->getProject(); } public function attachCutPointCommit( PhabricatorRepositoryCommit $commit = null) { $this->cutPointCommit = $commit; return $this; } public function getCutPointCommit() { return $this->assertAttached($this->cutPointCommit); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return $this->getProduct()->getCapabilities(); } public function getPolicy($capability) { return $this->getProduct()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getProduct()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'Release branches have the same policies as the product they are a '. 'part of.'); } } diff --git a/src/applications/releeph/storage/ReleephBranchTransaction.php b/src/applications/releeph/storage/ReleephBranchTransaction.php index 1b453c258..5dc2811c8 100644 --- a/src/applications/releeph/storage/ReleephBranchTransaction.php +++ b/src/applications/releeph/storage/ReleephBranchTransaction.php @@ -1,14 +1,14 @@ getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_ACTIVE: if ($new) { return 'green'; } else { return 'black'; } break; } return parent::getColor(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_ACTIVE: if ($new) { return 'fa-pencil'; } else { return 'fa-times'; } break; } return parent::getIcon(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_ACTIVE: if ($new) { return pht( '%s activated this product.', $this->renderHandleLink($author_phid)); } else { return pht( '%s deactivated this product.', $this->renderHandleLink($author_phid)); } break; } return parent::getTitle(); } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_ACTIVE: if ($new) { return pht( '%s activated release product %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } else { return pht( '%s deactivated release product %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } break; } return parent::getTitleForFeed($story); } public function getNoEffectDescription() { switch ($this->getTransactionType()) { case self::TYPE_ACTIVE: return pht('The product is already in that state.'); } return parent::getNoEffectDescription(); } } diff --git a/src/applications/releeph/storage/ReleephProject.php b/src/applications/releeph/storage/ReleephProject.php index 612922eee..f52b847eb 100644 --- a/src/applications/releeph/storage/ReleephProject.php +++ b/src/applications/releeph/storage/ReleephProject.php @@ -1,135 +1,135 @@ true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { - return PhabricatorPHID::generateNewPHID(ReleephPHIDTypeProduct::TYPECONST); + return PhabricatorPHID::generateNewPHID(ReleephProductPHIDType::TYPECONST); } public function getDetail($key, $default = null) { return idx($this->details, $key, $default); } public function getURI($path = null) { $components = array( '/releeph/product', $this->getID(), $path ); return implode('/', $components); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } public function getArcanistProject() { return $this->assertAttached($this->arcanistProject); } public function attachArcanistProject( PhabricatorRepositoryArcanistProject $arcanist_project = null) { $this->arcanistProject = $arcanist_project; return $this; } public function getPushers() { return $this->getDetail('pushers', array()); } public function isPusher(PhabricatorUser $user) { // TODO Deprecate this once `isPusher` is out of the Facebook codebase. return $this->isAuthoritative($user); } public function isAuthoritative(PhabricatorUser $user) { return $this->isAuthoritativePHID($user->getPHID()); } public function isAuthoritativePHID($phid) { $pushers = $this->getPushers(); if (!$pushers) { return true; } else { return in_array($phid, $pushers); } } public function attachRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; } public function getRepository() { return $this->assertAttached($this->repository); } public function getReleephFieldSelector() { return new ReleephDefaultFieldSelector(); } public function isTestFile($filename) { $test_paths = $this->getDetail('testPaths', array()); foreach ($test_paths as $test_path) { if (preg_match($test_path, $filename)) { return true; } } return false; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return PhabricatorPolicies::POLICY_USER; } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/releeph/storage/ReleephRequest.php b/src/applications/releeph/storage/ReleephRequest.php index 56b201cf6..2c495099b 100644 --- a/src/applications/releeph/storage/ReleephRequest.php +++ b/src/applications/releeph/storage/ReleephRequest.php @@ -1,320 +1,320 @@ getPusherIntent() == self::INTENT_WANT && /** * We use "!= pass" instead of "== want" in case the requestor intent is * not present. In other words, only revert if the requestor explicitly * passed. */ $this->getRequestorIntent() != self::INTENT_PASS; } /** * Will return INTENT_WANT if any pusher wants this request, and no pusher * passes on this request. */ public function getPusherIntent() { $product = $this->getBranch()->getProduct(); if (!$product->getPushers()) { return self::INTENT_WANT; } $found_pusher_want = false; foreach ($this->userIntents as $phid => $intent) { if ($product->isAuthoritativePHID($phid)) { if ($intent == self::INTENT_PASS) { return self::INTENT_PASS; } $found_pusher_want = true; } } if ($found_pusher_want) { return self::INTENT_WANT; } else { return null; } } public function getRequestorIntent() { return idx($this->userIntents, $this->requestUserPHID); } public function getStatus() { return $this->calculateStatus(); } public function getMonogram() { return 'Y'.$this->getID(); } public function getBranch() { return $this->assertAttached($this->branch); } public function attachBranch(ReleephBranch $branch) { $this->branch = $branch; return $this; } public function getRequestedObject() { return $this->assertAttached($this->requestedObject); } public function attachRequestedObject($object) { $this->requestedObject = $object; return $this; } private function calculateStatus() { if ($this->shouldBeInBranch()) { if ($this->getInBranch()) { return ReleephRequestStatus::STATUS_PICKED; } else { return ReleephRequestStatus::STATUS_NEEDS_PICK; } } else { if ($this->getInBranch()) { return ReleephRequestStatus::STATUS_NEEDS_REVERT; } else { $has_been_in_branch = $this->getCommitIdentifier(); // Regardless of why we reverted something, always say reverted if it // was once in the branch. if ($has_been_in_branch) { return ReleephRequestStatus::STATUS_REVERTED; } else if ($this->getPusherIntent() === ReleephRequest::INTENT_PASS) { // Otherwise, if it has never been in the branch, explicitly say why: return ReleephRequestStatus::STATUS_REJECTED; } else if ($this->getRequestorIntent() === ReleephRequest::INTENT_WANT) { return ReleephRequestStatus::STATUS_REQUESTED; } else { return ReleephRequestStatus::STATUS_ABANDONED; } } } } /* -( Lisk mechanics )----------------------------------------------------- */ public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, 'userIntents' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - ReleephPHIDTypeRequest::TYPECONST); + ReleephRequestPHIDType::TYPECONST); } public function save() { if (!$this->getMailKey()) { $this->setMailKey(Filesystem::readRandomCharacters(20)); } return parent::save(); } /* -( Helpful accessors )--------------------------------------------------- */ public function getDetail($key, $default = null) { return idx($this->getDetails(), $key, $default); } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } /** * Get the commit PHIDs this request is requesting. * * NOTE: For now, this always returns one PHID. * * @return list Commit PHIDs requested by this request. */ public function getCommitPHIDs() { return array( $this->requestCommitPHID, ); } public function getReason() { // Backward compatibility: reason used to be called comments $reason = $this->getDetail('reason'); if (!$reason) { return $this->getDetail('comments'); } return $reason; } /** * Allow a null summary, and fall back to the title of the commit. */ public function getSummaryForDisplay() { $summary = $this->getDetail('summary'); if (!strlen($summary)) { $commit = $this->loadPhabricatorRepositoryCommit(); if ($commit) { $summary = $commit->getSummary(); } } if (!strlen($summary)) { $summary = pht('None'); } return $summary; } /* -( Loading external objects )------------------------------------------- */ public function loadPhabricatorRepositoryCommit() { return $this->loadOneRelative( new PhabricatorRepositoryCommit(), 'phid', 'getRequestCommitPHID'); } public function loadPhabricatorRepositoryCommitData() { $commit = $this->loadPhabricatorRepositoryCommit(); if ($commit) { return $commit->loadOneRelative( new PhabricatorRepositoryCommitData(), 'commitID'); } } /* -( State change helpers )----------------------------------------------- */ public function setUserIntent(PhabricatorUser $user, $intent) { $this->userIntents[$user->getPHID()] = $intent; return $this; } /* -( Migrating to status-less ReleephRequests )--------------------------- */ protected function didReadData() { if ($this->userIntents === null) { $this->userIntents = array(); } } public function setStatus($value) { throw new Exception('`status` is now deprecated!'); } /* -( Make magic Lisk methods private )------------------------------------ */ private function setUserIntents(array $ar) { return parent::setUserIntents($ar); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getBranch()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getBranch()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'Pull requests have the same policies as the branches they are '. 'requested against.'); } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { return PhabricatorEnv::getEnvConfig('releeph.fields'); } public function getCustomFieldBaseClass() { return 'ReleephFieldSpecification'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } } diff --git a/src/applications/releeph/storage/ReleephRequestTransaction.php b/src/applications/releeph/storage/ReleephRequestTransaction.php index 1df45416b..bd17ad43c 100644 --- a/src/applications/releeph/storage/ReleephRequestTransaction.php +++ b/src/applications/releeph/storage/ReleephRequestTransaction.php @@ -1,279 +1,279 @@ getTransactionType()) { default; break; } return parent::hasChangeDetails(); } public function getRequiredHandlePHIDs() { $phids = parent::getRequiredHandlePHIDs(); $phids[] = $this->getObjectPHID(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case ReleephRequestTransaction::TYPE_REQUEST: case ReleephRequestTransaction::TYPE_DISCOVERY: $phids[] = $new; break; case ReleephRequestTransaction::TYPE_EDIT_FIELD: self::searchForPHIDs($this->getOldValue(), $phids); self::searchForPHIDs($this->getNewValue(), $phids); break; } return $phids; } public function getTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case ReleephRequestTransaction::TYPE_REQUEST: return pht( '%s requested %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($new)); break; case ReleephRequestTransaction::TYPE_USER_INTENT: return $this->getIntentTitle(); break; case ReleephRequestTransaction::TYPE_EDIT_FIELD: $field = newv($this->getMetadataValue('fieldClass'), array()); $name = $field->getName(); $markup = $name; if ($this->getRenderingTarget() === PhabricatorApplicationTransaction::TARGET_HTML) { $markup = hsprintf('%s', $name); } return pht( '%s changed the %s to "%s"', $this->renderHandleLink($author_phid), $markup, $field->normalizeForTransactionView($this, $new)); break; case ReleephRequestTransaction::TYPE_PICK_STATUS: switch ($new) { case ReleephRequest::PICK_OK: return pht('%s found this request picks without error', $this->renderHandleLink($author_phid)); case ReleephRequest::REVERT_OK: return pht('%s found this request reverts without error', $this->renderHandleLink($author_phid)); case ReleephRequest::PICK_FAILED: return pht("%s couldn't pick this request", $this->renderHandleLink($author_phid)); case ReleephRequest::REVERT_FAILED: return pht("%s couldn't revert this request", $this->renderHandleLink($author_phid)); } break; case ReleephRequestTransaction::TYPE_COMMIT: $action_type = $this->getMetadataValue('action'); switch ($action_type) { case 'pick': return pht( '%s picked this request and committed the result upstream', $this->renderHandleLink($author_phid)); break; case 'revert': return pht( '%s reverted this request and committed the result upstream', $this->renderHandleLink($author_phid)); break; } break; case ReleephRequestTransaction::TYPE_MANUAL_IN_BRANCH: $action = $new ? pht('picked') : pht('reverted'); return pht( '%s marked this request as manually %s', $this->renderHandleLink($author_phid), $action); break; case ReleephRequestTransaction::TYPE_DISCOVERY: return pht('%s discovered this commit as %s', $this->renderHandleLink($author_phid), $this->renderHandleLink($new)); break; default: return parent::getTitle(); break; } } public function getActionStrength() { return parent::getActionStrength(); } public function getActionName() { switch ($this->getTransactionType()) { case self::TYPE_REQUEST: return pht('Requested'); case self::TYPE_COMMIT: $action_type = $this->getMetadataValue('action'); switch ($action_type) { case 'pick': return pht('Picked'); case 'revert': return pht('Reverted'); } } return parent::getActionName(); } public function getColor() { $new = $this->getNewValue(); switch ($this->getTransactionType()) { case ReleephRequestTransaction::TYPE_USER_INTENT: switch ($new) { case ReleephRequest::INTENT_WANT: return PhabricatorTransactions::COLOR_GREEN; case ReleephRequest::INTENT_PASS: return PhabricatorTransactions::COLOR_RED; } } return parent::getColor(); } private static function searchForPHIDs($thing, array &$phids) { /** * To implement something like getRequiredHandlePHIDs() in a * ReleephFieldSpecification, we'd have to provide the field with its * ReleephRequest (so that it could load the PHIDs from the * ReleephRequest's storage, and return them.) * * We don't have fields initialized with their ReleephRequests, but we can * make a good guess at what handles will be needed for rendering the field * in this transaction by inspecting the old and new values. */ if (!is_array($thing)) { $thing = array($thing); } foreach ($thing as $value) { if (phid_get_type($value) !== PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { $phids[] = $value; } } } private function getIntentTitle() { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $new = $this->getNewValue(); $is_pusher = $this->getMetadataValue('isPusher'); switch ($new) { case ReleephRequest::INTENT_WANT: if ($is_pusher) { return pht( '%s approved this request', $this->renderHandleLink($author_phid)); } else { return pht( '%s wanted this request', $this->renderHandleLink($author_phid)); } case ReleephRequest::INTENT_PASS: if ($is_pusher) { return pht( '%s rejected this request', $this->renderHandleLink($author_phid)); } else { return pht( '%s passed on this request', $this->renderHandleLink($author_phid)); } } } public function shouldHide() { $type = $this->getTransactionType(); if ($type === ReleephRequestTransaction::TYPE_USER_INTENT && $this->getMetadataValue('isRQCreate')) { return true; } if ($this->isBoringPickStatus()) { return true; } // ReleephSummaryFieldSpecification is usually blank when an RQ is created, // creating a transaction change from null to "". Hide these! if ($type === ReleephRequestTransaction::TYPE_EDIT_FIELD) { if ($this->getOldValue() === null && $this->getNewValue() === '') { return true; } } return parent::shouldHide(); } public function isBoringPickStatus() { $type = $this->getTransactionType(); if ($type === ReleephRequestTransaction::TYPE_PICK_STATUS) { $new = $this->getNewValue(); if ($new === ReleephRequest::PICK_OK || $new === ReleephRequest::REVERT_OK) { return true; } } return false; } } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeArcanistProject.php b/src/applications/repository/phid/PhabricatorRepositoryArcanistProjectPHIDType.php similarity index 92% rename from src/applications/repository/phid/PhabricatorRepositoryPHIDTypeArcanistProject.php rename to src/applications/repository/phid/PhabricatorRepositoryArcanistProjectPHIDType.php index dcbb76b3e..7a71e86c7 100644 --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeArcanistProject.php +++ b/src/applications/repository/phid/PhabricatorRepositoryArcanistProjectPHIDType.php @@ -1,35 +1,35 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $project = $objects[$phid]; $handle->setName($project->getName()); } } } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php b/src/applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php similarity index 96% rename from src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php rename to src/applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php index 9b4334996..75beddeef 100644 --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeCommit.php +++ b/src/applications/repository/phid/PhabricatorRepositoryCommitPHIDType.php @@ -1,82 +1,82 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $commit = $objects[$phid]; $repository = $commit->getRepository(); $commit_identifier = $commit->getCommitIdentifier(); $name = $repository->formatCommitName($commit_identifier); $summary = $commit->getSummary(); if (strlen($summary)) { $full_name = $name.': '.$summary; } else { $full_name = $name; } $handle->setName($name); $handle->setFullName($full_name); $handle->setURI($commit->getURI()); $handle->setTimestamp($commit->getEpoch()); } } public static function getCommitObjectNamePattern() { $min_unqualified = PhabricatorRepository::MINIMUM_UNQUALIFIED_HASH; $min_qualified = PhabricatorRepository::MINIMUM_QUALIFIED_HASH; return 'r[A-Z]+[1-9]\d*'. '|'. 'r[A-Z]+[a-f0-9]{'.$min_qualified.',40}'. '|'. '[a-f0-9]{'.$min_unqualified.',40}'; } public function canLoadNamedObject($name) { $pattern = self::getCommitObjectNamePattern(); return preg_match('(^'.$pattern.'$)', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $query = id(new DiffusionCommitQuery()) ->setViewer($query->getViewer()) ->withIdentifiers($names); $query->execute(); return $query->getIdentifierMap(); } } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php b/src/applications/repository/phid/PhabricatorRepositoryMirrorPHIDType.php similarity index 92% rename from src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php rename to src/applications/repository/phid/PhabricatorRepositoryMirrorPHIDType.php index 541893844..f10af8ac5 100644 --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeMirror.php +++ b/src/applications/repository/phid/PhabricatorRepositoryMirrorPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $mirror = $objects[$phid]; $handle->setName( pht('Mirror %d %s', $mirror->getID(), $mirror->getRemoteURI())); $handle->setURI('/diffusion/mirror/'.$mirror->getID().'/'); } } } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypePushEvent.php b/src/applications/repository/phid/PhabricatorRepositoryPushEventPHIDType.php similarity index 91% rename from src/applications/repository/phid/PhabricatorRepositoryPHIDTypePushEvent.php rename to src/applications/repository/phid/PhabricatorRepositoryPushEventPHIDType.php index 95daf9d2b..db02bd8c1 100644 --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypePushEvent.php +++ b/src/applications/repository/phid/PhabricatorRepositoryPushEventPHIDType.php @@ -1,35 +1,35 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $event = $objects[$phid]; $handle->setName(pht('Push Event %d', $event->getID())); } } } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypePushLog.php b/src/applications/repository/phid/PhabricatorRepositoryPushLogPHIDType.php similarity index 90% rename from src/applications/repository/phid/PhabricatorRepositoryPHIDTypePushLog.php rename to src/applications/repository/phid/PhabricatorRepositoryPushLogPHIDType.php index c734b05b6..4a315ac00 100644 --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypePushLog.php +++ b/src/applications/repository/phid/PhabricatorRepositoryPushLogPHIDType.php @@ -1,35 +1,35 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $log = $objects[$phid]; $handle->setName(pht('Push Log %d', $log->getID())); } } } diff --git a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php b/src/applications/repository/phid/PhabricatorRepositoryRepositoryPHIDType.php similarity index 96% rename from src/applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php rename to src/applications/repository/phid/PhabricatorRepositoryRepositoryPHIDType.php index 7f20c3d02..a98eb02f0 100644 --- a/src/applications/repository/phid/PhabricatorRepositoryPHIDTypeRepository.php +++ b/src/applications/repository/phid/PhabricatorRepositoryRepositoryPHIDType.php @@ -1,76 +1,76 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $repository = $objects[$phid]; $monogram = $repository->getMonogram(); $callsign = $repository->getCallsign(); $name = $repository->getName(); $handle->setName($monogram); $handle->setFullName("{$monogram} {$name}"); $handle->setURI("/diffusion/{$callsign}/"); } } public function canLoadNamedObject($name) { return preg_match('/^r[A-Z]+$/', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PhabricatorRepositoryQuery()) ->setViewer($query->getViewer()) ->withCallsigns(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $object) { $callsign = $object->getCallsign(); foreach (idx($id_map, $callsign, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php b/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php index 673efe67e..9e73330da 100644 --- a/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php +++ b/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php @@ -1,134 +1,134 @@ setParameter( 'repositoryPHIDs', $this->readPHIDsFromRequest( $request, 'repositories', array( - PhabricatorRepositoryPHIDTypeRepository::TYPECONST, + PhabricatorRepositoryRepositoryPHIDType::TYPECONST, ))); $saved->setParameter( 'pusherPHIDs', $this->readUsersFromRequest( $request, 'pushers')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new PhabricatorRepositoryPushLogQuery()); $repository_phids = $saved->getParameter('repositoryPHIDs'); if ($repository_phids) { $query->withRepositoryPHIDs($repository_phids); } $pusher_phids = $saved->getParameter('pusherPHIDs'); if ($pusher_phids) { $query->withPusherPHIDs($pusher_phids); } return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved_query) { $repository_phids = $saved_query->getParameter('repositoryPHIDs', array()); $pusher_phids = $saved_query->getParameter('pusherPHIDs', array()); $all_phids = array_merge( $repository_phids, $pusher_phids); if ($all_phids) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($all_phids) ->execute(); } else { $handles = array(); } $repository_handles = array_select_keys($handles, $repository_phids); $pusher_handles = array_select_keys($handles, $pusher_phids); $form ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource(new DiffusionRepositoryDatasource()) ->setName('repositories') ->setLabel(pht('Repositories')) ->setValue($repository_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setDatasource(new PhabricatorPeopleDatasource()) ->setName('pushers') ->setLabel(pht('Pushers')) ->setValue($pusher_handles)); } protected function getURI($path) { return '/diffusion/pushlog/'.$path; } public function getBuiltinQueryNames() { return array( 'all' => pht('All Push Logs'), ); } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; } return parent::buildSavedQueryFromBuiltin($query_key); } protected function getRequiredHandlePHIDsForResultList( array $logs, PhabricatorSavedQuery $query) { return mpull($logs, 'getPusherPHID'); } protected function renderResultList( array $logs, PhabricatorSavedQuery $query, array $handles) { $table = id(new DiffusionPushLogListView()) ->setUser($this->requireViewer()) ->setHandles($handles) ->setLogs($logs); $box = id(new PHUIBoxView()) ->addMargin(PHUI::MARGIN_LARGE) ->appendChild($table); return $box; } } diff --git a/src/applications/repository/search/PhabricatorRepositoryCommitSearchIndexer.php b/src/applications/repository/search/PhabricatorRepositoryCommitSearchIndexer.php index 4e9f622d8..868f6c400 100644 --- a/src/applications/repository/search/PhabricatorRepositoryCommitSearchIndexer.php +++ b/src/applications/repository/search/PhabricatorRepositoryCommitSearchIndexer.php @@ -1,93 +1,93 @@ loadDocumentByPHID($phid); $commit_data = id(new PhabricatorRepositoryCommitData())->loadOneWhere( 'commitID = %d', $commit->getID()); $date_created = $commit->getEpoch(); $commit_message = $commit_data->getCommitMessage(); $author_phid = $commit_data->getCommitDetail('authorPHID'); $repository = id(new PhabricatorRepositoryQuery()) ->setViewer($this->getViewer()) ->withIDs(array($commit->getRepositoryID())) ->executeOne(); if (!$repository) { throw new Exception('No such repository!'); } $title = 'r'.$repository->getCallsign().$commit->getCommitIdentifier(). ' '.$commit_data->getSummary(); $doc = new PhabricatorSearchAbstractDocument(); $doc->setPHID($commit->getPHID()); - $doc->setDocumentType(PhabricatorRepositoryPHIDTypeCommit::TYPECONST); + $doc->setDocumentType(PhabricatorRepositoryCommitPHIDType::TYPECONST); $doc->setDocumentCreated($date_created); $doc->setDocumentModified($date_created); $doc->setDocumentTitle($title); $doc->addField( PhabricatorSearchField::FIELD_BODY, $commit_message); if ($author_phid) { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_AUTHOR, $author_phid, - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, $date_created); } $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $commit->getPHID(), PhabricatorEdgeConfig::TYPE_COMMIT_HAS_PROJECT); if ($project_phids) { foreach ($project_phids as $project_phid) { $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_PROJECT, $project_phid, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, $date_created); } } $doc->addRelationship( PhabricatorSearchRelationship::RELATIONSHIP_REPOSITORY, $repository->getPHID(), - PhabricatorRepositoryPHIDTypeRepository::TYPECONST, + PhabricatorRepositoryRepositoryPHIDType::TYPECONST, $date_created); $comments = id(new PhabricatorAuditComment())->loadAllWhere( 'targetPHID = %s', $commit->getPHID()); foreach ($comments as $comment) { if (strlen($comment->getContent())) { $doc->addField( PhabricatorSearchField::FIELD_COMMENT, $comment->getContent()); } } $inlines = id(new PhabricatorAuditInlineComment())->loadAllWhere( 'commitPHID = %s AND (auditCommentID IS NOT NULL)', $commit->getPHID()); foreach ($inlines as $inline) { if (strlen($inline->getContent())) { $doc->addField( PhabricatorSearchField::FIELD_COMMENT, $inline->getContent()); } } return $doc; } } diff --git a/src/applications/repository/storage/PhabricatorRepository.php b/src/applications/repository/storage/PhabricatorRepository.php index 2ae773e02..d4e5adc58 100644 --- a/src/applications/repository/storage/PhabricatorRepository.php +++ b/src/applications/repository/storage/PhabricatorRepository.php @@ -1,1400 +1,1400 @@ setViewer($actor) ->withClasses(array('PhabricatorDiffusionApplication')) ->executeOne(); $view_policy = $app->getPolicy(DiffusionCapabilityDefaultView::CAPABILITY); $edit_policy = $app->getPolicy(DiffusionCapabilityDefaultEdit::CAPABILITY); $push_policy = $app->getPolicy(DiffusionCapabilityDefaultPush::CAPABILITY); return id(new PhabricatorRepository()) ->setViewPolicy($view_policy) ->setEditPolicy($edit_policy) ->setPushPolicy($push_policy); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'details' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorRepositoryPHIDTypeRepository::TYPECONST); + PhabricatorRepositoryRepositoryPHIDType::TYPECONST); } public function toDictionary() { return array( 'id' => $this->getID(), 'name' => $this->getName(), 'phid' => $this->getPHID(), 'callsign' => $this->getCallsign(), 'monogram' => $this->getMonogram(), 'vcs' => $this->getVersionControlSystem(), 'uri' => PhabricatorEnv::getProductionURI($this->getURI()), 'remoteURI' => (string)$this->getRemoteURI(), 'description' => $this->getDetail('description'), 'isActive' => $this->isTracked(), 'isHosted' => $this->isHosted(), 'isImporting' => $this->isImporting(), ); } public function getMonogram() { return 'r'.$this->getCallsign(); } public function getDetail($key, $default = null) { return idx($this->details, $key, $default); } public function getHumanReadableDetail($key, $default = null) { $value = $this->getDetail($key, $default); switch ($key) { case 'branch-filter': case 'close-commits-filter': $value = array_keys($value); $value = implode(', ', $value); break; } return $value; } public function setDetail($key, $value) { $this->details[$key] = $value; return $this; } public function attachCommitCount($count) { $this->commitCount = $count; return $this; } public function getCommitCount() { return $this->assertAttached($this->commitCount); } public function attachMostRecentCommit( PhabricatorRepositoryCommit $commit = null) { $this->mostRecentCommit = $commit; return $this; } public function getMostRecentCommit() { return $this->assertAttached($this->mostRecentCommit); } public function getDiffusionBrowseURIForPath( PhabricatorUser $user, $path, $line = null, $branch = null) { $drequest = DiffusionRequest::newFromDictionary( array( 'user' => $user, 'repository' => $this, 'path' => $path, 'branch' => $branch, )); return $drequest->generateURI( array( 'action' => 'browse', 'line' => $line, )); } public function getLocalPath() { return $this->getDetail('local-path'); } public function getSubversionBaseURI($commit = null) { $subpath = $this->getDetail('svn-subpath'); if (!strlen($subpath)) { $subpath = null; } return $this->getSubversionPathURI($subpath, $commit); } public function getSubversionPathURI($path = null, $commit = null) { $vcs = $this->getVersionControlSystem(); if ($vcs != PhabricatorRepositoryType::REPOSITORY_TYPE_SVN) { throw new Exception('Not a subversion repository!'); } if ($this->isHosted()) { $uri = 'file://'.$this->getLocalPath(); } else { $uri = $this->getDetail('remote-uri'); } $uri = rtrim($uri, '/'); if (strlen($path)) { $path = rawurlencode($path); $path = str_replace('%2F', '/', $path); $uri = $uri.'/'.ltrim($path, '/'); } if ($path !== null || $commit !== null) { $uri .= '@'; } if ($commit !== null) { $uri .= $commit; } return $uri; } public function attachProjectPHIDs(array $project_phids) { $this->projectPHIDs = $project_phids; return $this; } public function getProjectPHIDs() { return $this->assertAttached($this->projectPHIDs); } /** * Get the name of the directory this repository should clone or checkout * into. For example, if the repository name is "Example Repository", a * reasonable name might be "example-repository". This is used to help users * get reasonable results when cloning repositories, since they generally do * not want to clone into directories called "X/" or "Example Repository/". * * @return string */ public function getCloneName() { $name = $this->getDetail('clone-name'); // Make some reasonable effort to produce reasonable default directory // names from repository names. if (!strlen($name)) { $name = $this->getName(); $name = phutil_utf8_strtolower($name); $name = preg_replace('@[/ -:]+@', '-', $name); $name = trim($name, '-'); if (!strlen($name)) { $name = $this->getCallsign(); } } return $name; } /* -( Remote Command Execution )------------------------------------------- */ public function execRemoteCommand($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newRemoteCommandFuture($args)->resolve(); } public function execxRemoteCommand($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newRemoteCommandFuture($args)->resolvex(); } public function getRemoteCommandFuture($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newRemoteCommandFuture($args); } public function passthruRemoteCommand($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newRemoteCommandPassthru($args)->execute(); } private function newRemoteCommandFuture(array $argv) { $argv = $this->formatRemoteCommand($argv); $future = newv('ExecFuture', $argv); $future->setEnv($this->getRemoteCommandEnvironment()); return $future; } private function newRemoteCommandPassthru(array $argv) { $argv = $this->formatRemoteCommand($argv); $passthru = newv('PhutilExecPassthru', $argv); $passthru->setEnv($this->getRemoteCommandEnvironment()); return $passthru; } /* -( Local Command Execution )-------------------------------------------- */ public function execLocalCommand($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newLocalCommandFuture($args)->resolve(); } public function execxLocalCommand($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newLocalCommandFuture($args)->resolvex(); } public function getLocalCommandFuture($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newLocalCommandFuture($args); } public function passthruLocalCommand($pattern /* , $arg, ... */) { $args = func_get_args(); return $this->newLocalCommandPassthru($args)->execute(); } private function newLocalCommandFuture(array $argv) { $this->assertLocalExists(); $argv = $this->formatLocalCommand($argv); $future = newv('ExecFuture', $argv); $future->setEnv($this->getLocalCommandEnvironment()); if ($this->usesLocalWorkingCopy()) { $future->setCWD($this->getLocalPath()); } return $future; } private function newLocalCommandPassthru(array $argv) { $this->assertLocalExists(); $argv = $this->formatLocalCommand($argv); $future = newv('PhutilExecPassthru', $argv); $future->setEnv($this->getLocalCommandEnvironment()); if ($this->usesLocalWorkingCopy()) { $future->setCWD($this->getLocalPath()); } return $future; } /* -( Command Infrastructure )--------------------------------------------- */ private function getSSHWrapper() { $root = dirname(phutil_get_library_root('phabricator')); return $root.'/bin/ssh-connect'; } private function getCommonCommandEnvironment() { $env = array( // NOTE: Force the language to "en_US.UTF-8", which overrides locale // settings. This makes stuff print in English instead of, e.g., French, // so we can parse the output of some commands, error messages, etc. 'LANG' => 'en_US.UTF-8', // Propagate PHABRICATOR_ENV explicitly. For discussion, see T4155. 'PHABRICATOR_ENV' => PhabricatorEnv::getSelectedEnvironmentName(), ); switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: break; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: // NOTE: See T2965. Some time after Git 1.7.5.4, Git started fataling if // it can not read $HOME. For many users, $HOME points at /root (this // seems to be a default result of Apache setup). Instead, explicitly // point $HOME at a readable, empty directory so that Git looks for the // config file it's after, fails to locate it, and moves on. This is // really silly, but seems like the least damaging approach to // mitigating the issue. $root = dirname(phutil_get_library_root('phabricator')); $env['HOME'] = $root.'/support/empty/'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: // NOTE: This overrides certain configuration, extensions, and settings // which make Mercurial commands do random unusual things. $env['HGPLAIN'] = 1; break; default: throw new Exception('Unrecognized version control system.'); } return $env; } private function getLocalCommandEnvironment() { return $this->getCommonCommandEnvironment(); } private function getRemoteCommandEnvironment() { $env = $this->getCommonCommandEnvironment(); if ($this->shouldUseSSH()) { // NOTE: This is read by `bin/ssh-connect`, and tells it which credentials // to use. $env['PHABRICATOR_CREDENTIAL'] = $this->getCredentialPHID(); switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: // Force SVN to use `bin/ssh-connect`. $env['SVN_SSH'] = $this->getSSHWrapper(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: // Force Git to use `bin/ssh-connect`. $env['GIT_SSH'] = $this->getSSHWrapper(); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: // We force Mercurial through `bin/ssh-connect` too, but it uses a // command-line flag instead of an environmental variable. break; default: throw new Exception('Unrecognized version control system.'); } } return $env; } private function formatRemoteCommand(array $args) { $pattern = $args[0]; $args = array_slice($args, 1); switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: if ($this->shouldUseHTTP() || $this->shouldUseSVNProtocol()) { $flags = array(); $flag_args = array(); $flags[] = '--non-interactive'; $flags[] = '--no-auth-cache'; if ($this->shouldUseHTTP()) { $flags[] = '--trust-server-cert'; } $credential_phid = $this->getCredentialPHID(); if ($credential_phid) { $key = PassphrasePasswordKey::loadFromPHID( $credential_phid, PhabricatorUser::getOmnipotentUser()); $flags[] = '--username %P'; $flags[] = '--password %P'; $flag_args[] = $key->getUsernameEnvelope(); $flag_args[] = $key->getPasswordEnvelope(); } $flags = implode(' ', $flags); $pattern = "svn {$flags} {$pattern}"; $args = array_mergev(array($flag_args, $args)); } else { $pattern = "svn --non-interactive {$pattern}"; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $pattern = "git {$pattern}"; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: if ($this->shouldUseSSH()) { $pattern = "hg --config ui.ssh=%s {$pattern}"; array_unshift( $args, $this->getSSHWrapper()); } else { $pattern = "hg {$pattern}"; } break; default: throw new Exception('Unrecognized version control system.'); } array_unshift($args, $pattern); return $args; } private function formatLocalCommand(array $args) { $pattern = $args[0]; $args = array_slice($args, 1); switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $pattern = "svn --non-interactive {$pattern}"; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $pattern = "git {$pattern}"; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $pattern = "hg {$pattern}"; break; default: throw new Exception('Unrecognized version control system.'); } array_unshift($args, $pattern); return $args; } /** * Sanitize output of an `hg` command invoked with the `--debug` flag to make * it usable. * * @param string Output from `hg --debug ...` * @return string Usable output. */ public static function filterMercurialDebugOutput($stdout) { // When hg commands are run with `--debug` and some config file isn't // trusted, Mercurial prints out a warning to stdout, twice, after Feb 2011. // // http://selenic.com/pipermail/mercurial-devel/2011-February/028541.html $lines = preg_split('/(?<=\n)/', $stdout); $regex = '/ignoring untrusted configuration option .*\n$/'; foreach ($lines as $key => $line) { $lines[$key] = preg_replace($regex, '', $line); } return implode('', $lines); } public function getURI() { return '/diffusion/'.$this->getCallsign().'/'; } public function getNormalizedPath() { $uri = (string)$this->getCloneURIObject(); switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $normalized_uri = new PhabricatorRepositoryURINormalizer( PhabricatorRepositoryURINormalizer::TYPE_GIT, $uri); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $normalized_uri = new PhabricatorRepositoryURINormalizer( PhabricatorRepositoryURINormalizer::TYPE_SVN, $uri); break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: $normalized_uri = new PhabricatorRepositoryURINormalizer( PhabricatorRepositoryURINormalizer::TYPE_MERCURIAL, $uri); break; default: throw new Exception('Unrecognized version control system.'); } return $normalized_uri->getNormalizedPath(); } public function isTracked() { return $this->getDetail('tracking-enabled', false); } public function getDefaultBranch() { $default = $this->getDetail('default-branch'); if (strlen($default)) { return $default; } $default_branches = array( PhabricatorRepositoryType::REPOSITORY_TYPE_GIT => 'master', PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL => 'default', ); return idx($default_branches, $this->getVersionControlSystem()); } public function getDefaultArcanistBranch() { return coalesce($this->getDefaultBranch(), 'svn'); } private function isBranchInFilter($branch, $filter_key) { $vcs = $this->getVersionControlSystem(); $is_git = ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT); $use_filter = ($is_git); if ($use_filter) { $filter = $this->getDetail($filter_key, array()); if ($filter && empty($filter[$branch])) { return false; } } // By default, all branches pass. return true; } public function shouldTrackBranch($branch) { return $this->isBranchInFilter($branch, 'branch-filter'); } public function shouldAutocloseBranch($branch) { if ($this->isImporting()) { return false; } if ($this->getDetail('disable-autoclose', false)) { return false; } if (!$this->shouldTrackBranch($branch)) { return false; } return $this->isBranchInFilter($branch, 'close-commits-filter'); } public function shouldAutocloseCommit( PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommitData $data) { if ($this->getDetail('disable-autoclose', false)) { return false; } switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: return true; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: return true; default: throw new Exception('Unrecognized version control system.'); } $closeable_flag = PhabricatorRepositoryCommit::IMPORTED_CLOSEABLE; if ($commit->isPartiallyImported($closeable_flag)) { return true; } // TODO: Remove this eventually, it's no longer written to by the import // pipeline (however, old tasks may still be queued which don't reflect // the new data format). $branches = $data->getCommitDetail('seenOnBranches', array()); foreach ($branches as $branch) { if ($this->shouldAutocloseBranch($branch)) { return true; } } return false; } public function formatCommitName($commit_identifier) { $vcs = $this->getVersionControlSystem(); $type_git = PhabricatorRepositoryType::REPOSITORY_TYPE_GIT; $type_hg = PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL; $is_git = ($vcs == $type_git); $is_hg = ($vcs == $type_hg); if ($is_git || $is_hg) { $short_identifier = substr($commit_identifier, 0, 12); } else { $short_identifier = $commit_identifier; } return 'r'.$this->getCallsign().$short_identifier; } public function isImporting() { return (bool)$this->getDetail('importing', false); } /* -( Repository URI Management )------------------------------------------ */ /** * Get the remote URI for this repository. * * @return string * @task uri */ public function getRemoteURI() { return (string)$this->getRemoteURIObject(); } /** * Get the remote URI for this repository, including credentials if they're * used by this repository. * * @return PhutilOpaqueEnvelope URI, possibly including credentials. * @task uri */ public function getRemoteURIEnvelope() { $uri = $this->getRemoteURIObject(); $remote_protocol = $this->getRemoteProtocol(); if ($remote_protocol == 'http' || $remote_protocol == 'https') { // For SVN, we use `--username` and `--password` flags separately, so // don't add any credentials here. if (!$this->isSVN()) { $credential_phid = $this->getCredentialPHID(); if ($credential_phid) { $key = PassphrasePasswordKey::loadFromPHID( $credential_phid, PhabricatorUser::getOmnipotentUser()); $uri->setUser($key->getUsernameEnvelope()->openEnvelope()); $uri->setPass($key->getPasswordEnvelope()->openEnvelope()); } } } return new PhutilOpaqueEnvelope((string)$uri); } /** * Get the clone (or checkout) URI for this repository, without authentication * information. * * @return string Repository URI. * @task uri */ public function getPublicCloneURI() { $uri = $this->getCloneURIObject(); // Make sure we don't leak anything if this repo is using HTTP Basic Auth // with the credentials in the URI or something zany like that. // If repository is not accessed over SSH we remove both username and // password. if (!$this->isHosted()) { if (!$this->shouldUseSSH()) { $uri->setUser(null); // This might be a Git URI or a normal URI. If it's Git, there's no // password support. if ($uri instanceof PhutilURI) { $uri->setPass(null); } } } return (string)$uri; } /** * Get the protocol for the repository's remote. * * @return string Protocol, like "ssh" or "git". * @task uri */ public function getRemoteProtocol() { $uri = $this->getRemoteURIObject(); if ($uri instanceof PhutilGitURI) { return 'ssh'; } else { return $uri->getProtocol(); } } /** * Get a parsed object representation of the repository's remote URI. This * may be a normal URI (returned as a @{class@libphutil:PhutilURI}) or a git * URI (returned as a @{class@libphutil:PhutilGitURI}). * * @return wild A @{class@libphutil:PhutilURI} or * @{class@libphutil:PhutilGitURI}. * @task uri */ public function getRemoteURIObject() { $raw_uri = $this->getDetail('remote-uri'); if (!$raw_uri) { return new PhutilURI(''); } if (!strncmp($raw_uri, '/', 1)) { return new PhutilURI('file://'.$raw_uri); } $uri = new PhutilURI($raw_uri); if ($uri->getProtocol()) { return $uri; } $uri = new PhutilGitURI($raw_uri); if ($uri->getDomain()) { return $uri; } throw new Exception("Remote URI '{$raw_uri}' could not be parsed!"); } /** * Get the "best" clone/checkout URI for this repository, on any protocol. */ public function getCloneURIObject() { if (!$this->isHosted()) { if ($this->isSVN()) { // Make sure we pick up the "Import Only" path for Subversion, so // the user clones the repository starting at the correct path, not // from the root. $base_uri = $this->getSubversionBaseURI(); $base_uri = new PhutilURI($base_uri); $path = $base_uri->getPath(); if (!$path) { $path = '/'; } // If the trailing "@" is not required to escape the URI, strip it for // readability. if (!preg_match('/@.*@/', $path)) { $path = rtrim($path, '@'); } $base_uri->setPath($path); return $base_uri; } else { return $this->getRemoteURIObject(); } } // Choose the best URI: pick a read/write URI over a URI which is not // read/write, and SSH over HTTP. $serve_ssh = $this->getServeOverSSH(); $serve_http = $this->getServeOverHTTP(); if ($serve_ssh === self::SERVE_READWRITE) { return $this->getSSHCloneURIObject(); } else if ($serve_http === self::SERVE_READWRITE) { return $this->getHTTPCloneURIObject(); } else if ($serve_ssh !== self::SERVE_OFF) { return $this->getSSHCloneURIObject(); } else if ($serve_http !== self::SERVE_OFF) { return $this->getHTTPCloneURIObject(); } else { return null; } } /** * Get the repository's SSH clone/checkout URI, if one exists. */ public function getSSHCloneURIObject() { if (!$this->isHosted()) { if ($this->shouldUseSSH()) { return $this->getRemoteURIObject(); } else { return null; } } $serve_ssh = $this->getServeOverSSH(); if ($serve_ssh === self::SERVE_OFF) { return null; } $uri = new PhutilURI(PhabricatorEnv::getProductionURI($this->getURI())); if ($this->isSVN()) { $uri->setProtocol('svn+ssh'); } else { $uri->setProtocol('ssh'); } if ($this->isGit()) { $uri->setPath($uri->getPath().$this->getCloneName().'.git'); } else if ($this->isHg()) { $uri->setPath($uri->getPath().$this->getCloneName().'/'); } $ssh_user = PhabricatorEnv::getEnvConfig('diffusion.ssh-user'); if ($ssh_user) { $uri->setUser($ssh_user); } $uri->setPort(PhabricatorEnv::getEnvConfig('diffusion.ssh-port')); return $uri; } /** * Get the repository's HTTP clone/checkout URI, if one exists. */ public function getHTTPCloneURIObject() { if (!$this->isHosted()) { if ($this->shouldUseHTTP()) { return $this->getRemoteURIObject(); } else { return null; } } $serve_http = $this->getServeOverHTTP(); if ($serve_http === self::SERVE_OFF) { return null; } $uri = PhabricatorEnv::getProductionURI($this->getURI()); $uri = new PhutilURI($uri); if ($this->isGit()) { $uri->setPath($uri->getPath().$this->getCloneName().'.git'); } else if ($this->isHg()) { $uri->setPath($uri->getPath().$this->getCloneName().'/'); } return $uri; } /** * Determine if we should connect to the remote using SSH flags and * credentials. * * @return bool True to use the SSH protocol. * @task uri */ private function shouldUseSSH() { if ($this->isHosted()) { return false; } $protocol = $this->getRemoteProtocol(); if ($this->isSSHProtocol($protocol)) { return true; } return false; } /** * Determine if we should connect to the remote using HTTP flags and * credentials. * * @return bool True to use the HTTP protocol. * @task uri */ private function shouldUseHTTP() { if ($this->isHosted()) { return false; } $protocol = $this->getRemoteProtocol(); return ($protocol == 'http' || $protocol == 'https'); } /** * Determine if we should connect to the remote using SVN flags and * credentials. * * @return bool True to use the SVN protocol. * @task uri */ private function shouldUseSVNProtocol() { if ($this->isHosted()) { return false; } $protocol = $this->getRemoteProtocol(); return ($protocol == 'svn'); } /** * Determine if a protocol is SSH or SSH-like. * * @param string A protocol string, like "http" or "ssh". * @return bool True if the protocol is SSH-like. * @task uri */ private function isSSHProtocol($protocol) { return ($protocol == 'ssh' || $protocol == 'svn+ssh'); } public function delete() { $this->openTransaction(); $paths = id(new PhabricatorOwnersPath()) ->loadAllWhere('repositoryPHID = %s', $this->getPHID()); foreach ($paths as $path) { $path->delete(); } $projects = id(new PhabricatorRepositoryArcanistProject()) ->loadAllWhere('repositoryID = %d', $this->getID()); foreach ($projects as $project) { // note each project deletes its PhabricatorRepositorySymbols $project->delete(); } $commits = id(new PhabricatorRepositoryCommit()) ->loadAllWhere('repositoryID = %d', $this->getID()); foreach ($commits as $commit) { // note PhabricatorRepositoryAuditRequests and // PhabricatorRepositoryCommitData are deleted here too. $commit->delete(); } $mirrors = id(new PhabricatorRepositoryMirror()) ->loadAllWhere('repositoryPHID = %s', $this->getPHID()); foreach ($mirrors as $mirror) { $mirror->delete(); } $ref_cursors = id(new PhabricatorRepositoryRefCursor()) ->loadAllWhere('repositoryPHID = %s', $this->getPHID()); foreach ($ref_cursors as $cursor) { $cursor->delete(); } $conn_w = $this->establishConnection('w'); queryfx( $conn_w, 'DELETE FROM %T WHERE repositoryID = %d', self::TABLE_FILESYSTEM, $this->getID()); queryfx( $conn_w, 'DELETE FROM %T WHERE repositoryID = %d', self::TABLE_PATHCHANGE, $this->getID()); queryfx( $conn_w, 'DELETE FROM %T WHERE repositoryID = %d', self::TABLE_SUMMARY, $this->getID()); $result = parent::delete(); $this->saveTransaction(); return $result; } public function isGit() { $vcs = $this->getVersionControlSystem(); return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_GIT); } public function isSVN() { $vcs = $this->getVersionControlSystem(); return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_SVN); } public function isHg() { $vcs = $this->getVersionControlSystem(); return ($vcs == PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL); } public function isHosted() { return (bool)$this->getDetail('hosting-enabled', false); } public function setHosted($enabled) { return $this->setDetail('hosting-enabled', $enabled); } public function getServeOverHTTP() { if ($this->isSVN()) { return self::SERVE_OFF; } $serve = $this->getDetail('serve-over-http', self::SERVE_OFF); return $this->normalizeServeConfigSetting($serve); } public function setServeOverHTTP($mode) { return $this->setDetail('serve-over-http', $mode); } public function getServeOverSSH() { $serve = $this->getDetail('serve-over-ssh', self::SERVE_OFF); return $this->normalizeServeConfigSetting($serve); } public function setServeOverSSH($mode) { return $this->setDetail('serve-over-ssh', $mode); } public static function getProtocolAvailabilityName($constant) { switch ($constant) { case self::SERVE_OFF: return pht('Off'); case self::SERVE_READONLY: return pht('Read Only'); case self::SERVE_READWRITE: return pht('Read/Write'); default: return pht('Unknown'); } } private function normalizeServeConfigSetting($value) { switch ($value) { case self::SERVE_OFF: case self::SERVE_READONLY: return $value; case self::SERVE_READWRITE: if ($this->isHosted()) { return self::SERVE_READWRITE; } else { return self::SERVE_READONLY; } default: return self::SERVE_OFF; } } /** * Raise more useful errors when there are basic filesystem problems. */ private function assertLocalExists() { if (!$this->usesLocalWorkingCopy()) { return; } $local = $this->getLocalPath(); Filesystem::assertExists($local); Filesystem::assertIsDirectory($local); Filesystem::assertReadable($local); } /** * Determine if the working copy is bare or not. In Git, this corresponds * to `--bare`. In Mercurial, `--noupdate`. */ public function isWorkingCopyBare() { switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: return false; case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: $local = $this->getLocalPath(); if (Filesystem::pathExists($local.'/.git')) { return false; } else { return true; } } } public function usesLocalWorkingCopy() { switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: return $this->isHosted(); case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: return true; } } public function getHookDirectories() { $directories = array(); if (!$this->isHosted()) { return $directories; } $root = $this->getLocalPath(); switch ($this->getVersionControlSystem()) { case PhabricatorRepositoryType::REPOSITORY_TYPE_GIT: if ($this->isWorkingCopyBare()) { $directories[] = $root.'/hooks/pre-receive-phabricator.d/'; } else { $directories[] = $root.'/.git/hooks/pre-receive-phabricator.d/'; } break; case PhabricatorRepositoryType::REPOSITORY_TYPE_SVN: $directories[] = $root.'/hooks/pre-commit-phabricator.d/'; break; case PhabricatorRepositoryType::REPOSITORY_TYPE_MERCURIAL: // NOTE: We don't support custom Mercurial hooks for now because they're // messy and we can't easily just drop a `hooks.d/` directory next to // the hooks. break; } return $directories; } public function canDestroyWorkingCopy() { if ($this->isHosted()) { // Never destroy hosted working copies. return false; } $default_path = PhabricatorEnv::getEnvConfig( 'repository.default-local-path'); return Filesystem::isDescendant($this->getLocalPath(), $default_path); } public function canUsePathTree() { return !$this->isSVN(); } public function canMirror() { if ($this->isGit() || $this->isHg()) { return true; } return false; } public function canAllowDangerousChanges() { if (!$this->isHosted()) { return false; } if ($this->isGit() || $this->isHg()) { return true; } return false; } public function shouldAllowDangerousChanges() { return (bool)$this->getDetail('allow-dangerous-changes'); } public function writeStatusMessage( $status_type, $status_code, array $parameters = array()) { $table = new PhabricatorRepositoryStatusMessage(); $conn_w = $table->establishConnection('w'); $table_name = $table->getTableName(); if ($status_code === null) { queryfx( $conn_w, 'DELETE FROM %T WHERE repositoryID = %d AND statusType = %s', $table_name, $this->getID(), $status_type); } else { queryfx( $conn_w, 'INSERT INTO %T (repositoryID, statusType, statusCode, parameters, epoch) VALUES (%d, %s, %s, %s, %d) ON DUPLICATE KEY UPDATE statusCode = VALUES(statusCode), parameters = VALUES(parameters), epoch = VALUES(epoch)', $table_name, $this->getID(), $status_type, $status_code, json_encode($parameters), time()); } return $this; } public static function getRemoteURIProtocol($raw_uri) { $uri = new PhutilURI($raw_uri); if ($uri->getProtocol()) { return strtolower($uri->getProtocol()); } $git_uri = new PhutilGitURI($raw_uri); if (strlen($git_uri->getDomain()) && strlen($git_uri->getPath())) { return 'ssh'; } return null; } public static function assertValidRemoteURI($uri) { if (trim($uri) != $uri) { throw new Exception( pht( 'The remote URI has leading or trailing whitespace.')); } $protocol = self::getRemoteURIProtocol($uri); // Catch confusion between Git/SCP-style URIs and normal URIs. See T3619 // for discussion. This is usually a user adding "ssh://" to an implicit // SSH Git URI. if ($protocol == 'ssh') { if (preg_match('(^[^:@]+://[^/:]+:[^\d])', $uri)) { throw new Exception( pht( "The remote URI is not formatted correctly. Remote URIs ". "with an explicit protocol should be in the form ". "'proto://domain/path', not 'proto://domain:/path'. ". "The ':/path' syntax is only valid in SCP-style URIs.")); } } switch ($protocol) { case 'ssh': case 'http': case 'https': case 'git': case 'svn': case 'svn+ssh': break; default: // NOTE: We're explicitly rejecting 'file://' because it can be // used to clone from the working copy of another repository on disk // that you don't normally have permission to access. throw new Exception( pht( "The URI protocol is unrecognized. It should begin ". "'ssh://', 'http://', 'https://', 'git://', 'svn://', ". "'svn+ssh://', or be in the form 'git@domain.com:path'.")); } return true; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, DiffusionCapabilityPush::CAPABILITY, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); case DiffusionCapabilityPush::CAPABILITY: return $this->getPushPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $user) { return false; } public function describeAutomaticCapability($capability) { return null; } /* -( PhabricatorMarkupInterface )----------------------------------------- */ public function getMarkupFieldKey($field) { $hash = PhabricatorHash::digestForIndex($this->getMarkupText($field)); return "repo:{$hash}"; } public function newMarkupEngine($field) { return PhabricatorMarkupEngine::newMarkupEngine(array()); } public function getMarkupText($field) { return $this->getDetail('description'); } public function didMarkupText( $field, $output, PhutilMarkupEngine $engine) { require_celerity_resource('phabricator-remarkup-css'); return phutil_tag( 'div', array( 'class' => 'phabricator-remarkup', ), $output); } public function shouldUseMarkupCache($field) { return true; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php b/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php index 1665845cf..b325cc245 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php +++ b/src/applications/repository/storage/PhabricatorRepositoryArcanistProject.php @@ -1,103 +1,103 @@ true, self::CONFIG_TIMESTAMPS => false, self::CONFIG_SERIALIZATION => array( 'symbolIndexLanguages' => self::SERIALIZATION_JSON, 'symbolIndexProjects' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorRepositoryPHIDTypeArcanistProject::TYPECONST); + PhabricatorRepositoryArcanistProjectPHIDType::TYPECONST); } // TODO: Remove. Also, T603. public function loadRepository() { if (!$this->getRepositoryID()) { return null; } return id(new PhabricatorRepository())->load($this->getRepositoryID()); } public function delete() { $this->openTransaction(); queryfx( $this->establishConnection('w'), 'DELETE FROM %T WHERE arcanistProjectID = %d', id(new PhabricatorRepositorySymbol())->getTableName(), $this->getID()); $result = parent::delete(); $this->saveTransaction(); return $result; } public function getRepository() { return $this->assertAttached($this->repository); } public function attachRepository(PhabricatorRepository $repository = null) { $this->repository = $repository; return $this; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return PhabricatorPolicies::POLICY_USER; case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_ADMIN; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return false; } public function describeAutomaticCapability($capability) { return null; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php b/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php index 3019692d4..78d969f74 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php +++ b/src/applications/repository/storage/PhabricatorRepositoryAuditRequest.php @@ -1,59 +1,59 @@ false, self::CONFIG_SERIALIZATION => array( 'auditReasons' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function isUser() { - $user_type = PhabricatorPeoplePHIDTypeUser::TYPECONST; + $user_type = PhabricatorPeopleUserPHIDType::TYPECONST; return (phid_get_type($this->getAuditorPHID()) == $user_type); } public function attachCommit(PhabricatorRepositoryCommit $commit) { $this->commit = $commit; return $this; } public function getCommit() { return $this->assertAttached($this->commit); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return $this->getCommit()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getCommit()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'This audit is attached to a commit, and inherits its policies.'); } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryCommit.php b/src/applications/repository/storage/PhabricatorRepositoryCommit.php index b09842645..6b0cf47fe 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryCommit.php +++ b/src/applications/repository/storage/PhabricatorRepositoryCommit.php @@ -1,333 +1,333 @@ repository = $repository; return $this; } public function getRepository() { return $this->assertAttached($this->repository); } public function isPartiallyImported($mask) { return (($mask & $this->getImportStatus()) == $mask); } public function isImported() { return $this->isPartiallyImported(self::IMPORTED_ALL); } public function writeImportStatusFlag($flag) { queryfx( $this->establishConnection('w'), 'UPDATE %T SET importStatus = (importStatus | %d) WHERE id = %d', $this->getTableName(), $flag, $this->getID()); return $this; } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_TIMESTAMPS => false, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorRepositoryPHIDTypeCommit::TYPECONST); + PhabricatorRepositoryCommitPHIDType::TYPECONST); } public function loadCommitData() { if (!$this->getID()) { return null; } return id(new PhabricatorRepositoryCommitData())->loadOneWhere( 'commitID = %d', $this->getID()); } public function attachCommitData( PhabricatorRepositoryCommitData $data = null) { $this->commitData = $data; return $this; } public function getCommitData() { return $this->assertAttached($this->commitData); } public function attachAudits(array $audits) { assert_instances_of($audits, 'PhabricatorRepositoryAuditRequest'); $this->audits = $audits; return $this; } public function getAudits() { return $this->assertAttached($this->audits); } public function getAuthorityAudits( PhabricatorUser $user, array $authority_phids) { $authority = array_fill_keys($authority_phids, true); $audits = $this->getAudits(); $authority_audits = array(); foreach ($audits as $audit) { $has_authority = !empty($authority[$audit->getAuditorPHID()]); if ($has_authority) { $commit_author = $this->getAuthorPHID(); // You don't have authority over package and project audits on your // own commits. $auditor_is_user = ($audit->getAuditorPHID() == $user->getPHID()); $user_is_author = ($commit_author == $user->getPHID()); if ($auditor_is_user || !$user_is_author) { $authority_audits[$audit->getID()] = $audit; } } } return $authority_audits; } public function save() { if (!$this->mailKey) { $this->mailKey = Filesystem::readRandomCharacters(20); } return parent::save(); } public function delete() { $data = $this->loadCommitData(); $audits = id(new PhabricatorRepositoryAuditRequest()) ->loadAllWhere('commitPHID = %s', $this->getPHID()); $this->openTransaction(); if ($data) { $data->delete(); } foreach ($audits as $audit) { $audit->delete(); } $result = parent::delete(); $this->saveTransaction(); return $result; } public function getDateCreated() { // This is primarily to make analysis of commits with the Fact engine work. return $this->getEpoch(); } public function getURI() { $repository = $this->getRepository(); $callsign = $repository->getCallsign(); $commit_identifier = $this->getCommitIdentifier(); return '/r'.$callsign.$commit_identifier; } /** * Synchronize a commit's overall audit status with the individual audit * triggers. */ public function updateAuditStatus(array $requests) { assert_instances_of($requests, 'PhabricatorRepositoryAuditRequest'); $any_concern = false; $any_accept = false; $any_need = false; foreach ($requests as $request) { switch ($request->getAuditStatus()) { case PhabricatorAuditStatusConstants::AUDIT_REQUIRED: $any_need = true; break; case PhabricatorAuditStatusConstants::ACCEPTED: $any_accept = true; break; case PhabricatorAuditStatusConstants::CONCERNED: $any_concern = true; break; } } if ($any_concern) { $status = PhabricatorAuditCommitStatusConstants::CONCERN_RAISED; } else if ($any_accept) { if ($any_need) { $status = PhabricatorAuditCommitStatusConstants::PARTIALLY_AUDITED; } else { $status = PhabricatorAuditCommitStatusConstants::FULLY_AUDITED; } } else if ($any_need) { $status = PhabricatorAuditCommitStatusConstants::NEEDS_AUDIT; } else { $status = PhabricatorAuditCommitStatusConstants::NONE; } return $this->setAuditStatus($status); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getRepository()->getPolicy($capability); case PhabricatorPolicyCapability::CAN_EDIT: // TODO: (T603) Who should be able to edit a commit? For now, retain // the existing policy. return PhabricatorPolicies::POLICY_USER; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getRepository()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( 'Commits inherit the policies of the repository they belong to.'); } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array( $this->getAuthorPHID(), ); } /* -( Stuff for serialization )---------------------------------------------- */ /** * NOTE: this is not a complete serialization; only the 'protected' fields are * involved. This is due to ease of (ab)using the Lisk abstraction to get this * done, as well as complexity of the other fields. */ public function toDictionary() { return array( 'repositoryID' => $this->getRepositoryID(), 'phid' => $this->getPHID(), 'commitIdentifier' => $this->getCommitIdentifier(), 'epoch' => $this->getEpoch(), 'mailKey' => $this->getMailKey(), 'authorPHID' => $this->getAuthorPHID(), 'auditStatus' => $this->getAuditStatus(), 'summary' => $this->getSummary(), 'importStatus' => $this->getImportStatus(), ); } public static function newFromDictionary(array $dict) { return id(new PhabricatorRepositoryCommit()) ->loadFromArray($dict); } /* -( HarbormasterBuildableInterface )------------------------------------- */ public function getHarbormasterBuildablePHID() { return $this->getPHID(); } public function getHarbormasterContainerPHID() { return $this->getRepository()->getPHID(); } public function getBuildVariables() { $results = array(); $results['buildable.commit'] = $this->getCommitIdentifier(); $repo = $this->getRepository(); $results['repository.callsign'] = $repo->getCallsign(); $results['repository.vcs'] = $repo->getVersionControlSystem(); $results['repository.uri'] = $repo->getPublicCloneURI(); return $results; } public function getAvailableBuildVariables() { return array( 'buildable.commit' => pht('The commit identifier, if applicable.'), 'repository.callsign' => pht('The callsign of the repository in Phabricator.'), 'repository.vcs' => pht('The version control system, either "svn", "hg" or "git".'), 'repository.uri' => pht('The URI to clone or checkout the repository from.'), ); } /* -( PhabricatorCustomFieldInterface )------------------------------------ */ public function getCustomFieldSpecificationForRole($role) { // TODO: We could make this configurable eventually, but just use the // defaults for now. return array(); } public function getCustomFieldBaseClass() { return 'PhabricatorCommitCustomField'; } public function getCustomFields() { return $this->assertAttached($this->customFields); } public function attachCustomFields(PhabricatorCustomFieldAttachment $fields) { $this->customFields = $fields; return $this; } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryMirror.php b/src/applications/repository/storage/PhabricatorRepositoryMirror.php index a4205d4dc..d215a83d0 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryMirror.php +++ b/src/applications/repository/storage/PhabricatorRepositoryMirror.php @@ -1,60 +1,60 @@ setRemoteURI(''); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorRepositoryPHIDTypeMirror::TYPECONST); + PhabricatorRepositoryMirrorPHIDType::TYPECONST); } public function attachRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; } public function getRepository() { return $this->assertAttached($this->repository); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { return $this->getRepository()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getRepository()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return null; } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php b/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php index d58f5c539..b2539a228 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php +++ b/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php @@ -1,81 +1,81 @@ setPusherPHID($viewer->getPHID()); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_TIMESTAMPS => false, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorRepositoryPHIDTypePushEvent::TYPECONST); + PhabricatorRepositoryPushEventPHIDType::TYPECONST); } public function attachRepository(PhabricatorRepository $repository) { $this->repository = $repository; return $this; } public function getRepository() { return $this->assertAttached($this->repository); } public function attachLogs(array $logs) { $this->logs = $logs; return $this; } public function getLogs() { return $this->assertAttached($this->logs); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { return $this->getRepository()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getRepository()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( "A repository's push events are visible to users who can see the ". "repository."); } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryPushLog.php b/src/applications/repository/storage/PhabricatorRepositoryPushLog.php index 789636a81..a96f89c49 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryPushLog.php +++ b/src/applications/repository/storage/PhabricatorRepositoryPushLog.php @@ -1,174 +1,174 @@ setPusherPHID($viewer->getPHID()); } public static function getHeraldChangeFlagConditionOptions() { return array( PhabricatorRepositoryPushLog::CHANGEFLAG_ADD => pht('change creates ref'), PhabricatorRepositoryPushLog::CHANGEFLAG_DELETE => pht('change deletes ref'), PhabricatorRepositoryPushLog::CHANGEFLAG_REWRITE => pht('change rewrites ref'), PhabricatorRepositoryPushLog::CHANGEFLAG_DANGEROUS => pht('dangerous change')); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_TIMESTAMPS => false, self::CONFIG_BINARY => array( 'refNameRaw' => true, ), ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorRepositoryPHIDTypePushLog::TYPECONST); + PhabricatorRepositoryPushLogPHIDType::TYPECONST); } public function attachPushEvent(PhabricatorRepositoryPushEvent $push_event) { $this->pushEvent = $push_event; return $this; } public function getPushEvent() { return $this->assertAttached($this->pushEvent); } public function getRefName() { return $this->getUTF8StringFromStorage( $this->getRefNameRaw(), $this->getRefNameEncoding()); } public function setRefName($ref_raw) { $this->setRefNameRaw($ref_raw); $this->setRefNameHash(PhabricatorHash::digestForIndex($ref_raw)); $this->setRefNameEncoding($this->detectEncodingForStorage($ref_raw)); return $this; } public function getRefOldShort() { if ($this->getRepository()->isSVN()) { return $this->getRefOld(); } return substr($this->getRefOld(), 0, 12); } public function getRefNewShort() { if ($this->getRepository()->isSVN()) { return $this->getRefNew(); } return substr($this->getRefNew(), 0, 12); } public function hasChangeFlags($mask) { return ($this->changeFlags & $mask); } public function attachDangerousChangeDescription($description) { $this->dangerousChangeDescription = $description; return $this; } public function getDangerousChangeDescription() { return $this->assertAttached($this->dangerousChangeDescription); } public function attachRepository(PhabricatorRepository $repository) { // NOTE: Some gymnastics around this because of object construction order // in the hook engine. Particularly, web build the logs before we build // their push event. $this->repository = $repository; return $this; } public function getRepository() { if ($this->repository == self::ATTACHABLE) { return $this->getPushEvent()->getRepository(); } return $this->assertAttached($this->repository); } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, ); } public function getPolicy($capability) { // NOTE: We're passing through the repository rather than the push event // mostly because we need to do policy checks in Herald before we create // the event. The two approaches are equivalent in practice. return $this->getRepository()->getPolicy($capability); } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return $this->getRepository()->hasAutomaticCapability($capability, $viewer); } public function describeAutomaticCapability($capability) { return pht( "A repository's push logs are visible to users who can see the ". "repository."); } } diff --git a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php index c4c9ed8b5..34be86927 100644 --- a/src/applications/repository/storage/PhabricatorRepositoryTransaction.php +++ b/src/applications/repository/storage/PhabricatorRepositoryTransaction.php @@ -1,390 +1,390 @@ getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_PUSH_POLICY: $phids[] = $old; $phids[] = $new; break; } return $phids; } public function shouldHide() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_REMOTE_URI: case self::TYPE_SSH_LOGIN: case self::TYPE_SSH_KEY: case self::TYPE_SSH_KEYFILE: case self::TYPE_HTTP_LOGIN: case self::TYPE_HTTP_PASS: // Hide null vs empty string changes. return (!strlen($old) && !strlen($new)); case self::TYPE_LOCAL_PATH: case self::TYPE_NAME: // Hide these on create, they aren't interesting and we have an // explicit "create" transaction. if (!strlen($old)) { return true; } break; } return parent::shouldHide(); } public function getIcon() { switch ($this->getTransactionType()) { case self::TYPE_VCS: return 'fa-plus'; } return parent::getIcon(); } public function getColor() { switch ($this->getTransactionType()) { case self::TYPE_VCS: return 'green'; } return parent::getIcon(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case self::TYPE_VCS: return pht( '%s created this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_ACTIVATE: if ($new) { return pht( '%s activated this repository.', $this->renderHandleLink($author_phid)); } else { return pht( '%s deactivated this repository.', $this->renderHandleLink($author_phid)); } case self::TYPE_NAME: return pht( '%s renamed this repository from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); case self::TYPE_DESCRIPTION: return pht( '%s updated the description of this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_ENCODING: if (strlen($old) && !strlen($new)) { return pht( '%s removed the "%s" encoding configured for this repository.', $this->renderHandleLink($author_phid), $old); } else if (strlen($new) && !strlen($old)) { return pht( '%s set the encoding for this repository to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s changed the repository encoding from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } case self::TYPE_DEFAULT_BRANCH: if (!strlen($new)) { return pht( '%s removed "%s" as the default branch.', $this->renderHandleLink($author_phid), $old); } else if (!strlen($old)) { return pht( '%s set the default branch to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s changed the default branch from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case self::TYPE_TRACK_ONLY: if (!$new) { return pht( '%s set this repository to track all branches.', $this->renderHandleLink($author_phid)); } else if (!$old) { return pht( '%s set this repository to track branches: %s.', $this->renderHandleLink($author_phid), implode(', ', $new)); } else { return pht( '%s changed track branches from "%s" to "%s".', $this->renderHandleLink($author_phid), implode(', ', $old), implode(', ', $new)); } break; case self::TYPE_AUTOCLOSE_ONLY: if (!$new) { return pht( '%s set this repository to autoclose on all branches.', $this->renderHandleLink($author_phid)); } else if (!$old) { return pht( '%s set this repository to autoclose on branches: %s.', $this->renderHandleLink($author_phid), implode(', ', $new)); } else { return pht( '%s changed autoclose branches from "%s" to "%s".', $this->renderHandleLink($author_phid), implode(', ', $old), implode(', ', $new)); } break; case self::TYPE_UUID: if (!strlen($new)) { return pht( '%s removed "%s" as the repository UUID.', $this->renderHandleLink($author_phid), $old); } else if (!strlen($old)) { return pht( '%s set the repository UUID to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s changed the repository UUID from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case self::TYPE_SVN_SUBPATH: if (!strlen($new)) { return pht( '%s removed "%s" as the Import Only path.', $this->renderHandleLink($author_phid), $old); } else if (!strlen($old)) { return pht( '%s set the repository to import only "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s changed the import path from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case self::TYPE_NOTIFY: if ($new) { return pht( '%s enabled notifications and publishing for this repository.', $this->renderHandleLink($author_phid)); } else { return pht( '%s disabled notifications and publishing for this repository.', $this->renderHandleLink($author_phid)); } break; case self::TYPE_AUTOCLOSE: if ($new) { return pht( '%s enabled autoclose for this repository.', $this->renderHandleLink($author_phid)); } else { return pht( '%s disabled autoclose for this repository.', $this->renderHandleLink($author_phid)); } break; case self::TYPE_REMOTE_URI: if (!strlen($old)) { return pht( '%s set the remote URI for this repository to "%s".', $this->renderHandleLink($author_phid), $new); } else if (!strlen($new)) { return pht( '%s removed the remote URI for this repository.', $this->renderHandleLink($author_phid)); } else { return pht( '%s changed the remote URI for this repository from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case self::TYPE_SSH_LOGIN: return pht( '%s updated the SSH login for this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_SSH_KEY: return pht( '%s updated the SSH key for this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_SSH_KEYFILE: return pht( '%s updated the SSH keyfile for this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_HTTP_LOGIN: return pht( '%s updated the HTTP login for this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_HTTP_PASS: return pht( '%s updated the HTTP password for this repository.', $this->renderHandleLink($author_phid)); case self::TYPE_LOCAL_PATH: return pht( '%s changed the local path from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); case self::TYPE_HOSTING: if ($new) { return pht( '%s changed this repository to be hosted on Phabricator.', $this->renderHandleLink($author_phid)); } else { return pht( '%s changed this repository to track a remote elsewhere.', $this->renderHandleLink($author_phid)); } case self::TYPE_PROTOCOL_HTTP: return pht( '%s changed the availability of this repository over HTTP from '. '"%s" to "%s".', $this->renderHandleLink($author_phid), PhabricatorRepository::getProtocolAvailabilityName($old), PhabricatorRepository::getProtocolAvailabilityName($new)); case self::TYPE_PROTOCOL_SSH: return pht( '%s changed the availability of this repository over SSH from '. '"%s" to "%s".', $this->renderHandleLink($author_phid), PhabricatorRepository::getProtocolAvailabilityName($old), PhabricatorRepository::getProtocolAvailabilityName($new)); case self::TYPE_PUSH_POLICY: return pht( '%s changed the push policy of this repository from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->renderPolicyName($old, 'old'), $this->renderPolicyName($new, 'new')); case self::TYPE_DANGEROUS: if ($new) { return pht( '%s disabled protection against dangerous changes.', $this->renderHandleLink($author_phid)); } else { return pht( '%s enabled protection against dangerous changes.', $this->renderHandleLink($author_phid)); } case self::TYPE_CLONE_NAME: if (strlen($old) && !strlen($new)) { return pht( '%s removed the clone name of this repository.', $this->renderHandleLink($author_phid)); } else if (strlen($new) && !strlen($old)) { return pht( '%s set the clone name of this repository to "%s".', $this->renderHandleLink($author_phid), $new); } else { return pht( '%s changed the clone name of this repository from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } } return parent::getTitle(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case self::TYPE_DESCRIPTION: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } } diff --git a/src/applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php b/src/applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php index 355ec5731..cd2e26854 100644 --- a/src/applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php +++ b/src/applications/repository/worker/PhabricatorRepositoryCommitHeraldWorker.php @@ -1,482 +1,482 @@ applyHeraldRules($repository, $commit); $commit->writeImportStatusFlag( PhabricatorRepositoryCommit::IMPORTED_HERALD); return $result; } private function applyHeraldRules( PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { $commit->attachRepository($repository); // Don't take any actions on an importing repository. Principally, this // avoids generating thousands of audits or emails when you import an // established repository on an existing install. if ($repository->isImporting()) { return; } if ($repository->getDetail('herald-disabled')) { return; } $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere( 'commitID = %d', $commit->getID()); if (!$data) { throw new PhabricatorWorkerPermanentFailureException( pht( 'Unable to load commit data. The data for this task is invalid '. 'or no longer exists.')); } $adapter = id(new HeraldCommitAdapter()) ->setCommit($commit); $rules = id(new HeraldRuleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withContentTypes(array($adapter->getAdapterContentType())) ->withDisabled(false) ->needConditionsAndActions(true) ->needAppliedToPHIDs(array($adapter->getPHID())) ->needValidateAuthors(true) ->execute(); $engine = new HeraldEngine(); $effects = $engine->applyRules($rules, $adapter); $engine->applyEffects($effects, $adapter, $rules); $xscript = $engine->getTranscript(); $audit_phids = $adapter->getAuditMap(); $cc_phids = $adapter->getAddCCMap(); if ($audit_phids || $cc_phids) { $this->createAudits($commit, $audit_phids, $cc_phids, $rules); } HarbormasterBuildable::applyBuildPlans( $commit->getPHID(), $repository->getPHID(), $adapter->getBuildPlans()); $explicit_auditors = $this->createAuditsFromCommitMessage($commit, $data); $this->publishFeedStory($repository, $commit, $data); $herald_targets = $adapter->getEmailPHIDs(); $email_phids = array_unique( array_merge( $explicit_auditors, array_keys($cc_phids), $herald_targets)); if (!$email_phids) { return; } $revision = $adapter->loadDifferentialRevision(); if ($revision) { $name = $revision->getTitle(); } else { $name = $data->getSummary(); } $author_phid = $data->getCommitDetail('authorPHID'); $reviewer_phid = $data->getCommitDetail('reviewerPHID'); $phids = array_filter( array( $author_phid, $reviewer_phid, $commit->getPHID(), )); $handles = id(new PhabricatorHandleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs($phids) ->execute(); $commit_handle = $handles[$commit->getPHID()]; $commit_name = $commit_handle->getName(); if ($author_phid) { $author_name = $handles[$author_phid]->getName(); } else { $author_name = $data->getAuthorName(); } if ($reviewer_phid) { $reviewer_name = $handles[$reviewer_phid]->getName(); } else { $reviewer_name = null; } $who = implode(', ', array_filter(array($author_name, $reviewer_name))); $description = $data->getCommitMessage(); $commit_uri = PhabricatorEnv::getProductionURI($commit_handle->getURI()); $differential = $revision ? PhabricatorEnv::getProductionURI('/D'.$revision->getID()) : 'No revision.'; $limit = self::MAX_FILES_SHOWN_IN_EMAIL; $files = $adapter->loadAffectedPaths(); sort($files); if (count($files) > $limit) { array_splice($files, $limit); $files[] = '(This commit affected more than '.$limit.' files. '. 'Only '.$limit.' are shown here and additional ones are truncated.)'; } $files = implode("\n", $files); $xscript_id = $xscript->getID(); $why_uri = '/herald/transcript/'.$xscript_id.'/'; $reply_handler = PhabricatorAuditCommentEditor::newReplyHandlerForCommit( $commit); $template = new PhabricatorMetaMTAMail(); $inline_patch_text = $this->buildPatch($template, $repository, $commit); $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection($description); $body->addTextSection(pht('DETAILS'), $commit_uri); // TODO: This should be integrated properly once we move to // ApplicationTransactions. $field_list = PhabricatorCustomField::getObjectFields( $commit, PhabricatorCustomField::ROLE_APPLICATIONTRANSACTIONS); $field_list ->setViewer(PhabricatorUser::getOmnipotentUser()) ->readFieldsFromStorage($commit); foreach ($field_list->getFields() as $field) { try { $field->buildApplicationTransactionMailBody( new DifferentialTransaction(), // Bogus object to satisfy typehint. $body); } catch (Exception $ex) { // Log the exception and continue. phlog($ex); } } $body->addTextSection(pht('DIFFERENTIAL REVISION'), $differential); $body->addTextSection(pht('AFFECTED FILES'), $files); $body->addReplySection($reply_handler->getReplyHandlerInstructions()); $body->addHeraldSection($why_uri); $body->addRawSection($inline_patch_text); $body = $body->render(); $prefix = PhabricatorEnv::getEnvConfig('metamta.diffusion.subject-prefix'); $threading = PhabricatorAuditCommentEditor::getMailThreading( $repository, $commit); list($thread_id, $thread_topic) = $threading; $template->setRelatedPHID($commit->getPHID()); $template->setSubject("{$commit_name}: {$name}"); $template->setSubjectPrefix($prefix); $template->setVarySubjectPrefix('[Commit]'); $template->setBody($body); $template->setThreadID($thread_id, $is_new = true); $template->addHeader('Thread-Topic', $thread_topic); $template->setIsBulk(true); $template->addHeader('X-Herald-Rules', $xscript->getXHeraldRulesHeader()); if ($author_phid) { $template->setFrom($author_phid); } // TODO: We should verify that each recipient can actually see the // commit before sending them email (T603). $mails = $reply_handler->multiplexMail( $template, id(new PhabricatorHandleQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->withPHIDs($email_phids) ->execute(), array()); foreach ($mails as $mail) { $mail->saveAndSend(); } } private function createAudits( PhabricatorRepositoryCommit $commit, array $map, array $ccmap, array $rules) { assert_instances_of($rules, 'HeraldRule'); $requests = id(new PhabricatorRepositoryAuditRequest())->loadAllWhere( 'commitPHID = %s', $commit->getPHID()); $requests = mpull($requests, null, 'getAuditorPHID'); $rules = mpull($rules, null, 'getID'); $maps = array( PhabricatorAuditStatusConstants::AUDIT_REQUIRED => $map, PhabricatorAuditStatusConstants::CC => $ccmap, ); foreach ($maps as $status => $map) { foreach ($map as $phid => $rule_ids) { $request = idx($requests, $phid); if ($request) { continue; } $reasons = array(); foreach ($rule_ids as $id) { $rule_name = '?'; if ($rules[$id]) { $rule_name = $rules[$id]->getName(); } if ($status == PhabricatorAuditStatusConstants::AUDIT_REQUIRED) { $reasons[] = pht( '%s Triggered Audit', "H{$id} {$rule_name}"); } else { $reasons[] = pht( '%s Triggered CC', "H{$id} {$rule_name}"); } } $request = new PhabricatorRepositoryAuditRequest(); $request->setCommitPHID($commit->getPHID()); $request->setAuditorPHID($phid); $request->setAuditStatus($status); $request->setAuditReasons($reasons); $request->save(); } } $commit->updateAuditStatus($requests); $commit->save(); } /** * Find audit requests in the "Auditors" field if it is present and trigger * explicit audit requests. */ private function createAuditsFromCommitMessage( PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommitData $data) { $message = $data->getCommitMessage(); $matches = null; if (!preg_match('/^Auditors:\s*(.*)$/im', $message, $matches)) { return array(); } $phids = id(new PhabricatorObjectListQuery()) ->setViewer(PhabricatorUser::getOmnipotentUser()) ->setAllowPartialResults(true) ->setAllowedTypes( array( - PhabricatorPeoplePHIDTypeUser::TYPECONST, - PhabricatorProjectPHIDTypeProject::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, + PhabricatorProjectProjectPHIDType::TYPECONST, )) ->setObjectList($matches[1]) ->execute(); if (!$phids) { return array(); } $requests = id(new PhabricatorRepositoryAuditRequest())->loadAllWhere( 'commitPHID = %s', $commit->getPHID()); $requests = mpull($requests, null, 'getAuditorPHID'); foreach ($phids as $phid) { if (isset($requests[$phid])) { continue; } $request = new PhabricatorRepositoryAuditRequest(); $request->setCommitPHID($commit->getPHID()); $request->setAuditorPHID($phid); $request->setAuditStatus( PhabricatorAuditStatusConstants::AUDIT_REQUESTED); $request->setAuditReasons( array( 'Requested by Author', )); $request->save(); $requests[$phid] = $request; } $commit->updateAuditStatus($requests); $commit->save(); return $phids; } private function publishFeedStory( PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit, PhabricatorRepositoryCommitData $data) { if (time() > $commit->getEpoch() + (24 * 60 * 60)) { // Don't publish stories that are more than 24 hours old, to avoid // ridiculous levels of feed spam if a repository is imported without // disabling feed publishing. return; } $author_phid = $commit->getAuthorPHID(); $committer_phid = $data->getCommitDetail('committerPHID'); $publisher = new PhabricatorFeedStoryPublisher(); $publisher->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_COMMIT); $publisher->setStoryData( array( 'commitPHID' => $commit->getPHID(), 'summary' => $data->getSummary(), 'authorName' => $data->getAuthorName(), 'authorPHID' => $author_phid, 'committerName' => $data->getCommitDetail('committer'), 'committerPHID' => $committer_phid, )); $publisher->setStoryTime($commit->getEpoch()); $publisher->setRelatedPHIDs( array_filter( array( $author_phid, $committer_phid, ))); if ($author_phid) { $publisher->setStoryAuthorPHID($author_phid); } $publisher->publish(); } private function buildPatch( PhabricatorMetaMTAMail $template, PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { $attach_key = 'metamta.diffusion.attach-patches'; $inline_key = 'metamta.diffusion.inline-patches'; $attach_patches = PhabricatorEnv::getEnvConfig($attach_key); $inline_patches = PhabricatorEnv::getEnvConfig($inline_key); if (!$attach_patches && !$inline_patches) { return; } $encoding = $repository->getDetail('encoding', 'UTF-8'); $result = null; $patch_error = null; try { $raw_patch = $this->loadRawPatchText($repository, $commit); if ($attach_patches) { $commit_name = $repository->formatCommitName( $commit->getCommitIdentifier()); $template->addAttachment( new PhabricatorMetaMTAAttachment( $raw_patch, $commit_name.'.patch', 'text/x-patch; charset='.$encoding)); } } catch (Exception $ex) { phlog($ex); $patch_error = 'Unable to generate: '.$ex->getMessage(); } if ($patch_error) { $result = $patch_error; } else if ($inline_patches) { $len = substr_count($raw_patch, "\n"); if ($len <= $inline_patches) { // We send email as utf8, so we need to convert the text to utf8 if // we can. if ($encoding) { $raw_patch = phutil_utf8_convert($raw_patch, 'UTF-8', $encoding); } $result = phutil_utf8ize($raw_patch); } } if ($result) { $result = "PATCH\n\n{$result}\n"; } return $result; } private function loadRawPatchText( PhabricatorRepository $repository, PhabricatorRepositoryCommit $commit) { $drequest = DiffusionRequest::newFromDictionary( array( 'user' => PhabricatorUser::getOmnipotentUser(), 'initFromConduit' => false, 'repository' => $repository, 'commit' => $commit->getCommitIdentifier(), )); $raw_query = DiffusionRawDiffQuery::newFromDiffusionRequest($drequest); $raw_query->setLinesOfContext(3); $time_key = 'metamta.diffusion.time-limit'; $byte_key = 'metamta.diffusion.byte-limit'; $time_limit = PhabricatorEnv::getEnvConfig($time_key); $byte_limit = PhabricatorEnv::getEnvConfig($byte_key); if ($time_limit) { $raw_query->setTimeout($time_limit); } $raw_diff = $raw_query->loadRawDiff(); $size = strlen($raw_diff); if ($byte_limit && $size > $byte_limit) { $pretty_size = phutil_format_bytes($size); $pretty_limit = phutil_format_bytes($byte_limit); throw new Exception( "Patch size of {$pretty_size} exceeds configured byte size limit of ". "{$pretty_limit}."); } return $raw_diff; } } diff --git a/src/applications/search/controller/PhabricatorSearchAttachController.php b/src/applications/search/controller/PhabricatorSearchAttachController.php index bd0d57520..59c55e1ff 100644 --- a/src/applications/search/controller/PhabricatorSearchAttachController.php +++ b/src/applications/search/controller/PhabricatorSearchAttachController.php @@ -1,365 +1,365 @@ phid = $data['phid']; $this->type = $data['type']; $this->action = idx($data, 'action', self::ACTION_ATTACH); } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $handle = id(new PhabricatorHandleQuery()) ->setViewer($user) ->withPHIDs(array($this->phid)) ->executeOne(); $object_type = $handle->getType(); $attach_type = $this->type; $object = id(new PhabricatorObjectQuery()) ->setViewer($user) ->withPHIDs(array($this->phid)) ->executeOne(); if (!$object) { return new Aphront404Response(); } $edge_type = null; switch ($this->action) { case self::ACTION_EDGE: case self::ACTION_DEPENDENCIES: case self::ACTION_BLOCKS: case self::ACTION_ATTACH: $edge_type = $this->getEdgeType($object_type, $attach_type); break; } if ($request->isFormPost()) { $phids = explode(';', $request->getStr('phids')); $phids = array_filter($phids); $phids = array_values($phids); if ($edge_type) { if ($object instanceof PhabricatorRepositoryCommit) { // TODO: Remove this entire branch of special cased grossness // after T4896. $old_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $this->phid, $edge_type); $add_phids = $phids; $rem_phids = array_diff($old_phids, $add_phids); // Doing this correctly (in a way that writes edge transactions) would // be a huge mess and we don't get the commit half of the transaction // anyway until T4896, so just write the edges themselves and skip // the transactions for now. $editor = new PhabricatorEdgeEditor(); foreach ($add_phids as $phid) { $editor->addEdge( $object->getPHID(), DiffusionCommitHasTaskEdgeType::EDGECONST, $phid); } foreach ($rem_phids as $phid) { $editor->removeEdge( $object->getPHID(), DiffusionCommitHasTaskEdgeType::EDGECONST, $phid); } $editor->save(); } else { if (!$object instanceof PhabricatorApplicationTransactionInterface) { throw new Exception( pht( 'Expected object ("%s") to implement interface "%s".', get_class($object), 'PhabricatorApplicationTransactionInterface')); } $old_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $this->phid, $edge_type); $add_phids = $phids; $rem_phids = array_diff($old_phids, $add_phids); $txn_editor = $object->getApplicationTransactionEditor() ->setActor($user) ->setContentSourceFromRequest($request); $txn_template = $object->getApplicationTransactionTemplate() ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $edge_type) ->setNewValue(array( '+' => array_fuse($add_phids), '-' => array_fuse($rem_phids))); $txn_editor->applyTransactions( $object->getApplicationTransactionObject(), array($txn_template)); } return id(new AphrontReloadResponse())->setURI($handle->getURI()); } else { return $this->performMerge($object, $handle, $phids); } } else { if ($edge_type) { $phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $this->phid, $edge_type); } else { // This is a merge. $phids = array(); } } $strings = $this->getStrings(); $handles = $this->loadViewerHandles($phids); $obj_dialog = new PhabricatorObjectSelectorDialog(); $obj_dialog ->setUser($user) ->setHandles($handles) ->setFilters($this->getFilters($strings)) ->setSelectedFilter($strings['selected']) ->setExcluded($this->phid) ->setCancelURI($handle->getURI()) ->setSearchURI('/search/select/'.$attach_type.'/') ->setTitle($strings['title']) ->setHeader($strings['header']) ->setButtonText($strings['button']) ->setInstructions($strings['instructions']); $dialog = $obj_dialog->buildDialog(); return id(new AphrontDialogResponse())->setDialog($dialog); } private function performMerge( ManiphestTask $task, PhabricatorObjectHandle $handle, array $phids) { $user = $this->getRequest()->getUser(); $response = id(new AphrontReloadResponse())->setURI($handle->getURI()); $phids = array_fill_keys($phids, true); unset($phids[$task->getPHID()]); // Prevent merging a task into itself. if (!$phids) { return $response; } $targets = id(new ManiphestTaskQuery()) ->setViewer($user) ->withPHIDs(array_keys($phids)) ->execute(); if (empty($targets)) { return $response; } $editor = id(new ManiphestTransactionEditor()) ->setActor($user) ->setContentSourceFromRequest($this->getRequest()) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true); $task_names = array(); $merge_into_name = 'T'.$task->getID(); $cc_vector = array(); $cc_vector[] = $task->getCCPHIDs(); foreach ($targets as $target) { $cc_vector[] = $target->getCCPHIDs(); $cc_vector[] = array( $target->getAuthorPHID(), $target->getOwnerPHID()); $close_task = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTransaction::TYPE_STATUS) ->setNewValue(ManiphestTaskStatus::getDuplicateStatus()); $merge_comment = id(new ManiphestTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) ->attachComment( id(new ManiphestTransactionComment()) ->setContent("\xE2\x9C\x98 Merged into {$merge_into_name}.")); $editor->applyTransactions( $target, array( $close_task, $merge_comment, )); $task_names[] = 'T'.$target->getID(); } $all_ccs = array_mergev($cc_vector); $all_ccs = array_filter($all_ccs); $all_ccs = array_unique($all_ccs); $task_names = implode(', ', $task_names); $add_ccs = id(new ManiphestTransaction()) ->setTransactionType(ManiphestTransaction::TYPE_CCS) ->setNewValue($all_ccs); $merged_comment = id(new ManiphestTransaction()) ->setTransactionType(PhabricatorTransactions::TYPE_COMMENT) ->attachComment( id(new ManiphestTransactionComment()) ->setContent("\xE2\x97\x80 Merged tasks: {$task_names}.")); $editor->applyTransactions($task, array($add_ccs, $merged_comment)); return $response; } private function getStrings() { switch ($this->type) { - case DifferentialPHIDTypeRevision::TYPECONST: + case DifferentialRevisionPHIDType::TYPECONST: $noun = 'Revisions'; $selected = 'created'; break; - case ManiphestPHIDTypeTask::TYPECONST: + case ManiphestTaskPHIDType::TYPECONST: $noun = 'Tasks'; $selected = 'assigned'; break; - case PhabricatorRepositoryPHIDTypeCommit::TYPECONST: + case PhabricatorRepositoryCommitPHIDType::TYPECONST: $noun = 'Commits'; $selected = 'created'; break; - case PholioPHIDTypeMock::TYPECONST: + case PholioMockPHIDType::TYPECONST: $noun = 'Mocks'; $selected = 'created'; break; } switch ($this->action) { case self::ACTION_EDGE: case self::ACTION_ATTACH: $dialog_title = "Manage Attached {$noun}"; $header_text = "Currently Attached {$noun}"; $button_text = "Save {$noun}"; $instructions = null; break; case self::ACTION_MERGE: $dialog_title = 'Merge Duplicate Tasks'; $header_text = 'Tasks To Merge'; $button_text = "Merge {$noun}"; $instructions = 'These tasks will be merged into the current task and then closed. '. 'The current task will grow stronger.'; break; case self::ACTION_DEPENDENCIES: $dialog_title = 'Edit Dependencies'; $header_text = 'Current Dependencies'; $button_text = 'Save Dependencies'; $instructions = null; break; case self::ACTION_BLOCKS: $dialog_title = pht('Edit Blocking Tasks'); $header_text = pht('Current Blocking Tasks'); $button_text = pht('Save Blocking Tasks'); $instructions = null; break; } return array( 'target_plural_noun' => $noun, 'selected' => $selected, 'title' => $dialog_title, 'header' => $header_text, 'button' => $button_text, 'instructions' => $instructions, ); } private function getFilters(array $strings) { - if ($this->type == PholioPHIDTypeMock::TYPECONST) { + if ($this->type == PholioMockPHIDType::TYPECONST) { $filters = array( 'created' => 'Created By Me', 'all' => 'All '.$strings['target_plural_noun'], ); } else { $filters = array( 'assigned' => 'Assigned to Me', 'created' => 'Created By Me', 'open' => 'All Open '.$strings['target_plural_noun'], 'all' => 'All '.$strings['target_plural_noun'], ); } return $filters; } private function getEdgeType($src_type, $dst_type) { - $t_cmit = PhabricatorRepositoryPHIDTypeCommit::TYPECONST; - $t_task = ManiphestPHIDTypeTask::TYPECONST; - $t_drev = DifferentialPHIDTypeRevision::TYPECONST; - $t_mock = PholioPHIDTypeMock::TYPECONST; + $t_cmit = PhabricatorRepositoryCommitPHIDType::TYPECONST; + $t_task = ManiphestTaskPHIDType::TYPECONST; + $t_drev = DifferentialRevisionPHIDType::TYPECONST; + $t_mock = PholioMockPHIDType::TYPECONST; $map = array( $t_cmit => array( $t_task => DiffusionCommitHasTaskEdgeType::EDGECONST, ), $t_task => array( $t_cmit => ManiphestTaskHasCommitEdgeType::EDGECONST, $t_task => PhabricatorEdgeConfig::TYPE_TASK_DEPENDS_ON_TASK, $t_drev => ManiphestTaskHasRevisionEdgeType::EDGECONST, $t_mock => PhabricatorEdgeConfig::TYPE_TASK_HAS_MOCK, ), $t_drev => array( $t_drev => PhabricatorEdgeConfig::TYPE_DREV_DEPENDS_ON_DREV, $t_task => DifferentialRevisionHasTaskEdgeType::EDGECONST, ), $t_mock => array( $t_task => PhabricatorEdgeConfig::TYPE_MOCK_HAS_TASK, ), ); if (empty($map[$src_type][$dst_type])) { return null; } return $map[$src_type][$dst_type]; } private function raiseGraphCycleException(PhabricatorEdgeCycleException $ex) { $cycle = $ex->getCycle(); $handles = $this->loadViewerHandles($cycle); $names = array(); foreach ($cycle as $cycle_phid) { $names[] = $handles[$cycle_phid]->getFullName(); } $names = implode(" \xE2\x86\x92 ", $names); throw new Exception( "You can not create that dependency, because it would create a ". "circular dependency: {$names}."); } } diff --git a/src/applications/search/controller/PhabricatorSearchSelectController.php b/src/applications/search/controller/PhabricatorSearchSelectController.php index 7c4568254..03d3ca4c6 100644 --- a/src/applications/search/controller/PhabricatorSearchSelectController.php +++ b/src/applications/search/controller/PhabricatorSearchSelectController.php @@ -1,79 +1,79 @@ type = $data['type']; } public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $query = new PhabricatorSavedQuery(); $query_str = $request->getStr('query'); $query->setEngineClassName('PhabricatorSearchApplicationSearchEngine'); $query->setParameter('query', $query_str); $query->setParameter('types', array($this->type)); $status_open = PhabricatorSearchRelationship::RELATIONSHIP_OPEN; switch ($request->getStr('filter')) { case 'assigned': $query->setParameter('ownerPHIDs', array($user->getPHID())); $query->setParameter('statuses', array($status_open)); break; case 'created'; $query->setParameter('authorPHIDs', array($user->getPHID())); // TODO - if / when we allow pholio mocks to be archived, etc // update this - if ($this->type != PholioPHIDTypeMock::TYPECONST) { + if ($this->type != PholioMockPHIDType::TYPECONST) { $query->setParameter('statuses', array($status_open)); } break; case 'open': $query->setParameter('statuses', array($status_open)); break; } $query->setParameter('excludePHIDs', array($request->getStr('exclude'))); $results = id(new PhabricatorSearchDocumentQuery()) ->setViewer($user) ->withSavedQuery($query) ->setOffset(0) ->setLimit(100) ->execute(); $phids = array_fill_keys(mpull($results, 'getPHID'), true); $phids += $this->queryObjectNames($query_str); $phids = array_keys($phids); $handles = $this->loadViewerHandles($phids); $data = array(); foreach ($handles as $handle) { $view = new PhabricatorHandleObjectSelectorDataView($handle); $data[] = $view->renderData(); } return id(new AphrontAjaxResponse())->setContent($data); } private function queryObjectNames($query) { $viewer = $this->getRequest()->getUser(); $objects = id(new PhabricatorObjectQuery()) ->setViewer($viewer) ->withTypes(array($this->type)) ->withNames(array($query)) ->execute(); return mpull($objects, 'getPHID'); } } diff --git a/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php b/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php index a589a1dd1..b56a3466f 100644 --- a/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php +++ b/src/applications/search/query/PhabricatorSearchApplicationSearchEngine.php @@ -1,283 +1,283 @@ setParameter('query', $request->getStr('query')); $saved->setParameter( 'statuses', $this->readListFromRequest($request, 'statuses')); $saved->setParameter( 'types', $this->readListFromRequest($request, 'types')); $saved->setParameter( 'authorPHIDs', $this->readUsersFromRequest($request, 'authorPHIDs')); $saved->setParameter( 'ownerPHIDs', $this->readUsersFromRequest($request, 'ownerPHIDs')); $saved->setParameter( 'withUnowned', $this->readBoolFromRequest($request, 'withUnowned')); $saved->setParameter( 'subscriberPHIDs', $this->readPHIDsFromRequest($request, 'subscriberPHIDs')); $saved->setParameter( 'projectPHIDs', $this->readPHIDsFromRequest($request, 'projectPHIDs')); return $saved; } public function buildQueryFromSavedQuery(PhabricatorSavedQuery $saved) { $query = id(new PhabricatorSearchDocumentQuery()) ->withSavedQuery($saved); return $query; } public function buildSearchForm( AphrontFormView $form, PhabricatorSavedQuery $saved) { $options = array(); $author_value = null; $owner_value = null; $subscribers_value = null; $project_value = null; $author_phids = $saved->getParameter('authorPHIDs', array()); $owner_phids = $saved->getParameter('ownerPHIDs', array()); $subscriber_phids = $saved->getParameter('subscriberPHIDs', array()); $project_phids = $saved->getParameter('projectPHIDs', array()); $all_phids = array_merge( $author_phids, $owner_phids, $subscriber_phids, $project_phids); $all_handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireViewer()) ->withPHIDs($all_phids) ->execute(); $author_handles = array_select_keys($all_handles, $author_phids); $owner_handles = array_select_keys($all_handles, $owner_phids); $subscriber_handles = array_select_keys($all_handles, $subscriber_phids); $project_handles = array_select_keys($all_handles, $project_phids); $with_unowned = $saved->getParameter('withUnowned', array()); $status_values = $saved->getParameter('statuses', array()); $status_values = array_fuse($status_values); $statuses = array( PhabricatorSearchRelationship::RELATIONSHIP_OPEN => pht('Open'), PhabricatorSearchRelationship::RELATIONSHIP_CLOSED => pht('Closed'), ); $status_control = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Document Status')); foreach ($statuses as $status => $name) { $status_control->addCheckbox( 'statuses[]', $status, $name, isset($status_values[$status])); } $type_values = $saved->getParameter('types', array()); $type_values = array_fuse($type_values); $types = self::getIndexableDocumentTypes($this->requireViewer()); $types_control = id(new AphrontFormCheckboxControl()) ->setLabel(pht('Document Types')); foreach ($types as $type => $name) { $types_control->addCheckbox( 'types[]', $type, $name, isset($type_values[$type])); } $form ->appendChild( phutil_tag( 'input', array( 'type' => 'hidden', 'name' => 'jump', 'value' => 'no', ))) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Query') ->setName('query') ->setValue($saved->getParameter('query'))) ->appendChild($status_control) ->appendChild($types_control) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('authorPHIDs') ->setLabel('Authors') ->setDatasource(new PhabricatorPeopleDatasource()) ->setValue($author_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('ownerPHIDs') ->setLabel('Owners') ->setDatasource(new PhabricatorTypeaheadOwnerDatasource()) ->setValue($owner_handles)) ->appendChild( id(new AphrontFormCheckboxControl()) ->addCheckbox( 'withUnowned', 1, pht('Show only unowned documents.'), $with_unowned)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('subscriberPHIDs') ->setLabel('Subscribers') ->setDatasource(new PhabricatorPeopleDatasource()) ->setValue($subscriber_handles)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setName('projectPHIDs') ->setLabel('In Any Project') ->setDatasource(new PhabricatorProjectDatasource()) ->setValue($project_handles)); } protected function getURI($path) { return '/search/'.$path; } public function getBuiltinQueryNames() { return array( 'all' => pht('All Documents'), 'open' => pht('Open Documents'), 'open-tasks' => pht('Open Tasks'), ); } public function buildSavedQueryFromBuiltin($query_key) { $query = $this->newSavedQuery(); $query->setQueryKey($query_key); switch ($query_key) { case 'all': return $query; case 'open': return $query->setParameter('statuses', array('open')); case 'open-tasks': return $query ->setParameter('statuses', array('open')) - ->setParameter('types', array(ManiphestPHIDTypeTask::TYPECONST)); + ->setParameter('types', array(ManiphestTaskPHIDType::TYPECONST)); } return parent::buildSavedQueryFromBuiltin($query_key); } public static function getIndexableDocumentTypes( PhabricatorUser $viewer = null) { // TODO: This is inelegant and not very efficient, but gets us reasonable // results. It would be nice to do this more elegantly. $indexers = id(new PhutilSymbolLoader()) ->setAncestorClass('PhabricatorSearchDocumentIndexer') ->loadObjects(); if ($viewer) { $types = PhabricatorPHIDType::getAllInstalledTypes($viewer); } else { $types = PhabricatorPHIDType::getAllTypes(); } $results = array(); foreach ($types as $type) { $typeconst = $type->getTypeConstant(); foreach ($indexers as $indexer) { $fake_phid = 'PHID-'.$typeconst.'-fake'; if ($indexer->shouldIndexDocumentByPHID($fake_phid)) { $results[$typeconst] = $type->getTypeName(); } } } asort($results); // Put tasks first, see T4606. $results = array_select_keys( $results, array( - ManiphestPHIDTypeTask::TYPECONST, + ManiphestTaskPHIDType::TYPECONST, )) + $results; return $results; } public function shouldUseOffsetPaging() { return true; } protected function renderResultList( array $results, PhabricatorSavedQuery $query, array $handles) { $viewer = $this->requireViewer(); if ($results) { $objects = id(new PhabricatorObjectQuery()) ->setViewer($viewer) ->withPHIDs(mpull($results, 'getPHID')) ->execute(); $output = array(); foreach ($results as $phid => $handle) { $view = id(new PhabricatorSearchResultView()) ->setHandle($handle) ->setQuery($query) ->setObject(idx($objects, $phid)); $output[] = $view->render(); } $results = phutil_tag_div( 'phabricator-search-result-list', $output); } else { $results = phutil_tag_div( 'phabricator-search-result-list', phutil_tag( 'p', array('class' => 'phabricator-search-no-results'), pht('No search results.'))); } return id(new PHUIBoxView()) ->addMargin(PHUI::MARGIN_LARGE) ->addPadding(PHUI::PADDING_LARGE) ->setBorder(true) ->appendChild($results) ->addClass('phabricator-search-result-box'); } } diff --git a/src/applications/slowvote/phid/PhabricatorSlowvotePHIDTypePoll.php b/src/applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php similarity index 95% rename from src/applications/slowvote/phid/PhabricatorSlowvotePHIDTypePoll.php rename to src/applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php index 834b70c69..927e6a394 100644 --- a/src/applications/slowvote/phid/PhabricatorSlowvotePHIDTypePoll.php +++ b/src/applications/slowvote/phid/PhabricatorSlowvotePollPHIDType.php @@ -1,66 +1,66 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $poll = $objects[$phid]; $handle->setName('V'.$poll->getID()); $handle->setFullName('V'.$poll->getID().': '.$poll->getQuestion()); $handle->setURI('/V'.$poll->getID()); } } public function canLoadNamedObject($name) { return preg_match('/^V\d*[1-9]\d*$/i', $name); } public function loadNamedObjects( PhabricatorObjectQuery $query, array $names) { $id_map = array(); foreach ($names as $name) { $id = (int)substr($name, 1); $id_map[$id][] = $name; } $objects = id(new PhabricatorSlowvoteQuery()) ->setViewer($query->getViewer()) ->withIDs(array_keys($id_map)) ->execute(); $results = array(); foreach ($objects as $id => $object) { foreach (idx($id_map, $id, array()) as $name) { $results[$name] = $object; } } return $results; } } diff --git a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php index 59ffc9726..d9a107ced 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvotePoll.php @@ -1,144 +1,144 @@ setViewer($actor) ->withClasses(array('PhabricatorSlowvoteApplication')) ->executeOne(); $view_policy = $app->getPolicy( PhabricatorSlowvoteCapabilityDefaultView::CAPABILITY); return id(new PhabricatorSlowvotePoll()) ->setAuthorPHID($actor->getPHID()) ->setViewPolicy($view_policy); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID( - PhabricatorSlowvotePHIDTypePoll::TYPECONST); + PhabricatorSlowvotePollPHIDType::TYPECONST); } public function getOptions() { return $this->assertAttached($this->options); } public function attachOptions(array $options) { assert_instances_of($options, 'PhabricatorSlowvoteOption'); $this->options = $options; return $this; } public function getChoices() { return $this->assertAttached($this->choices); } public function attachChoices(array $choices) { assert_instances_of($choices, 'PhabricatorSlowvoteChoice'); $this->choices = $choices; return $this; } public function getViewerChoices(PhabricatorUser $viewer) { return $this->assertAttachedKey($this->viewerChoices, $viewer->getPHID()); } public function attachViewerChoices(PhabricatorUser $viewer, array $choices) { if ($this->viewerChoices === self::ATTACHABLE) { $this->viewerChoices = array(); } assert_instances_of($choices, 'PhabricatorSlowvoteChoice'); $this->viewerChoices[$viewer->getPHID()] = $choices; return $this; } /* -( PhabricatorPolicyInterface )----------------------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->viewPolicy; case PhabricatorPolicyCapability::CAN_EDIT: return PhabricatorPolicies::POLICY_NOONE; } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { return pht( 'The author of a poll can always view and edit it.'); } /* -( PhabricatorSubscribableInterface )----------------------------------- */ public function isAutomaticallySubscribed($phid) { return ($phid == $this->getAuthorPHID()); } public function shouldShowSubscribersProperty() { return true; } public function shouldAllowSubscription($phid) { return true; } /* -( PhabricatorTokenReceiverInterface )---------------------------------- */ public function getUsersToNotifyOfTokenGiven() { return array($this->getAuthorPHID()); } } diff --git a/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php b/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php index f10760a8d..2d7361995 100644 --- a/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php +++ b/src/applications/slowvote/storage/PhabricatorSlowvoteTransaction.php @@ -1,153 +1,153 @@ getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: case PhabricatorSlowvoteTransaction::TYPE_CLOSE: return ($old === null); } return parent::shouldHide(); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorSlowvoteTransaction::TYPE_QUESTION: if ($old === null) { return pht( '%s created this poll.', $this->renderHandleLink($author_phid)); } else { return pht( '%s changed the poll question from "%s" to "%s".', $this->renderHandleLink($author_phid), $old, $new); } break; case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: return pht( '%s updated the description for this poll.', $this->renderHandleLink($author_phid)); case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: // TODO: This could be more detailed return pht( '%s changed who can see the responses.', $this->renderHandleLink($author_phid)); case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: if ($new) { return pht( '%s made poll responses appear in a random order.', $this->renderHandleLink($author_phid)); } else { return pht( '%s made poll responses appear in a fixed order.', $this->renderHandleLink($author_phid)); } break; case PhabricatorSlowvoteTransaction::TYPE_CLOSE: if ($new) { return pht( '%s closed this poll.', $this->renderHandleLink($author_phid)); } else { return pht( '%s reopened this poll.', $this->renderHandleLink($author_phid)); } break; } return parent::getTitle(); } public function getIcon() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorSlowvoteTransaction::TYPE_QUESTION: if ($old === null) { return 'fa-plus'; } else { return 'fa-pencil'; } case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: return 'fa-pencil'; case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: return 'fa-refresh'; case PhabricatorSlowvoteTransaction::TYPE_CLOSE: if ($new) { return 'fa-ban'; } else { return 'fa-pencil'; } } return parent::getIcon(); } public function getColor() { $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorSlowvoteTransaction::TYPE_QUESTION: case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: case PhabricatorSlowvoteTransaction::TYPE_RESPONSES: case PhabricatorSlowvoteTransaction::TYPE_SHUFFLE: case PhabricatorSlowvoteTransaction::TYPE_CLOSE: return PhabricatorTransactions::COLOR_BLUE; } return parent::getColor(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case PhabricatorSlowvoteTransaction::TYPE_DESCRIPTION: return true; } return parent::hasChangeDetails(); } public function renderChangeDetails(PhabricatorUser $viewer) { return $this->renderTextCorpusChangeDetails($viewer); } } diff --git a/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php b/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php index 10c8cbe47..acc8f5ebe 100644 --- a/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php +++ b/src/applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php @@ -1,139 +1,139 @@ phid = idx($data, 'phid'); $this->action = idx($data, 'action'); } public function processRequest() { $request = $this->getRequest(); if (!$request->isFormPost()) { return new Aphront400Response(); } switch ($this->action) { case 'add': $is_add = true; break; case 'delete': $is_add = false; break; default: return new Aphront400Response(); } $user = $request->getUser(); $phid = $this->phid; $handle = id(new PhabricatorHandleQuery()) ->setViewer($user) ->withPHIDs(array($phid)) ->executeOne(); - if (phid_get_type($phid) == PhabricatorProjectPHIDTypeProject::TYPECONST) { + if (phid_get_type($phid) == PhabricatorProjectProjectPHIDType::TYPECONST) { // TODO: This is a big hack, but a weak argument for adding some kind // of "load for role" feature to ObjectQuery, and also not a really great // argument for adding some kind of "load extra stuff" feature to // SubscriberInterface. Do this for now and wait for the best way forward // to become more clear? $object = id(new PhabricatorProjectQuery()) ->setViewer($user) ->withPHIDs(array($phid)) ->needWatchers(true) ->executeOne(); } else { $object = id(new PhabricatorObjectQuery()) ->setViewer($user) ->withPHIDs(array($phid)) ->executeOne(); } if (!($object instanceof PhabricatorSubscribableInterface)) { return $this->buildErrorResponse( pht('Bad Object'), pht('This object is not subscribable.'), $handle->getURI()); } if ($object->isAutomaticallySubscribed($user->getPHID())) { return $this->buildErrorResponse( pht('Automatically Subscribed'), pht('You are automatically subscribed to this object.'), $handle->getURI()); } if (!$object->shouldAllowSubscription($user->getPHID())) { return $this->buildErrorResponse( pht('You Can Not Subscribe'), pht('You can not subscribe to this object.'), $handle->getURI()); } if ($object instanceof PhabricatorApplicationTransactionInterface) { if ($is_add) { $xaction_value = array( '+' => array($user->getPHID()), ); } else { $xaction_value = array( '-' => array($user->getPHID()), ); } $xaction = id($object->getApplicationTransactionTemplate()) ->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS) ->setNewValue($xaction_value); $editor = id($object->getApplicationTransactionEditor()) ->setActor($user) ->setContinueOnNoEffect(true) ->setContentSourceFromRequest($request); $editor->applyTransactions( $object->getApplicationTransactionObject(), array($xaction)); } else { // TODO: Eventually, get rid of this once everything implements // PhabriatorApplicationTransactionInterface. $editor = id(new PhabricatorSubscriptionsEditor()) ->setActor($user) ->setObject($object); if ($is_add) { $editor->subscribeExplicit(array($user->getPHID()), $explicit = true); } else { $editor->unsubscribe(array($user->getPHID())); } $editor->save(); } // TODO: We should just render the "Unsubscribe" action and swap it out // in the document for Ajax requests. return id(new AphrontReloadResponse())->setURI($handle->getURI()); } private function buildErrorResponse($title, $message, $uri) { $request = $this->getRequest(); $user = $request->getUser(); $dialog = id(new AphrontDialogView()) ->setUser($user) ->setTitle($title) ->appendChild($message) ->addCancelButton($uri); return id(new AphrontDialogResponse())->setDialog($dialog); } } diff --git a/src/applications/tokens/phid/PhabricatorTokenPHIDTypeToken.php b/src/applications/tokens/phid/PhabricatorTokenTokenPHIDType.php similarity index 90% rename from src/applications/tokens/phid/PhabricatorTokenPHIDTypeToken.php rename to src/applications/tokens/phid/PhabricatorTokenTokenPHIDType.php index ee5e5375a..c458c52fb 100644 --- a/src/applications/tokens/phid/PhabricatorTokenPHIDTypeToken.php +++ b/src/applications/tokens/phid/PhabricatorTokenTokenPHIDType.php @@ -1,37 +1,37 @@ withPHIDs($phids); } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { foreach ($handles as $phid => $handle) { $token = $objects[$phid]; $name = $token->getName(); $handle->setName("{$name} Token"); } } } diff --git a/src/applications/tokens/query/PhabricatorTokenQuery.php b/src/applications/tokens/query/PhabricatorTokenQuery.php index 141ac18a0..8992e719f 100644 --- a/src/applications/tokens/query/PhabricatorTokenQuery.php +++ b/src/applications/tokens/query/PhabricatorTokenQuery.php @@ -1,69 +1,69 @@ phids = $phids; return $this; } protected function loadPage() { $tokens = $this->getBuiltinTokens(); if ($this->phids) { $map = array_fill_keys($this->phids, true); foreach ($tokens as $key => $token) { if (empty($map[$token->getPHID()])) { unset($tokens[$key]); } } } return $tokens; } private function getBuiltinTokens() { $specs = array( array('like-1', pht('Like')), array('like-2', pht('Dislike')), array('heart-1', pht('Love')), array('heart-2', pht('Heartbreak')), array('medal-1', pht('Orange Medal')), array('medal-2', pht('Grey Medal')), array('medal-3', pht('Yellow Medal')), array('medal-4', pht('Manufacturing Defect?')), array('coin-1', pht('Haypence')), array('coin-2', pht('Piece of Eight')), array('coin-3', pht('Doubloon')), array('coin-4', pht('Mountain of Wealth')), array('misc-1', pht('Pterodactyl')), array('misc-2', pht('Evil Spooky Haunted Tree')), array('misc-3', pht('Baby Tequila')), array('misc-4', pht('The World Burns')), ); - $type = PhabricatorTokenPHIDTypeToken::TYPECONST; + $type = PhabricatorTokenTokenPHIDType::TYPECONST; $tokens = array(); foreach ($specs as $id => $spec) { list($image, $name) = $spec; $token = id(new PhabricatorToken()) ->setID($id) ->setName($name) ->setPHID('PHID-'.$type.'-'.$image); $tokens[] = $token; } return $tokens; } public function getQueryApplicationClass() { return 'PhabricatorTokensApplication'; } } diff --git a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php index 1ed804c6f..685dcc6ea 100644 --- a/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php +++ b/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php @@ -1,2411 +1,2411 @@ actingAsPHID = $acting_as_phid; return $this; } public function getActingAsPHID() { if ($this->actingAsPHID) { return $this->actingAsPHID; } return $this->getActor()->getPHID(); } /** * When the editor tries to apply transactions that have no effect, should * it raise an exception (default) or drop them and continue? * * Generally, you will set this flag for edits coming from "Edit" interfaces, * and leave it cleared for edits coming from "Comment" interfaces, so the * user will get a useful error if they try to submit a comment that does * nothing (e.g., empty comment with a status change that has already been * performed by another user). * * @param bool True to drop transactions without effect and continue. * @return this */ public function setContinueOnNoEffect($continue) { $this->continueOnNoEffect = $continue; return $this; } public function getContinueOnNoEffect() { return $this->continueOnNoEffect; } /** * When the editor tries to apply transactions which don't populate all of * an object's required fields, should it raise an exception (default) or * drop them and continue? * * For example, if a user adds a new required custom field (like "Severity") * to a task, all existing tasks won't have it populated. When users * manually edit existing tasks, it's usually desirable to have them provide * a severity. However, other operations (like batch editing just the * owner of a task) will fail by default. * * By setting this flag for edit operations which apply to specific fields * (like the priority, batch, and merge editors in Maniphest), these * operations can continue to function even if an object is outdated. * * @param bool True to continue when transactions don't completely satisfy * all required fields. * @return this */ public function setContinueOnMissingFields($continue_on_missing_fields) { $this->continueOnMissingFields = $continue_on_missing_fields; return $this; } public function getContinueOnMissingFields() { return $this->continueOnMissingFields; } /** * Not strictly necessary, but reply handlers ideally set this value to * make email threading work better. */ public function setParentMessageID($parent_message_id) { $this->parentMessageID = $parent_message_id; return $this; } public function getParentMessageID() { return $this->parentMessageID; } public function getIsNewObject() { return $this->isNewObject; } protected function getMentionedPHIDs() { return $this->mentionedPHIDs; } public function setIsPreview($is_preview) { $this->isPreview = $is_preview; return $this; } public function getIsPreview() { return $this->isPreview; } public function setIsInverseEdgeEditor($is_inverse_edge_editor) { $this->isInverseEdgeEditor = $is_inverse_edge_editor; return $this; } public function getIsInverseEdgeEditor() { return $this->isInverseEdgeEditor; } public function setIsHeraldEditor($is_herald_editor) { $this->isHeraldEditor = $is_herald_editor; return $this; } public function getIsHeraldEditor() { return $this->isHeraldEditor; } /** * Prevent this editor from generating email when applying transactions. * * @param bool True to disable email. * @return this */ public function setDisableEmail($disable_email) { $this->disableEmail = $disable_email; return $this; } public function getDisableEmail() { return $this->disableEmail; } public function getTransactionTypes() { $types = array(); if ($this->object instanceof PhabricatorSubscribableInterface) { $types[] = PhabricatorTransactions::TYPE_SUBSCRIBERS; } if ($this->object instanceof PhabricatorCustomFieldInterface) { $types[] = PhabricatorTransactions::TYPE_CUSTOMFIELD; } if ($this->object instanceof HarbormasterBuildableInterface) { $types[] = PhabricatorTransactions::TYPE_BUILDABLE; } if ($this->object instanceof PhabricatorTokenReceiverInterface) { $types[] = PhabricatorTransactions::TYPE_TOKEN; } if ($this->object instanceof PhabricatorProjectInterface) { $types[] = PhabricatorTransactions::TYPE_EDGE; } return $types; } private function adjustTransactionValues( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { if ($xaction->shouldGenerateOldValue()) { $old = $this->getTransactionOldValue($object, $xaction); $xaction->setOldValue($old); } $new = $this->getTransactionNewValue($object, $xaction); $xaction->setNewValue($new); } private function getTransactionOldValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_SUBSCRIBERS: return array_values($this->subscribers); case PhabricatorTransactions::TYPE_VIEW_POLICY: return $object->getViewPolicy(); case PhabricatorTransactions::TYPE_EDIT_POLICY: return $object->getEditPolicy(); case PhabricatorTransactions::TYPE_JOIN_POLICY: return $object->getJoinPolicy(); case PhabricatorTransactions::TYPE_EDGE: $edge_type = $xaction->getMetadataValue('edge:type'); if (!$edge_type) { throw new Exception("Edge transaction has no 'edge:type'!"); } $old_edges = array(); if ($object->getPHID()) { $edge_src = $object->getPHID(); $old_edges = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs(array($edge_src)) ->withEdgeTypes(array($edge_type)) ->needEdgeData(true) ->execute(); $old_edges = $old_edges[$edge_src][$edge_type]; } return $old_edges; case PhabricatorTransactions::TYPE_CUSTOMFIELD: // NOTE: Custom fields have their old value pre-populated when they are // built by PhabricatorCustomFieldList. return $xaction->getOldValue(); case PhabricatorTransactions::TYPE_COMMENT: return null; default: return $this->getCustomTransactionOldValue($object, $xaction); } } private function getTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_SUBSCRIBERS: return $this->getPHIDTransactionNewValue($xaction); case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: case PhabricatorTransactions::TYPE_BUILDABLE: case PhabricatorTransactions::TYPE_TOKEN: return $xaction->getNewValue(); case PhabricatorTransactions::TYPE_EDGE: return $this->getEdgeTransactionNewValue($xaction); case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getCustomFieldForTransaction($object, $xaction); return $field->getNewValueFromApplicationTransactions($xaction); case PhabricatorTransactions::TYPE_COMMENT: return null; default: return $this->getCustomTransactionNewValue($object, $xaction); } } protected function getCustomTransactionOldValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { throw new Exception('Capability not supported!'); } protected function getCustomTransactionNewValue( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { throw new Exception('Capability not supported!'); } protected function transactionHasEffect( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return $xaction->hasComment(); case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getCustomFieldForTransaction($object, $xaction); return $field->getApplicationTransactionHasEffect($xaction); case PhabricatorTransactions::TYPE_EDGE: // A straight value comparison here doesn't always get the right // result, because newly added edges aren't fully populated. Instead, // compare the changes in a more granular way. $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); $old_dst = array_keys($old); $new_dst = array_keys($new); // NOTE: For now, we don't consider edge reordering to be a change. // We have very few order-dependent edges and effectively no order // oriented UI. This might change in the future. sort($old_dst); sort($new_dst); if ($old_dst !== $new_dst) { // We've added or removed edges, so this transaction definitely // has an effect. return true; } // We haven't added or removed edges, but we might have changed // edge data. foreach ($old as $key => $old_value) { $new_value = $new[$key]; if ($old_value['data'] !== $new_value['data']) { return true; } } return false; } return ($xaction->getOldValue() !== $xaction->getNewValue()); } protected function shouldApplyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { return false; } protected function applyInitialEffects( PhabricatorLiskDAO $object, array $xactions) { throw new PhutilMethodNotImplementedException(); } private function applyInternalEffects( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: case PhabricatorTransactions::TYPE_TOKEN: return; case PhabricatorTransactions::TYPE_VIEW_POLICY: $object->setViewPolicy($xaction->getNewValue()); break; case PhabricatorTransactions::TYPE_EDIT_POLICY: $object->setEditPolicy($xaction->getNewValue()); break; case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getCustomFieldForTransaction($object, $xaction); return $field->applyApplicationTransactionInternalEffects($xaction); } return $this->applyCustomInternalTransaction($object, $xaction); } private function applyExternalEffects( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: case PhabricatorTransactions::TYPE_TOKEN: return; case PhabricatorTransactions::TYPE_SUBSCRIBERS: $subeditor = id(new PhabricatorSubscriptionsEditor()) ->setObject($object) ->setActor($this->requireActor()); $old_map = array_fuse($xaction->getOldValue()); $new_map = array_fuse($xaction->getNewValue()); $subeditor->unsubscribe( array_keys( array_diff_key($old_map, $new_map))); $subeditor->subscribeExplicit( array_keys( array_diff_key($new_map, $old_map))); $subeditor->save(); // for the rest of these edits, subscribers should include those just // added as well as those just removed. $subscribers = array_unique(array_merge( $this->subscribers, $xaction->getOldValue(), $xaction->getNewValue())); $this->subscribers = $subscribers; break; case PhabricatorTransactions::TYPE_EDGE: if ($this->getIsInverseEdgeEditor()) { // If we're writing an inverse edge transaction, don't actually // do anything. The initiating editor on the other side of the // transaction will take care of the edge writes. break; } $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); $src = $object->getPHID(); $const = $xaction->getMetadataValue('edge:type'); $type = PhabricatorEdgeType::getByConstant($const); if ($type->shouldWriteInverseTransactions()) { $this->applyInverseEdgeTransactions( $object, $xaction, $type->getInverseEdgeConstant()); } foreach ($new as $dst_phid => $edge) { $new[$dst_phid]['src'] = $src; } $editor = new PhabricatorEdgeEditor(); foreach ($old as $dst_phid => $edge) { if (!empty($new[$dst_phid])) { if ($old[$dst_phid]['data'] === $new[$dst_phid]['data']) { continue; } } $editor->removeEdge($src, $const, $dst_phid); } foreach ($new as $dst_phid => $edge) { if (!empty($old[$dst_phid])) { if ($old[$dst_phid]['data'] === $new[$dst_phid]['data']) { continue; } } $data = array( 'data' => $edge['data'], ); $editor->addEdge($src, $const, $dst_phid, $data); } $editor->save(); break; case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getCustomFieldForTransaction($object, $xaction); return $field->applyApplicationTransactionExternalEffects($xaction); } return $this->applyCustomExternalTransaction($object, $xaction); } protected function applyCustomInternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $type = $xaction->getTransactionType(); throw new Exception( "Transaction type '{$type}' is missing an internal apply ". "implementation!"); } protected function applyCustomExternalTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $type = $xaction->getTransactionType(); throw new Exception( "Transaction type '{$type}' is missing an external apply ". "implementation!"); } /** * Fill in a transaction's common values, like author and content source. */ protected function populateTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $actor = $this->getActor(); // TODO: This needs to be more sophisticated once we have meta-policies. $xaction->setViewPolicy(PhabricatorPolicies::POLICY_PUBLIC); if ($actor->isOmnipotent()) { $xaction->setEditPolicy(PhabricatorPolicies::POLICY_NOONE); } else { $xaction->setEditPolicy($actor->getPHID()); } $xaction->setAuthorPHID($this->getActingAsPHID()); $xaction->setContentSource($this->getContentSource()); $xaction->attachViewer($actor); $xaction->attachObject($object); if ($object->getPHID()) { $xaction->setObjectPHID($object->getPHID()); } return $xaction; } protected function applyFinalEffects( PhabricatorLiskDAO $object, array $xactions) { return $xactions; } public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source; return $this; } public function setContentSourceFromRequest(AphrontRequest $request) { return $this->setContentSource( PhabricatorContentSource::newFromRequest($request)); } public function setContentSourceFromConduitRequest( ConduitAPIRequest $request) { $content_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_CONDUIT, array()); return $this->setContentSource($content_source); } public function getContentSource() { return $this->contentSource; } final public function applyTransactions( PhabricatorLiskDAO $object, array $xactions) { $this->object = $object; $this->xactions = $xactions; $this->isNewObject = ($object->getPHID() === null); $this->validateEditParameters($object, $xactions); $actor = $this->requireActor(); // NOTE: Some transaction expansion requires that the edited object be // attached. foreach ($xactions as $xaction) { $xaction->attachObject($object); $xaction->attachViewer($actor); } $xactions = $this->expandTransactions($object, $xactions); $xactions = $this->expandSupportTransactions($object, $xactions); $xactions = $this->combineTransactions($xactions); foreach ($xactions as $xaction) { $xaction = $this->populateTransaction($object, $xaction); } $is_preview = $this->getIsPreview(); $read_locking = false; $transaction_open = false; if (!$is_preview) { $errors = array(); $type_map = mgroup($xactions, 'getTransactionType'); foreach ($this->getTransactionTypes() as $type) { $type_xactions = idx($type_map, $type, array()); $errors[] = $this->validateTransaction($object, $type, $type_xactions); } $errors = array_mergev($errors); $continue_on_missing = $this->getContinueOnMissingFields(); foreach ($errors as $key => $error) { if ($continue_on_missing && $error->getIsMissingFieldError()) { unset($errors[$key]); } } if ($errors) { throw new PhabricatorApplicationTransactionValidationException($errors); } $file_phids = $this->extractFilePHIDs($object, $xactions); if ($object->getID()) { foreach ($xactions as $xaction) { // If any of the transactions require a read lock, hold one and // reload the object. We need to do this fairly early so that the // call to `adjustTransactionValues()` (which populates old values) // is based on the synchronized state of the object, which may differ // from the state when it was originally loaded. if ($this->shouldReadLock($object, $xaction)) { $object->openTransaction(); $object->beginReadLocking(); $transaction_open = true; $read_locking = true; $object->reload(); break; } } } if ($this->shouldApplyInitialEffects($object, $xactions)) { if (!$transaction_open) { $object->openTransaction(); $transaction_open = true; } } } if ($this->shouldApplyInitialEffects($object, $xactions)) { $this->applyInitialEffects($object, $xactions); } foreach ($xactions as $xaction) { $this->adjustTransactionValues($object, $xaction); } $xactions = $this->filterTransactions($object, $xactions); if (!$xactions) { if ($read_locking) { $object->endReadLocking(); $read_locking = false; } if ($transaction_open) { $object->killTransaction(); $transaction_open = false; } return array(); } // Now that we've merged, filtered, and combined transactions, check for // required capabilities. foreach ($xactions as $xaction) { $this->requireCapabilities($object, $xaction); } $xactions = $this->sortTransactions($xactions); if ($is_preview) { $this->loadHandles($xactions); return $xactions; } $comment_editor = id(new PhabricatorApplicationTransactionCommentEditor()) ->setActor($actor) ->setContentSource($this->getContentSource()); if (!$transaction_open) { $object->openTransaction(); } foreach ($xactions as $xaction) { $this->applyInternalEffects($object, $xaction); } $object->save(); foreach ($xactions as $xaction) { $xaction->setObjectPHID($object->getPHID()); if ($xaction->getComment()) { $xaction->setPHID($xaction->generatePHID()); $comment_editor->applyEdit($xaction, $xaction->getComment()); } else { $xaction->save(); } } if ($file_phids) { $this->attachFiles($object, $file_phids); } foreach ($xactions as $xaction) { $this->applyExternalEffects($object, $xaction); } $xactions = $this->applyFinalEffects($object, $xactions); if ($read_locking) { $object->endReadLocking(); $read_locking = false; } $object->saveTransaction(); // Now that we've completely applied the core transaction set, try to apply // Herald rules. Herald rules are allowed to either take direct actions on // the database (like writing flags), or take indirect actions (like saving // some targets for CC when we generate mail a little later), or return // transactions which we'll apply normally using another Editor. // First, check if *this* is a sub-editor which is itself applying Herald // rules: if it is, stop working and return so we don't descend into // madness. // Otherwise, we're not a Herald editor, so process Herald rules (possibly // using a Herald editor to apply resulting transactions) and then send out // mail, notifications, and feed updates about everything. if ($this->getIsHeraldEditor()) { // We are the Herald editor, so stop work here and return the updated // transactions. return $xactions; } else if ($this->shouldApplyHeraldRules($object, $xactions)) { // We are not the Herald editor, so try to apply Herald rules. $herald_xactions = $this->applyHeraldRules($object, $xactions); if ($herald_xactions) { $xscript_id = $this->getHeraldTranscript()->getID(); foreach ($herald_xactions as $herald_xaction) { $herald_xaction->setMetadataValue('herald:transcriptID', $xscript_id); } // NOTE: We're acting as the omnipotent user because rules deal with // their own policy issues. We use a synthetic author PHID (the // Herald application) as the author of record, so that transactions // will render in a reasonable way ("Herald assigned this task ..."). $herald_actor = PhabricatorUser::getOmnipotentUser(); $herald_phid = id(new PhabricatorHeraldApplication())->getPHID(); // TODO: It would be nice to give transactions a more specific source // which points at the rule which generated them. You can figure this // out from transcripts, but it would be cleaner if you didn't have to. $herald_source = PhabricatorContentSource::newForSource( PhabricatorContentSource::SOURCE_HERALD, array()); $herald_editor = newv(get_class($this), array()) ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->setParentMessageID($this->getParentMessageID()) ->setIsHeraldEditor(true) ->setActor($herald_actor) ->setActingAsPHID($herald_phid) ->setContentSource($herald_source); $herald_xactions = $herald_editor->applyTransactions( $object, $herald_xactions); // Merge the new transactions into the transaction list: we want to // send email and publish feed stories about them, too. $xactions = array_merge($xactions, $herald_xactions); } } // Before sending mail or publishing feed stories, reload the object // subscribers to pick up changes caused by Herald (or by other side effects // in various transaction phases). $this->loadSubscribers($object); $this->loadHandles($xactions); $mail = null; if (!$this->getDisableEmail()) { if ($this->shouldSendMail($object, $xactions)) { $mail = $this->sendMail($object, $xactions); } } if ($this->supportsSearch()) { id(new PhabricatorSearchIndexer()) ->queueDocumentForIndexing($object->getPHID()); } if ($this->shouldPublishFeedStory($object, $xactions)) { $mailed = array(); if ($mail) { $mailed = $mail->buildRecipientList(); } $this->publishFeedStory( $object, $xactions, $mailed); } $this->didApplyTransactions($xactions); if ($object instanceof PhabricatorCustomFieldInterface) { // Maybe this makes more sense to move into the search index itself? For // now I'm putting it here since I think we might end up with things that // need it to be up to date once the next page loads, but if we don't go // there we we could move it into search once search moves to the daemons. // It now happens in the search indexer as well, but the search indexer is // always daemonized, so the logic above still potentially holds. We could // possibly get rid of this. The major motivation for putting it in the // indexer was to enable reindexing to work. $fields = PhabricatorCustomField::getObjectFields( $object, PhabricatorCustomField::ROLE_APPLICATIONSEARCH); $fields->readFieldsFromStorage($object); $fields->rebuildIndexes($object); } return $xactions; } protected function didApplyTransactions(array $xactions) { // Hook for subclasses. return; } /** * Determine if the editor should hold a read lock on the object while * applying a transaction. * * If the editor does not hold a lock, two editors may read an object at the * same time, then apply their changes without any synchronization. For most * transactions, this does not matter much. However, it is important for some * transactions. For example, if an object has a transaction count on it, both * editors may read the object with `count = 23`, then independently update it * and save the object with `count = 24` twice. This will produce the wrong * state: the object really has 25 transactions, but the count is only 24. * * Generally, transactions fall into one of four buckets: * * - Append operations: Actions like adding a comment to an object purely * add information to its state, and do not depend on the current object * state in any way. These transactions never need to hold locks. * - Overwrite operations: Actions like changing the title or description * of an object replace the current value with a new value, so the end * state is consistent without a lock. We currently do not lock these * transactions, although we may in the future. * - Edge operations: Edge and subscription operations have internal * synchronization which limits the damage race conditions can cause. * We do not currently lock these transactions, although we may in the * future. * - Update operations: Actions like incrementing a count on an object. * These operations generally should use locks, unless it is not * important that the state remain consistent in the presence of races. * * @param PhabricatorLiskDAO Object being updated. * @param PhabricatorApplicationTransaction Transaction being applied. * @return bool True to synchronize the edit with a lock. */ protected function shouldReadLock( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { return false; } private function loadHandles(array $xactions) { $phids = array(); foreach ($xactions as $key => $xaction) { $phids[$key] = $xaction->getRequiredHandlePHIDs(); } $handles = array(); $merged = array_mergev($phids); if ($merged) { $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireActor()) ->withPHIDs($merged) ->execute(); } foreach ($xactions as $key => $xaction) { $xaction->setHandles(array_select_keys($handles, $phids[$key])); } } private function loadSubscribers(PhabricatorLiskDAO $object) { if ($object->getPHID() && ($object instanceof PhabricatorSubscribableInterface)) { $subs = PhabricatorSubscribersQuery::loadSubscribersForPHID( $object->getPHID()); $this->subscribers = array_fuse($subs); } else { $this->subscribers = array(); } } private function validateEditParameters( PhabricatorLiskDAO $object, array $xactions) { if (!$this->getContentSource()) { throw new Exception( 'Call setContentSource() before applyTransactions()!'); } // Do a bunch of sanity checks that the incoming transactions are fresh. // They should be unsaved and have only "transactionType" and "newValue" // set. $types = array_fill_keys($this->getTransactionTypes(), true); assert_instances_of($xactions, 'PhabricatorApplicationTransaction'); foreach ($xactions as $xaction) { if ($xaction->getPHID() || $xaction->getID()) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'You can not apply transactions which already have IDs/PHIDs!')); } if ($xaction->getObjectPHID()) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'You can not apply transactions which already have objectPHIDs!')); } if ($xaction->getAuthorPHID()) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'You can not apply transactions which already have authorPHIDs!')); } if ($xaction->getCommentPHID()) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'You can not apply transactions which already have '. 'commentPHIDs!')); } if ($xaction->getCommentVersion() !== 0) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'You can not apply transactions which already have '. 'commentVersions!')); } $expect_value = !$xaction->shouldGenerateOldValue(); $has_value = $xaction->hasOldValue(); if ($expect_value && !$has_value) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'This transaction is supposed to have an oldValue set, but '. 'it does not!')); } if ($has_value && !$expect_value) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'This transaction should generate its oldValue automatically, '. 'but has already had one set!')); } $type = $xaction->getTransactionType(); if (empty($types[$type])) { throw new PhabricatorApplicationTransactionStructureException( $xaction, pht( 'Transaction has type "%s", but that transaction type is not '. 'supported by this editor (%s).', $type, get_class($this))); } } } protected function requireCapabilities( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { if ($this->getIsNewObject()) { return; } $actor = $this->requireActor(); switch ($xaction->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: PhabricatorPolicyFilter::requireCapability( $actor, $object, PhabricatorPolicyCapability::CAN_VIEW); break; case PhabricatorTransactions::TYPE_VIEW_POLICY: PhabricatorPolicyFilter::requireCapability( $actor, $object, PhabricatorPolicyCapability::CAN_EDIT); break; case PhabricatorTransactions::TYPE_EDIT_POLICY: PhabricatorPolicyFilter::requireCapability( $actor, $object, PhabricatorPolicyCapability::CAN_EDIT); break; case PhabricatorTransactions::TYPE_JOIN_POLICY: PhabricatorPolicyFilter::requireCapability( $actor, $object, PhabricatorPolicyCapability::CAN_EDIT); break; } } private function buildMentionTransaction( PhabricatorLiskDAO $object, array $xactions, array $blocks) { if (!($object instanceof PhabricatorSubscribableInterface)) { return null; } $texts = array_mergev($blocks); $phids = PhabricatorMarkupEngine::extractPHIDsFromMentions( $this->getActor(), $texts); $this->mentionedPHIDs = $phids; if ($object->getPHID()) { // Don't try to subscribe already-subscribed mentions: we want to generate // a dialog about an action having no effect if the user explicitly adds // existing CCs, but not if they merely mention existing subscribers. $phids = array_diff($phids, $this->subscribers); } foreach ($phids as $key => $phid) { if ($object->isAutomaticallySubscribed($phid)) { unset($phids[$key]); } } $phids = array_values($phids); if (!$phids) { return null; } $xaction = newv(get_class(head($xactions)), array()); $xaction->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS); $xaction->setNewValue(array('+' => $phids)); return $xaction; } protected function getRemarkupBlocksFromTransaction( PhabricatorApplicationTransaction $transaction) { return $transaction->getRemarkupBlocks(); } protected function mergeTransactions( PhabricatorApplicationTransaction $u, PhabricatorApplicationTransaction $v) { $type = $u->getTransactionType(); switch ($type) { case PhabricatorTransactions::TYPE_SUBSCRIBERS: return $this->mergePHIDOrEdgeTransactions($u, $v); case PhabricatorTransactions::TYPE_EDGE: $u_type = $u->getMetadataValue('edge:type'); $v_type = $v->getMetadataValue('edge:type'); if ($u_type == $v_type) { return $this->mergePHIDOrEdgeTransactions($u, $v); } return null; } // By default, do not merge the transactions. return null; } /** * Optionally expand transactions which imply other effects. For example, * resigning from a revision in Differential implies removing yourself as * a reviewer. */ private function expandTransactions( PhabricatorLiskDAO $object, array $xactions) { $results = array(); foreach ($xactions as $xaction) { foreach ($this->expandTransaction($object, $xaction) as $expanded) { $results[] = $expanded; } } return $results; } protected function expandTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { return array($xaction); } private function expandSupportTransactions( PhabricatorLiskDAO $object, array $xactions) { $this->loadSubscribers($object); $xactions = $this->applyImplicitCC($object, $xactions); $blocks = array(); foreach ($xactions as $key => $xaction) { $blocks[$key] = $this->getRemarkupBlocksFromTransaction($xaction); } $mention_xaction = $this->buildMentionTransaction( $object, $xactions, $blocks); if ($mention_xaction) { $xactions[] = $mention_xaction; } // TODO: For now, this is just a placeholder. $engine = PhabricatorMarkupEngine::getEngine('extract'); $engine->setConfig('viewer', $this->requireActor()); $block_xactions = $this->expandRemarkupBlockTransactions( $object, $xactions, $blocks, $engine); foreach ($block_xactions as $xaction) { $xactions[] = $xaction; } return $xactions; } private function expandRemarkupBlockTransactions( PhabricatorLiskDAO $object, array $xactions, $blocks, PhutilMarkupEngine $engine) { $block_xactions = $this->expandCustomRemarkupBlockTransactions( $object, $xactions, $blocks, $engine); if ($object instanceof PhabricatorProjectInterface) { $phids = array(); foreach ($blocks as $key => $xaction_blocks) { foreach ($xaction_blocks as $block) { $engine->markupText($block); $phids += $engine->getTextMetadata( PhabricatorRemarkupRuleObject::KEY_MENTIONED_OBJECTS, array()); } } - $project_type = PhabricatorProjectPHIDTypeProject::TYPECONST; + $project_type = PhabricatorProjectProjectPHIDType::TYPECONST; foreach ($phids as $key => $phid) { if (phid_get_type($phid) != $project_type) { unset($phids[$key]); } } if ($phids) { $edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; $block_xactions[] = newv(get_class(head($xactions)), array()) ->setIgnoreOnNoEffect(true) ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) ->setMetadataValue('edge:type', $edge_type) ->setNewValue(array('+' => $phids)); } } return $block_xactions; } protected function expandCustomRemarkupBlockTransactions( PhabricatorLiskDAO $object, array $xactions, $blocks, PhutilMarkupEngine $engine) { return array(); } /** * Attempt to combine similar transactions into a smaller number of total * transactions. For example, two transactions which edit the title of an * object can be merged into a single edit. */ private function combineTransactions(array $xactions) { $stray_comments = array(); $result = array(); $types = array(); foreach ($xactions as $key => $xaction) { $type = $xaction->getTransactionType(); if (isset($types[$type])) { foreach ($types[$type] as $other_key) { $merged = $this->mergeTransactions($result[$other_key], $xaction); if ($merged) { $result[$other_key] = $merged; if ($xaction->getComment() && ($xaction->getComment() !== $merged->getComment())) { $stray_comments[] = $xaction->getComment(); } if ($result[$other_key]->getComment() && ($result[$other_key]->getComment() !== $merged->getComment())) { $stray_comments[] = $result[$other_key]->getComment(); } // Move on to the next transaction. continue 2; } } } $result[$key] = $xaction; $types[$type][] = $key; } // If we merged any comments away, restore them. foreach ($stray_comments as $comment) { $xaction = newv(get_class(head($result)), array()); $xaction->setTransactionType(PhabricatorTransactions::TYPE_COMMENT); $xaction->setComment($comment); $result[] = $xaction; } return array_values($result); } protected function mergePHIDOrEdgeTransactions( PhabricatorApplicationTransaction $u, PhabricatorApplicationTransaction $v) { $result = $u->getNewValue(); foreach ($v->getNewValue() as $key => $value) { if ($u->getTransactionType() == PhabricatorTransactions::TYPE_EDGE) { if (empty($result[$key])) { $result[$key] = $value; } else { // We're merging two lists of edge adds, sets, or removes. Merge // them by merging individual PHIDs within them. $merged = $result[$key]; foreach ($value as $dst => $v_spec) { if (empty($merged[$dst])) { $merged[$dst] = $v_spec; } else { // Two transactions are trying to perform the same operation on // the same edge. Normalize the edge data and then merge it. This // allows transactions to specify how data merges execute in a // precise way. $u_spec = $merged[$dst]; if (!is_array($u_spec)) { $u_spec = array('dst' => $u_spec); } if (!is_array($v_spec)) { $v_spec = array('dst' => $v_spec); } $ux_data = idx($u_spec, 'data', array()); $vx_data = idx($v_spec, 'data', array()); $merged_data = $this->mergeEdgeData( $u->getMetadataValue('edge:type'), $ux_data, $vx_data); $u_spec['data'] = $merged_data; $merged[$dst] = $u_spec; } } $result[$key] = $merged; } } else { $result[$key] = array_merge($value, idx($result, $key, array())); } } $u->setNewValue($result); // When combining an "ignore" transaction with a normal transaction, make // sure we don't propagate the "ignore" flag. if (!$v->getIgnoreOnNoEffect()) { $u->setIgnoreOnNoEffect(false); } return $u; } protected function mergeEdgeData($type, array $u, array $v) { return $v + $u; } protected function getPHIDTransactionNewValue( PhabricatorApplicationTransaction $xaction) { $old = array_fuse($xaction->getOldValue()); $new = $xaction->getNewValue(); $new_add = idx($new, '+', array()); unset($new['+']); $new_rem = idx($new, '-', array()); unset($new['-']); $new_set = idx($new, '=', null); if ($new_set !== null) { $new_set = array_fuse($new_set); } unset($new['=']); if ($new) { throw new Exception( "Invalid 'new' value for PHID transaction. Value should contain only ". "keys '+' (add PHIDs), '-' (remove PHIDs) and '=' (set PHIDS)."); } $result = array(); foreach ($old as $phid) { if ($new_set !== null && empty($new_set[$phid])) { continue; } $result[$phid] = $phid; } if ($new_set !== null) { foreach ($new_set as $phid) { $result[$phid] = $phid; } } foreach ($new_add as $phid) { $result[$phid] = $phid; } foreach ($new_rem as $phid) { unset($result[$phid]); } return array_values($result); } protected function getEdgeTransactionNewValue( PhabricatorApplicationTransaction $xaction) { $new = $xaction->getNewValue(); $new_add = idx($new, '+', array()); unset($new['+']); $new_rem = idx($new, '-', array()); unset($new['-']); $new_set = idx($new, '=', null); unset($new['=']); if ($new) { throw new Exception( "Invalid 'new' value for Edge transaction. Value should contain only ". "keys '+' (add edges), '-' (remove edges) and '=' (set edges)."); } $old = $xaction->getOldValue(); $lists = array($new_set, $new_add, $new_rem); foreach ($lists as $list) { $this->checkEdgeList($list); } $result = array(); foreach ($old as $dst_phid => $edge) { if ($new_set !== null && empty($new_set[$dst_phid])) { continue; } $result[$dst_phid] = $this->normalizeEdgeTransactionValue( $xaction, $edge, $dst_phid); } if ($new_set !== null) { foreach ($new_set as $dst_phid => $edge) { $result[$dst_phid] = $this->normalizeEdgeTransactionValue( $xaction, $edge, $dst_phid); } } foreach ($new_add as $dst_phid => $edge) { $result[$dst_phid] = $this->normalizeEdgeTransactionValue( $xaction, $edge, $dst_phid); } foreach ($new_rem as $dst_phid => $edge) { unset($result[$dst_phid]); } return $result; } private function checkEdgeList($list) { if (!$list) { return; } foreach ($list as $key => $item) { if (phid_get_type($key) === PhabricatorPHIDConstants::PHID_TYPE_UNKNOWN) { throw new Exception( "Edge transactions must have destination PHIDs as in edge ". "lists (found key '{$key}')."); } if (!is_array($item) && $item !== $key) { throw new Exception( "Edge transactions must have PHIDs or edge specs as values ". "(found value '{$item}')."); } } } private function normalizeEdgeTransactionValue( PhabricatorApplicationTransaction $xaction, $edge, $dst_phid) { if (!is_array($edge)) { if ($edge != $dst_phid) { throw new Exception( pht( 'Transaction edge data must either be the edge PHID or an edge '. 'specification dictionary.')); } $edge = array(); } else { foreach ($edge as $key => $value) { switch ($key) { case 'src': case 'dst': case 'type': case 'data': case 'dateCreated': case 'dateModified': case 'seq': case 'dataID': break; default: throw new Exception( pht( 'Transaction edge specification contains unexpected key '. '"%s".', $key)); } } } $edge['dst'] = $dst_phid; $edge_type = $xaction->getMetadataValue('edge:type'); if (empty($edge['type'])) { $edge['type'] = $edge_type; } else { if ($edge['type'] != $edge_type) { $this_type = $edge['type']; throw new Exception( "Edge transaction includes edge of type '{$this_type}', but ". "transaction is of type '{$edge_type}'. Each edge transaction must ". "alter edges of only one type."); } } if (!isset($edge['data'])) { $edge['data'] = array(); } return $edge; } protected function sortTransactions(array $xactions) { $head = array(); $tail = array(); // Move bare comments to the end, so the actions precede them. foreach ($xactions as $xaction) { $type = $xaction->getTransactionType(); if ($type == PhabricatorTransactions::TYPE_COMMENT) { $tail[] = $xaction; } else { $head[] = $xaction; } } return array_values(array_merge($head, $tail)); } protected function filterTransactions( PhabricatorLiskDAO $object, array $xactions) { $type_comment = PhabricatorTransactions::TYPE_COMMENT; $no_effect = array(); $has_comment = false; $any_effect = false; foreach ($xactions as $key => $xaction) { if ($this->transactionHasEffect($object, $xaction)) { if ($xaction->getTransactionType() != $type_comment) { $any_effect = true; } } else if ($xaction->getIgnoreOnNoEffect()) { unset($xactions[$key]); } else { $no_effect[$key] = $xaction; } if ($xaction->hasComment()) { $has_comment = true; } } if (!$no_effect) { return $xactions; } if (!$this->getContinueOnNoEffect() && !$this->getIsPreview()) { throw new PhabricatorApplicationTransactionNoEffectException( $no_effect, $any_effect, $has_comment); } if (!$any_effect && !$has_comment) { // If we only have empty comment transactions, just drop them all. return array(); } foreach ($no_effect as $key => $xaction) { if ($xaction->getComment()) { $xaction->setTransactionType($type_comment); $xaction->setOldValue(null); $xaction->setNewValue(null); } else { unset($xactions[$key]); } } return $xactions; } /** * Hook for validating transactions. This callback will be invoked for each * available transaction type, even if an edit does not apply any transactions * of that type. This allows you to raise exceptions when required fields are * missing, by detecting that the object has no field value and there is no * transaction which sets one. * * @param PhabricatorLiskDAO Object being edited. * @param string Transaction type to validate. * @param list Transactions of given type, * which may be empty if the edit does not apply any transactions of the * given type. * @return list List of * validation errors. */ protected function validateTransaction( PhabricatorLiskDAO $object, $type, array $xactions) { $errors = array(); switch ($type) { case PhabricatorTransactions::TYPE_VIEW_POLICY: $errors[] = $this->validatePolicyTransaction( $object, $xactions, $type, PhabricatorPolicyCapability::CAN_VIEW); break; case PhabricatorTransactions::TYPE_EDIT_POLICY: $errors[] = $this->validatePolicyTransaction( $object, $xactions, $type, PhabricatorPolicyCapability::CAN_EDIT); break; case PhabricatorTransactions::TYPE_CUSTOMFIELD: $groups = array(); foreach ($xactions as $xaction) { $groups[$xaction->getMetadataValue('customfield:key')][] = $xaction; } $field_list = PhabricatorCustomField::getObjectFields( $object, PhabricatorCustomField::ROLE_EDIT); $field_list->setViewer($this->getActor()); $role_xactions = PhabricatorCustomField::ROLE_APPLICATIONTRANSACTIONS; foreach ($field_list->getFields() as $field) { if (!$field->shouldEnableForRole($role_xactions)) { continue; } $errors[] = $field->validateApplicationTransactions( $this, $type, idx($groups, $field->getFieldKey(), array())); } break; } return array_mergev($errors); } private function validatePolicyTransaction( PhabricatorLiskDAO $object, array $xactions, $transaction_type, $capability) { $actor = $this->requireActor(); $errors = array(); // Note $this->xactions is necessary; $xactions is $this->xactions of // $transaction_type $policy_object = $this->adjustObjectForPolicyChecks( $object, $this->xactions); // Make sure the user isn't editing away their ability to $capability this // object. foreach ($xactions as $xaction) { try { PhabricatorPolicyFilter::requireCapabilityWithForcedPolicy( $actor, $policy_object, $capability, $xaction->getNewValue()); } catch (PhabricatorPolicyException $ex) { $errors[] = new PhabricatorApplicationTransactionValidationError( $transaction_type, pht('Invalid'), pht( 'You can not select this %s policy, because you would no longer '. 'be able to %s the object.', $capability, $capability), $xaction); } } if ($this->getIsNewObject()) { if (!$xactions) { $has_capability = PhabricatorPolicyFilter::hasCapability( $actor, $policy_object, $capability); if (!$has_capability) { $errors[] = new PhabricatorApplicationTransactionValidationError( $transaction_type, pht('Invalid'), pht('The selected %s policy excludes you. Choose a %s policy '. 'which allows you to %s the object.', $capability, $capability, $capability)); } } } return $errors; } protected function adjustObjectForPolicyChecks( PhabricatorLiskDAO $object, array $xactions) { return clone $object; } /** * Check for a missing text field. * * A text field is missing if the object has no value and there are no * transactions which set a value, or if the transactions remove the value. * This method is intended to make implementing @{method:validateTransaction} * more convenient: * * $missing = $this->validateIsEmptyTextField( * $object->getName(), * $xactions); * * This will return `true` if the net effect of the object and transactions * is an empty field. * * @param wild Current field value. * @param list Transactions editing the * field. * @return bool True if the field will be an empty text field after edits. */ protected function validateIsEmptyTextField($field_value, array $xactions) { if (strlen($field_value) && empty($xactions)) { return false; } if ($xactions && strlen(last($xactions)->getNewValue())) { return false; } return true; } /* -( Implicit CCs )------------------------------------------------------- */ /** * When a user interacts with an object, we might want to add them to CC. */ final public function applyImplicitCC( PhabricatorLiskDAO $object, array $xactions) { if (!($object instanceof PhabricatorSubscribableInterface)) { // If the object isn't subscribable, we can't CC them. return $xactions; } $actor_phid = $this->requireActor()->getPHID(); if ($object->isAutomaticallySubscribed($actor_phid)) { // If they're auto-subscribed, don't CC them. return $xactions; } $should_cc = false; foreach ($xactions as $xaction) { if ($this->shouldImplyCC($object, $xaction)) { $should_cc = true; break; } } if (!$should_cc) { // Only some types of actions imply a CC (like adding a comment). return $xactions; } if ($object->getPHID()) { if (isset($this->subscribers[$actor_phid])) { // If the user is already subscribed, don't implicitly CC them. return $xactions; } $unsub = PhabricatorEdgeQuery::loadDestinationPHIDs( $object->getPHID(), PhabricatorEdgeConfig::TYPE_OBJECT_HAS_UNSUBSCRIBER); $unsub = array_fuse($unsub); if (isset($unsub[$actor_phid])) { // If the user has previously unsubscribed from this object explicitly, // don't implicitly CC them. return $xactions; } } $xaction = newv(get_class(head($xactions)), array()); $xaction->setTransactionType(PhabricatorTransactions::TYPE_SUBSCRIBERS); $xaction->setNewValue(array('+' => array($actor_phid))); array_unshift($xactions, $xaction); return $xactions; } protected function shouldImplyCC( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { return $xaction->isCommentTransaction(); } /* -( Sending Mail )------------------------------------------------------- */ /** * @task mail */ protected function shouldSendMail( PhabricatorLiskDAO $object, array $xactions) { return false; } /** * @task mail */ protected function sendMail( PhabricatorLiskDAO $object, array $xactions) { // Check if any of the transactions are visible. If we don't have any // visible transactions, don't send the mail. $any_visible = false; foreach ($xactions as $xaction) { if (!$xaction->shouldHideForMail($xactions)) { $any_visible = true; break; } } if (!$any_visible) { return; } $email_to = array_filter(array_unique($this->getMailTo($object))); $email_cc = array_filter(array_unique($this->getMailCC($object))); $phids = array_merge($email_to, $email_cc); $handles = id(new PhabricatorHandleQuery()) ->setViewer($this->requireActor()) ->withPHIDs($phids) ->execute(); $template = $this->buildMailTemplate($object); $body = $this->buildMailBody($object, $xactions); $mail_tags = $this->getMailTags($object, $xactions); $action = $this->getMailAction($object, $xactions); $reply_handler = $this->buildReplyHandler($object); $reply_section = $reply_handler->getReplyHandlerInstructions(); if ($reply_section !== null) { $body->addReplySection($reply_section); } $template ->setFrom($this->requireActor()->getPHID()) ->setSubjectPrefix($this->getMailSubjectPrefix()) ->setVarySubjectPrefix('['.$action.']') ->setThreadID($this->getMailThreadID($object), $this->getIsNewObject()) ->setRelatedPHID($object->getPHID()) ->setExcludeMailRecipientPHIDs($this->getExcludeMailRecipientPHIDs()) ->setMailTags($mail_tags) ->setIsBulk(true) ->setBody($body->render()); foreach ($body->getAttachments() as $attachment) { $template->addAttachment($attachment); } $herald_xscript = $this->getHeraldTranscript(); if ($herald_xscript) { $herald_header = $herald_xscript->getXHeraldRulesHeader(); $herald_header = HeraldTranscript::saveXHeraldRulesHeader( $object->getPHID(), $herald_header); } else { $herald_header = HeraldTranscript::loadXHeraldRulesHeader( $object->getPHID()); } if ($herald_header) { $template->addHeader('X-Herald-Rules', $herald_header); } if ($this->getParentMessageID()) { $template->setParentMessageID($this->getParentMessageID()); } $mails = $reply_handler->multiplexMail( $template, array_select_keys($handles, $email_to), array_select_keys($handles, $email_cc)); foreach ($mails as $mail) { $mail->saveAndSend(); } $template->addTos($email_to); $template->addCCs($email_cc); return $template; } protected function getMailThreadID(PhabricatorLiskDAO $object) { return $object->getPHID(); } /** * @task mail */ protected function getStrongestAction( PhabricatorLiskDAO $object, array $xactions) { return last(msort($xactions, 'getActionStrength')); } /** * @task mail */ protected function buildReplyHandler(PhabricatorLiskDAO $object) { throw new Exception('Capability not supported.'); } /** * @task mail */ protected function getMailSubjectPrefix() { throw new Exception('Capability not supported.'); } /** * @task mail */ protected function getMailTags( PhabricatorLiskDAO $object, array $xactions) { $tags = array(); foreach ($xactions as $xaction) { $tags[] = $xaction->getMailTags(); } return array_mergev($tags); } /** * @task mail */ protected function getMailAction( PhabricatorLiskDAO $object, array $xactions) { return $this->getStrongestAction($object, $xactions)->getActionName(); } /** * @task mail */ protected function buildMailTemplate(PhabricatorLiskDAO $object) { throw new Exception('Capability not supported.'); } /** * @task mail */ protected function getMailTo(PhabricatorLiskDAO $object) { throw new Exception('Capability not supported.'); } /** * @task mail */ protected function getMailCC(PhabricatorLiskDAO $object) { $phids = array(); $has_support = false; if ($object instanceof PhabricatorSubscribableInterface) { $phids[] = $this->subscribers; $has_support = true; } // TODO: The Maniphest legacy stuff should get cleaned up here. if (($object instanceof ManiphestTask) || ($object instanceof PhabricatorProjectInterface)) { if ($object instanceof PhabricatorProjectInterface) { $project_phids = PhabricatorEdgeQuery::loadDestinationPHIDs( $object->getPHID(), PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); } else { $project_phids = $object->getProjectPHIDs(); } if ($project_phids) { $watcher_type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_WATCHER; $query = id(new PhabricatorEdgeQuery()) ->withSourcePHIDs($project_phids) ->withEdgeTypes(array($watcher_type)); $query->execute(); $watcher_phids = $query->getDestinationPHIDs(); if ($watcher_phids) { // We need to do a visibility check for all the watchers, as // watching a project is not a guarantee that you can see objects // associated with it. $users = id(new PhabricatorPeopleQuery()) ->setViewer($this->requireActor()) ->withPHIDs($watcher_phids) ->execute(); $watchers = array(); foreach ($users as $user) { $can_see = PhabricatorPolicyFilter::hasCapability( $user, $object, PhabricatorPolicyCapability::CAN_VIEW); if ($can_see) { $watchers[] = $user->getPHID(); } } $phids[] = $watchers; } } $has_support = true; } if (!$has_support) { throw new Exception('Capability not supported.'); } return array_mergev($phids); } /** * @task mail */ protected function buildMailBody( PhabricatorLiskDAO $object, array $xactions) { $headers = array(); $comments = array(); foreach ($xactions as $xaction) { if ($xaction->shouldHideForMail($xactions)) { continue; } $header = $xaction->getTitleForMail(); if ($header !== null) { $headers[] = $header; } $comment = $xaction->getBodyForMail(); if ($comment !== null) { $comments[] = $comment; } } $body = new PhabricatorMetaMTAMailBody(); $body->addRawSection(implode("\n", $headers)); foreach ($comments as $comment) { $body->addRawSection($comment); } if ($object instanceof PhabricatorCustomFieldInterface) { $field_list = PhabricatorCustomField::getObjectFields( $object, PhabricatorCustomField::ROLE_TRANSACTIONMAIL); $field_list->setViewer($this->getActor()); $field_list->readFieldsFromStorage($object); foreach ($field_list->getFields() as $field) { $field->updateTransactionMailBody( $body, $this, $xactions); } } return $body; } /* -( Publishing Feed Stories )-------------------------------------------- */ /** * @task feed */ protected function shouldPublishFeedStory( PhabricatorLiskDAO $object, array $xactions) { return false; } /** * @task feed */ protected function getFeedStoryType() { return 'PhabricatorApplicationTransactionFeedStory'; } /** * @task feed */ protected function getFeedRelatedPHIDs( PhabricatorLiskDAO $object, array $xactions) { return array( $object->getPHID(), $this->requireActor()->getPHID(), ); } /** * @task feed */ protected function getFeedNotifyPHIDs( PhabricatorLiskDAO $object, array $xactions) { return array_unique(array_merge( $this->getMailTo($object), $this->getMailCC($object))); } /** * @task feed */ protected function getFeedStoryData( PhabricatorLiskDAO $object, array $xactions) { $xactions = msort($xactions, 'getActionStrength'); $xactions = array_reverse($xactions); return array( 'objectPHID' => $object->getPHID(), 'transactionPHIDs' => mpull($xactions, 'getPHID'), ); } /** * @task feed */ protected function publishFeedStory( PhabricatorLiskDAO $object, array $xactions, array $mailed_phids) { $xactions = mfilter($xactions, 'shouldHideForFeed', true); if (!$xactions) { return; } $related_phids = $this->getFeedRelatedPHIDs($object, $xactions); $subscribed_phids = $this->getFeedNotifyPHIDs($object, $xactions); $story_type = $this->getFeedStoryType(); $story_data = $this->getFeedStoryData($object, $xactions); id(new PhabricatorFeedStoryPublisher()) ->setStoryType($story_type) ->setStoryData($story_data) ->setStoryTime(time()) ->setStoryAuthorPHID($this->requireActor()->getPHID()) ->setRelatedPHIDs($related_phids) ->setPrimaryObjectPHID($object->getPHID()) ->setSubscribedPHIDs($subscribed_phids) ->setMailRecipientPHIDs($mailed_phids) ->publish(); } /* -( Search Index )------------------------------------------------------- */ /** * @task search */ protected function supportsSearch() { return false; } /* -( Herald Integration )-------------------------------------------------- */ protected function shouldApplyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { return false; } protected function buildHeraldAdapter( PhabricatorLiskDAO $object, array $xactions) { throw new Exception('No herald adapter specified.'); } private function setHeraldAdapter(HeraldAdapter $adapter) { $this->heraldAdapter = $adapter; return $this; } protected function getHeraldAdapter() { return $this->heraldAdapter; } private function setHeraldTranscript(HeraldTranscript $transcript) { $this->heraldTranscript = $transcript; return $this; } protected function getHeraldTranscript() { return $this->heraldTranscript; } private function applyHeraldRules( PhabricatorLiskDAO $object, array $xactions) { $adapter = $this->buildHeraldAdapter($object, $xactions); $adapter->setContentSource($this->getContentSource()); $adapter->setIsNewObject($this->getIsNewObject()); $xscript = HeraldEngine::loadAndApplyRules($adapter); $this->setHeraldAdapter($adapter); $this->setHeraldTranscript($xscript); return array_merge( $this->didApplyHeraldRules($object, $adapter, $xscript), $adapter->getQueuedTransactions()); } protected function didApplyHeraldRules( PhabricatorLiskDAO $object, HeraldAdapter $adapter, HeraldTranscript $transcript) { return array(); } /* -( Custom Fields )------------------------------------------------------ */ /** * @task customfield */ private function getCustomFieldForTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { $field_key = $xaction->getMetadataValue('customfield:key'); if (!$field_key) { throw new Exception( "Custom field transaction has no 'customfield:key'!"); } $field = PhabricatorCustomField::getObjectField( $object, PhabricatorCustomField::ROLE_APPLICATIONTRANSACTIONS, $field_key); if (!$field) { throw new Exception( "Custom field transaction has invalid 'customfield:key'; field ". "'{$field_key}' is disabled or does not exist."); } if (!$field->shouldAppearInApplicationTransactions()) { throw new Exception( "Custom field transaction '{$field_key}' does not implement ". "integration for ApplicationTransactions."); } $field->setViewer($this->getActor()); return $field; } /* -( Files )-------------------------------------------------------------- */ /** * Extract the PHIDs of any files which these transactions attach. * * @task files */ private function extractFilePHIDs( PhabricatorLiskDAO $object, array $xactions) { $blocks = array(); foreach ($xactions as $xaction) { $blocks[] = $this->getRemarkupBlocksFromTransaction($xaction); } $blocks = array_mergev($blocks); $phids = array(); if ($blocks) { $phids[] = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles( $this->getActor(), $blocks); } foreach ($xactions as $xaction) { $phids[] = $this->extractFilePHIDsFromCustomTransaction( $object, $xaction); } $phids = array_unique(array_filter(array_mergev($phids))); if (!$phids) { return array(); } // Only let a user attach files they can actually see, since this would // otherwise let you access any file by attaching it to an object you have // view permission on. $files = id(new PhabricatorFileQuery()) ->setViewer($this->getActor()) ->withPHIDs($phids) ->execute(); return mpull($files, 'getPHID'); } /** * @task files */ protected function extractFilePHIDsFromCustomTransaction( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction) { return array(); } /** * @task files */ private function attachFiles( PhabricatorLiskDAO $object, array $file_phids) { if (!$file_phids) { return; } $editor = new PhabricatorEdgeEditor(); $src = $object->getPHID(); $type = PhabricatorEdgeConfig::TYPE_OBJECT_HAS_FILE; foreach ($file_phids as $dst) { $editor->addEdge($src, $type, $dst); } $editor->save(); } private function applyInverseEdgeTransactions( PhabricatorLiskDAO $object, PhabricatorApplicationTransaction $xaction, $inverse_type) { $old = $xaction->getOldValue(); $new = $xaction->getNewValue(); $add = array_keys(array_diff_key($new, $old)); $rem = array_keys(array_diff_key($old, $new)); $add = array_fuse($add); $rem = array_fuse($rem); $all = $add + $rem; $nodes = id(new PhabricatorObjectQuery()) ->setViewer($this->requireActor()) ->withPHIDs($all) ->execute(); foreach ($nodes as $node) { if (!($node instanceof PhabricatorApplicationTransactionInterface)) { continue; } $editor = $node->getApplicationTransactionEditor(); $template = $node->getApplicationTransactionTemplate(); $target = $node->getApplicationTransactionObject(); if (isset($add[$node->getPHID()])) { $edge_edit_type = '+'; } else { $edge_edit_type = '-'; } $template ->setTransactionType($xaction->getTransactionType()) ->setMetadataValue('edge:type', $inverse_type) ->setNewValue( array( $edge_edit_type => array($object->getPHID() => $object->getPHID()), )); $editor ->setContinueOnNoEffect(true) ->setContinueOnMissingFields(true) ->setParentMessageID($this->getParentMessageID()) ->setIsInverseEdgeEditor(true) ->setActor($this->requireActor()) ->setContentSource($this->getContentSource()); $editor->applyTransactions($target, array($template)); } } } diff --git a/src/applications/transactions/phid/PhabricatorApplicationTransactionPHIDTypeTransaction.php b/src/applications/transactions/phid/PhabricatorApplicationTransactionTransactionPHIDType.php similarity index 97% rename from src/applications/transactions/phid/PhabricatorApplicationTransactionPHIDTypeTransaction.php rename to src/applications/transactions/phid/PhabricatorApplicationTransactionTransactionPHIDType.php index 195686d7b..bd5291efa 100644 --- a/src/applications/transactions/phid/PhabricatorApplicationTransactionPHIDTypeTransaction.php +++ b/src/applications/transactions/phid/PhabricatorApplicationTransactionTransactionPHIDType.php @@ -1,88 +1,88 @@ setAncestorClass('PhabricatorApplicationTransactionQuery') ->loadObjects(); $queries = array(); foreach ($objects as $object) { $type = $object ->getTemplateApplicationTransaction() ->getApplicationTransactionType(); $queries[$type] = $object; } } $phid_subtypes = array(); foreach ($phids as $phid) { $subtype = phid_get_subtype($phid); if ($subtype) { $phid_subtypes[$subtype][] = $phid; } } $results = array(); foreach ($phid_subtypes as $subtype => $subtype_phids) { $query = idx($queries, $subtype); if (!$query) { continue; } $xaction_query = id(clone $query) ->setViewer($object_query->getViewer()) ->setParentQuery($object_query) ->withPHIDs($subtype_phids); if (!$xaction_query->canViewerUseQueryApplication()) { $object_query->addPolicyFilteredPHIDs(array_fuse($subtype_phids)); continue; } $xactions = $xaction_query->execute(); $results += mpull($xactions, null, 'getPHID'); } return $results; } public function loadHandles( PhabricatorHandleQuery $query, array $handles, array $objects) { // NOTE: We don't produce meaningful handles here because they're // impractical to produce and no application uses them. } } diff --git a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php index 1469bfb6d..54a928df3 100644 --- a/src/applications/transactions/storage/PhabricatorApplicationTransaction.php +++ b/src/applications/transactions/storage/PhabricatorApplicationTransaction.php @@ -1,1057 +1,1057 @@ ignoreOnNoEffect = $ignore; return $this; } public function getIgnoreOnNoEffect() { return $this->ignoreOnNoEffect; } public function shouldGenerateOldValue() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_BUILDABLE: case PhabricatorTransactions::TYPE_TOKEN: case PhabricatorTransactions::TYPE_CUSTOMFIELD: return false; } return true; } abstract public function getApplicationTransactionType(); private function getApplicationObjectTypeName() { $types = PhabricatorPHIDType::getAllTypes(); $type = idx($types, $this->getApplicationTransactionType()); if ($type) { return $type->getTypeName(); } return pht('Object'); } public function getApplicationTransactionCommentObject() { throw new PhutilMethodNotImplementedException(); } public function getApplicationTransactionViewObject() { return new PhabricatorApplicationTransactionView(); } public function getMetadataValue($key, $default = null) { return idx($this->metadata, $key, $default); } public function setMetadataValue($key, $value) { $this->metadata[$key] = $value; return $this; } public function generatePHID() { - $type = PhabricatorApplicationTransactionPHIDTypeTransaction::TYPECONST; + $type = PhabricatorApplicationTransactionTransactionPHIDType::TYPECONST; $subtype = $this->getApplicationTransactionType(); return PhabricatorPHID::generateNewPHID($type, $subtype); } public function getConfiguration() { return array( self::CONFIG_AUX_PHID => true, self::CONFIG_SERIALIZATION => array( 'oldValue' => self::SERIALIZATION_JSON, 'newValue' => self::SERIALIZATION_JSON, 'metadata' => self::SERIALIZATION_JSON, ), ) + parent::getConfiguration(); } public function setContentSource(PhabricatorContentSource $content_source) { $this->contentSource = $content_source->serialize(); return $this; } public function getContentSource() { return PhabricatorContentSource::newFromSerialized($this->contentSource); } public function hasComment() { return $this->getComment() && strlen($this->getComment()->getContent()); } public function getComment() { if ($this->commentNotLoaded) { throw new Exception('Comment for this transaction was not loaded.'); } return $this->comment; } public function attachComment( PhabricatorApplicationTransactionComment $comment) { $this->comment = $comment; $this->commentNotLoaded = false; return $this; } public function setCommentNotLoaded($not_loaded) { $this->commentNotLoaded = $not_loaded; return $this; } public function attachObject($object) { $this->object = $object; return $this; } public function getObject() { return $this->assertAttached($this->object); } public function getRemarkupBlocks() { $blocks = array(); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { $custom_blocks = $field->getApplicationTransactionRemarkupBlocks( $this); foreach ($custom_blocks as $custom_block) { $blocks[] = $custom_block; } } break; } if ($this->getComment()) { $blocks[] = $this->getComment()->getContent(); } return $blocks; } public function setOldValue($value) { $this->oldValueHasBeenSet = true; $this->writeField('oldValue', $value); return $this; } public function hasOldValue() { return $this->oldValueHasBeenSet; } /* -( Rendering )---------------------------------------------------------- */ public function setRenderingTarget($rendering_target) { $this->renderingTarget = $rendering_target; return $this; } public function getRenderingTarget() { return $this->renderingTarget; } public function attachViewer(PhabricatorUser $viewer) { $this->viewer = $viewer; return $this; } public function getViewer() { return $this->assertAttached($this->viewer); } public function getRequiredHandlePHIDs() { $phids = array(); $old = $this->getOldValue(); $new = $this->getNewValue(); $phids[] = array($this->getAuthorPHID()); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { $phids[] = $field->getApplicationTransactionRequiredHandlePHIDs( $this); } break; case PhabricatorTransactions::TYPE_SUBSCRIBERS: $phids[] = $old; $phids[] = $new; break; case PhabricatorTransactions::TYPE_EDGE: $phids[] = ipull($old, 'dst'); $phids[] = ipull($new, 'dst'); break; case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: if (!PhabricatorPolicyQuery::isGlobalPolicy($old)) { $phids[] = array($old); } if (!PhabricatorPolicyQuery::isGlobalPolicy($new)) { $phids[] = array($new); } break; case PhabricatorTransactions::TYPE_TOKEN: break; case PhabricatorTransactions::TYPE_BUILDABLE: $phid = $this->getMetadataValue('harbormaster:buildablePHID'); if ($phid) { $phids[] = array($phid); } break; } if ($this->getComment()) { $phids[] = array($this->getComment()->getAuthorPHID()); } return array_mergev($phids); } public function setHandles(array $handles) { $this->handles = $handles; return $this; } public function getHandle($phid) { if (empty($this->handles[$phid])) { throw new Exception( pht( 'Transaction ("%s") requires a handle ("%s") that it did not '. 'load.', $this->getPHID(), $phid)); } return $this->handles[$phid]; } public function getHandleIfExists($phid) { return idx($this->handles, $phid); } public function getHandles() { if ($this->handles === null) { throw new Exception( 'Transaction requires handles and it did not load them.' ); } return $this->handles; } public function renderHandleLink($phid) { if ($this->renderingTarget == self::TARGET_HTML) { return $this->getHandle($phid)->renderLink(); } else { return $this->getHandle($phid)->getLinkName(); } } public function renderHandleList(array $phids) { $links = array(); foreach ($phids as $phid) { $links[] = $this->renderHandleLink($phid); } if ($this->renderingTarget == self::TARGET_HTML) { return phutil_implode_html(', ', $links); } else { return implode(', ', $links); } } private function renderSubscriberList(array $phids, $change_type) { if ($this->getRenderingTarget() == self::TARGET_TEXT) { return $this->renderHandleList($phids); } else { $handles = array_select_keys($this->getHandles(), $phids); return id(new SubscriptionListStringBuilder()) ->setHandles($handles) ->setObjectPHID($this->getPHID()) ->buildTransactionString($change_type); } } protected function renderPolicyName($phid, $state = 'old') { $policy = PhabricatorPolicy::newFromPolicyAndHandle( $phid, $this->getHandleIfExists($phid)); if ($this->renderingTarget == self::TARGET_HTML) { switch ($policy->getType()) { case PhabricatorPolicyType::TYPE_CUSTOM: $policy->setHref('/transactions/'.$state.'/'.$this->getPHID().'/'); $policy->setWorkflow(true); break; default: break; } $output = $policy->renderDescription(); } else { $output = hsprintf('%s', $policy->getFullName()); } return $output; } public function getIcon() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: $comment = $this->getComment(); if ($comment && $comment->getIsRemoved()) { return 'fa-eraser'; } return 'fa-comment'; case PhabricatorTransactions::TYPE_SUBSCRIBERS: return 'fa-envelope'; case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: return 'fa-lock'; case PhabricatorTransactions::TYPE_EDGE: return 'fa-link'; case PhabricatorTransactions::TYPE_BUILDABLE: return 'fa-wrench'; case PhabricatorTransactions::TYPE_TOKEN: return 'fa-trophy'; } return 'fa-pencil'; } public function getToken() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_TOKEN: $old = $this->getOldValue(); $new = $this->getNewValue(); if ($new) { $icon = substr($new, 10); } else { $icon = substr($old, 10); } return array($icon, !$this->getNewValue()); } return array(null, null); } public function getColor() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT; $comment = $this->getComment(); if ($comment && $comment->getIsRemoved()) { return 'black'; } break; case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_PASSED: return 'green'; case HarbormasterBuildable::STATUS_FAILED: return 'red'; } break; } return null; } protected function getTransactionCustomField() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CUSTOMFIELD: $key = $this->getMetadataValue('customfield:key'); if (!$key) { return null; } $field = PhabricatorCustomField::getObjectField( $this->getObject(), PhabricatorCustomField::ROLE_APPLICATIONTRANSACTIONS, $key); if (!$field) { return null; } $field->setViewer($this->getViewer()); return $field; } return null; } public function shouldHide() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: if ($this->getOldValue() === null) { return true; } else { return false; } break; case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { return $field->shouldHideInApplicationTransactions($this); } } return false; } public function shouldHideForMail(array $xactions) { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_TOKEN: return true; case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_FAILED: // For now, only ever send mail when builds fail. We might let // you customize this later, but in most cases this is probably // completely uninteresting. return false; } return true; } return $this->shouldHide(); } public function shouldHideForFeed() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_TOKEN: return true; case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_FAILED: // For now, don't notify on build passes either. These are pretty // high volume and annoying, with very little present value. We // might want to turn them back on in the specific case of // build successes on the current document? return false; } return true; } return $this->shouldHide(); } public function getTitleForMail() { return id(clone $this)->setRenderingTarget('text')->getTitle(); } public function getBodyForMail() { $comment = $this->getComment(); if ($comment && strlen($comment->getContent())) { return $comment->getContent(); } return null; } public function getNoEffectDescription() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return pht('You can not post an empty comment.'); case PhabricatorTransactions::TYPE_VIEW_POLICY: return pht( 'This %s already has that view policy.', $this->getApplicationObjectTypeName()); case PhabricatorTransactions::TYPE_EDIT_POLICY: return pht( 'This %s already has that edit policy.', $this->getApplicationObjectTypeName()); case PhabricatorTransactions::TYPE_JOIN_POLICY: return pht( 'This %s already has that join policy.', $this->getApplicationObjectTypeName()); case PhabricatorTransactions::TYPE_SUBSCRIBERS: return pht( 'All users are already subscribed to this %s.', $this->getApplicationObjectTypeName()); case PhabricatorTransactions::TYPE_EDGE: return pht('Edges already exist; transaction has no effect.'); } return pht('Transaction has no effect.'); } public function getTitle() { $author_phid = $this->getAuthorPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return pht( '%s added a comment.', $this->renderHandleLink($author_phid)); case PhabricatorTransactions::TYPE_VIEW_POLICY: return pht( '%s changed the visibility of this %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->getApplicationObjectTypeName(), $this->renderPolicyName($old, 'old'), $this->renderPolicyName($new, 'new')); case PhabricatorTransactions::TYPE_EDIT_POLICY: return pht( '%s changed the edit policy of this %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->getApplicationObjectTypeName(), $this->renderPolicyName($old, 'old'), $this->renderPolicyName($new, 'new')); case PhabricatorTransactions::TYPE_JOIN_POLICY: return pht( '%s changed the join policy of this %s from "%s" to "%s".', $this->renderHandleLink($author_phid), $this->getApplicationObjectTypeName(), $this->renderPolicyName($old, 'old'), $this->renderPolicyName($new, 'new')); case PhabricatorTransactions::TYPE_SUBSCRIBERS: $add = array_diff($new, $old); $rem = array_diff($old, $new); if ($add && $rem) { return pht( '%s edited subscriber(s), added %d: %s; removed %d: %s.', $this->renderHandleLink($author_phid), count($add), $this->renderSubscriberList($add, 'add'), count($rem), $this->renderSubscriberList($rem, 'rem')); } else if ($add) { return pht( '%s added %d subscriber(s): %s.', $this->renderHandleLink($author_phid), count($add), $this->renderSubscriberList($add, 'add')); } else if ($rem) { return pht( '%s removed %d subscriber(s): %s.', $this->renderHandleLink($author_phid), count($rem), $this->renderSubscriberList($rem, 'rem')); } else { // This is used when rendering previews, before the user actually // selects any CCs. return pht( '%s updated subscribers...', $this->renderHandleLink($author_phid)); } break; case PhabricatorTransactions::TYPE_EDGE: $new = ipull($new, 'dst'); $old = ipull($old, 'dst'); $add = array_diff($new, $old); $rem = array_diff($old, $new); $type = $this->getMetadata('edge:type'); $type = head($type); $type_obj = PhabricatorEdgeType::getByConstant($type); if ($add && $rem) { return $type_obj->getTransactionEditString( $this->renderHandleLink($author_phid), new PhutilNumber(count($add) + count($rem)), new PhutilNumber(count($add)), $this->renderHandleList($add), new PhutilNumber(count($rem)), $this->renderHandleList($rem)); } else if ($add) { return $type_obj->getTransactionAddString( $this->renderHandleLink($author_phid), new PhutilNumber(count($add)), $this->renderHandleList($add)); } else if ($rem) { return $type_obj->getTransactionRemoveString( $this->renderHandleLink($author_phid), new PhutilNumber(count($rem)), $this->renderHandleList($rem)); } else { return pht( '%s edited edge metadata.', $this->renderHandleLink($author_phid)); } case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { return $field->getApplicationTransactionTitle($this); } else { return pht( '%s edited a custom field.', $this->renderHandleLink($author_phid)); } case PhabricatorTransactions::TYPE_TOKEN: if ($old && $new) { return pht( '%s updated a token.', $this->renderHandleLink($author_phid)); } else if ($old) { return pht( '%s rescinded a token.', $this->renderHandleLink($author_phid)); } else { return pht( '%s awarded a token.', $this->renderHandleLink($author_phid)); } case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_BUILDING: return pht( '%s started building %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink( $this->getMetadataValue('harbormaster:buildablePHID'))); case HarbormasterBuildable::STATUS_PASSED: return pht( '%s completed building %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink( $this->getMetadataValue('harbormaster:buildablePHID'))); case HarbormasterBuildable::STATUS_FAILED: return pht( '%s failed to build %s!', $this->renderHandleLink($author_phid), $this->renderHandleLink( $this->getMetadataValue('harbormaster:buildablePHID'))); default: return null; } default: return pht( '%s edited this %s.', $this->renderHandleLink($author_phid), $this->getApplicationObjectTypeName()); } } public function getTitleForFeed(PhabricatorFeedStory $story) { $author_phid = $this->getAuthorPHID(); $object_phid = $this->getObjectPHID(); $old = $this->getOldValue(); $new = $this->getNewValue(); switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return pht( '%s added a comment to %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_VIEW_POLICY: return pht( '%s changed the visibility for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_EDIT_POLICY: return pht( '%s changed the edit policy for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_JOIN_POLICY: return pht( '%s changed the join policy for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_SUBSCRIBERS: return pht( '%s updated subscribers of %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); case PhabricatorTransactions::TYPE_EDGE: $new = ipull($new, 'dst'); $old = ipull($old, 'dst'); $add = array_diff($new, $old); $rem = array_diff($old, $new); $type = $this->getMetadata('edge:type'); $type = head($type); $type_obj = PhabricatorEdgeType::getByConstant($type); if ($add && $rem) { return $type_obj->getFeedEditString( $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), new PhutilNumber(count($add) + count($rem)), new PhutilNumber(count($add)), $this->renderHandleList($add), new PhutilNumber(count($rem)), $this->renderHandleList($rem)); } else if ($add) { return $type_obj->getFeedAddString( $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), new PhutilNumber(count($add)), $this->renderHandleList($add)); } else if ($rem) { return $type_obj->getFeedRemoveString( $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid), new PhutilNumber(count($rem)), $this->renderHandleList($rem)); } else { return pht( '%s edited edge metadata for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { return $field->getApplicationTransactionTitleForFeed($this, $story); } else { return pht( '%s edited a custom field on %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink($object_phid)); } case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_BUILDING: return pht( '%s started building %s for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink( $this->getMetadataValue('harbormaster:buildablePHID')), $this->renderHandleLink($object_phid)); case HarbormasterBuildable::STATUS_PASSED: return pht( '%s completed building %s for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink( $this->getMetadataValue('harbormaster:buildablePHID')), $this->renderHandleLink($object_phid)); case HarbormasterBuildable::STATUS_FAILED: return pht( '%s failed to build %s for %s.', $this->renderHandleLink($author_phid), $this->renderHandleLink( $this->getMetadataValue('harbormaster:buildablePHID')), $this->renderHandleLink($object_phid)); default: return null; } } return $this->getTitle(); } public function getBodyForFeed(PhabricatorFeedStory $story) { $old = $this->getOldValue(); $new = $this->getNewValue(); $body = null; switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: $text = $this->getComment()->getContent(); $body = phutil_escape_html_newlines( phutil_utf8_shorten($text, 128)); break; } return $body; } public function getActionStrength() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return 0.5; case PhabricatorTransactions::TYPE_SUBSCRIBERS: $old = $this->getOldValue(); $new = $this->getNewValue(); $add = array_diff($old, $new); $rem = array_diff($new, $old); // If this action is the actor subscribing or unsubscribing themselves, // it is less interesting. In particular, if someone makes a comment and // also implicitly subscribes themselves, we should treat the // transaction group as "comment", not "subscribe". In this specific // case (one affected user, and that affected user it the actor), // decrease the action strength. if ((count($add) + count($rem)) != 1) { // Not exactly one CC change. break; } $affected_phid = head(array_merge($add, $rem)); if ($affected_phid != $this->getAuthorPHID()) { // Affected user is someone else. break; } // Make this weaker than TYPE_COMMENT. return 0.25; } return 1.0; } public function isCommentTransaction() { if ($this->hasComment()) { return true; } switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return true; } return false; } public function getActionName() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_COMMENT: return pht('Commented On'); case PhabricatorTransactions::TYPE_VIEW_POLICY: case PhabricatorTransactions::TYPE_EDIT_POLICY: case PhabricatorTransactions::TYPE_JOIN_POLICY: return pht('Changed Policy'); case PhabricatorTransactions::TYPE_SUBSCRIBERS: return pht('Changed Subscribers'); case PhabricatorTransactions::TYPE_BUILDABLE: switch ($this->getNewValue()) { case HarbormasterBuildable::STATUS_PASSED: return pht('Build Passed'); case HarbormasterBuildable::STATUS_FAILED: return pht('Build Failed'); default: return pht('Build Status'); } default: return pht('Updated'); } } public function getMailTags() { return array(); } public function hasChangeDetails() { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { return $field->getApplicationTransactionHasChangeDetails($this); } break; } return false; } public function renderChangeDetails(PhabricatorUser $viewer) { switch ($this->getTransactionType()) { case PhabricatorTransactions::TYPE_CUSTOMFIELD: $field = $this->getTransactionCustomField(); if ($field) { return $field->getApplicationTransactionChangeDetails($this, $viewer); } break; } return $this->renderTextCorpusChangeDetails( $viewer, $this->getOldValue(), $this->getNewValue()); } public function renderTextCorpusChangeDetails( PhabricatorUser $viewer, $old, $new) { require_celerity_resource('differential-changeset-view-css'); $view = id(new PhabricatorApplicationTransactionTextDiffDetailView()) ->setUser($viewer) ->setOldText($old) ->setNewText($new); return $view->render(); } public function attachTransactionGroup(array $group) { assert_instances_of($group, 'PhabricatorApplicationTransaction'); $this->transactionGroup = $group; return $this; } public function getTransactionGroup() { return $this->transactionGroup; } /** * Should this transaction be visually grouped with an existing transaction * group? * * @param list List of transactions. * @return bool True to display in a group with the other transactions. */ public function shouldDisplayGroupWith(array $group) { $this_source = null; if ($this->getContentSource()) { $this_source = $this->getContentSource()->getSource(); } foreach ($group as $xaction) { // Don't group transactions by different authors. if ($xaction->getAuthorPHID() != $this->getAuthorPHID()) { return false; } // Don't group transactions for different objects. if ($xaction->getObjectPHID() != $this->getObjectPHID()) { return false; } // Don't group anything into a group which already has a comment. if ($xaction->isCommentTransaction()) { return false; } // Don't group transactions from different content sources. $other_source = null; if ($xaction->getContentSource()) { $other_source = $xaction->getContentSource()->getSource(); } if ($other_source != $this_source) { return false; } // Don't group transactions which happened more than 2 minutes apart. $apart = abs($xaction->getDateCreated() - $this->getDateCreated()); if ($apart > (60 * 2)) { return false; } } return true; } public function renderExtraInformationLink() { $herald_xscript_id = $this->getMetadataValue('herald:transcriptID'); if ($herald_xscript_id) { return phutil_tag( 'a', array( 'href' => '/herald/transcript/'.$herald_xscript_id.'/', ), pht('View Herald Transcript')); } return null; } /* -( PhabricatorPolicyInterface Implementation )-------------------------- */ public function getCapabilities() { return array( PhabricatorPolicyCapability::CAN_VIEW, PhabricatorPolicyCapability::CAN_EDIT, ); } public function getPolicy($capability) { switch ($capability) { case PhabricatorPolicyCapability::CAN_VIEW: return $this->getViewPolicy(); case PhabricatorPolicyCapability::CAN_EDIT: return $this->getEditPolicy(); } } public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { return ($viewer->getPHID() == $this->getAuthorPHID()); } public function describeAutomaticCapability($capability) { // TODO: (T603) Exact policies are unclear here. return null; } /* -( PhabricatorDestructibleInterface )----------------------------------- */ public function destroyObjectPermanently( PhabricatorDestructionEngine $engine) { $this->openTransaction(); $comment_template = null; try { $comment_template = $this->getApplicationTransactionCommentObject(); } catch (Exception $ex) { // Continue; no comments for these transactions. } if ($comment_template) { $comments = $comment_template->loadAllWhere( 'transactionPHID = %s', $this->getPHID()); foreach ($comments as $comment) { $engine->destroyObject($comment); } } $this->delete(); $this->saveTransaction(); } } diff --git a/src/applications/uiexample/examples/PhabricatorHovercardExample.php b/src/applications/uiexample/examples/PhabricatorHovercardExample.php index ca73039af..c6b7a3bbf 100644 --- a/src/applications/uiexample/examples/PhabricatorHovercardExample.php +++ b/src/applications/uiexample/examples/PhabricatorHovercardExample.php @@ -1,78 +1,78 @@ PhabricatorHovercardView to render '. 'hovercards. Aren\'t I genius?'); } public function renderExample() { $request = $this->getRequest(); $user = $request->getUser(); $elements = array(); $diff_handle = $this->createBasicDummyHandle( 'D123', - DifferentialPHIDTypeRevision::TYPECONST, + DifferentialRevisionPHIDType::TYPECONST, 'Introduce cooler Differential Revisions'); $panel = $this->createPanel('Differential Hovercard'); $panel->appendChild(id(new PhabricatorHovercardView()) ->setObjectHandle($diff_handle) ->addField(pht('Author'), $user->getUsername()) ->addField(pht('Updated'), phabricator_datetime(time(), $user)) ->addAction(pht('Subscribe'), '/dev/random') ->setUser($user)); $elements[] = $panel; $task_handle = $this->createBasicDummyHandle( 'T123', - ManiphestPHIDTypeTask::TYPECONST, + ManiphestTaskPHIDType::TYPECONST, 'Improve Mobile Experience for Phabricator'); $tag = id(new PHUITagView()) ->setType(PHUITagView::TYPE_STATE) ->setName('Closed, Resolved'); $panel = $this->createPanel('Maniphest Hovercard'); $panel->appendChild(id(new PhabricatorHovercardView()) ->setObjectHandle($task_handle) ->setUser($user) ->addField(pht('Assigned to'), $user->getUsername()) ->addField(pht('Dependent Tasks'), 'T123, T124, T125') ->addAction(pht('Subscribe'), '/dev/random') ->addAction(pht('Create Subtask'), '/dev/urandom') ->addTag($tag)); $elements[] = $panel; $user_handle = $this->createBasicDummyHandle( 'gwashington', - PhabricatorPeoplePHIDTypeUser::TYPECONST, + PhabricatorPeopleUserPHIDType::TYPECONST, 'George Washington'); $user_handle->setImageURI( celerity_get_resource_uri('/rsrc/image/people/washington.png')); $panel = $this->createPanel('Whatevery Hovercard'); $panel->appendChild(id(new PhabricatorHovercardView()) ->setObjectHandle($user_handle) ->addField(pht('Status'), 'Available') ->addField(pht('Member since'), '30. February 1750') ->addAction(pht('Send a Message'), '/dev/null') ->setUser($user)); $elements[] = $panel; return phutil_implode_html('', $elements); } private function createPanel($header) { $panel = new PHUIBoxView(); $panel->addClass('grouped'); $panel->addClass('ml'); return $panel; } } diff --git a/src/view/phui/PHUIFeedStoryView.php b/src/view/phui/PHUIFeedStoryView.php index 9c4c95dfc..60d71005a 100644 --- a/src/view/phui/PHUIFeedStoryView.php +++ b/src/view/phui/PHUIFeedStoryView.php @@ -1,275 +1,275 @@ chronologicalKey = $chronological_key; return $this; } public function getChronologicalKey() { return $this->chronologicalKey; } public function setTitle($title) { $this->title = $title; return $this; } public function getTitle() { return $this->title; } public function setEpoch($epoch) { $this->epoch = $epoch; return $this; } public function setImage($image) { $this->image = $image; return $this; } public function setImageHref($image_href) { $this->imageHref = $image_href; return $this; } public function setAppIcon($icon) { $this->appIcon = $icon; return $this; } public function setViewed($viewed) { $this->viewed = $viewed; return $this; } public function getViewed() { return $this->viewed; } public function setHref($href) { $this->href = $href; return $this; } public function setTokenBar(array $tokens) { $this->tokenBar = $tokens; return $this; } public function addProject($project) { $this->projects[] = $project; return $this; } public function addAction(PHUIIconView $action) { $this->actions[] = $action; return $this; } public function setPontification($text, $title = null) { if ($title) { $title = phutil_tag('h3', array(), $title); } $copy = phutil_tag( 'div', array( 'class' => 'phui-feed-story-bigtext-post', ), array( $title, $text)); $this->appendChild($copy); return $this; } public function getHref() { return $this->href; } public function renderNotification($user) { $classes = array( 'phabricator-notification', ); if (!$this->viewed) { $classes[] = 'phabricator-notification-unread'; } if ($this->epoch) { if ($user) { $foot = phabricator_datetime($this->epoch, $user); $foot = phutil_tag( 'span', array( 'class' => 'phabricator-notification-date'), $foot); } else { $foot = null; } } else { $foot = pht('No time specified.'); } return javelin_tag( 'div', array( 'class' => implode(' ', $classes), 'sigil' => 'notification', 'meta' => array( 'href' => $this->getHref(), ), ), array($this->title, $foot)); } public function render() { require_celerity_resource('phui-feed-story-css'); Javelin::initBehavior('phabricator-hovercards'); $body = null; $foot = null; $image_style = null; $actor = ''; if ($this->image) { $actor = new PHUIIconView(); $actor->setImage($this->image); $actor->addClass('phui-feed-story-actor-image'); if ($this->imageHref) { $actor->setHref($this->imageHref); } } if ($this->epoch) { // TODO: This is really bad; when rendering through Conduit and via // renderText() we don't have a user. if ($this->user) { $foot = phabricator_datetime($this->epoch, $this->user); } else { $foot = null; } } else { $foot = pht('No time specified.'); } if ($this->chronologicalKey) { $foot = phutil_tag( 'a', array( 'href' => '/feed/'.$this->chronologicalKey.'/', ), $foot); } $icon = null; if ($this->appIcon) { $icon = new PHUIIconView(); $icon->setSpriteIcon($this->appIcon); $icon->setSpriteSheet(PHUIIconView::SPRITE_APPS); } $action_list = array(); $icons = null; foreach ($this->actions as $action) { $action_list[] = phutil_tag( 'li', array( 'class' => 'phui-feed-story-action-item' ), $action); } if (!empty($action_list)) { $icons = phutil_tag( 'ul', array( 'class' => 'phui-feed-story-action-list' ), $action_list); } $head = phutil_tag( 'div', array( 'class' => 'phui-feed-story-head', ), array( $actor, nonempty($this->title, pht('Untitled Story')), $icons, )); if (!empty($this->tokenBar)) { $tokenview = phutil_tag( 'div', array( 'class' => 'phui-feed-token-bar' ), $this->tokenBar); $this->appendChild($tokenview); } $body_content = $this->renderChildren(); if ($body_content) { $body = phutil_tag( 'div', array( 'class' => 'phui-feed-story-body', ), $body_content); } $foot = phutil_tag( 'div', array( 'class' => 'phui-feed-story-foot', ), array( $icon, $foot)); $classes = array('phui-feed-story'); return id(new PHUIBoxView()) ->addClass(implode(' ', $classes)) ->setBorder(true) ->addMargin(PHUI::MARGIN_MEDIUM_BOTTOM) ->appendChild(array($head, $body, $foot)); } public function setAppIconFromPHID($phid) { switch (phid_get_type($phid)) { - case PholioPHIDTypeMock::TYPECONST: + case PholioMockPHIDType::TYPECONST: $this->setAppIcon('pholio-dark'); break; - case PhabricatorMacroPHIDTypeMacro::TYPECONST: + case PhabricatorMacroMacroPHIDType::TYPECONST: $this->setAppIcon('macro-dark'); break; - case ManiphestPHIDTypeTask::TYPECONST: + case ManiphestTaskPHIDType::TYPECONST: $this->setAppIcon('maniphest-dark'); break; - case DifferentialPHIDTypeRevision::TYPECONST: + case DifferentialRevisionPHIDType::TYPECONST: $this->setAppIcon('differential-dark'); break; - case PhabricatorCalendarPHIDTypeEvent::TYPECONST: + case PhabricatorCalendarEventPHIDType::TYPECONST: $this->setAppIcon('calendar-dark'); break; } } }