server/users: add user removal
This commit is contained in:
parent
6ff160b9c6
commit
450a61c1e1
3 changed files with 98 additions and 5 deletions
19
API.md
19
API.md
|
@ -17,6 +17,7 @@
|
||||||
- [Creating user](#creating-user)
|
- [Creating user](#creating-user)
|
||||||
- [Updating user](#updating-user)
|
- [Updating user](#updating-user)
|
||||||
- [Getting user](#getting-user)
|
- [Getting user](#getting-user)
|
||||||
|
- [Removing user](#removing-user)
|
||||||
- [Password reset - step 1: mail request](#password-reset---step-2-confirmation)
|
- [Password reset - step 1: mail request](#password-reset---step-2-confirmation)
|
||||||
- [Password reset - step 2: confirmation](#password-reset---step-2-confirmation)
|
- [Password reset - step 2: confirmation](#password-reset---step-2-confirmation)
|
||||||
|
|
||||||
|
@ -95,6 +96,7 @@ Output:
|
||||||
```
|
```
|
||||||
...where `<user>` is an [user resource](#user) and `query` contains standard
|
...where `<user>` is an [user resource](#user) and `query` contains standard
|
||||||
[search query](#search).
|
[search query](#search).
|
||||||
|
Errors: if privileges are too low.
|
||||||
|
|
||||||
Searches for users.
|
Searches for users.
|
||||||
|
|
||||||
|
@ -143,7 +145,7 @@ Output:
|
||||||
```
|
```
|
||||||
...where `<user>` is an [user resource](#user).
|
...where `<user>` is an [user resource](#user).
|
||||||
Errors: if such user already exists (names are case insensitive), or either of
|
Errors: if such user already exists (names are case insensitive), or either of
|
||||||
user name, password and email are invalid.
|
user name, password and email are invalid, or privileges are too low.
|
||||||
|
|
||||||
Creates a new user using specified parameters. Names and passwords must match
|
Creates a new user using specified parameters. Names and passwords must match
|
||||||
`user_name_regex` and `password_regex` from server's configuration,
|
`user_name_regex` and `password_regex` from server's configuration,
|
||||||
|
@ -174,7 +176,7 @@ Output:
|
||||||
Errors: if the user does not exist, or the user with new name already exists
|
Errors: if the user does not exist, or the user with new name already exists
|
||||||
(names are case insensitive), or either of user name, password, email or rank
|
(names are case insensitive), or either of user name, password, email or rank
|
||||||
are invalid, or the user is trying to update their or someone else's rank to
|
are invalid, or the user is trying to update their or someone else's rank to
|
||||||
higher than their own.
|
higher than their own, or privileges are too low.
|
||||||
|
|
||||||
Updates an existing user using specified parameters. Names and passwords must
|
Updates an existing user using specified parameters. Names and passwords must
|
||||||
match `user_name_regex` and `password_regex` from server's configuration,
|
match `user_name_regex` and `password_regex` from server's configuration,
|
||||||
|
@ -191,11 +193,22 @@ Output:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
...where `<user>` is an [user resource](#user).
|
...where `<user>` is an [user resource](#user).
|
||||||
Errors: if the user does not exist.
|
Errors: if the user does not exist or privileges are too low.
|
||||||
|
|
||||||
Retrieves information about an existing user.
|
Retrieves information about an existing user.
|
||||||
|
|
||||||
|
|
||||||
|
### Removing user
|
||||||
|
Request: `DELETE /user/<name>`
|
||||||
|
Output:
|
||||||
|
```json5
|
||||||
|
{}
|
||||||
|
```
|
||||||
|
Errors: if the user does not exist or privileges are too low.
|
||||||
|
|
||||||
|
Deletes existing user.
|
||||||
|
|
||||||
|
|
||||||
### Password reset - step 1: mail request
|
### Password reset - step 1: mail request
|
||||||
Request: `GET /password-reset/<email-or-name>`
|
Request: `GET /password-reset/<email-or-name>`
|
||||||
Output:
|
Output:
|
||||||
|
|
|
@ -111,3 +111,19 @@ class UserDetailApi(BaseApi):
|
||||||
|
|
||||||
context.session.commit()
|
context.session.commit()
|
||||||
return {'user': _serialize_user(context.user, user)}
|
return {'user': _serialize_user(context.user, user)}
|
||||||
|
|
||||||
|
def delete(self, context, user_name):
|
||||||
|
''' Delete an existing user. '''
|
||||||
|
user = users.get_by_name(context.session, user_name)
|
||||||
|
if not user:
|
||||||
|
raise errors.NotFoundError('User %r not found.' % user_name)
|
||||||
|
|
||||||
|
if context.user.user_id == user.user_id:
|
||||||
|
infix = 'self'
|
||||||
|
else:
|
||||||
|
infix = 'any'
|
||||||
|
|
||||||
|
auth.verify_privilege(context.user, 'users:delete:%s' % infix)
|
||||||
|
context.session.delete(user)
|
||||||
|
context.session.commit()
|
||||||
|
return {}
|
||||||
|
|
|
@ -10,8 +10,6 @@ class TestRetrievingUsers(DatabaseTestCase):
|
||||||
util.mock_config({
|
util.mock_config({
|
||||||
'privileges': {
|
'privileges': {
|
||||||
'users:list': 'regular_user',
|
'users:list': 'regular_user',
|
||||||
'users:view': 'regular_user',
|
|
||||||
'users:create': 'regular_user',
|
|
||||||
},
|
},
|
||||||
'avatar_thumbnail_size': 200,
|
'avatar_thumbnail_size': 200,
|
||||||
'ranks': ['anonymous', 'regular_user', 'mod', 'admin'],
|
'ranks': ['anonymous', 'regular_user', 'mod', 'admin'],
|
||||||
|
@ -39,6 +37,30 @@ class TestRetrievingUsers(DatabaseTestCase):
|
||||||
api_ = api.UserListApi()
|
api_ = api.UserListApi()
|
||||||
self.assertRaises(errors.AuthError, api_.get, self.context)
|
self.assertRaises(errors.AuthError, api_.get, self.context)
|
||||||
|
|
||||||
|
def test_retrieving_non_existing(self):
|
||||||
|
self.context.user.rank = 'regular_user'
|
||||||
|
util.mock_params(self.context, {'query': 'asd', 'page': 1})
|
||||||
|
api_ = api.UserListApi()
|
||||||
|
result = api_.get(self.context)
|
||||||
|
self.assertEqual(result['query'], 'asd')
|
||||||
|
self.assertEqual(result['page'], 1)
|
||||||
|
self.assertEqual(result['pageSize'], 100)
|
||||||
|
self.assertEqual(result['total'], 0)
|
||||||
|
self.assertEqual([u['name'] for u in result['users']], [])
|
||||||
|
|
||||||
|
class TestRetrievingUser(DatabaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
util.mock_config({
|
||||||
|
'privileges': {
|
||||||
|
'users:view': 'regular_user',
|
||||||
|
},
|
||||||
|
'avatar_thumbnail_size': 200,
|
||||||
|
'ranks': ['anonymous', 'regular_user', 'mod', 'admin'],
|
||||||
|
'rank_names': {},
|
||||||
|
})
|
||||||
|
util.mock_context(self)
|
||||||
|
|
||||||
def test_retrieving_single(self):
|
def test_retrieving_single(self):
|
||||||
user = util.mock_user('u1', 'regular_user')
|
user = util.mock_user('u1', 'regular_user')
|
||||||
self.session.add(user)
|
self.session.add(user)
|
||||||
|
@ -65,6 +87,48 @@ class TestRetrievingUsers(DatabaseTestCase):
|
||||||
api_ = api.UserDetailApi()
|
api_ = api.UserDetailApi()
|
||||||
self.assertRaises(errors.AuthError, api_.get, self.context, '-')
|
self.assertRaises(errors.AuthError, api_.get, self.context, '-')
|
||||||
|
|
||||||
|
class TestDeletingUser(DatabaseTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
super().setUp()
|
||||||
|
util.mock_config({
|
||||||
|
'privileges': {
|
||||||
|
'users:delete:self': 'regular_user',
|
||||||
|
'users:delete:any': 'mod',
|
||||||
|
},
|
||||||
|
'ranks': ['anonymous', 'regular_user', 'mod', 'admin'],
|
||||||
|
'rank_names': {},
|
||||||
|
})
|
||||||
|
util.mock_context(self)
|
||||||
|
|
||||||
|
def test_removing_oneself(self):
|
||||||
|
user1 = util.mock_user('u1', 'regular_user')
|
||||||
|
user2 = util.mock_user('u2', 'regular_user')
|
||||||
|
self.session.add_all([user1, user2])
|
||||||
|
self.session.commit()
|
||||||
|
self.context.user.user_id = user1.user_id
|
||||||
|
self.context.user.rank = 'regular_user'
|
||||||
|
api_ = api.UserDetailApi()
|
||||||
|
self.assertRaises(errors.AuthError, api_.delete, self.context, 'u2')
|
||||||
|
api_.delete(self.context, 'u1')
|
||||||
|
self.assertEqual(self.session.query(db.User).filter_by(name='u1').all(), [])
|
||||||
|
|
||||||
|
def test_removing_someone_else(self):
|
||||||
|
user1 = util.mock_user('u1', 'regular_user')
|
||||||
|
user2 = util.mock_user('u2', 'regular_user')
|
||||||
|
self.session.add_all([user1, user2])
|
||||||
|
self.session.commit()
|
||||||
|
self.context.user.rank = 'mod'
|
||||||
|
api_ = api.UserDetailApi()
|
||||||
|
api_.delete(self.context, 'u1')
|
||||||
|
api_.delete(self.context, 'u2')
|
||||||
|
self.assertEqual(self.session.query(db.User).filter_by(name='u1').all(), [])
|
||||||
|
self.assertEqual(self.session.query(db.User).filter_by(name='u2').all(), [])
|
||||||
|
|
||||||
|
def test_removing_non_existing(self):
|
||||||
|
self.context.user.rank = 'regular_user'
|
||||||
|
api_ = api.UserDetailApi()
|
||||||
|
self.assertRaises(errors.NotFoundError, api_.delete, self.context, 'bad')
|
||||||
|
|
||||||
class TestCreatingUser(DatabaseTestCase):
|
class TestCreatingUser(DatabaseTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
Loading…
Reference in a new issue