This repository has been archived on 2025-02-26. You can view files and clone it, but cannot push or open issues or pull requests.
szurubooru/server/szurubooru/tests/api/test_user_updating.py

189 lines
7.1 KiB
Python

import datetime
import pytest
from szurubooru import api, config, db, errors
from szurubooru.func import auth, util, users
EMPTY_PIXEL = \
b'\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00' \
b'\xff\xff\xff\x21\xf9\x04\x01\x00\x00\x01\x00\x2c\x00\x00\x00\x00' \
b'\x01\x00\x01\x00\x00\x02\x02\x4c\x01\x00\x3b'
def get_user(name):
return db.session.query(db.User).filter_by(name=name).first()
@pytest.fixture
def test_ctx(config_injector, context_factory, user_factory):
config_injector({
'secret': '',
'user_name_regex': '^[^!]{3,}$',
'password_regex': '^[^!]{3,}$',
'thumbnails': {'avatar_width': 200, 'avatar_height': 200},
'ranks': ['anonymous', 'regular_user', 'mod', 'admin'],
'rank_names': {},
'privileges': {
'users:edit:self:name': 'regular_user',
'users:edit:self:pass': 'regular_user',
'users:edit:self:email': 'regular_user',
'users:edit:self:rank': 'mod',
'users:edit:self:avatar': 'mod',
'users:edit:any:name': 'mod',
'users:edit:any:pass': 'mod',
'users:edit:any:email': 'mod',
'users:edit:any:rank': 'admin',
'users:edit:any:avatar': 'admin',
},
})
ret = util.dotdict()
ret.context_factory = context_factory
ret.user_factory = user_factory
ret.api = api.UserDetailApi()
return ret
def test_updating_user(test_ctx):
user = test_ctx.user_factory(name='u1', rank='admin')
db.session.add(user)
result = test_ctx.api.put(
test_ctx.context_factory(
input={
'name': 'chewie',
'email': 'asd@asd.asd',
'password': 'oks',
'rank': 'mod',
'avatarStyle': 'gravatar',
},
user=user),
'u1')
assert result == {
'user': {
'avatarStyle': 'gravatar',
'avatarUrl': 'http://gravatar.com/avatar/' +
'6f370c8c7109534c3d5c394123a477d7?d=retro&s=200',
'creationTime': datetime.datetime(1997, 1, 1),
'lastLoginTime': None,
'email': 'asd@asd.asd',
'name': 'chewie',
'rank': 'mod',
'rankName': 'Unknown',
}
}
user = get_user('chewie')
assert user.name == 'chewie'
assert user.email == 'asd@asd.asd'
assert user.rank == 'mod'
assert user.avatar_style == user.AVATAR_GRAVATAR
assert auth.is_valid_password(user, 'oks') is True
assert auth.is_valid_password(user, 'invalid') is False
@pytest.mark.parametrize('input,expected_exception', [
({'name': None}, users.InvalidUserNameError),
({'name': ''}, users.InvalidUserNameError),
({'name': '!bad'}, users.InvalidUserNameError),
({'name': 'x' * 51}, users.InvalidUserNameError),
({'password': None}, users.InvalidPasswordError),
({'password': ''}, users.InvalidPasswordError),
({'password': '!bad'}, users.InvalidPasswordError),
({'rank': None}, users.InvalidRankError),
({'rank': ''}, users.InvalidRankError),
({'rank': 'bad'}, users.InvalidRankError),
({'email': 'bad'}, users.InvalidEmailError),
({'email': 'x@' * 65 + '.com'}, users.InvalidEmailError),
({'avatarStyle': None}, users.InvalidAvatarError),
({'avatarStyle': ''}, users.InvalidAvatarError),
({'avatarStyle': 'invalid'}, users.InvalidAvatarError),
({'avatarStyle': 'manual'}, users.InvalidAvatarError), # missing file
])
def test_trying_to_pass_invalid_input(test_ctx, input, expected_exception):
user = test_ctx.user_factory(name='u1', rank='admin')
db.session.add(user)
with pytest.raises(expected_exception):
test_ctx.api.put(
test_ctx.context_factory(input=input, user=user), 'u1')
@pytest.mark.parametrize(
'field', ['name', 'email', 'password', 'rank', 'avatarStyle'])
def test_omitting_optional_field(test_ctx, tmpdir, field):
config.config['data_dir'] = str(tmpdir.mkdir('data'))
config.config['data_url'] = 'http://example.com/data/'
user = test_ctx.user_factory(name='u1', rank='admin')
db.session.add(user)
input = {
'name': 'chewie',
'email': 'asd@asd.asd',
'password': 'oks',
'rank': 'mod',
'avatarStyle': 'gravatar',
}
del input[field]
result = test_ctx.api.put(
test_ctx.context_factory(
input=input,
files={'avatar': EMPTY_PIXEL},
user=user),
'u1')
assert result is not None
def test_trying_to_update_non_existing(test_ctx):
user = test_ctx.user_factory(name='u1', rank='admin')
db.session.add(user)
with pytest.raises(users.UserNotFoundError):
test_ctx.api.put(test_ctx.context_factory(user=user), 'u2')
def test_removing_email(test_ctx):
user = test_ctx.user_factory(name='u1', rank='admin')
db.session.add(user)
test_ctx.api.put(
test_ctx.context_factory(input={'email': ''}, user=user), 'u1')
assert get_user('u1').email is None
@pytest.mark.parametrize('input', [
{'name': 'whatever'},
{'email': 'whatever'},
{'rank': 'whatever'},
{'password': 'whatever'},
{'avatarStyle': 'whatever'},
])
def test_trying_to_update_someone_else(test_ctx, input):
user1 = test_ctx.user_factory(name='u1', rank='regular_user')
user2 = test_ctx.user_factory(name='u2', rank='regular_user')
db.session.add_all([user1, user2])
with pytest.raises(errors.AuthError):
test_ctx.api.put(
test_ctx.context_factory(input=input, user=user1), user2.name)
def test_trying_to_become_someone_else(test_ctx):
user1 = test_ctx.user_factory(name='me', rank='regular_user')
user2 = test_ctx.user_factory(name='her', rank='regular_user')
db.session.add_all([user1, user2])
with pytest.raises(users.UserAlreadyExistsError):
test_ctx.api.put(
test_ctx.context_factory(input={'name': 'her'}, user=user1),
'me')
with pytest.raises(users.UserAlreadyExistsError):
test_ctx.api.put(
test_ctx.context_factory(input={'name': 'HER'}, user=user1), 'me')
def test_mods_trying_to_become_admin(test_ctx):
user1 = test_ctx.user_factory(name='u1', rank='mod')
user2 = test_ctx.user_factory(name='u2', rank='mod')
db.session.add_all([user1, user2])
context = test_ctx.context_factory(input={'rank': 'admin'}, user=user1)
with pytest.raises(errors.AuthError):
test_ctx.api.put(context, user1.name)
with pytest.raises(errors.AuthError):
test_ctx.api.put(context, user2.name)
def test_uploading_avatar(test_ctx, tmpdir):
config.config['data_dir'] = str(tmpdir.mkdir('data'))
config.config['data_url'] = 'http://example.com/data/'
user = test_ctx.user_factory(name='u1', rank='mod')
db.session.add(user)
response = test_ctx.api.put(
test_ctx.context_factory(
input={'avatarStyle': 'manual'},
files={'avatar': EMPTY_PIXEL},
user=user),
'u1')
user = get_user('u1')
assert user.avatar_style == user.AVATAR_MANUAL
assert response['user']['avatarUrl'] == \
'http://example.com/data/avatars/u1.jpg'