# -*- coding: utf-8; -*- from unittest.mock import patch from sqlalchemy import orm import colander from wuttaweb.views import users as mod from wuttaweb.testing import WebTestCase class TestUserView(WebTestCase): def make_view(self): return mod.UserView(self.request) def test_includeme(self): self.pyramid_config.include('wuttaweb.views.users') 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.User) self.assertFalse(grid.is_linked('person')) view.configure_grid(grid) self.assertTrue(grid.is_linked('person')) def test_grid_row_class(self): model = self.app.model user = model.User(username='barney', active=True) data = dict(user) view = self.make_view() self.assertIsNone(view.grid_row_class(user, data, 1)) user.active = False self.assertEqual(view.grid_row_class(user, data, 1), 'has-background-warning') def test_is_editable(self): model = self.app.model view = self.make_view() # active user is editable user = model.User(username='barney', active=True) self.assertTrue(view.is_editable(user)) # inactive also editable user = model.User(username='barney', active=False) self.assertTrue(view.is_editable(user)) # but not if prevent_edit flag is set user = model.User(username='barney', prevent_edit=True) self.assertFalse(view.is_editable(user)) # unless request user is root self.request.is_root = True self.assertTrue(view.is_editable(user)) def test_configure_form(self): model = self.app.model person = model.Person(first_name='Barney', last_name='Rubble', full_name='Barney Rubble') barney = model.User(username='barney', person=person) self.session.add(barney) self.session.commit() view = self.make_view() # person replaced with first/last name when creating or editing with patch.object(view, 'viewing', new=True): form = view.make_form(model_instance=barney) self.assertIn('person', form) self.assertNotIn('first_name', form) self.assertNotIn('last_name', form) view.configure_form(form) self.assertIn('person', form) self.assertNotIn('first_name', form) self.assertNotIn('last_name', form) with patch.object(view, 'creating', new=True): form = view.make_form(model_instance=barney) self.assertIn('person', form) self.assertNotIn('first_name', form) self.assertNotIn('last_name', form) view.configure_form(form) self.assertNotIn('person', form) self.assertIn('first_name', form) self.assertIn('last_name', form) with patch.object(view, 'editing', new=True): form = view.make_form(model_instance=barney) self.assertIn('person', form) self.assertNotIn('first_name', form) self.assertNotIn('last_name', form) view.configure_form(form) self.assertNotIn('person', form) self.assertIn('first_name', form) self.assertIn('last_name', form) # first/last name have default values when editing with patch.object(view, 'editing', new=True): form = view.make_form(model_instance=barney) self.assertNotIn('first_name', form.defaults) self.assertNotIn('last_name', form.defaults) view.configure_form(form) self.assertIn('first_name', form.defaults) self.assertEqual(form.defaults['first_name'], 'Barney') self.assertIn('last_name', form.defaults) self.assertEqual(form.defaults['last_name'], 'Rubble') # password removed (always, for now) with patch.object(view, 'viewing', new=True): form = view.make_form(model_instance=barney) self.assertIn('password', form) view.configure_form(form) self.assertNotIn('password', form) with patch.object(view, 'editing', new=True): form = view.make_form(model_instance=barney) self.assertIn('password', form) view.configure_form(form) self.assertNotIn('password', form) def test_unique_username(self): model = self.app.model view = self.make_view() user = model.User(username='foo') self.session.add(user) self.session.commit() with patch.object(view, 'Session', return_value=self.session): # invalid if same username in data node = colander.SchemaNode(colander.String(), name='username') self.assertRaises(colander.Invalid, view.unique_username, node, 'foo') # but not if username belongs to current user view.editing = True self.request.matchdict = {'uuid': user.uuid} node = colander.SchemaNode(colander.String(), name='username') self.assertIsNone(view.unique_username(node, 'foo')) def test_objectify(self): model = self.app.model auth = self.app.get_auth_handler() view = self.make_view() blokes = model.Role(name="Blokes") self.session.add(blokes) others = model.Role(name="Others") self.session.add(others) barney = model.User(username='barney') auth.set_user_password(barney, 'testpass') barney.roles.append(blokes) self.session.add(barney) self.session.commit() with patch.object(self.request, 'matchdict', new={'uuid': barney.uuid}): with patch.object(view, 'editing', new=True): # sanity check, user is just in 'blokes' role self.session.refresh(barney) self.assertEqual(len(barney.roles), 1) self.assertEqual(barney.roles[0].name, "Blokes") # form can update user password self.assertTrue(auth.check_user_password(barney, 'testpass')) form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'set_password': 'testpass2'} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIs(user, barney) self.assertTrue(auth.check_user_password(barney, 'testpass2')) # form can update user roles form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'roles': {others.uuid}} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIs(user, barney) self.assertEqual(len(user.roles), 1) self.assertEqual(user.roles[0].name, "Others") # person is auto-created self.assertIsNone(barney.person) form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'first_name': 'Barney', 'last_name': 'Rubble'} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIsNotNone(barney.person) self.assertEqual(barney.person.first_name, 'Barney') self.assertEqual(barney.person.last_name, 'Rubble') self.assertEqual(barney.person.full_name, 'Barney Rubble') # person is auto-removed self.assertIsNotNone(barney.person) form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'first_name': '', 'last_name': ''} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIsNone(barney.person) # nb. re-attach the person barney.person = self.session.query(model.Person).one() # person name is updated self.assertEqual(barney.person.first_name, 'Barney') self.assertEqual(barney.person.last_name, 'Rubble') self.assertEqual(barney.person.full_name, 'Barney Rubble') form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'first_name': 'Fred', 'last_name': 'Flintstone'} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIsNotNone(barney.person) self.assertEqual(barney.person.first_name, 'Fred') self.assertEqual(barney.person.last_name, 'Flintstone') self.assertEqual(barney.person.full_name, 'Fred Flintstone') with patch.object(view, 'creating', new=True): # person is auto-created when making new user form = view.make_model_form() form.validated = {'username': 'betty', 'first_name': 'Betty', 'last_name': 'Boop'} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIsNotNone(user.person) self.assertEqual(user.person.first_name, 'Betty') self.assertEqual(user.person.last_name, 'Boop') self.assertEqual(user.person.full_name, 'Betty Boop') # nb. keep ref to last user last_user = user # person is *not* auto-created if no name provided form = view.make_model_form() form.validated = {'username': 'betty', 'first_name': '', 'last_name': ''} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIsNone(user.person) self.assertIsNot(user, last_user) def test_update_roles(self): model = self.app.model auth = self.app.get_auth_handler() admin = auth.get_role_administrator(self.session) authed = auth.get_role_authenticated(self.session) anon = auth.get_role_anonymous(self.session) blokes = model.Role(name="Blokes") self.session.add(blokes) others = model.Role(name="Others") self.session.add(others) barney = model.User(username='barney') barney.roles.append(blokes) self.session.add(barney) self.session.commit() view = self.make_view() view.editing = True self.request.matchdict = {'uuid': barney.uuid} # no error if data is missing roles form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barneyx'} user = view.objectify(form) self.assertIs(user, barney) self.assertEqual(barney.username, 'barneyx') # sanity check, user is just in 'blokes' role self.session.refresh(barney) self.assertEqual(len(barney.roles), 1) self.assertEqual(barney.roles[0].name, "Blokes") # let's test a bunch at once to ensure: # - user roles are updated # - authed / anon roles are not added # - admin role not added if current user is not root form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'roles': {admin.uuid, authed.uuid, anon.uuid, others.uuid}} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIs(user, barney) self.assertEqual(len(user.roles), 1) self.assertEqual(user.roles[0].name, "Others") # let's test a bunch at once to ensure: # - user roles are updated # - admin role is added if current user is root self.request.is_root = True form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'roles': {admin.uuid, blokes.uuid, others.uuid}} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIs(user, barney) self.assertEqual(len(user.roles), 3) role_uuids = set([role.uuid for role in user.roles]) self.assertEqual(role_uuids, {admin.uuid, blokes.uuid, others.uuid}) # admin role not removed if current user is not root self.request.is_root = False form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'roles': {blokes.uuid, others.uuid}} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIs(user, barney) self.assertEqual(len(user.roles), 3) # admin role is removed if current user is root self.request.is_root = True form = view.make_model_form(model_instance=barney) form.validated = {'username': 'barney', 'roles': {blokes.uuid, others.uuid}} with patch.object(view, 'Session', return_value=self.session): user = view.objectify(form) self.assertIs(user, barney) self.assertEqual(len(user.roles), 2)