mirror of
https://github.com/element-hq/synapse.git
synced 2024-11-25 19:15:51 +03:00
Replace /admin/v1/users_paginate endpoint with /admin/v2/users (#5925)
This commit is contained in:
parent
d085a8a0a5
commit
649b6bc088
9 changed files with 162 additions and 110 deletions
1
changelog.d/5925.feature
Normal file
1
changelog.d/5925.feature
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Add admin/v2/users endpoint with pagination. Contributed by Awesome Technologies Innovationslabor GmbH.
|
1
changelog.d/5925.removal
Normal file
1
changelog.d/5925.removal
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Remove admin/v1/users_paginate endpoint. Contributed by Awesome Technologies Innovationslabor GmbH.
|
|
@ -1,3 +1,48 @@
|
||||||
|
List Accounts
|
||||||
|
=============
|
||||||
|
|
||||||
|
This API returns all local user accounts.
|
||||||
|
|
||||||
|
The api is::
|
||||||
|
|
||||||
|
GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
|
||||||
|
|
||||||
|
including an ``access_token`` of a server admin.
|
||||||
|
The parameters ``from`` and ``limit`` are required only for pagination.
|
||||||
|
By default, a ``limit`` of 100 is used.
|
||||||
|
The parameter ``user_id`` can be used to select only users with user ids that
|
||||||
|
contain this value.
|
||||||
|
The parameter ``guests=false`` can be used to exclude guest users,
|
||||||
|
default is to include guest users.
|
||||||
|
The parameter ``deactivated=true`` can be used to include deactivated users,
|
||||||
|
default is to exclude deactivated users.
|
||||||
|
If the endpoint does not return a ``next_token`` then there are no more users left.
|
||||||
|
It returns a JSON body like the following:
|
||||||
|
|
||||||
|
.. code:: json
|
||||||
|
|
||||||
|
{
|
||||||
|
"users": [
|
||||||
|
{
|
||||||
|
"name": "<user_id1>",
|
||||||
|
"password_hash": "<password_hash1>",
|
||||||
|
"is_guest": 0,
|
||||||
|
"admin": 0,
|
||||||
|
"user_type": null,
|
||||||
|
"deactivated": 0
|
||||||
|
}, {
|
||||||
|
"name": "<user_id2>",
|
||||||
|
"password_hash": "<password_hash2>",
|
||||||
|
"is_guest": 0,
|
||||||
|
"admin": 1,
|
||||||
|
"user_type": null,
|
||||||
|
"deactivated": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"next_token": "100"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Query Account
|
Query Account
|
||||||
=============
|
=============
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ class AdminHandler(BaseHandler):
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
"""Function to reterive a list of users in users table.
|
"""Function to retrieve a list of users in users table.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -67,19 +67,22 @@ class AdminHandler(BaseHandler):
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
@defer.inlineCallbacks
|
||||||
def get_users_paginate(self, order, start, limit):
|
def get_users_paginate(self, start, limit, name, guests, deactivated):
|
||||||
"""Function to reterive a paginated list of users from
|
"""Function to retrieve a paginated list of users from
|
||||||
users list. This will return a json object, which contains
|
users list. This will return a json list of users.
|
||||||
list of users and the total number of users in users table.
|
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
order (str): column name to order the select by this column
|
|
||||||
start (int): start number to begin the query from
|
start (int): start number to begin the query from
|
||||||
limit (int): number of rows to reterive
|
limit (int): number of rows to retrieve
|
||||||
|
name (string): filter for user names
|
||||||
|
guests (bool): whether to in include guest users
|
||||||
|
deactivated (bool): whether to include deactivated users
|
||||||
Returns:
|
Returns:
|
||||||
defer.Deferred: resolves to json object {list[dict[str, Any]], count}
|
defer.Deferred: resolves to json list[dict[str, Any]]
|
||||||
"""
|
"""
|
||||||
ret = yield self.store.get_users_paginate(order, start, limit)
|
ret = yield self.store.get_users_paginate(
|
||||||
|
start, limit, name, guests, deactivated
|
||||||
|
)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,12 @@ from synapse.rest.admin.server_notice_servlet import SendServerNoticeServlet
|
||||||
from synapse.rest.admin.users import (
|
from synapse.rest.admin.users import (
|
||||||
AccountValidityRenewServlet,
|
AccountValidityRenewServlet,
|
||||||
DeactivateAccountRestServlet,
|
DeactivateAccountRestServlet,
|
||||||
GetUsersPaginatedRestServlet,
|
|
||||||
ResetPasswordRestServlet,
|
ResetPasswordRestServlet,
|
||||||
SearchUsersRestServlet,
|
SearchUsersRestServlet,
|
||||||
UserAdminServlet,
|
UserAdminServlet,
|
||||||
UserRegisterServlet,
|
UserRegisterServlet,
|
||||||
UsersRestServlet,
|
UsersRestServlet,
|
||||||
|
UsersRestServletV2,
|
||||||
WhoisRestServlet,
|
WhoisRestServlet,
|
||||||
)
|
)
|
||||||
from synapse.util.versionstring import get_version_string
|
from synapse.util.versionstring import get_version_string
|
||||||
|
@ -191,6 +191,7 @@ def register_servlets(hs, http_server):
|
||||||
SendServerNoticeServlet(hs).register(http_server)
|
SendServerNoticeServlet(hs).register(http_server)
|
||||||
VersionServlet(hs).register(http_server)
|
VersionServlet(hs).register(http_server)
|
||||||
UserAdminServlet(hs).register(http_server)
|
UserAdminServlet(hs).register(http_server)
|
||||||
|
UsersRestServletV2(hs).register(http_server)
|
||||||
|
|
||||||
|
|
||||||
def register_servlets_for_client_rest_resource(hs, http_server):
|
def register_servlets_for_client_rest_resource(hs, http_server):
|
||||||
|
@ -201,7 +202,6 @@ def register_servlets_for_client_rest_resource(hs, http_server):
|
||||||
PurgeHistoryRestServlet(hs).register(http_server)
|
PurgeHistoryRestServlet(hs).register(http_server)
|
||||||
UsersRestServlet(hs).register(http_server)
|
UsersRestServlet(hs).register(http_server)
|
||||||
ResetPasswordRestServlet(hs).register(http_server)
|
ResetPasswordRestServlet(hs).register(http_server)
|
||||||
GetUsersPaginatedRestServlet(hs).register(http_server)
|
|
||||||
SearchUsersRestServlet(hs).register(http_server)
|
SearchUsersRestServlet(hs).register(http_server)
|
||||||
ShutdownRoomRestServlet(hs).register(http_server)
|
ShutdownRoomRestServlet(hs).register(http_server)
|
||||||
UserRegisterServlet(hs).register(http_server)
|
UserRegisterServlet(hs).register(http_server)
|
||||||
|
|
|
@ -25,6 +25,7 @@ from synapse.api.errors import Codes, SynapseError
|
||||||
from synapse.http.servlet import (
|
from synapse.http.servlet import (
|
||||||
RestServlet,
|
RestServlet,
|
||||||
assert_params_in_dict,
|
assert_params_in_dict,
|
||||||
|
parse_boolean,
|
||||||
parse_integer,
|
parse_integer,
|
||||||
parse_json_object_from_request,
|
parse_json_object_from_request,
|
||||||
parse_string,
|
parse_string,
|
||||||
|
@ -59,71 +60,45 @@ class UsersRestServlet(RestServlet):
|
||||||
return 200, ret
|
return 200, ret
|
||||||
|
|
||||||
|
|
||||||
class GetUsersPaginatedRestServlet(RestServlet):
|
class UsersRestServletV2(RestServlet):
|
||||||
"""Get request to get specific number of users from Synapse.
|
PATTERNS = (re.compile("^/_synapse/admin/v2/users$"),)
|
||||||
This needs user to have administrator access in Synapse.
|
|
||||||
Example:
|
|
||||||
http://localhost:8008/_synapse/admin/v1/users_paginate/
|
|
||||||
@admin:user?access_token=admin_access_token&start=0&limit=10
|
|
||||||
Returns:
|
|
||||||
200 OK with json object {list[dict[str, Any]], count} or empty object.
|
|
||||||
"""
|
|
||||||
|
|
||||||
PATTERNS = historical_admin_path_patterns(
|
"""Get request to list all local users.
|
||||||
"/users_paginate/(?P<target_user_id>[^/]*)"
|
This needs user to have administrator access in Synapse.
|
||||||
)
|
|
||||||
|
GET /_synapse/admin/v2/users?from=0&limit=10&guests=false
|
||||||
|
|
||||||
|
returns:
|
||||||
|
200 OK with list of users if success otherwise an error.
|
||||||
|
|
||||||
|
The parameters `from` and `limit` are required only for pagination.
|
||||||
|
By default, a `limit` of 100 is used.
|
||||||
|
The parameter `user_id` can be used to filter by user id.
|
||||||
|
The parameter `guests` can be used to exclude guest users.
|
||||||
|
The parameter `deactivated` can be used to include deactivated users.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, hs):
|
def __init__(self, hs):
|
||||||
self.store = hs.get_datastore()
|
|
||||||
self.hs = hs
|
self.hs = hs
|
||||||
self.auth = hs.get_auth()
|
self.auth = hs.get_auth()
|
||||||
self.handlers = hs.get_handlers()
|
self.admin_handler = hs.get_handlers().admin_handler
|
||||||
|
|
||||||
async def on_GET(self, request, target_user_id):
|
async def on_GET(self, request):
|
||||||
"""Get request to get specific number of users from Synapse.
|
|
||||||
This needs user to have administrator access in Synapse.
|
|
||||||
"""
|
|
||||||
await assert_requester_is_admin(self.auth, request)
|
await assert_requester_is_admin(self.auth, request)
|
||||||
|
|
||||||
target_user = UserID.from_string(target_user_id)
|
start = parse_integer(request, "from", default=0)
|
||||||
|
limit = parse_integer(request, "limit", default=100)
|
||||||
|
user_id = parse_string(request, "user_id", default=None)
|
||||||
|
guests = parse_boolean(request, "guests", default=True)
|
||||||
|
deactivated = parse_boolean(request, "deactivated", default=False)
|
||||||
|
|
||||||
if not self.hs.is_mine(target_user):
|
users = await self.admin_handler.get_users_paginate(
|
||||||
raise SynapseError(400, "Can only users a local user")
|
start, limit, user_id, guests, deactivated
|
||||||
|
)
|
||||||
|
ret = {"users": users}
|
||||||
|
if len(users) >= limit:
|
||||||
|
ret["next_token"] = str(start + len(users))
|
||||||
|
|
||||||
order = "name" # order by name in user table
|
|
||||||
start = parse_integer(request, "start", required=True)
|
|
||||||
limit = parse_integer(request, "limit", required=True)
|
|
||||||
|
|
||||||
logger.info("limit: %s, start: %s", limit, start)
|
|
||||||
|
|
||||||
ret = await self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
|
||||||
return 200, ret
|
|
||||||
|
|
||||||
async def on_POST(self, request, target_user_id):
|
|
||||||
"""Post request to get specific number of users from Synapse..
|
|
||||||
This needs user to have administrator access in Synapse.
|
|
||||||
Example:
|
|
||||||
http://localhost:8008/_synapse/admin/v1/users_paginate/
|
|
||||||
@admin:user?access_token=admin_access_token
|
|
||||||
JsonBodyToSend:
|
|
||||||
{
|
|
||||||
"start": "0",
|
|
||||||
"limit": "10
|
|
||||||
}
|
|
||||||
Returns:
|
|
||||||
200 OK with json object {list[dict[str, Any]], count} or empty object.
|
|
||||||
"""
|
|
||||||
await assert_requester_is_admin(self.auth, request)
|
|
||||||
UserID.from_string(target_user_id)
|
|
||||||
|
|
||||||
order = "name" # order by name in user table
|
|
||||||
params = parse_json_object_from_request(request)
|
|
||||||
assert_params_in_dict(params, ["limit", "start"])
|
|
||||||
limit = params["limit"]
|
|
||||||
start = params["start"]
|
|
||||||
logger.info("limit: %s, start: %s", limit, start)
|
|
||||||
|
|
||||||
ret = await self.handlers.admin_handler.get_users_paginate(order, start, limit)
|
|
||||||
return 200, ret
|
return 200, ret
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1350,11 +1350,12 @@ class SQLBaseStore(object):
|
||||||
def simple_select_list_paginate(
|
def simple_select_list_paginate(
|
||||||
self,
|
self,
|
||||||
table,
|
table,
|
||||||
keyvalues,
|
|
||||||
orderby,
|
orderby,
|
||||||
start,
|
start,
|
||||||
limit,
|
limit,
|
||||||
retcols,
|
retcols,
|
||||||
|
filters=None,
|
||||||
|
keyvalues=None,
|
||||||
order_direction="ASC",
|
order_direction="ASC",
|
||||||
desc="simple_select_list_paginate",
|
desc="simple_select_list_paginate",
|
||||||
):
|
):
|
||||||
|
@ -1365,6 +1366,9 @@ class SQLBaseStore(object):
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
table (str): the table name
|
table (str): the table name
|
||||||
|
filters (dict[str, T] | None):
|
||||||
|
column names and values to filter the rows with, or None to not
|
||||||
|
apply a WHERE ? LIKE ? clause.
|
||||||
keyvalues (dict[str, T] | None):
|
keyvalues (dict[str, T] | None):
|
||||||
column names and values to select the rows with, or None to not
|
column names and values to select the rows with, or None to not
|
||||||
apply a WHERE clause.
|
apply a WHERE clause.
|
||||||
|
@ -1380,11 +1384,12 @@ class SQLBaseStore(object):
|
||||||
desc,
|
desc,
|
||||||
self.simple_select_list_paginate_txn,
|
self.simple_select_list_paginate_txn,
|
||||||
table,
|
table,
|
||||||
keyvalues,
|
|
||||||
orderby,
|
orderby,
|
||||||
start,
|
start,
|
||||||
limit,
|
limit,
|
||||||
retcols,
|
retcols,
|
||||||
|
filters=filters,
|
||||||
|
keyvalues=keyvalues,
|
||||||
order_direction=order_direction,
|
order_direction=order_direction,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1393,11 +1398,12 @@ class SQLBaseStore(object):
|
||||||
cls,
|
cls,
|
||||||
txn,
|
txn,
|
||||||
table,
|
table,
|
||||||
keyvalues,
|
|
||||||
orderby,
|
orderby,
|
||||||
start,
|
start,
|
||||||
limit,
|
limit,
|
||||||
retcols,
|
retcols,
|
||||||
|
filters=None,
|
||||||
|
keyvalues=None,
|
||||||
order_direction="ASC",
|
order_direction="ASC",
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
@ -1405,16 +1411,23 @@ class SQLBaseStore(object):
|
||||||
of row numbers, which may return zero or number of rows from start to limit,
|
of row numbers, which may return zero or number of rows from start to limit,
|
||||||
returning the result as a list of dicts.
|
returning the result as a list of dicts.
|
||||||
|
|
||||||
|
Use `filters` to search attributes using SQL wildcards and/or `keyvalues` to
|
||||||
|
select attributes with exact matches. All constraints are joined together
|
||||||
|
using 'AND'.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
txn : Transaction object
|
txn : Transaction object
|
||||||
table (str): the table name
|
table (str): the table name
|
||||||
keyvalues (dict[str, T] | None):
|
|
||||||
column names and values to select the rows with, or None to not
|
|
||||||
apply a WHERE clause.
|
|
||||||
orderby (str): Column to order the results by.
|
orderby (str): Column to order the results by.
|
||||||
start (int): Index to begin the query at.
|
start (int): Index to begin the query at.
|
||||||
limit (int): Number of results to return.
|
limit (int): Number of results to return.
|
||||||
retcols (iterable[str]): the names of the columns to return
|
retcols (iterable[str]): the names of the columns to return
|
||||||
|
filters (dict[str, T] | None):
|
||||||
|
column names and values to filter the rows with, or None to not
|
||||||
|
apply a WHERE ? LIKE ? clause.
|
||||||
|
keyvalues (dict[str, T] | None):
|
||||||
|
column names and values to select the rows with, or None to not
|
||||||
|
apply a WHERE clause.
|
||||||
order_direction (str): Whether the results should be ordered "ASC" or "DESC".
|
order_direction (str): Whether the results should be ordered "ASC" or "DESC".
|
||||||
Returns:
|
Returns:
|
||||||
defer.Deferred: resolves to list[dict[str, Any]]
|
defer.Deferred: resolves to list[dict[str, Any]]
|
||||||
|
@ -1422,10 +1435,15 @@ class SQLBaseStore(object):
|
||||||
if order_direction not in ["ASC", "DESC"]:
|
if order_direction not in ["ASC", "DESC"]:
|
||||||
raise ValueError("order_direction must be one of 'ASC' or 'DESC'.")
|
raise ValueError("order_direction must be one of 'ASC' or 'DESC'.")
|
||||||
|
|
||||||
|
where_clause = "WHERE " if filters or keyvalues else ""
|
||||||
|
arg_list = []
|
||||||
|
if filters:
|
||||||
|
where_clause += " AND ".join("%s LIKE ?" % (k,) for k in filters)
|
||||||
|
arg_list += list(filters.values())
|
||||||
|
where_clause += " AND " if filters and keyvalues else ""
|
||||||
if keyvalues:
|
if keyvalues:
|
||||||
where_clause = "WHERE " + " AND ".join("%s = ?" % (k,) for k in keyvalues)
|
where_clause += " AND ".join("%s = ?" % (k,) for k in keyvalues)
|
||||||
else:
|
arg_list += list(keyvalues.values())
|
||||||
where_clause = ""
|
|
||||||
|
|
||||||
sql = "SELECT %s FROM %s %s ORDER BY %s %s LIMIT ? OFFSET ?" % (
|
sql = "SELECT %s FROM %s %s ORDER BY %s %s LIMIT ? OFFSET ?" % (
|
||||||
", ".join(retcols),
|
", ".join(retcols),
|
||||||
|
@ -1434,22 +1452,10 @@ class SQLBaseStore(object):
|
||||||
orderby,
|
orderby,
|
||||||
order_direction,
|
order_direction,
|
||||||
)
|
)
|
||||||
txn.execute(sql, list(keyvalues.values()) + [limit, start])
|
txn.execute(sql, arg_list + [limit, start])
|
||||||
|
|
||||||
return cls.cursor_to_dict(txn)
|
return cls.cursor_to_dict(txn)
|
||||||
|
|
||||||
def get_user_count_txn(self, txn):
|
|
||||||
"""Get a total number of registered users in the users list.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
txn : Transaction object
|
|
||||||
Returns:
|
|
||||||
int : number of users
|
|
||||||
"""
|
|
||||||
sql_count = "SELECT COUNT(*) FROM users WHERE is_guest = 0;"
|
|
||||||
txn.execute(sql_count)
|
|
||||||
return txn.fetchone()[0]
|
|
||||||
|
|
||||||
def simple_search_list(self, table, term, col, retcols, desc="simple_search_list"):
|
def simple_search_list(self, table, term, col, retcols, desc="simple_search_list"):
|
||||||
"""Executes a SELECT query on the named table, which may return zero or
|
"""Executes a SELECT query on the named table, which may return zero or
|
||||||
more rows, returning the result as a list of dicts.
|
more rows, returning the result as a list of dicts.
|
||||||
|
|
|
@ -19,8 +19,6 @@ import calendar
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from twisted.internet import defer
|
|
||||||
|
|
||||||
from synapse.api.constants import PresenceState
|
from synapse.api.constants import PresenceState
|
||||||
from synapse.storage.engines import PostgresEngine
|
from synapse.storage.engines import PostgresEngine
|
||||||
from synapse.storage.util.id_generators import (
|
from synapse.storage.util.id_generators import (
|
||||||
|
@ -476,7 +474,7 @@ class DataStore(
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_users(self):
|
def get_users(self):
|
||||||
"""Function to reterive a list of users in users table.
|
"""Function to retrieve a list of users in users table.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
Returns:
|
Returns:
|
||||||
|
@ -485,36 +483,59 @@ class DataStore(
|
||||||
return self.simple_select_list(
|
return self.simple_select_list(
|
||||||
table="users",
|
table="users",
|
||||||
keyvalues={},
|
keyvalues={},
|
||||||
retcols=["name", "password_hash", "is_guest", "admin", "user_type"],
|
retcols=[
|
||||||
|
"name",
|
||||||
|
"password_hash",
|
||||||
|
"is_guest",
|
||||||
|
"admin",
|
||||||
|
"user_type",
|
||||||
|
"deactivated",
|
||||||
|
],
|
||||||
desc="get_users",
|
desc="get_users",
|
||||||
)
|
)
|
||||||
|
|
||||||
@defer.inlineCallbacks
|
def get_users_paginate(
|
||||||
def get_users_paginate(self, order, start, limit):
|
self, start, limit, name=None, guests=True, deactivated=False
|
||||||
"""Function to reterive a paginated list of users from
|
):
|
||||||
users list. This will return a json object, which contains
|
"""Function to retrieve a paginated list of users from
|
||||||
list of users and the total number of users in users table.
|
users list. This will return a json list of users.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
order (str): column name to order the select by this column
|
|
||||||
start (int): start number to begin the query from
|
start (int): start number to begin the query from
|
||||||
limit (int): number of rows to reterive
|
limit (int): number of rows to retrieve
|
||||||
|
name (string): filter for user names
|
||||||
|
guests (bool): whether to in include guest users
|
||||||
|
deactivated (bool): whether to include deactivated users
|
||||||
Returns:
|
Returns:
|
||||||
defer.Deferred: resolves to json object {list[dict[str, Any]], count}
|
defer.Deferred: resolves to list[dict[str, Any]]
|
||||||
"""
|
"""
|
||||||
users = yield self.runInteraction(
|
name_filter = {}
|
||||||
"get_users_paginate",
|
if name:
|
||||||
self.simple_select_list_paginate_txn,
|
name_filter["name"] = "%" + name + "%"
|
||||||
|
|
||||||
|
attr_filter = {}
|
||||||
|
if not guests:
|
||||||
|
attr_filter["is_guest"] = False
|
||||||
|
if not deactivated:
|
||||||
|
attr_filter["deactivated"] = False
|
||||||
|
|
||||||
|
return self.simple_select_list_paginate(
|
||||||
|
desc="get_users_paginate",
|
||||||
table="users",
|
table="users",
|
||||||
keyvalues={"is_guest": False},
|
orderby="name",
|
||||||
orderby=order,
|
|
||||||
start=start,
|
start=start,
|
||||||
limit=limit,
|
limit=limit,
|
||||||
retcols=["name", "password_hash", "is_guest", "admin", "user_type"],
|
filters=name_filter,
|
||||||
|
keyvalues=attr_filter,
|
||||||
|
retcols=[
|
||||||
|
"name",
|
||||||
|
"password_hash",
|
||||||
|
"is_guest",
|
||||||
|
"admin",
|
||||||
|
"user_type",
|
||||||
|
"deactivated",
|
||||||
|
],
|
||||||
)
|
)
|
||||||
count = yield self.runInteraction("get_users_paginate", self.get_user_count_txn)
|
|
||||||
retval = {"users": users, "total": count}
|
|
||||||
return retval
|
|
||||||
|
|
||||||
def search_users(self, term):
|
def search_users(self, term):
|
||||||
"""Function to search users list for one or more users with
|
"""Function to search users list for one or more users with
|
||||||
|
|
|
@ -260,11 +260,11 @@ class StatsStore(StateDeltasStore):
|
||||||
slice_list = self.simple_select_list_paginate_txn(
|
slice_list = self.simple_select_list_paginate_txn(
|
||||||
txn,
|
txn,
|
||||||
table + "_historical",
|
table + "_historical",
|
||||||
{id_col: stats_id},
|
|
||||||
"end_ts",
|
"end_ts",
|
||||||
start,
|
start,
|
||||||
size,
|
size,
|
||||||
retcols=selected_columns + ["bucket_size", "end_ts"],
|
retcols=selected_columns + ["bucket_size", "end_ts"],
|
||||||
|
keyvalues={id_col: stats_id},
|
||||||
order_direction="DESC",
|
order_direction="DESC",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue