diff --git a/aurweb/models/user.py b/aurweb/models/user.py index 5ead606e..9f1a9c17 100644 --- a/aurweb/models/user.py +++ b/aurweb/models/user.py @@ -182,14 +182,24 @@ class User(Base): aurweb.models.account_type.TRUSTED_USER_AND_DEV_ID, } - def can_edit_user(self, user): - """ Can this account record edit the target user? It must either - be the target user or a user with enough permissions to do so. - - :param user: Target user - :return: Boolean indicating whether this instance can edit `user` + def can_edit_user(self, target: "User") -> bool: """ - return self == user or self.is_trusted_user() or self.is_developer() + Whether this User instance can edit `target`. + + This User can edit user `target` if we both: have credentials and + self.AccountTypeID is greater or equal to `target`.AccountTypeID. + + In short, a user must at least have credentials and be at least + the same account type as the target. + + User < Trusted User < Developer < Trusted User & Developer + + :param target: Target User to be edited + :return: Boolean indicating whether `self` can edit `target` + """ + from aurweb.auth import creds + has_cred = self.has_credential(creds.ACCOUNT_EDIT, approved=[target]) + return has_cred and self.AccountTypeID >= target.AccountTypeID def voted_for(self, package) -> bool: """ Has this User voted for package? """ diff --git a/test/test_user.py b/test/test_user.py index 2c8dd847..7871cd61 100644 --- a/test/test_user.py +++ b/test/test_user.py @@ -12,6 +12,7 @@ import aurweb.models.account_type as at from aurweb import db from aurweb.auth import creds +from aurweb.models.account_type import DEVELOPER_ID, TRUSTED_USER_AND_DEV_ID, TRUSTED_USER_ID, USER_ID from aurweb.models.ban import Ban from aurweb.models.package import Package from aurweb.models.package_base import PackageBase @@ -28,12 +29,36 @@ def setup(db_test): return +def create_user(username: str, account_type_id: int): + with db.begin(): + user = db.create(User, Username=username, + Email=f"{username}@example.org", + RealName=username.title(), Passwd="testPassword", + AccountTypeID=account_type_id) + return user + + @pytest.fixture def user() -> User: - with db.begin(): - user = db.create(User, Username="test", Email="test@example.org", - RealName="Test User", Passwd="testPassword", - AccountTypeID=at.USER_ID) + user = create_user("test", USER_ID) + yield user + + +@pytest.fixture +def tu_user() -> User: + user = create_user("test_tu", TRUSTED_USER_ID) + yield user + + +@pytest.fixture +def dev_user() -> User: + user = create_user("test_dev", DEVELOPER_ID) + yield user + + +@pytest.fixture +def tu_and_dev_user() -> User: + user = create_user("test_tu_and_dev", TRUSTED_USER_AND_DEV_ID) yield user @@ -256,3 +281,36 @@ def test_user_notified(user: User, package: Package): def test_user_packages(user: User, package: Package): assert package in user.packages() + + +def test_can_edit_user(user: User, tu_user: User, dev_user: User, + tu_and_dev_user: User): + # User can edit. + assert user.can_edit_user(user) + + # User cannot edit. + assert not user.can_edit_user(tu_user) + assert not user.can_edit_user(dev_user) + assert not user.can_edit_user(tu_and_dev_user) + + # Trusted User can edit. + assert tu_user.can_edit_user(user) + assert tu_user.can_edit_user(tu_user) + + # Trusted User cannot edit. + assert not tu_user.can_edit_user(dev_user) + assert not tu_user.can_edit_user(tu_and_dev_user) + + # Developer can edit. + assert dev_user.can_edit_user(user) + assert dev_user.can_edit_user(tu_user) + assert dev_user.can_edit_user(dev_user) + + # Developer cannot edit. + assert not dev_user.can_edit_user(tu_and_dev_user) + + # Trusted User & Developer can edit. + assert tu_and_dev_user.can_edit_user(user) + assert tu_and_dev_user.can_edit_user(tu_user) + assert tu_and_dev_user.can_edit_user(dev_user) + assert tu_and_dev_user.can_edit_user(tu_and_dev_user)