2012-05-07 22:35:09 +02:00
|
|
|
<?php
|
|
|
|
|
2013-05-31 19:51:20 +02:00
|
|
|
final class PhabricatorPeopleQuery
|
|
|
|
extends PhabricatorCursorPagedPolicyAwareQuery {
|
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
private $usernames;
|
|
|
|
private $realnames;
|
|
|
|
private $emails;
|
|
|
|
private $phids;
|
|
|
|
private $ids;
|
2013-05-31 19:51:20 +02:00
|
|
|
private $dateCreatedAfter;
|
|
|
|
private $dateCreatedBefore;
|
|
|
|
private $isAdmin;
|
|
|
|
private $isSystemAgent;
|
|
|
|
private $isDisabled;
|
2013-11-13 20:24:18 +01:00
|
|
|
private $isApproved;
|
2013-05-31 19:51:20 +02:00
|
|
|
private $nameLike;
|
2012-05-07 22:35:09 +02:00
|
|
|
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
private $needPrimaryEmail;
|
2013-03-24 14:42:31 +01:00
|
|
|
private $needProfile;
|
|
|
|
private $needProfileImage;
|
2013-07-26 23:05:19 +02:00
|
|
|
private $needStatus;
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
|
2013-05-31 19:51:20 +02:00
|
|
|
public function withIDs(array $ids) {
|
2012-05-07 22:35:09 +02:00
|
|
|
$this->ids = $ids;
|
|
|
|
return $this;
|
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
|
|
|
public function withPHIDs(array $phids) {
|
2012-05-07 22:35:09 +02:00
|
|
|
$this->phids = $phids;
|
|
|
|
return $this;
|
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
public function withEmails(array $emails) {
|
|
|
|
$this->emails = $emails;
|
|
|
|
return $this;
|
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
public function withRealnames(array $realnames) {
|
|
|
|
$this->realnames = $realnames;
|
|
|
|
return $this;
|
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
public function withUsernames(array $usernames) {
|
|
|
|
$this->usernames = $usernames;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-05-31 19:51:20 +02:00
|
|
|
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 withIsAdmin($admin) {
|
|
|
|
$this->isAdmin = $admin;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function withIsSystemAgent($system_agent) {
|
|
|
|
$this->isSystemAgent = $system_agent;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function withIsDisabled($disabled) {
|
|
|
|
$this->isDisabled = $disabled;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-11-13 20:24:18 +01:00
|
|
|
public function withIsApproved($approved) {
|
|
|
|
$this->isApproved = $approved;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-05-31 19:51:20 +02:00
|
|
|
public function withNameLike($like) {
|
|
|
|
$this->nameLike = $like;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
public function needPrimaryEmail($need) {
|
|
|
|
$this->needPrimaryEmail = $need;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-03-24 14:42:31 +01:00
|
|
|
public function needProfile($need) {
|
|
|
|
$this->needProfile = $need;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
|
|
|
public function needProfileImage($need) {
|
|
|
|
$this->needProfileImage = $need;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2013-07-26 23:05:19 +02:00
|
|
|
public function needStatus($need) {
|
|
|
|
$this->needStatus = $need;
|
|
|
|
return $this;
|
|
|
|
}
|
|
|
|
|
2015-01-13 20:56:07 +01:00
|
|
|
protected function loadPage() {
|
2012-05-07 22:35:09 +02:00
|
|
|
$table = new PhabricatorUser();
|
|
|
|
$conn_r = $table->establishConnection('r');
|
|
|
|
|
|
|
|
$data = queryfx_all(
|
|
|
|
$conn_r,
|
Integrate ApplicationSearch with CustomField
Summary:
Ref T2625. Ref T3794. Ref T418. Ref T1703.
This is a more general version of D5278. It expands CustomField support to include real integration with ApplicationSearch.
Broadly, custom fields may elect to:
- build indicies when objects are updated;
- populate ApplicationSearch forms with new controls;
- read inputs entered into those controls out of the request; and
- apply constraints to search queries.
Some utility/helper stuff is provided to make this easier. This part could be cleaner, but seems reasonable for a first cut. In particular, the Query and SearchEngine must manually call all the hooks right now instead of everything happening magically. I think that's fine for the moment; they're pretty easy to get right.
Test Plan:
I added a new searchable "Company" field to People:
{F58229}
This also cleaned up the disable/reorder view a little bit:
{F58230}
As it did before, this field appears on the edit screen:
{F58231}
However, because it has `search`, it also appears on the search screen:
{F58232}
When queried, it returns the expected results:
{F58233}
And the actually good bit of all this is that the query can take advantage of indexes:
mysql> explain SELECT * FROM `user` user JOIN `user_customfieldstringindex` `appsearch_0` ON `appsearch_0`.objectPHID = user.phid AND `appsearch_0`.indexKey = 'mk3Ndy476ge6' AND `appsearch_0`.indexValue IN ('phacility') ORDER BY user.id DESC LIMIT 101;
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | appsearch_0 | ref | key_join,key_find | key_find | 232 | const,const | 1 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | user | eq_ref | phid | phid | 194 | phabricator2_user.appsearch_0.objectPHID | 1 | |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T418, T1703, T2625, T3794
Differential Revision: https://secure.phabricator.com/D6992
2013-09-16 22:44:34 +02:00
|
|
|
'SELECT * FROM %T user %Q %Q %Q %Q %Q',
|
2012-05-07 22:35:09 +02:00
|
|
|
$table->getTableName(),
|
2013-05-31 19:51:20 +02:00
|
|
|
$this->buildJoinsClause($conn_r),
|
|
|
|
$this->buildWhereClause($conn_r),
|
Integrate ApplicationSearch with CustomField
Summary:
Ref T2625. Ref T3794. Ref T418. Ref T1703.
This is a more general version of D5278. It expands CustomField support to include real integration with ApplicationSearch.
Broadly, custom fields may elect to:
- build indicies when objects are updated;
- populate ApplicationSearch forms with new controls;
- read inputs entered into those controls out of the request; and
- apply constraints to search queries.
Some utility/helper stuff is provided to make this easier. This part could be cleaner, but seems reasonable for a first cut. In particular, the Query and SearchEngine must manually call all the hooks right now instead of everything happening magically. I think that's fine for the moment; they're pretty easy to get right.
Test Plan:
I added a new searchable "Company" field to People:
{F58229}
This also cleaned up the disable/reorder view a little bit:
{F58230}
As it did before, this field appears on the edit screen:
{F58231}
However, because it has `search`, it also appears on the search screen:
{F58232}
When queried, it returns the expected results:
{F58233}
And the actually good bit of all this is that the query can take advantage of indexes:
mysql> explain SELECT * FROM `user` user JOIN `user_customfieldstringindex` `appsearch_0` ON `appsearch_0`.objectPHID = user.phid AND `appsearch_0`.indexKey = 'mk3Ndy476ge6' AND `appsearch_0`.indexValue IN ('phacility') ORDER BY user.id DESC LIMIT 101;
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | appsearch_0 | ref | key_join,key_find | key_find | 232 | const,const | 1 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | user | eq_ref | phid | phid | 194 | phabricator2_user.appsearch_0.objectPHID | 1 | |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T418, T1703, T2625, T3794
Differential Revision: https://secure.phabricator.com/D6992
2013-09-16 22:44:34 +02:00
|
|
|
$this->buildApplicationSearchGroupClause($conn_r),
|
2013-09-17 01:04:46 +02:00
|
|
|
$this->buildOrderClause($conn_r),
|
2013-05-31 19:51:20 +02:00
|
|
|
$this->buildLimitClause($conn_r));
|
2012-05-07 22:35:09 +02:00
|
|
|
|
2012-05-25 22:11:33 +02:00
|
|
|
if ($this->needPrimaryEmail) {
|
|
|
|
$table->putInSet(new LiskDAOSet());
|
Allow installs to require email verification
Summary:
Allow installs to require users to verify email addresses before they can use Phabricator. If a user logs in without a verified email address, they're given instructions to verify their address.
This isn't too useful on its own since we don't actually have arbitrary email registration, but the next step is to allow installs to restrict email to only some domains (e.g., @mycompany.com).
Test Plan:
- Verification
- Set verification requirement to `true`.
- Tried to use Phabricator with an unverified account, was told to verify.
- Tried to use Conduit, was given a verification error.
- Verified account, used Phabricator.
- Unverified account, reset password, verified implicit verification, used Phabricator.
- People Admin Interface
- Viewed as admin. Clicked "Administrate User".
- Viewed as non-admin
- Sanity Checks
- Used Conduit normally from web/CLI with a verified account.
- Logged in/out.
- Sent password reset email.
- Created a new user.
- Logged in with an unverified user but with the configuration set to off.
Reviewers: btrahan, vrana, jungejason
Reviewed By: btrahan
CC: aran, csilvers
Maniphest Tasks: T1184
Differential Revision: https://secure.phabricator.com/D2520
2012-05-21 21:47:38 +02:00
|
|
|
}
|
|
|
|
|
Fix some file policy issues and add a "Query Workspace"
Summary:
Ref T603. Several issues here:
1. Currently, `FileQuery` does not actually respect object attachment edges when doing policy checks. Everything else works fine, but this was missing an `array_keys()`.
2. Once that's fixed, we hit a bunch of recursion issues. For example, when loading a User we load the profile picture, and then that loads the User, and that loads the profile picture, etc.
3. Introduce a "Query Workspace", which holds objects we know we've loaded and know we can see but haven't finished filtering and/or attaching data to. This allows subqueries to look up objects instead of querying for them.
- We can probably generalize this a bit to make a few other queries more efficient. Pholio currently has a similar (but less general) "mock cache". However, it's keyed by ID instead of PHID so it's not easy to reuse this right now.
This is a bit complex for the problem being solved, but I think it's the cleanest approach and I believe the primitive will be useful in the future.
Test Plan: Looked at pastes, macros, mocks and projects as a logged-in and logged-out user.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T603
Differential Revision: https://secure.phabricator.com/D7309
2013-10-14 23:36:06 +02:00
|
|
|
return $table->loadAllFromArray($data);
|
|
|
|
}
|
2013-03-24 14:42:31 +01:00
|
|
|
|
Fix some file policy issues and add a "Query Workspace"
Summary:
Ref T603. Several issues here:
1. Currently, `FileQuery` does not actually respect object attachment edges when doing policy checks. Everything else works fine, but this was missing an `array_keys()`.
2. Once that's fixed, we hit a bunch of recursion issues. For example, when loading a User we load the profile picture, and then that loads the User, and that loads the profile picture, etc.
3. Introduce a "Query Workspace", which holds objects we know we've loaded and know we can see but haven't finished filtering and/or attaching data to. This allows subqueries to look up objects instead of querying for them.
- We can probably generalize this a bit to make a few other queries more efficient. Pholio currently has a similar (but less general) "mock cache". However, it's keyed by ID instead of PHID so it's not easy to reuse this right now.
This is a bit complex for the problem being solved, but I think it's the cleanest approach and I believe the primitive will be useful in the future.
Test Plan: Looked at pastes, macros, mocks and projects as a logged-in and logged-out user.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T603
Differential Revision: https://secure.phabricator.com/D7309
2013-10-14 23:36:06 +02:00
|
|
|
protected function didFilterPage(array $users) {
|
2013-03-24 14:42:31 +01:00
|
|
|
if ($this->needProfile) {
|
|
|
|
$user_list = mpull($users, null, 'getPHID');
|
|
|
|
$profiles = new PhabricatorUserProfile();
|
|
|
|
$profiles = $profiles->loadAllWhere('userPHID IN (%Ls)',
|
|
|
|
array_keys($user_list));
|
|
|
|
|
|
|
|
$profiles = mpull($profiles, null, 'getUserPHID');
|
|
|
|
foreach ($user_list as $user_phid => $user) {
|
|
|
|
$profile = idx($profiles, $user_phid);
|
|
|
|
if (!$profile) {
|
|
|
|
$profile = new PhabricatorUserProfile();
|
|
|
|
$profile->setUserPHID($user_phid);
|
|
|
|
}
|
|
|
|
|
|
|
|
$user->attachUserProfile($profile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->needProfileImage) {
|
2013-09-08 18:43:27 +02:00
|
|
|
$user_profile_file_phids = mpull($users, 'getProfileImagePHID');
|
|
|
|
$user_profile_file_phids = array_filter($user_profile_file_phids);
|
|
|
|
if ($user_profile_file_phids) {
|
|
|
|
$files = id(new PhabricatorFileQuery())
|
Fix some file policy issues and add a "Query Workspace"
Summary:
Ref T603. Several issues here:
1. Currently, `FileQuery` does not actually respect object attachment edges when doing policy checks. Everything else works fine, but this was missing an `array_keys()`.
2. Once that's fixed, we hit a bunch of recursion issues. For example, when loading a User we load the profile picture, and then that loads the User, and that loads the profile picture, etc.
3. Introduce a "Query Workspace", which holds objects we know we've loaded and know we can see but haven't finished filtering and/or attaching data to. This allows subqueries to look up objects instead of querying for them.
- We can probably generalize this a bit to make a few other queries more efficient. Pholio currently has a similar (but less general) "mock cache". However, it's keyed by ID instead of PHID so it's not easy to reuse this right now.
This is a bit complex for the problem being solved, but I think it's the cleanest approach and I believe the primitive will be useful in the future.
Test Plan: Looked at pastes, macros, mocks and projects as a logged-in and logged-out user.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T603
Differential Revision: https://secure.phabricator.com/D7309
2013-10-14 23:36:06 +02:00
|
|
|
->setParentQuery($this)
|
2013-09-08 18:43:27 +02:00
|
|
|
->setViewer($this->getViewer())
|
|
|
|
->withPHIDs($user_profile_file_phids)
|
|
|
|
->execute();
|
|
|
|
$files = mpull($files, null, 'getPHID');
|
|
|
|
} else {
|
|
|
|
$files = array();
|
|
|
|
}
|
2013-03-24 14:42:31 +01:00
|
|
|
foreach ($users as $user) {
|
|
|
|
$image_phid = $user->getProfileImagePHID();
|
|
|
|
if (isset($files[$image_phid])) {
|
|
|
|
$profile_image_uri = $files[$image_phid]->getBestURI();
|
|
|
|
} else {
|
|
|
|
$profile_image_uri = PhabricatorUser::getDefaultProfileImageURI();
|
|
|
|
}
|
|
|
|
$user->attachProfileImageURI($profile_image_uri);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-26 23:05:19 +02:00
|
|
|
if ($this->needStatus) {
|
|
|
|
$user_list = mpull($users, null, 'getPHID');
|
2014-02-06 19:07:29 +01:00
|
|
|
$statuses = id(new PhabricatorCalendarEvent())->loadCurrentStatuses(
|
2013-07-26 23:05:19 +02:00
|
|
|
array_keys($user_list));
|
|
|
|
foreach ($user_list as $phid => $user) {
|
|
|
|
$status = idx($statuses, $phid);
|
|
|
|
if ($status) {
|
|
|
|
$user->attachStatus($status);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
return $users;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildJoinsClause($conn_r) {
|
|
|
|
$joins = array();
|
|
|
|
|
|
|
|
if ($this->emails) {
|
|
|
|
$email_table = new PhabricatorUserEmail();
|
|
|
|
$joins[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'JOIN %T email ON email.userPHID = user.PHID',
|
|
|
|
$email_table->getTableName());
|
|
|
|
}
|
|
|
|
|
Integrate ApplicationSearch with CustomField
Summary:
Ref T2625. Ref T3794. Ref T418. Ref T1703.
This is a more general version of D5278. It expands CustomField support to include real integration with ApplicationSearch.
Broadly, custom fields may elect to:
- build indicies when objects are updated;
- populate ApplicationSearch forms with new controls;
- read inputs entered into those controls out of the request; and
- apply constraints to search queries.
Some utility/helper stuff is provided to make this easier. This part could be cleaner, but seems reasonable for a first cut. In particular, the Query and SearchEngine must manually call all the hooks right now instead of everything happening magically. I think that's fine for the moment; they're pretty easy to get right.
Test Plan:
I added a new searchable "Company" field to People:
{F58229}
This also cleaned up the disable/reorder view a little bit:
{F58230}
As it did before, this field appears on the edit screen:
{F58231}
However, because it has `search`, it also appears on the search screen:
{F58232}
When queried, it returns the expected results:
{F58233}
And the actually good bit of all this is that the query can take advantage of indexes:
mysql> explain SELECT * FROM `user` user JOIN `user_customfieldstringindex` `appsearch_0` ON `appsearch_0`.objectPHID = user.phid AND `appsearch_0`.indexKey = 'mk3Ndy476ge6' AND `appsearch_0`.indexValue IN ('phacility') ORDER BY user.id DESC LIMIT 101;
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | appsearch_0 | ref | key_join,key_find | key_find | 232 | const,const | 1 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | user | eq_ref | phid | phid | 194 | phabricator2_user.appsearch_0.objectPHID | 1 | |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T418, T1703, T2625, T3794
Differential Revision: https://secure.phabricator.com/D6992
2013-09-16 22:44:34 +02:00
|
|
|
$joins[] = $this->buildApplicationSearchJoinClause($conn_r);
|
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
$joins = implode(' ', $joins);
|
|
|
|
return $joins;
|
|
|
|
}
|
|
|
|
|
|
|
|
private function buildWhereClause($conn_r) {
|
|
|
|
$where = array();
|
|
|
|
|
2014-05-20 17:26:55 +02:00
|
|
|
if ($this->usernames !== null) {
|
2013-05-31 19:51:20 +02:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.userName IN (%Ls)',
|
|
|
|
$this->usernames);
|
2012-05-07 22:35:09 +02:00
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2014-05-20 17:26:55 +02:00
|
|
|
if ($this->emails !== null) {
|
2013-05-31 19:51:20 +02:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'email.address IN (%Ls)',
|
|
|
|
$this->emails);
|
2012-05-07 22:35:09 +02:00
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2014-05-20 17:26:55 +02:00
|
|
|
if ($this->realnames !== null) {
|
2013-05-31 19:51:20 +02:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.realName IN (%Ls)',
|
|
|
|
$this->realnames);
|
2012-05-07 22:35:09 +02:00
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2014-05-20 17:26:55 +02:00
|
|
|
if ($this->phids !== null) {
|
2013-05-31 19:51:20 +02:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.phid IN (%Ls)',
|
|
|
|
$this->phids);
|
2012-05-07 22:35:09 +02:00
|
|
|
}
|
2013-05-31 19:51:20 +02:00
|
|
|
|
2014-05-20 17:26:55 +02:00
|
|
|
if ($this->ids !== null) {
|
2013-05-31 19:51:20 +02:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.id IN (%Ld)',
|
|
|
|
$this->ids);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->dateCreatedAfter) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.dateCreated >= %d',
|
|
|
|
$this->dateCreatedAfter);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->dateCreatedBefore) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.dateCreated <= %d',
|
|
|
|
$this->dateCreatedBefore);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->isAdmin) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.isAdmin = 1');
|
|
|
|
}
|
|
|
|
|
2013-11-13 20:24:18 +01:00
|
|
|
if ($this->isDisabled !== null) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.isDisabled = %d',
|
|
|
|
(int)$this->isDisabled);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->isApproved !== null) {
|
2013-05-31 19:51:20 +02:00
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
2013-11-13 20:24:18 +01:00
|
|
|
'user.isApproved = %d',
|
|
|
|
(int)$this->isApproved);
|
2013-05-31 19:51:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ($this->isSystemAgent) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.isSystemAgent = 1');
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen($this->nameLike)) {
|
|
|
|
$where[] = qsprintf(
|
|
|
|
$conn_r,
|
|
|
|
'user.username LIKE %~ OR user.realname LIKE %~',
|
|
|
|
$this->nameLike,
|
|
|
|
$this->nameLike);
|
2012-05-07 22:35:09 +02:00
|
|
|
}
|
|
|
|
|
2013-09-17 01:03:09 +02:00
|
|
|
$where[] = $this->buildPagingClause($conn_r);
|
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
return $this->formatWhereClause($where);
|
|
|
|
}
|
2013-03-24 14:42:31 +01:00
|
|
|
|
2013-06-19 20:18:40 +02:00
|
|
|
protected function getPagingColumn() {
|
|
|
|
return 'user.id';
|
|
|
|
}
|
|
|
|
|
Integrate ApplicationSearch with CustomField
Summary:
Ref T2625. Ref T3794. Ref T418. Ref T1703.
This is a more general version of D5278. It expands CustomField support to include real integration with ApplicationSearch.
Broadly, custom fields may elect to:
- build indicies when objects are updated;
- populate ApplicationSearch forms with new controls;
- read inputs entered into those controls out of the request; and
- apply constraints to search queries.
Some utility/helper stuff is provided to make this easier. This part could be cleaner, but seems reasonable for a first cut. In particular, the Query and SearchEngine must manually call all the hooks right now instead of everything happening magically. I think that's fine for the moment; they're pretty easy to get right.
Test Plan:
I added a new searchable "Company" field to People:
{F58229}
This also cleaned up the disable/reorder view a little bit:
{F58230}
As it did before, this field appears on the edit screen:
{F58231}
However, because it has `search`, it also appears on the search screen:
{F58232}
When queried, it returns the expected results:
{F58233}
And the actually good bit of all this is that the query can take advantage of indexes:
mysql> explain SELECT * FROM `user` user JOIN `user_customfieldstringindex` `appsearch_0` ON `appsearch_0`.objectPHID = user.phid AND `appsearch_0`.indexKey = 'mk3Ndy476ge6' AND `appsearch_0`.indexValue IN ('phacility') ORDER BY user.id DESC LIMIT 101;
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | appsearch_0 | ref | key_join,key_find | key_find | 232 | const,const | 1 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | user | eq_ref | phid | phid | 194 | phabricator2_user.appsearch_0.objectPHID | 1 | |
+----+-------------+-------------+--------+-------------------+----------+---------+------------------------------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T418, T1703, T2625, T3794
Differential Revision: https://secure.phabricator.com/D6992
2013-09-16 22:44:34 +02:00
|
|
|
protected function getApplicationSearchObjectPHIDColumn() {
|
|
|
|
return 'user.phid';
|
|
|
|
}
|
|
|
|
|
Lock policy queries to their applications
Summary:
While we mostly have reasonable effective object accessibility when you lock a user out of an application, it's primarily enforced at the controller level. Users can still, e.g., load the handles of objects they can't actually see. Instead, lock the queries to the applications so that you can, e.g., never load a revision if you don't have access to Differential.
This has several parts:
- For PolicyAware queries, provide an application class name method.
- If the query specifies a class name and the user doesn't have permission to use it, fail the entire query unconditionally.
- For handles, simplify query construction and count all the PHIDs as "restricted" so we get a UI full of "restricted" instead of "unknown" handles.
Test Plan:
- Added a unit test to verify I got all the class names right.
- Browsed around, logged in/out as a normal user with public policies on and off.
- Browsed around, logged in/out as a restricted user with public policies on and off. With restrictions, saw all traces of restricted apps removed or restricted.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D7367
2013-10-22 02:20:27 +02:00
|
|
|
public function getQueryApplicationClass() {
|
2014-07-23 02:03:09 +02:00
|
|
|
return 'PhabricatorPeopleApplication';
|
Lock policy queries to their applications
Summary:
While we mostly have reasonable effective object accessibility when you lock a user out of an application, it's primarily enforced at the controller level. Users can still, e.g., load the handles of objects they can't actually see. Instead, lock the queries to the applications so that you can, e.g., never load a revision if you don't have access to Differential.
This has several parts:
- For PolicyAware queries, provide an application class name method.
- If the query specifies a class name and the user doesn't have permission to use it, fail the entire query unconditionally.
- For handles, simplify query construction and count all the PHIDs as "restricted" so we get a UI full of "restricted" instead of "unknown" handles.
Test Plan:
- Added a unit test to verify I got all the class names right.
- Browsed around, logged in/out as a normal user with public policies on and off.
- Browsed around, logged in/out as a restricted user with public policies on and off. With restrictions, saw all traces of restricted apps removed or restricted.
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Differential Revision: https://secure.phabricator.com/D7367
2013-10-22 02:20:27 +02:00
|
|
|
}
|
|
|
|
|
2012-05-07 22:35:09 +02:00
|
|
|
}
|