mirror of
https://github.com/nextcloud/server.git
synced 2026-02-19 02:38:40 -05:00
fix: rebased the branch with master and resolved conflicts
fix: added a new endpoint users/recent and getting users based on last login info in the same. Reverted old code that was breaking LDAP Signed-off-by: yemkareems <yemkareems@gmail.com>
This commit is contained in:
parent
76c875a588
commit
4cb85f7c9e
10 changed files with 183 additions and 41 deletions
|
|
@ -28,6 +28,7 @@ return [
|
|||
['root' => '/cloud', 'name' => 'Users#getUsers', 'url' => '/users', 'verb' => 'GET'],
|
||||
['root' => '/cloud', 'name' => 'Users#getUsersDetails', 'url' => '/users/details', 'verb' => 'GET'],
|
||||
['root' => '/cloud', 'name' => 'Users#getDisabledUsersDetails', 'url' => '/users/disabled', 'verb' => 'GET'],
|
||||
['root' => '/cloud', 'name' => 'Users#getLastLoggedInUsers', 'url' => '/users/recent', 'verb' => 'GET'],
|
||||
['root' => '/cloud', 'name' => 'Users#searchByPhoneNumbers', 'url' => '/users/search/by-phone', 'verb' => 'POST'],
|
||||
['root' => '/cloud', 'name' => 'Users#addUser', 'url' => '/users', 'verb' => 'POST'],
|
||||
['root' => '/cloud', 'name' => 'Users#getUser', 'url' => '/users/{userId}', 'verb' => 'GET'],
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ class UsersController extends AUserData {
|
|||
*
|
||||
* 200: Users returned
|
||||
*/
|
||||
public function getUsers(string $search = '', ?int $limit = null, int $offset = 0, string $sortMode = 'uid', string $sortOrder = 'asc'): DataResponse {
|
||||
public function getUsers(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
|
||||
$user = $this->userSession->getUser();
|
||||
$users = [];
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ class UsersController extends AUserData {
|
|||
$uid = $user->getUID();
|
||||
$subAdminManager = $this->groupManager->getSubAdmin();
|
||||
if ($this->groupManager->isAdmin($uid)) {
|
||||
$users = $this->userManager->search($search, $limit, $offset, $sortMode, $sortOrder);
|
||||
$users = $this->userManager->search($search, $limit, $offset);
|
||||
} elseif ($subAdminManager->isSubAdmin($user)) {
|
||||
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($user);
|
||||
foreach ($subAdminOfGroups as $key => $group) {
|
||||
|
|
@ -131,13 +131,11 @@ class UsersController extends AUserData {
|
|||
* @param string $search Text to search for
|
||||
* @param int|null $limit Limit the amount of groups returned
|
||||
* @param int $offset Offset for searching for groups
|
||||
* @param string $sortMode Field to order the results with
|
||||
* @param string $sortOrder asc or desc
|
||||
* @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
|
||||
*
|
||||
* 200: Users details returned
|
||||
*/
|
||||
public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0, string $sortMode = 'uid', string $sortOrder = 'asc'): DataResponse {
|
||||
public function getUsersDetails(string $search = '', ?int $limit = null, int $offset = 0): DataResponse {
|
||||
$currentUser = $this->userSession->getUser();
|
||||
$users = [];
|
||||
|
||||
|
|
@ -145,7 +143,7 @@ class UsersController extends AUserData {
|
|||
$uid = $currentUser->getUID();
|
||||
$subAdminManager = $this->groupManager->getSubAdmin();
|
||||
if ($this->groupManager->isAdmin($uid)) {
|
||||
$users = $this->userManager->search($search, $limit, $offset, $sortMode, $sortOrder);
|
||||
$users = $this->userManager->search($search, $limit, $offset);
|
||||
$users = array_keys($users);
|
||||
} elseif ($subAdminManager->isSubAdmin($currentUser)) {
|
||||
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
|
||||
|
|
@ -155,7 +153,7 @@ class UsersController extends AUserData {
|
|||
|
||||
$users = [];
|
||||
foreach ($subAdminOfGroups as $group) {
|
||||
$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset, $sortMode, $sortOrder));
|
||||
$users[] = array_keys($this->groupManager->displayNamesInGroup($group, $search, $limit, $offset));
|
||||
}
|
||||
$users = array_merge(...$users);
|
||||
}
|
||||
|
|
@ -267,6 +265,96 @@ class UsersController extends AUserData {
|
|||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
* @NoCSRFRequired
|
||||
*
|
||||
* Get the list of disabled users and their details
|
||||
*
|
||||
* @param string $search Text to search for
|
||||
* @param ?int $limit Limit the amount of users returned
|
||||
* @param int $offset Offset
|
||||
* @param string $sortMode Field to order the results with
|
||||
* @param string $sortOrder asc or desc
|
||||
* @return DataResponse<Http::STATUS_OK, array{users: array<string, Provisioning_APIUserDetails|array{id: string}>}, array{}>
|
||||
*
|
||||
* 200: Users details returned based on last logged in information
|
||||
*/
|
||||
public function getLastLoggedInUsers(string $search = '',
|
||||
?int $limit = null,
|
||||
int $offset = 0,
|
||||
string $sortMode = 'lastLogin',
|
||||
string $sortOrder = 'desc'
|
||||
): DataResponse {
|
||||
$currentUser = $this->userSession->getUser();
|
||||
if ($currentUser === null) {
|
||||
return new DataResponse(['users' => []]);
|
||||
}
|
||||
if ($limit !== null && $limit < 0) {
|
||||
throw new InvalidArgumentException("Invalid limit value: $limit");
|
||||
}
|
||||
if ($offset < 0) {
|
||||
throw new InvalidArgumentException("Invalid offset value: $offset");
|
||||
}
|
||||
|
||||
$users = [];
|
||||
|
||||
// Admin? Or SubAdmin?
|
||||
$uid = $currentUser->getUID();
|
||||
$subAdminManager = $this->groupManager->getSubAdmin();
|
||||
if ($this->groupManager->isAdmin($uid)) {
|
||||
$users = $this->userManager->getUsersSortedByLastLogin($limit, $offset, $search, $sortMode, $sortOrder);
|
||||
$users = array_map(fn (IUser $user): string => $user->getUID(), $users);
|
||||
} elseif ($subAdminManager->isSubAdmin($currentUser)) {
|
||||
$subAdminOfGroups = $subAdminManager->getSubAdminsGroups($currentUser);
|
||||
|
||||
$users = [];
|
||||
/* We have to handle offset ourselve for correctness */
|
||||
$tempLimit = ($limit === null ? null : $limit + $offset);
|
||||
foreach ($subAdminOfGroups as $group) {
|
||||
$users = array_merge(
|
||||
$users,
|
||||
array_map(
|
||||
fn (IUser $user): string => $user->getUID(),
|
||||
array_filter(
|
||||
$group->searchUsers($search, ($tempLimit === null ? null : $tempLimit - count($users))),
|
||||
fn (IUser $user): bool => !$user->isEnabled()
|
||||
)
|
||||
)
|
||||
);
|
||||
if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
$users = array_slice($users, $offset);
|
||||
}
|
||||
|
||||
$usersDetails = [];
|
||||
foreach ($users as $userId) {
|
||||
try {
|
||||
$userData = $this->getUserData($userId);
|
||||
} catch (OCSNotFoundException $e) {
|
||||
// We still want to return all other accounts, but this one was removed from the backends
|
||||
// yet they are still in our database. Might be a LDAP remnant.
|
||||
$userData = null;
|
||||
$this->logger->warning('Found one disabled account that was removed from its backend, but still exists in Nextcloud database', ['accountId' => $userId]);
|
||||
}
|
||||
// Do not insert empty entry
|
||||
if ($userData !== null) {
|
||||
$usersDetails[$userId] = $userData;
|
||||
} else {
|
||||
// Currently logged in user does not have permissions to see this user
|
||||
// only showing its id
|
||||
$usersDetails[$userId] = ['id' => $userId];
|
||||
}
|
||||
}
|
||||
|
||||
return new DataResponse([
|
||||
'users' => $usersDetails
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @NoAdminRequired
|
||||
|
|
|
|||
|
|
@ -491,6 +491,49 @@ class AllConfig implements IConfig {
|
|||
return $userIDs;
|
||||
}
|
||||
|
||||
public function getLastLoggedInUsers($search, $sortMode, $sortOrder): array {
|
||||
// TODO - FIXME
|
||||
$this->fixDIInit();
|
||||
|
||||
$query = $this->connection->getQueryBuilder();
|
||||
|
||||
if ($sortMode === 'lastLogin') {
|
||||
$lastLoginSubSelect = $this->connection->getQueryBuilder();
|
||||
$lastLoginSubSelect->select('configvalue')
|
||||
->from('preferences', 'p2')
|
||||
->where($lastLoginSubSelect->expr()->andX(
|
||||
$lastLoginSubSelect->expr()->eq('p2.userid', 'uid'),
|
||||
$lastLoginSubSelect->expr()->eq('p2.appid', $lastLoginSubSelect->expr()->literal('login')),
|
||||
$lastLoginSubSelect->expr()->eq('p2.configkey', $lastLoginSubSelect->expr()->literal('lastLogin')),
|
||||
));
|
||||
$orderByExpression = $query->createFunction('(' . $lastLoginSubSelect->getSQL() .')');
|
||||
} else {
|
||||
$orderByExpression = $query->func()->lower('displayname');
|
||||
}
|
||||
|
||||
$query->select('uid', 'displayname', $orderByExpression)
|
||||
->from('users', 'u')
|
||||
->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
|
||||
$query->expr()->eq('userid', 'uid'),
|
||||
$query->expr()->eq('appid', $query->expr()->literal('settings')),
|
||||
$query->expr()->eq('configkey', $query->expr()->literal('email')))
|
||||
)
|
||||
// sqlite doesn't like re-using a single named parameter here
|
||||
->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->connection->escapeLikeParameter($search) . '%')))
|
||||
->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->connection->escapeLikeParameter($search) . '%')))
|
||||
->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->connection->escapeLikeParameter($search) . '%')))
|
||||
->orderBy($orderByExpression, $sortOrder)
|
||||
->addOrderBy('uid_lower', 'ASC');
|
||||
|
||||
$result = $query->executeQuery();
|
||||
$displayNames = [];
|
||||
while ($row = $result->fetch()) {
|
||||
$displayNames[(string)$row['uid']] = (string)$row['uid'];
|
||||
}
|
||||
|
||||
return $displayNames;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the users that have the given value set for a specific app-key-pair
|
||||
*
|
||||
|
|
|
|||
|
|
@ -401,7 +401,7 @@ class Manager extends PublicEmitter implements IGroupManager {
|
|||
* @param int $offset
|
||||
* @return array an array of display names (value) and user ids (key)
|
||||
*/
|
||||
public function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0, $sortMode = 'uid', $sortOrder = 'asc') {
|
||||
public function displayNamesInGroup($gid, $search = '', $limit = -1, $offset = 0) {
|
||||
$group = $this->get($gid);
|
||||
if (is_null($group)) {
|
||||
return [];
|
||||
|
|
@ -419,7 +419,7 @@ class Manager extends PublicEmitter implements IGroupManager {
|
|||
}
|
||||
|
||||
do {
|
||||
$filteredUsers = $this->userManager->searchDisplayName($search, $searchLimit, $searchOffset, $sortMode, $sortOrder);
|
||||
$filteredUsers = $this->userManager->searchDisplayName($search, $searchLimit, $searchOffset);
|
||||
foreach ($filteredUsers as $filteredUser) {
|
||||
if ($group->inGroup($filteredUser)) {
|
||||
$groupUsers[] = $filteredUser;
|
||||
|
|
|
|||
|
|
@ -89,11 +89,9 @@ abstract class Backend implements UserInterface {
|
|||
* @param string $search
|
||||
* @param null|int $limit
|
||||
* @param null|int $offset
|
||||
* @param string $sortMode
|
||||
* @param string $sortOrder
|
||||
* @return string[] an array of all uids
|
||||
*/
|
||||
public function getUsers($search = '', $limit = null, $offset = null, string $sortMode = 'uid', string $sortOrder = 'asc') {
|
||||
public function getUsers($search = '', $limit = null, $offset = null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
|
@ -130,11 +128,9 @@ abstract class Backend implements UserInterface {
|
|||
* @param string $search
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @param string $sortMode
|
||||
* @param string $sortOrder
|
||||
* @return array an array of all displayNames (value) and the corresponding uids (key)
|
||||
*/
|
||||
public function getDisplayNames($search = '', $limit = null, $offset = null, string $sortMode = 'uid', string $sortOrder = 'asc'): array {
|
||||
public function getDisplayNames($search = '', $limit = null, $offset = null) {
|
||||
$displayNames = [];
|
||||
$users = $this->getUsers($search, $limit, $offset);
|
||||
foreach ($users as $user) {
|
||||
|
|
|
|||
|
|
@ -227,32 +227,16 @@ class Database extends ABackend implements
|
|||
* @param string $search
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @param string $sortMode
|
||||
* @param string $sortOrder
|
||||
* @return array an array of all displayNames (value) and the corresponding uids (key)
|
||||
*/
|
||||
public function getDisplayNames($search = '', $limit = null, $offset = null, string $sortMode = 'uid', string $sortOrder = 'asc'): array {
|
||||
public function getDisplayNames($search = '', $limit = null, $offset = null) {
|
||||
$limit = $this->fixLimit($limit);
|
||||
|
||||
$this->fixDI();
|
||||
|
||||
$query = $this->dbConn->getQueryBuilder();
|
||||
|
||||
if ($sortMode === 'lastLogin') {
|
||||
$lastLoginSubSelect = $this->dbConn->getQueryBuilder();
|
||||
$lastLoginSubSelect->select('configvalue')
|
||||
->from('preferences', 'p2')
|
||||
->where($lastLoginSubSelect->expr()->andX(
|
||||
$lastLoginSubSelect->expr()->eq('p2.userid', 'uid'),
|
||||
$lastLoginSubSelect->expr()->eq('p2.appid', $lastLoginSubSelect->expr()->literal('login')),
|
||||
$lastLoginSubSelect->expr()->eq('p2.configkey', $lastLoginSubSelect->expr()->literal('lastLogin')),
|
||||
));
|
||||
$orderByExpression = $query->createFunction('(' . $lastLoginSubSelect->getSQL() .')');
|
||||
} else {
|
||||
$orderByExpression = $query->func()->lower('displayname');
|
||||
}
|
||||
|
||||
$query->select('uid', 'displayname', $orderByExpression)
|
||||
$query->select('uid', 'displayname')
|
||||
->from($this->table, 'u')
|
||||
->leftJoin('u', 'preferences', 'p', $query->expr()->andX(
|
||||
$query->expr()->eq('userid', 'uid'),
|
||||
|
|
@ -263,7 +247,7 @@ class Database extends ABackend implements
|
|||
->where($query->expr()->iLike('uid', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
|
||||
->orWhere($query->expr()->iLike('displayname', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
|
||||
->orWhere($query->expr()->iLike('configvalue', $query->createPositionalParameter('%' . $this->dbConn->escapeLikeParameter($search) . '%')))
|
||||
->orderBy($orderByExpression, $sortOrder)
|
||||
->orderBy($query->func()->lower('displayname'), 'ASC')
|
||||
->addOrderBy('uid_lower', 'ASC')
|
||||
->setMaxResults($limit)
|
||||
->setFirstResult($offset);
|
||||
|
|
@ -397,13 +381,15 @@ class Database extends ABackend implements
|
|||
* @param null|int $offset
|
||||
* @return string[] an array of all uids
|
||||
*/
|
||||
public function getUsers($search = '', $limit = null, $offset = null, $orderBy = 'lastLogin', $sort = 'DESC'): array {
|
||||
public function getUsers($search = '', $limit = null, $offset = null) {
|
||||
$limit = $this->fixLimit($limit);
|
||||
|
||||
$users = $this->getDisplayNames($search, $limit, $offset, $orderBy, $sort);
|
||||
return array_map(function ($uid) {
|
||||
$users = $this->getDisplayNames($search, $limit, $offset);
|
||||
$userIds = array_map(function ($uid) {
|
||||
return (string)$uid;
|
||||
}, array_keys($users));
|
||||
sort($userIds, SORT_STRING | SORT_FLAG_CASE);
|
||||
return $userIds;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -402,6 +402,33 @@ class Manager extends PublicEmitter implements IUserManager {
|
|||
return array_slice($users, $offset, $limit);
|
||||
}
|
||||
|
||||
public function getUsersSortedByLastLogin(?int $limit = null, int $offset = 0, $search = '', $sortMode = 'lastLogin', $sortOrder = 'desc'): array {
|
||||
$users = $this->config->getLastLoggedInUsers($search, $sortMode, $sortOrder);
|
||||
$users = array_combine(
|
||||
$users,
|
||||
array_map(
|
||||
fn (string $uid): IUser => new LazyUser($uid, $this),
|
||||
$users
|
||||
)
|
||||
);
|
||||
|
||||
$tempLimit = ($limit === null ? null : $limit + $offset);
|
||||
foreach ($this->backends as $backend) {
|
||||
if (($tempLimit !== null) && (count($users) >= $tempLimit)) {
|
||||
break;
|
||||
}
|
||||
if ($backend instanceof IProvideEnabledStateBackend) {
|
||||
$backendUsers = $backend->getDisabledUserList(($tempLimit === null ? null : $tempLimit - count($users)));
|
||||
foreach ($backendUsers as $uid) {
|
||||
$users[$uid] = new LazyUser($uid, $this, null, $backend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_slice($users, $offset, $limit);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Search known users (from phonebook sync) by displayName
|
||||
*
|
||||
|
|
|
|||
|
|
@ -249,4 +249,6 @@ interface IConfig {
|
|||
* @since 8.0.0
|
||||
*/
|
||||
public function getUsersForUserValue($appName, $key, $value);
|
||||
|
||||
public function getLastLoggedInUsers($search, $sortMode, $sortOrder);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ interface IUserManager {
|
|||
*/
|
||||
public function getDisabledUsers(?int $limit = null, int $offset = 0, string $search = ''): array;
|
||||
|
||||
public function getUsersSortedByLastLogin(?int $limit = null, int $offset = 0, $search = '', $sortMode = 'lastLogin', $sortOrder = 'desc'): array;
|
||||
/**
|
||||
* Search known users (from phonebook sync) by displayName
|
||||
*
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ interface UserInterface {
|
|||
* @return string[] an array of all uids
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function getUsers($search = '', $limit = null, $offset = null, string $sortMode = 'uid', string $sortOrder = 'asc');
|
||||
public function getUsers($search = '', $limit = null, $offset = null);
|
||||
|
||||
/**
|
||||
* check if a user exists
|
||||
|
|
@ -69,12 +69,10 @@ interface UserInterface {
|
|||
* @param string $search
|
||||
* @param int|null $limit
|
||||
* @param int|null $offset
|
||||
* @param string $sortMode
|
||||
* @param string $sortOrder
|
||||
* @return array an array of all displayNames (value) and the corresponding uids (key)
|
||||
* @since 4.5.0
|
||||
*/
|
||||
public function getDisplayNames($search = '', $limit = null, $offset = null, string $sortMode = 'uid', string $sortOrder = 'asc');
|
||||
public function getDisplayNames($search = '', $limit = null, $offset = null);
|
||||
|
||||
/**
|
||||
* Check if a user list is available or not
|
||||
|
|
|
|||
Loading…
Reference in a new issue