Skip to content

Commit b4c19f1

Browse files
committed
Add new API changes for user access management and indexes
1 parent d754590 commit b4c19f1

25 files changed

+522
-311
lines changed

arango/client.py

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ def run_tests(self, tests): # pragma: no cover
393393
raise ServerRunTestsError(res)
394394
return res.body
395395

396-
def execute(self, program):
396+
def execute(self, program): # pragma: no cover
397397
"""Execute a Javascript program on the server.
398398
399399
:param program: the body of the Javascript program to execute.
@@ -875,35 +875,42 @@ def delete_user(self, username, ignore_missing=False):
875875
return False
876876
raise UserDeleteError(res)
877877

878-
def user_access(self, username):
879-
"""Return the database access details of a user.
878+
def user_access(self, username, full=False):
879+
"""Return a user's access details for databases (and collections).
880880
881-
:param username: the name of the user
881+
:param username: The name of the user.
882882
:type username: str | unicode
883-
:returns: the names of the databases the user can access
884-
:rtype: [str]
885-
:raises: arango.exceptions.UserAccessError: if the retrieval fails
883+
:param full: Return the full set of access levels for all databases and
884+
collections for the user.
885+
:type full: bool
886+
:returns: The names of the databases (and collections) the user has
887+
access to.
888+
:rtype: [str] | [unicode]
889+
:raises: arango.exceptions.UserAccessError: If the retrieval fails.
886890
887891
.. note::
888892
Only the root user can access this method. For non-root users,
889893
use :func:`arango.database.Database.user_access` (via a database
890894
the users have access to) instead.
891895
"""
892-
res = self._conn.get('/_api/user/{}/database'.format(username))
896+
res = self._conn.get(
897+
'/_api/user/{}/database'.format(username),
898+
params={'full': full}
899+
)
893900
if res.status_code in HTTP_OK:
894901
return list(res.body['result'])
895902
raise UserAccessError(res)
896903

897904
def grant_user_access(self, username, database):
898905
"""Grant user access to a database.
899906
900-
:param username: the name of the user
907+
:param username: The name of the user.
901908
:type username: str | unicode
902-
:param database: the name of the database
909+
:param database: The name of the database.
903910
:type database: str | unicode
904-
:returns: whether the operation was successful
911+
:returns: Whether the operation was successful or not.
905912
:rtype: bool
906-
:raises arango.exceptions.UserGrantAccessError: if the operation fails
913+
:raises arango.exceptions.UserGrantAccessError: If the operation fails.
907914
908915
.. note::
909916
Only the root user can access this method. For non-root users,
@@ -921,22 +928,21 @@ def grant_user_access(self, username, database):
921928
def revoke_user_access(self, username, database):
922929
"""Revoke user access to a database.
923930
924-
:param username: the name of the user
931+
:param username: The name of the user.
925932
:type username: str | unicode
926-
:param database: the name of the database
933+
:param database: The name of the database.
927934
:type database: str | unicode | unicode
928-
:returns: whether the operation was successful
935+
:returns: Whether the operation was successful or not.
929936
:rtype: bool
930-
:raises arango.exceptions.UserRevokeAccessError: if the operation fails
937+
:raises arango.exceptions.UserRevokeAccessError: If the operation fails.
931938
932939
.. note::
933940
Only the root user can access this method. For non-root users,
934941
use :func:`arango.database.Database.revoke_user_access` (via a
935942
database the users have access to) instead.
936943
"""
937-
res = self._conn.put(
938-
'/_api/user/{}/database/{}'.format(username, database),
939-
data={'grant': 'none'}
944+
res = self._conn.delete(
945+
'/_api/user/{}/database/{}'.format(username, database)
940946
)
941947
if res.status_code in HTTP_OK:
942948
return True

arango/collections/base.py

Lines changed: 120 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,15 @@ def name(self):
123123
"""
124124
return self._name
125125

126+
@property
127+
def database(self):
128+
"""Return the name of the database the collection belongs to.
129+
130+
:returns: The name of the database.
131+
:rtype: str | unicode
132+
"""
133+
return self._conn.database
134+
126135
@api_method
127136
def rename(self, new_name):
128137
"""Rename the collection.
@@ -930,6 +939,7 @@ def indexes(self):
930939
:rtype: [dict]
931940
:raises arango.exceptions.IndexListError: if the list of indexes
932941
cannot be retrieved
942+
933943
"""
934944
request = Request(
935945
method='get',
@@ -988,7 +998,11 @@ def handler(res):
988998
return request, handler
989999

9901000
@api_method
991-
def add_hash_index(self, fields, unique=None, sparse=None):
1001+
def add_hash_index(self,
1002+
fields,
1003+
unique=None,
1004+
sparse=None,
1005+
deduplicate=None):
9921006
"""Create a new hash index in the collection.
9931007
9941008
:param fields: the document fields to index
@@ -997,6 +1011,14 @@ def add_hash_index(self, fields, unique=None, sparse=None):
9971011
:type unique: bool
9981012
:param sparse: index ``None``'s
9991013
:type sparse: bool
1014+
:param deduplicate: Controls whether inserting duplicate index values
1015+
from the same document into a unique array index leads to a unique
1016+
constraint error or not. If set to ``True`` (default), only a
1017+
single instance of each non-unique index values is inserted into
1018+
the index per document. Trying to insert a value into the index
1019+
that already exists will always fail, regardless of the value of
1020+
this field.
1021+
:param deduplicate: bool
10001022
:returns: the details on the new index
10011023
:rtype: dict
10021024
:raises arango.exceptions.IndexCreateError: if the hash index cannot
@@ -1007,10 +1029,16 @@ def add_hash_index(self, fields, unique=None, sparse=None):
10071029
data['unique'] = unique
10081030
if sparse is not None:
10091031
data['sparse'] = sparse
1032+
if deduplicate is not None:
1033+
data['deduplicate'] = deduplicate
10101034
return self._add_index(data)
10111035

10121036
@api_method
1013-
def add_skiplist_index(self, fields, unique=None, sparse=None):
1037+
def add_skiplist_index(self,
1038+
fields,
1039+
unique=None,
1040+
sparse=None,
1041+
deduplicate=None):
10141042
"""Create a new skiplist index in the collection.
10151043
10161044
A skiplist index is used to find the ranges of documents (e.g. time).
@@ -1021,6 +1049,14 @@ def add_skiplist_index(self, fields, unique=None, sparse=None):
10211049
:type unique: bool
10221050
:param sparse: index ``None``'s
10231051
:type sparse: bool
1052+
:param deduplicate: Controls whether inserting duplicate index values
1053+
from the same document into a unique array index leads to a unique
1054+
constraint error or not. If set to ``True`` (default), only a
1055+
single instance of each non-unique index values is inserted into
1056+
the index per document. Trying to insert a value into the index
1057+
that already exists will always fail, regardless of the value of
1058+
this field.
1059+
:param deduplicate: bool
10241060
:returns: the details on the new index
10251061
:rtype: dict
10261062
:raises arango.exceptions.IndexCreateError: if the skiplist index
@@ -1031,6 +1067,8 @@ def add_skiplist_index(self, fields, unique=None, sparse=None):
10311067
data['unique'] = unique
10321068
if sparse is not None:
10331069
data['sparse'] = sparse
1070+
if deduplicate is not None:
1071+
data['deduplicate'] = deduplicate
10341072
return self._add_index(data)
10351073

10361074
@api_method
@@ -1138,3 +1176,83 @@ def handler(res):
11381176
return not res.body['error']
11391177

11401178
return request, handler
1179+
1180+
@api_method
1181+
def user_access(self, username):
1182+
"""Return a user's access details for the collection.
1183+
1184+
Appropriate permissions are required in order to execute this method.
1185+
1186+
:param username: The name of the user.
1187+
:type username: str | unicode
1188+
:returns: The access details (e.g. ``"rw"``, ``None``)
1189+
:rtype: str | unicode | None
1190+
:raises: arango.exceptions.UserAccessError: If the retrieval fails.
1191+
"""
1192+
request = Request(
1193+
method='get',
1194+
endpoint='/_api/user/{}/database/{}/{}'.format(
1195+
username, self.database, self.name
1196+
)
1197+
)
1198+
1199+
def handler(res):
1200+
if res.status_code in HTTP_OK:
1201+
result = res.body['result'].lower()
1202+
return None if result == 'none' else result
1203+
raise UserAccessError(res)
1204+
1205+
return request, handler
1206+
1207+
@api_method
1208+
def grant_user_access(self, username):
1209+
"""Grant user access to the collection.
1210+
1211+
Appropriate permissions are required in order to execute this method.
1212+
1213+
:param username: The name of the user.
1214+
:type username: str | unicode
1215+
:returns: Whether the operation was successful or not.
1216+
:rtype: bool
1217+
:raises arango.exceptions.UserGrantAccessError: If the operation fails.
1218+
"""
1219+
request = Request(
1220+
method='put',
1221+
endpoint='/_api/user/{}/database/{}/{}'.format(
1222+
username, self.database, self.name
1223+
),
1224+
data={'grant': 'rw'}
1225+
)
1226+
1227+
def handler(res):
1228+
if res.status_code in HTTP_OK:
1229+
return True
1230+
raise UserGrantAccessError(res)
1231+
1232+
return request, handler
1233+
1234+
@api_method
1235+
def revoke_user_access(self, username):
1236+
"""Revoke user access to the collection.
1237+
1238+
Appropriate permissions are required in order to execute this method.
1239+
1240+
:param username: The name of the user.
1241+
:type username: str | unicode
1242+
:returns: Whether the operation was successful or not.
1243+
:rtype: bool
1244+
:raises arango.exceptions.UserRevokeAccessError: If the operation fails.
1245+
"""
1246+
request = Request(
1247+
method='delete',
1248+
endpoint='/_api/user/{}/database/{}/{}'.format(
1249+
username, self.database, self.name
1250+
)
1251+
)
1252+
1253+
def handler(res):
1254+
if res.status_code in HTTP_OK:
1255+
return True
1256+
raise UserRevokeAccessError(res)
1257+
1258+
return request, handler

arango/connection.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,6 @@ def type(self):
142142
def handle_request(self, request, handler):
143143
# from arango.async import AsyncExecution
144144
# from arango.exceptions import ArangoError
145-
#
146145
# async = AsyncExecution(self, return_result=True)
147146
# response = async.handle_request(request, handler)
148147
# while response.status() != 'done':

0 commit comments

Comments
 (0)