diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 350e135731..44def0cba1 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -929,6 +929,7 @@ phutil_register_library_map(array( ), 'function' => array( + '__phabricator_date_format' => 'view/utils', '__phabricator_format_local_time' => 'view/utils', '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', @@ -939,8 +940,12 @@ phutil_register_library_map(array( 'phabricator_datetime' => 'view/utils', 'phabricator_format_relative_time' => 'view/utils', 'phabricator_format_units_generic' => 'view/utils', + 'phabricator_on_relative_date' => 'view/utils', + 'phabricator_relative_date' => 'view/utils', 'phabricator_render_form' => 'infrastructure/javelin/markup', 'phabricator_time' => 'view/utils', + 'phid_get_type' => 'applications/phid/utils', + 'phid_group_by_type' => 'applications/phid/utils', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', diff --git a/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php b/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php index aa990e2ff0..9ef8b1ad06 100644 --- a/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php +++ b/src/applications/audit/editor/comment/PhabricatorAuditCommentEditor.php @@ -202,9 +202,9 @@ final class PhabricatorAuditCommentEditor { $phids[$user->getPHID()] = true; // The user can audit on behalf of all packages they own. - $owned_packages = id(new PhabricatorOwnersOwner())->loadAllWhere( - 'userPHID = %s', + $owned_packages = PhabricatorOwnersOwner::loadAffiliatedPackages( $user->getPHID()); + if ($owned_packages) { $packages = id(new PhabricatorOwnersPackage())->loadAllWhere( 'id IN (%Ld)', diff --git a/src/applications/herald/adapter/differential/HeraldDifferentialRevisionAdapter.php b/src/applications/herald/adapter/differential/HeraldDifferentialRevisionAdapter.php index f06aca63bd..b6ce5da89e 100644 --- a/src/applications/herald/adapter/differential/HeraldDifferentialRevisionAdapter.php +++ b/src/applications/herald/adapter/differential/HeraldDifferentialRevisionAdapter.php @@ -217,8 +217,8 @@ final class HeraldDifferentialRevisionAdapter extends HeraldObjectAdapter { return mpull($packages, 'getPHID'); case HeraldFieldConfig::FIELD_AFFECTED_PACKAGE_OWNER: $packages = $this->loadAffectedPackages(); - $owners = PhabricatorOwnersOwner::loadAllForPackages($packages); - return mpull($owners, 'getUserPHID'); + return PhabricatorOwnersOwner::loadAffiliatedUserPHIDs( + mpull($packages, 'getID')); default: throw new Exception("Invalid field '{$field}'."); } diff --git a/src/applications/owners/controller/edit/PhabricatorOwnersEditController.php b/src/applications/owners/controller/edit/PhabricatorOwnersEditController.php index 6f69faa18c..3f219106ed 100644 --- a/src/applications/owners/controller/edit/PhabricatorOwnersEditController.php +++ b/src/applications/owners/controller/edit/PhabricatorOwnersEditController.php @@ -203,7 +203,7 @@ final class PhabricatorOwnersEditController ->setError($e_name)) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setDatasource('/typeahead/common/users/') + ->setDatasource('/typeahead/common/usersorprojects/') ->setLabel('Primary Owner') ->setName('primary') ->setLimit(1) @@ -211,7 +211,7 @@ final class PhabricatorOwnersEditController ->setError($e_primary)) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setDatasource('/typeahead/common/users/') + ->setDatasource('/typeahead/common/usersorprojects/') ->setLabel('Owners') ->setName('owners') ->setValue($token_all_owners) diff --git a/src/applications/owners/controller/list/PhabricatorOwnersListController.php b/src/applications/owners/controller/list/PhabricatorOwnersListController.php index 06fea5393c..24b5b04369 100644 --- a/src/applications/owners/controller/list/PhabricatorOwnersListController.php +++ b/src/applications/owners/controller/list/PhabricatorOwnersListController.php @@ -171,7 +171,7 @@ final class PhabricatorOwnersListController ->setValue($request->getStr('name'))) ->appendChild( id(new AphrontFormTokenizerControl()) - ->setDatasource('/typeahead/common/users/') + ->setDatasource('/typeahead/common/usersorprojects/') ->setLimit(1) ->setName('owner') ->setLabel('Owner') diff --git a/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php b/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php index ab61a556ca..40cafebb3d 100644 --- a/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php +++ b/src/applications/owners/storage/owner/PhabricatorOwnersOwner.php @@ -19,6 +19,10 @@ final class PhabricatorOwnersOwner extends PhabricatorOwnersDAO { protected $packageID; + + // this can be a project or a user. We assume that all members of a project + // owner also own the package; use the loadAffiliatedUserPHIDs method if + // you want to recursively grab all user ids that own a package protected $userPHID; public function getConfiguration() { @@ -37,4 +41,43 @@ final class PhabricatorOwnersOwner extends PhabricatorOwnersDAO { 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) { + $owners = id(new PhabricatorOwnersOwner())->loadAllWhere( + 'packageID IN (%Ls)', + $package_ids); + + $all_phids = phid_group_by_type(mpull($owners, 'getUserPHID')); + + $user_phids = idx($all_phids, + PhabricatorPHIDConstants::PHID_TYPE_USER, + array()); + + $users_in_project_phids = array(); + if (idx($all_phids, PhabricatorPHIDConstants::PHID_TYPE_PROJ)) { + $users_in_project_phids = mpull( + id(new PhabricatorProjectAffiliation())->loadAllWhere( + 'projectPHID IN (%Ls)', + idx($all_phids, PhabricatorPHIDConstants::PHID_TYPE_PROJ, array())), + 'getUserPHID'); + } + + return array_unique(array_merge($users_in_project_phids, $user_phids)); + } + + // Loads all affiliated packages for a user. This includes packages owned by + // any project the user is a member of. + public static function loadAffiliatedPackages($user_phid) { + $query = new PhabricatorProjectQuery(); + $query->setMembers(array($user_phid)); + $query->withStatus(PhabricatorProjectQuery::STATUS_ACTIVE); + $projects = $query->execute(); + + $phids = mpull($projects, 'getPHID') + array($user_phid); + return + id(new PhabricatorOwnersOwner())->loadAllWhere( + 'userPHID in (%Ls)', + $phids); + } } diff --git a/src/applications/owners/storage/owner/__init__.php b/src/applications/owners/storage/owner/__init__.php index 4336d4c323..79da434fec 100644 --- a/src/applications/owners/storage/owner/__init__.php +++ b/src/applications/owners/storage/owner/__init__.php @@ -7,6 +7,10 @@ phutil_require_module('phabricator', 'applications/owners/storage/base'); +phutil_require_module('phabricator', 'applications/phid/constants'); +phutil_require_module('phabricator', 'applications/phid/utils'); +phutil_require_module('phabricator', 'applications/project/query/project'); +phutil_require_module('phabricator', 'applications/project/storage/affiliation'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/repository/worker/owner/PhabricatorRepositoryCommitOwnersWorker.php b/src/applications/repository/worker/owner/PhabricatorRepositoryCommitOwnersWorker.php index 5c8eb12ef5..cc46a3fc01 100644 --- a/src/applications/repository/worker/owner/PhabricatorRepositoryCommitOwnersWorker.php +++ b/src/applications/repository/worker/owner/PhabricatorRepositoryCommitOwnersWorker.php @@ -126,10 +126,8 @@ final class PhabricatorRepositoryCommitOwnersWorker $reasons[] = "No Revision Specified"; } - $owners = id(new PhabricatorOwnersOwner())->loadAllWhere( - 'packageID = %d', - $package->getID()); - $owners_phids = mpull($owners, 'getUserPHID'); + $owners_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs( + array($package->getID())); if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $commit_reviewedby_phid && in_array($commit_reviewedby_phid, diff --git a/src/applications/typeahead/controller/common/PhabricatorTypeaheadCommonDatasourceController.php b/src/applications/typeahead/controller/common/PhabricatorTypeaheadCommonDatasourceController.php index a2dc9b895d..3095737f58 100644 --- a/src/applications/typeahead/controller/common/PhabricatorTypeaheadCommonDatasourceController.php +++ b/src/applications/typeahead/controller/common/PhabricatorTypeaheadCommonDatasourceController.php @@ -61,6 +61,10 @@ final class PhabricatorTypeaheadCommonDatasourceController case 'projects': $need_projs = true; break; + case 'usersorprojects': + $need_users = true; + $need_projs = true; + break; case 'repositories': $need_repos = true; break; diff --git a/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php b/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php index fb2813ae2d..cc7672f9cd 100644 --- a/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php +++ b/src/view/form/control/tokenizer/AphrontFormTokenizerControl.php @@ -105,6 +105,7 @@ final class AphrontFormTokenizerControl extends AphrontFormControl { $map = array( 'users' => 'Type a user name...', + 'usersorprojects' => 'Type a user or project name...', 'searchowner' => 'Type a user name...', 'accounts' => 'Type a user name...', 'mailable' => 'Type a user or mailing list...',