2024-08-13 10:52:30 -05:00
|
|
|
# -*- coding: utf-8; -*-
|
|
|
|
|
|
|
|
from unittest.mock import patch
|
|
|
|
|
|
|
|
from sqlalchemy import orm
|
|
|
|
|
|
|
|
import colander
|
|
|
|
|
|
|
|
from wuttaweb.views import roles as mod
|
2025-01-24 19:00:46 -06:00
|
|
|
from wuttaweb.grids import Grid
|
2024-12-12 19:24:36 -06:00
|
|
|
from wuttaweb.forms.schema import RoleRef
|
2025-01-06 16:47:48 -06:00
|
|
|
from wuttaweb.testing import WebTestCase
|
2024-08-13 10:52:30 -05:00
|
|
|
|
|
|
|
|
|
|
|
class TestRoleView(WebTestCase):
|
|
|
|
|
|
|
|
def make_view(self):
|
|
|
|
return mod.RoleView(self.request)
|
|
|
|
|
2024-08-14 15:10:54 -05:00
|
|
|
def test_includeme(self):
|
2025-08-31 12:26:43 -05:00
|
|
|
self.pyramid_config.include("wuttaweb.views.roles")
|
2024-08-14 15:10:54 -05:00
|
|
|
|
2024-08-13 10:52:30 -05:00
|
|
|
def test_get_query(self):
|
|
|
|
view = self.make_view()
|
|
|
|
query = view.get_query(session=self.session)
|
|
|
|
self.assertIsInstance(query, orm.Query)
|
|
|
|
|
|
|
|
def test_configure_grid(self):
|
|
|
|
model = self.app.model
|
|
|
|
view = self.make_view()
|
|
|
|
grid = view.make_grid(model_class=model.Role)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertFalse(grid.is_linked("name"))
|
2024-08-13 10:52:30 -05:00
|
|
|
view.configure_grid(grid)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertTrue(grid.is_linked("name"))
|
2024-08-13 10:52:30 -05:00
|
|
|
|
2024-08-14 21:20:00 -05:00
|
|
|
def test_is_editable(self):
|
|
|
|
model = self.app.model
|
|
|
|
auth = self.app.get_auth_handler()
|
|
|
|
blokes = model.Role(name="Blokes")
|
|
|
|
self.session.add(blokes)
|
|
|
|
self.session.commit()
|
|
|
|
view = self.make_view()
|
|
|
|
|
|
|
|
admin = auth.get_role_administrator(self.session)
|
|
|
|
authed = auth.get_role_authenticated(self.session)
|
|
|
|
anon = auth.get_role_anonymous(self.session)
|
|
|
|
|
|
|
|
# editable by default
|
|
|
|
self.assertTrue(view.is_editable(blokes))
|
|
|
|
|
|
|
|
# built-in roles not editable by default
|
|
|
|
self.assertFalse(view.is_editable(admin))
|
|
|
|
self.assertFalse(view.is_editable(authed))
|
|
|
|
self.assertFalse(view.is_editable(anon))
|
|
|
|
|
|
|
|
# reset
|
|
|
|
del self.request.user_permissions
|
|
|
|
|
2025-08-31 12:26:43 -05:00
|
|
|
barney = model.User(username="barney")
|
2024-08-14 21:20:00 -05:00
|
|
|
self.session.add(barney)
|
|
|
|
barney.roles.append(blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
auth.grant_permission(blokes, "roles.edit_builtin")
|
2024-08-14 21:20:00 -05:00
|
|
|
self.session.commit()
|
|
|
|
|
|
|
|
# user with perms can edit *some* built-in
|
|
|
|
self.request.user = barney
|
|
|
|
self.assertTrue(view.is_editable(authed))
|
|
|
|
self.assertTrue(view.is_editable(anon))
|
|
|
|
# nb. not this one yet
|
|
|
|
self.assertFalse(view.is_editable(admin))
|
|
|
|
|
2024-08-14 16:58:08 -05:00
|
|
|
def test_is_deletable(self):
|
|
|
|
model = self.app.model
|
|
|
|
auth = self.app.get_auth_handler()
|
|
|
|
blokes = model.Role(name="Blokes")
|
|
|
|
self.session.add(blokes)
|
|
|
|
self.session.commit()
|
|
|
|
view = self.make_view()
|
|
|
|
|
|
|
|
# deletable by default
|
|
|
|
self.assertTrue(view.is_deletable(blokes))
|
|
|
|
|
|
|
|
# built-in roles not deletable
|
|
|
|
self.assertFalse(view.is_deletable(auth.get_role_administrator(self.session)))
|
|
|
|
self.assertFalse(view.is_deletable(auth.get_role_authenticated(self.session)))
|
|
|
|
self.assertFalse(view.is_deletable(auth.get_role_anonymous(self.session)))
|
|
|
|
|
2024-08-13 10:52:30 -05:00
|
|
|
def test_configure_form(self):
|
|
|
|
model = self.app.model
|
2024-08-14 15:10:54 -05:00
|
|
|
role = model.Role(name="Foo")
|
2024-08-13 10:52:30 -05:00
|
|
|
view = self.make_view()
|
2024-08-14 15:10:54 -05:00
|
|
|
form = view.make_form(model_instance=role)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertNotIn("name", form.validators)
|
2024-08-13 10:52:30 -05:00
|
|
|
view.configure_form(form)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertIsNotNone(form.validators["name"])
|
2024-08-13 10:52:30 -05:00
|
|
|
|
2025-01-24 19:00:46 -06:00
|
|
|
def test_make_users_grid(self):
|
2025-08-31 23:02:38 -05:00
|
|
|
self.pyramid_config.add_route("users.view", "/users/{uuid}/view")
|
|
|
|
self.pyramid_config.add_route("users.edit", "/users/{uuid}/edit")
|
2025-01-24 19:00:46 -06:00
|
|
|
model = self.app.model
|
|
|
|
view = self.make_view()
|
|
|
|
role = model.Role(name="Manager")
|
2025-08-31 23:02:38 -05:00
|
|
|
self.session.add(role)
|
|
|
|
user = model.User(username="freddie")
|
|
|
|
user.roles.append(role)
|
|
|
|
self.session.add(user)
|
|
|
|
self.session.commit()
|
2025-01-24 19:00:46 -06:00
|
|
|
|
|
|
|
# basic
|
|
|
|
grid = view.make_users_grid(role)
|
|
|
|
self.assertIsInstance(grid, Grid)
|
|
|
|
self.assertFalse(grid.linked_columns)
|
|
|
|
self.assertFalse(grid.actions)
|
|
|
|
|
|
|
|
# view + edit actions
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(self.request, "is_root", new=True):
|
2025-01-24 19:00:46 -06:00
|
|
|
grid = view.make_users_grid(role)
|
|
|
|
self.assertIsInstance(grid, Grid)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertIn("person", grid.linked_columns)
|
|
|
|
self.assertIn("username", grid.linked_columns)
|
2025-01-24 19:00:46 -06:00
|
|
|
self.assertEqual(len(grid.actions), 2)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(grid.actions[0].key, "view")
|
|
|
|
self.assertEqual(grid.actions[1].key, "edit")
|
2025-01-24 19:00:46 -06:00
|
|
|
|
2025-08-31 23:02:38 -05:00
|
|
|
# render grid to ensure coverage for link urls
|
|
|
|
grid.render_vue_template()
|
|
|
|
|
2024-08-13 10:52:30 -05:00
|
|
|
def test_unique_name(self):
|
|
|
|
model = self.app.model
|
|
|
|
view = self.make_view()
|
|
|
|
|
2025-08-31 12:26:43 -05:00
|
|
|
role = model.Role(name="Foo")
|
2024-08-13 10:52:30 -05:00
|
|
|
self.session.add(role)
|
|
|
|
self.session.commit()
|
|
|
|
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(mod, "Session", return_value=self.session):
|
2024-08-13 10:52:30 -05:00
|
|
|
|
|
|
|
# invalid if same name in data
|
2025-08-31 12:26:43 -05:00
|
|
|
node = colander.SchemaNode(colander.String(), name="name")
|
|
|
|
self.assertRaises(colander.Invalid, view.unique_name, node, "Foo")
|
2024-08-13 10:52:30 -05:00
|
|
|
|
|
|
|
# but not if name belongs to current role
|
|
|
|
view.editing = True
|
2025-08-31 12:26:43 -05:00
|
|
|
self.request.matchdict = {"uuid": role.uuid}
|
|
|
|
node = colander.SchemaNode(colander.String(), name="name")
|
|
|
|
self.assertIsNone(view.unique_name(node, "Foo"))
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
def get_permissions(self):
|
|
|
|
return {
|
2025-08-31 12:26:43 -05:00
|
|
|
"widgets": {
|
|
|
|
"label": "Widgets",
|
|
|
|
"perms": {
|
|
|
|
"widgets.list": {
|
|
|
|
"label": "List widgets",
|
2024-08-14 15:10:54 -05:00
|
|
|
},
|
2025-08-31 12:26:43 -05:00
|
|
|
"widgets.polish": {
|
|
|
|
"label": "Polish the widgets",
|
2024-08-14 15:10:54 -05:00
|
|
|
},
|
2025-08-31 12:26:43 -05:00
|
|
|
"widgets.view": {
|
|
|
|
"label": "View widget",
|
2024-08-14 15:10:54 -05:00
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
def test_get_available_permissions(self):
|
|
|
|
model = self.app.model
|
|
|
|
auth = self.app.get_auth_handler()
|
|
|
|
blokes = model.Role(name="Blokes")
|
2025-08-31 12:26:43 -05:00
|
|
|
auth.grant_permission(blokes, "widgets.list")
|
2024-08-14 15:10:54 -05:00
|
|
|
self.session.add(blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
barney = model.User(username="barney")
|
2024-08-14 15:10:54 -05:00
|
|
|
barney.roles.append(blokes)
|
|
|
|
self.session.add(barney)
|
|
|
|
self.session.commit()
|
|
|
|
view = self.make_view()
|
|
|
|
all_perms = self.get_permissions()
|
2025-08-31 12:26:43 -05:00
|
|
|
self.request.registry.settings["wutta_permissions"] = all_perms
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
def has_perm(perm):
|
2025-08-31 12:26:43 -05:00
|
|
|
if perm == "widgets.list":
|
2024-08-14 15:10:54 -05:00
|
|
|
return True
|
|
|
|
return False
|
|
|
|
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(self.request, "has_perm", new=has_perm, create=True):
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# sanity check; current request has 1 perm
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertTrue(self.request.has_perm("widgets.list"))
|
|
|
|
self.assertFalse(self.request.has_perm("widgets.polish"))
|
|
|
|
self.assertFalse(self.request.has_perm("widgets.view"))
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# when editing, user sees only the 1 perm
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(view, "editing", new=True):
|
2024-08-14 15:10:54 -05:00
|
|
|
perms = view.get_available_permissions()
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(list(perms), ["widgets"])
|
|
|
|
self.assertEqual(list(perms["widgets"]["perms"]), ["widgets.list"])
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# but when viewing, same user sees all perms
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(view, "viewing", new=True):
|
2024-08-14 15:10:54 -05:00
|
|
|
perms = view.get_available_permissions()
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(list(perms), ["widgets"])
|
|
|
|
self.assertEqual(
|
|
|
|
list(perms["widgets"]["perms"]),
|
|
|
|
["widgets.list", "widgets.polish", "widgets.view"],
|
|
|
|
)
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# also, when admin user is editing, sees all perms
|
|
|
|
self.request.is_admin = True
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(view, "editing", new=True):
|
2024-08-14 15:10:54 -05:00
|
|
|
perms = view.get_available_permissions()
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(list(perms), ["widgets"])
|
|
|
|
self.assertEqual(
|
|
|
|
list(perms["widgets"]["perms"]),
|
|
|
|
["widgets.list", "widgets.polish", "widgets.view"],
|
|
|
|
)
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
def test_objectify(self):
|
|
|
|
model = self.app.model
|
|
|
|
auth = self.app.get_auth_handler()
|
|
|
|
blokes = model.Role(name="Blokes")
|
|
|
|
self.session.add(blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
barney = model.User(username="barney")
|
2024-08-14 15:10:54 -05:00
|
|
|
barney.roles.append(blokes)
|
|
|
|
self.session.add(barney)
|
|
|
|
self.session.commit()
|
|
|
|
view = self.make_view()
|
|
|
|
permissions = self.get_permissions()
|
|
|
|
|
|
|
|
# sanity check, role has just 1 perm
|
2025-08-31 12:26:43 -05:00
|
|
|
auth.grant_permission(blokes, "widgets.list")
|
2024-08-14 15:10:54 -05:00
|
|
|
self.session.commit()
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(blokes.permissions, ["widgets.list"])
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# form can update role perms
|
|
|
|
view.editing = True
|
2025-08-31 12:26:43 -05:00
|
|
|
self.request.matchdict = {"uuid": blokes.uuid}
|
|
|
|
with patch.object(view, "get_available_permissions", return_value=permissions):
|
2024-08-14 15:10:54 -05:00
|
|
|
form = view.make_model_form(model_instance=blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
form.validated = {
|
|
|
|
"name": "Blokes",
|
|
|
|
"permissions": {"widgets.list", "widgets.polish", "widgets.view"},
|
|
|
|
}
|
2024-08-14 15:10:54 -05:00
|
|
|
role = view.objectify(form)
|
|
|
|
self.session.commit()
|
|
|
|
self.assertIs(role, blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(
|
|
|
|
blokes.permissions, ["widgets.list", "widgets.polish", "widgets.view"]
|
|
|
|
)
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
def test_update_permissions(self):
|
|
|
|
model = self.app.model
|
|
|
|
auth = self.app.get_auth_handler()
|
|
|
|
blokes = model.Role(name="Blokes")
|
2025-08-31 12:26:43 -05:00
|
|
|
auth.grant_permission(blokes, "widgets.list")
|
2024-08-14 15:10:54 -05:00
|
|
|
self.session.add(blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
barney = model.User(username="barney")
|
2024-08-14 15:10:54 -05:00
|
|
|
barney.roles.append(blokes)
|
|
|
|
self.session.add(barney)
|
|
|
|
self.session.commit()
|
|
|
|
view = self.make_view()
|
|
|
|
permissions = self.get_permissions()
|
|
|
|
|
2025-08-31 12:26:43 -05:00
|
|
|
with patch.object(view, "get_available_permissions", return_value=permissions):
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# no error if data is missing perms
|
|
|
|
form = view.make_model_form(model_instance=blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
form.validated = {"name": "BloX"}
|
2024-08-14 15:10:54 -05:00
|
|
|
role = view.objectify(form)
|
|
|
|
self.session.commit()
|
|
|
|
self.assertIs(role, blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(blokes.name, "BloX")
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# sanity check, role has just 1 perm
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(blokes.permissions, ["widgets.list"])
|
2024-08-14 15:10:54 -05:00
|
|
|
|
|
|
|
# role perms are updated
|
|
|
|
form = view.make_model_form(model_instance=blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
form.validated = {
|
|
|
|
"name": "Blokes",
|
|
|
|
"permissions": {"widgets.polish", "widgets.view"},
|
|
|
|
}
|
2024-08-14 15:10:54 -05:00
|
|
|
role = view.objectify(form)
|
|
|
|
self.session.commit()
|
|
|
|
self.assertIs(role, blokes)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertEqual(blokes.permissions, ["widgets.polish", "widgets.view"])
|
2024-12-12 19:24:36 -06:00
|
|
|
|
|
|
|
|
|
|
|
class TestPermissionView(WebTestCase):
|
|
|
|
|
|
|
|
def make_view(self):
|
|
|
|
return mod.PermissionView(self.request)
|
|
|
|
|
|
|
|
def test_get_query(self):
|
|
|
|
view = self.make_view()
|
|
|
|
query = view.get_query(session=self.session)
|
|
|
|
self.assertIsInstance(query, orm.Query)
|
|
|
|
|
|
|
|
def test_configure_grid(self):
|
|
|
|
model = self.app.model
|
|
|
|
view = self.make_view()
|
|
|
|
grid = view.make_grid(model_class=model.Permission)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertFalse(grid.is_linked("role"))
|
2024-12-12 19:24:36 -06:00
|
|
|
view.configure_grid(grid)
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertTrue(grid.is_linked("role"))
|
2024-12-12 19:24:36 -06:00
|
|
|
|
|
|
|
def test_configure_form(self):
|
|
|
|
model = self.app.model
|
|
|
|
role = model.Role(name="Foo")
|
2025-08-31 12:26:43 -05:00
|
|
|
perm = model.Permission(role=role, permission="whatever")
|
2024-12-12 19:24:36 -06:00
|
|
|
view = self.make_view()
|
|
|
|
form = view.make_form(model_instance=perm)
|
|
|
|
self.assertIsNone(form.schema)
|
|
|
|
view.configure_form(form)
|
|
|
|
schema = form.get_schema()
|
2025-08-31 12:26:43 -05:00
|
|
|
self.assertIsInstance(schema["role"].typ, RoleRef)
|