Skip to content

Commit fbf5852

Browse files
#827 ability for users to set permission equal to anothers and to ALL permissinos
1 parent eaf0c32 commit fbf5852

File tree

9 files changed

+86
-1161
lines changed

9 files changed

+86
-1161
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,4 @@ dist/*
1414
*.egg-info
1515
.cache
1616
.idea
17+
.pytest_cache/*

.pytest_cache/v/cache/lastfailed

Lines changed: 0 additions & 5 deletions
This file was deleted.

.pytest_cache/v/cache/nodeids

Lines changed: 0 additions & 1130 deletions
This file was deleted.

SoftLayer/CLI/user/edit_permissions.py

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,22 @@
1212
@click.argument('identifier')
1313
@click.option('--enable/--disable', default=True,
1414
help="Enable (DEFAULT) or Disable selected permissions")
15-
@click.option('--permission', '-p', multiple=True, required=True,
16-
help="Permission keyName to set, multiple instances allowed. Use keyword ALL to select ALL permisssions")
17-
@click.option('--from-user', '-u', default=None,
18-
help="Set permissions to match this user's permissions")
15+
@click.option('--permission', '-p', multiple=True,
16+
help="Permission keyName to set, multiple instances allowed. "
17+
"Use keyword ALL to select ALL permisssions")
18+
@click.option('--from-user', '-u', default=None,
19+
help="Set permissions to match this user's permissions. "
20+
"Will add then remove the appropriate permissions")
1921
@environment.pass_env
2022
def cli(env, identifier, enable, permission, from_user):
2123
"""Enable or Disable specific permissions."""
2224
mgr = SoftLayer.UserManager(env.client)
2325
user_id = helpers.resolve_id(mgr.resolve_ids, identifier, 'username')
2426
result = False
25-
# TODO, this bit. Make sure from-user and permission/enable are exclusive
2627
if from_user:
27-
result = mgr.permissions_from_user(user_id, from_user)
28-
if enable:
28+
from_user_id = helpers.resolve_id(mgr.resolve_ids, from_user, 'username')
29+
result = mgr.permissions_from_user(user_id, from_user_id)
30+
elif enable:
2931
result = mgr.add_permissions(user_id, permission)
3032
else:
3133
result = mgr.remove_permissions(user_id, permission)

SoftLayer/CLI/user/list.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
from SoftLayer.CLI import environment
99
from SoftLayer.CLI import formatting
1010

11-
from pprint import pprint as pp
1211

1312
COLUMNS = [
1413
column_helper.Column('id', ('id',)),

SoftLayer/fixtures/SoftLayer_User_Customer_CustomerPermission_Permission.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,10 @@
33
"key": "T_1",
44
"keyName": "TICKET_VIEW",
55
"name": "View Tickets"
6+
},
7+
{
8+
"key": "T_2",
9+
"keyName": "TEST",
10+
"name": "A Testing Permission"
611
}
712
]

SoftLayer/managers/user.py

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@
66
:license: MIT, see LICENSE for more details.
77
"""
88
import datetime
9+
import logging
910
from operator import itemgetter
1011

1112
from SoftLayer import exceptions
1213
from SoftLayer import utils
1314

14-
from pprint import pprint as pp
15+
LOGGER = logging.getLogger(__name__)
16+
1517

1618
class UserManager(utils.IdentifierMixin, object):
1719
"""Manages Users.
@@ -34,6 +36,7 @@ def __init__(self, client):
3436
self.user_service = self.client['SoftLayer_User_Customer']
3537
self.account_service = self.client['SoftLayer_Account']
3638
self.resolvers = [self._get_id_from_username]
39+
self.all_permissions = None
3740

3841
def list_users(self, objectmask=None, objectfilter=None):
3942
"""Lists all users on an account
@@ -66,10 +69,13 @@ def get_user(self, user_id, objectmask=None):
6669
def get_all_permissions(self):
6770
"""Calls SoftLayer_User_CustomerPermissions_Permission::getAllObjects
6871
72+
Stores the result in self.all_permissions
6973
:returns: A list of dictionaries that contains all valid permissions
7074
"""
71-
permissions = self.client.call('User_Customer_CustomerPermission_Permission', 'getAllObjects')
72-
return sorted(permissions, key=itemgetter('keyName'))
75+
if self.all_permissions is None:
76+
permissions = self.client.call('User_Customer_CustomerPermission_Permission', 'getAllObjects')
77+
self.all_permissions = sorted(permissions, key=itemgetter('keyName'))
78+
return self.all_permissions
7379

7480
def add_permissions(self, user_id, permissions):
7581
"""Enables a list of permissions for a user
@@ -82,6 +88,7 @@ def add_permissions(self, user_id, permissions):
8288
add_permissions(123, ['BANDWIDTH_MANAGE'])
8389
"""
8490
pretty_permissions = self.format_permission_object(permissions)
91+
LOGGER.warning("Adding the following permissions to %s: %s", user_id, pretty_permissions)
8592
return self.user_service.addBulkPortalPermission(pretty_permissions, id=user_id)
8693

8794
def remove_permissions(self, user_id, permissions):
@@ -95,8 +102,32 @@ def remove_permissions(self, user_id, permissions):
95102
remove_permissions(123, ['BANDWIDTH_MANAGE'])
96103
"""
97104
pretty_permissions = self.format_permission_object(permissions)
105+
LOGGER.warning("Removing the following permissions to %s: %s", user_id, pretty_permissions)
98106
return self.user_service.removeBulkPortalPermission(pretty_permissions, id=user_id)
99107

108+
def permissions_from_user(self, user_id, from_user_id):
109+
"""Sets user_id's permission to be the same as from_user_id's
110+
111+
Any permissions from_user_id has will be added to user_id.
112+
Any permissions from_user_id doesn't have will be removed from user_id.
113+
114+
:param int user_id: The user to change permissions.
115+
:param int from_user_id: The use to base permissions from.
116+
:returns: True on success, Exception otherwise.
117+
"""
118+
from_permissions = self.get_user_permissions(from_user_id)
119+
self.add_permissions(user_id, from_permissions)
120+
all_permissions = self.get_all_permissions()
121+
remove_permissions = []
122+
for permission in all_permissions:
123+
# If permission does not exist for from_user_id add it to the list to be removed
124+
if _keyname_search(all_permissions, permission):
125+
continue
126+
else:
127+
remove_permissions.append({'keyName': permission['keyName']})
128+
self.remove_permissions(user_id, remove_permissions)
129+
return True
130+
100131
def get_user_permissions(self, user_id):
101132
"""Returns a sorted list of a users permissions"""
102133
permissions = self.user_service.getPermissions(id=user_id)
@@ -131,13 +162,14 @@ def get_events(self, user_id, start_date=None):
131162
"""Gets the event log for a specific user, default start_date is 30 days ago
132163
133164
:param int id: User id to view
134-
:param string start_date: "%Y-%m-%dT%H:%M:%s.0000-06:00" formatted string. Anything else wont work
165+
:param string start_date: "%Y-%m-%dT%H:%M:%s.0000-06:00" is the full formatted string.
166+
The Timezone part has to be HH:MM, notice the : there.
135167
:returns: https://softlayer.github.io/reference/datatypes/SoftLayer_Event_Log/
136168
"""
137169

138170
if start_date is None:
139171
date_object = datetime.date.today() - datetime.timedelta(days=30)
140-
start_date = date_object.strftime("%Y-%m-%dT00:00:00.0000-06:00")
172+
start_date = date_object.strftime("%Y-%m-%dT00:00:00")
141173

142174
object_filter = {
143175
'userId': {
@@ -149,7 +181,10 @@ def get_events(self, user_id, start_date=None):
149181
}
150182
}
151183

152-
return self.client.call('Event_Log', 'getAllObjects', filter=object_filter)
184+
events = self.client.call('Event_Log', 'getAllObjects', filter=object_filter)
185+
if events is None:
186+
events = [{'eventName': 'No Events Found'}]
187+
return events
153188

154189
def _get_id_from_username(self, username):
155190
"""Looks up a username's id
@@ -162,24 +197,39 @@ def _get_id_from_username(self, username):
162197
user = self.list_users(_mask, _filter)
163198
if len(user) == 1:
164199
return [user[0]['id']]
200+
elif len(user) > 1:
201+
raise exceptions.SoftLayerError("Multiple users found with the name: %s" % username)
165202
else:
166-
# Might eventually want to throw an exception if len(user) > 1
167203
raise exceptions.SoftLayerError("Unable to find user id for %s" % username)
168204

169-
170205
def format_permission_object(self, permissions):
171-
"""Formats a list of permission key names into something the SLAPI will respect"""
206+
"""Formats a list of permission key names into something the SLAPI will respect.
207+
208+
:param list permissions: A list of SLAPI permissions keyNames.
209+
keyName of ALL will return all permissions.
210+
:returns: list of dictionaries that can be sent to the api to add or remove permissions
211+
:throws SoftLayerError: If any permission is invalid this exception will be thrown.
212+
"""
172213
pretty_permissions = []
173214
available_permissions = self.get_all_permissions()
174215
# pp(available_permissions)
175216
for permission in permissions:
217+
# Handle data retrieved directly from the API
218+
if isinstance(permission, dict):
219+
permission = permission['keyName']
176220
permission = permission.upper()
177221
if permission == 'ALL':
178222
return available_permissions
179223
# Search through available_permissions to make sure what the user entered was valid
180-
if next(filter(lambda x: x['keyName'] == permission, available_permissions), False):
224+
if _keyname_search(available_permissions, permission):
181225
pretty_permissions.append({'keyName': permission})
182226
else:
183-
raise exceptions.SoftLayerError("%s is not a valid permission" % permission)
184-
pp(pretty_permissions)
227+
raise exceptions.SoftLayerError("|%s| is not a valid permission" % permission)
185228
return pretty_permissions
229+
230+
231+
def _keyname_search(haystack, needle):
232+
for item in haystack:
233+
if item.get('keyName') == needle:
234+
return True
235+
return False

tests/CLI/modules/user_tests.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
import json
1010

1111

12-
class UserTests(testing.TestCase):
12+
class UserCLITests(testing.TestCase):
1313

1414
"""User list tests"""
1515

@@ -83,11 +83,15 @@ def test_permissions_list(self):
8383
"""User edit-permissions tests"""
8484

8585
def test_edit_perms_on(self):
86-
result = self.run_command(['user', 'edit-permissions', '11100', '--enable', '-p TEST'])
86+
result = self.run_command(['user', 'edit-permissions', '11100', '--enable', '-p', 'TEST'])
8787
self.assert_no_fail(result)
8888
self.assert_called_with('SoftLayer_User_Customer', 'addBulkPortalPermission', identifier=11100)
8989

90+
def test_edit_perms_on_bad(self):
91+
result = self.run_command(['user', 'edit-permissions', '11100', '--enable', '-p', 'TEST_NOt_exist'])
92+
self.assertEqual(result.exit_code, -1)
93+
9094
def test_edit_perms_off(self):
91-
result = self.run_command(['user', 'edit-permissions', '11100', '--disable', '-p TEST'])
95+
result = self.run_command(['user', 'edit-permissions', '11100', '--disable', '-p', 'TEST'])
9296
self.assert_no_fail(result)
9397
self.assert_called_with('SoftLayer_User_Customer', 'removeBulkPortalPermission', identifier=11100)

tests/managers/user_tests.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,7 @@ def set_up(self):
1515

1616
def test_list_user_defaults(self):
1717
self.manager.list_users()
18-
expected_mask = "mask[id, username, displayName, userStatus[name], hardwareCount, virtualGuestCount]"
19-
self.assert_called_with('SoftLayer_Account', 'getUsers', mask=expected_mask)
18+
self.assert_called_with('SoftLayer_Account', 'getUsers', mask=mock.ANY)
2019

2120
def test_list_user_mask(self):
2221
self.manager.list_users(objectmask="mask[id]")
@@ -86,7 +85,7 @@ def test_get_events_default(self):
8685
},
8786
'eventCreateDate': {
8887
'operation': 'greaterThanDate',
89-
'options': [{'name': 'date', 'value': ['2018-04-15T00:00:00.0000-06:00']}]
88+
'options': [{'name': 'date', 'value': ['2018-04-15T00:00:00']}]
9089
}
9190
}
9291
self.assert_called_with('SoftLayer_Event_Log', 'getAllObjects', filter=expected_filter)

0 commit comments

Comments
 (0)