| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | # -*- coding: utf-8; -*- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from unittest.mock import patch | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | from sqlalchemy import orm | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import colander | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | from wuttaweb.grids import Grid | 
					
						
							| 
									
										
										
										
											2024-08-13 10:52:30 -05:00
										 |  |  | from wuttaweb.views import users as mod | 
					
						
							| 
									
										
										
										
											2025-01-06 16:47:48 -06:00
										 |  |  | from wuttaweb.testing import WebTestCase | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 10:52:30 -05:00
										 |  |  | class TestUserView(WebTestCase): | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def make_view(self): | 
					
						
							| 
									
										
										
										
											2024-08-13 10:52:30 -05:00
										 |  |  |         return mod.UserView(self.request) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  |     def test_includeme(self): | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.pyramid_config.include("wuttaweb.views.users") | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -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.User) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertFalse(grid.is_linked("person")) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         view.configure_grid(grid) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertTrue(grid.is_linked("person")) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  |     def test_grid_row_class(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="barney", active=True) | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  |         data = dict(user) | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         self.assertIsNone(view.grid_row_class(user, data, 1)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         user.active = False | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(view.grid_row_class(user, data, 1), "has-background-warning") | 
					
						
							| 
									
										
										
										
											2024-08-23 14:14:41 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-11-24 17:19:50 -06:00
										 |  |  |     def test_is_editable(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # active user is editable | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="barney", active=True) | 
					
						
							| 
									
										
										
										
											2024-11-24 17:19:50 -06:00
										 |  |  |         self.assertTrue(view.is_editable(user)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # inactive also editable | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="barney", active=False) | 
					
						
							| 
									
										
										
										
											2024-11-24 17:19:50 -06:00
										 |  |  |         self.assertTrue(view.is_editable(user)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # but not if prevent_edit flag is set | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="barney", prevent_edit=True) | 
					
						
							| 
									
										
										
										
											2024-11-24 17:19:50 -06:00
										 |  |  |         self.assertFalse(view.is_editable(user)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # unless request user is root | 
					
						
							|  |  |  |         self.request.is_root = True | 
					
						
							|  |  |  |         self.assertTrue(view.is_editable(user)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |     def test_configure_form(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         person = model.Person( | 
					
						
							|  |  |  |             first_name="Barney", last_name="Rubble", full_name="Barney Rubble" | 
					
						
							|  |  |  |         ) | 
					
						
							|  |  |  |         barney = model.User(username="barney", person=person) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         self.session.add(barney) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         view = self.make_view() | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |         # person replaced with first/last name when creating or editing | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "viewing", new=True): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("person", form) | 
					
						
							|  |  |  |             self.assertNotIn("first_name", form) | 
					
						
							|  |  |  |             self.assertNotIn("last_name", form) | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("person", form) | 
					
						
							|  |  |  |             self.assertNotIn("first_name", form) | 
					
						
							|  |  |  |             self.assertNotIn("last_name", form) | 
					
						
							|  |  |  |         with patch.object(view, "creating", new=True): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("person", form) | 
					
						
							|  |  |  |             self.assertNotIn("first_name", form) | 
					
						
							|  |  |  |             self.assertNotIn("last_name", form) | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertNotIn("person", form) | 
					
						
							|  |  |  |             self.assertIn("first_name", form) | 
					
						
							|  |  |  |             self.assertIn("last_name", form) | 
					
						
							|  |  |  |         with patch.object(view, "editing", new=True): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("person", form) | 
					
						
							|  |  |  |             self.assertNotIn("first_name", form) | 
					
						
							|  |  |  |             self.assertNotIn("last_name", form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertNotIn("person", form) | 
					
						
							|  |  |  |             self.assertIn("first_name", form) | 
					
						
							|  |  |  |             self.assertIn("last_name", form) | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # first/last name have default values when editing | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "editing", new=True): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertNotIn("first_name", form.defaults) | 
					
						
							|  |  |  |             self.assertNotIn("last_name", form.defaults) | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             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") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # password removed (always, for now) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "viewing", new=True): | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("password", form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertNotIn("password", form) | 
					
						
							|  |  |  |         with patch.object(view, "editing", new=True): | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("password", form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertNotIn("password", form) | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         # api tokens grid shown only if current user has perm | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "viewing", new=True): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |             form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("api_tokens", form) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |             view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertNotIn("api_tokens", form) | 
					
						
							|  |  |  |             with patch.object(self.request, "is_root", new=True): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                 form = view.make_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertIn("api_tokens", form) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                 view.configure_form(form) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertIn("api_tokens", form) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |     def test_unique_username(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="foo") | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  |         self.session.add(user) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # invalid if same username in data | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             node = colander.SchemaNode(colander.String(), name="username") | 
					
						
							|  |  |  |             self.assertRaises(colander.Invalid, view.unique_username, node, "foo") | 
					
						
							| 
									
										
										
										
											2024-08-12 21:17:08 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # but not if username belongs to current user | 
					
						
							|  |  |  |             view.editing = True | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.request.matchdict = {"uuid": user.uuid} | 
					
						
							|  |  |  |             node = colander.SchemaNode(colander.String(), name="username") | 
					
						
							|  |  |  |             self.assertIsNone(view.unique_username(node, "foo")) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_objectify(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  |         auth = self.app.get_auth_handler() | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         blokes = model.Role(name="Blokes") | 
					
						
							|  |  |  |         self.session.add(blokes) | 
					
						
							|  |  |  |         others = model.Role(name="Others") | 
					
						
							|  |  |  |         self.session.add(others) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         barney = model.User(username="barney") | 
					
						
							|  |  |  |         auth.set_user_password(barney, "testpass") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         barney.roles.append(blokes) | 
					
						
							|  |  |  |         self.session.add(barney) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(self.request, "matchdict", new={"uuid": barney.uuid}): | 
					
						
							|  |  |  |             with patch.object(view, "editing", new=True): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # 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 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertTrue(auth.check_user_password(barney, "testpass")) | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                 form = view.make_model_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 form.validated = {"username": "barney", "set_password": "testpass2"} | 
					
						
							|  |  |  |                 with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                     user = view.objectify(form) | 
					
						
							|  |  |  |                 self.assertIs(user, barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertTrue(auth.check_user_password(barney, "testpass2")) | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # form can update user roles | 
					
						
							|  |  |  |                 form = view.make_model_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 form.validated = {"username": "barney", "roles": {others.uuid}} | 
					
						
							|  |  |  |                 with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                     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) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 form.validated = { | 
					
						
							|  |  |  |                     "username": "barney", | 
					
						
							|  |  |  |                     "first_name": "Barney", | 
					
						
							|  |  |  |                     "last_name": "Rubble", | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                     user = view.objectify(form) | 
					
						
							|  |  |  |                 self.assertIsNotNone(barney.person) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertEqual(barney.person.first_name, "Barney") | 
					
						
							|  |  |  |                 self.assertEqual(barney.person.last_name, "Rubble") | 
					
						
							|  |  |  |                 self.assertEqual(barney.person.full_name, "Barney Rubble") | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # person is auto-removed | 
					
						
							|  |  |  |                 self.assertIsNotNone(barney.person) | 
					
						
							|  |  |  |                 form = view.make_model_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 form.validated = { | 
					
						
							|  |  |  |                     "username": "barney", | 
					
						
							|  |  |  |                     "first_name": "", | 
					
						
							|  |  |  |                     "last_name": "", | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                     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 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertEqual(barney.person.first_name, "Barney") | 
					
						
							|  |  |  |                 self.assertEqual(barney.person.last_name, "Rubble") | 
					
						
							|  |  |  |                 self.assertEqual(barney.person.full_name, "Barney Rubble") | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                 form = view.make_model_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 form.validated = { | 
					
						
							|  |  |  |                     "username": "barney", | 
					
						
							|  |  |  |                     "first_name": "Fred", | 
					
						
							|  |  |  |                     "last_name": "Flintstone", | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                     user = view.objectify(form) | 
					
						
							|  |  |  |                 self.assertIsNotNone(barney.person) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 self.assertEqual(barney.person.first_name, "Fred") | 
					
						
							|  |  |  |                 self.assertEqual(barney.person.last_name, "Flintstone") | 
					
						
							|  |  |  |                 self.assertEqual(barney.person.full_name, "Fred Flintstone") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "creating", new=True): | 
					
						
							| 
									
										
										
										
											2024-08-14 15:55:10 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             # person is auto-created when making new user | 
					
						
							|  |  |  |             form = view.make_model_form() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             form.validated = { | 
					
						
							|  |  |  |                 "username": "betty", | 
					
						
							|  |  |  |                 "first_name": "Betty", | 
					
						
							|  |  |  |                 "last_name": "Boop", | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                 user = view.objectify(form) | 
					
						
							|  |  |  |             self.assertIsNotNone(user.person) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertEqual(user.person.first_name, "Betty") | 
					
						
							|  |  |  |             self.assertEqual(user.person.last_name, "Boop") | 
					
						
							|  |  |  |             self.assertEqual(user.person.full_name, "Betty Boop") | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |             # nb. keep ref to last user | 
					
						
							|  |  |  |             last_user = user | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # person is *not* auto-created if no name provided | 
					
						
							|  |  |  |             form = view.make_model_form() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             form.validated = {"username": "betty", "first_name": "", "last_name": ""} | 
					
						
							|  |  |  |             with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |                 user = view.objectify(form) | 
					
						
							|  |  |  |             self.assertIsNone(user.person) | 
					
						
							|  |  |  |             self.assertIsNot(user, last_user) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         barney = model.User(username="barney") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         barney.roles.append(blokes) | 
					
						
							|  |  |  |         self.session.add(barney) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  |         view.editing = True | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.request.matchdict = {"uuid": barney.uuid} | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # no error if data is missing roles | 
					
						
							|  |  |  |         form = view.make_model_form(model_instance=barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.validated = {"username": "barneyx"} | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |         user = view.objectify(form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         self.assertIs(user, barney) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertEqual(barney.username, "barneyx") | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # 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) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.validated = { | 
					
						
							|  |  |  |             "username": "barney", | 
					
						
							|  |  |  |             "roles": {admin.uuid, authed.uuid, anon.uuid, others.uuid}, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             user = view.objectify(form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         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) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.validated = { | 
					
						
							|  |  |  |             "username": "barney", | 
					
						
							|  |  |  |             "roles": {admin.uuid, blokes.uuid, others.uuid}, | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             user = view.objectify(form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         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) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.validated = {"username": "barney", "roles": {blokes.uuid, others.uuid}} | 
					
						
							|  |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             user = view.objectify(form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         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) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         form.validated = {"username": "barney", "roles": {blokes.uuid, others.uuid}} | 
					
						
							|  |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							| 
									
										
										
										
											2025-01-27 17:07:42 -06:00
										 |  |  |             user = view.objectify(form) | 
					
						
							| 
									
										
										
										
											2024-08-13 21:43:56 -05:00
										 |  |  |         self.assertIs(user, barney) | 
					
						
							|  |  |  |         self.assertEqual(len(user.roles), 2) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_normalize_api_token(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         auth = self.app.get_auth_handler() | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="foo") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.add(user) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         token = auth.add_api_token(user, "test token") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         normal = view.normalize_api_token(token) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         self.assertIn("uuid", normal) | 
					
						
							|  |  |  |         self.assertEqual(normal["uuid"], token.uuid.hex) | 
					
						
							|  |  |  |         self.assertIn("description", normal) | 
					
						
							|  |  |  |         self.assertEqual(normal["description"], "test token") | 
					
						
							|  |  |  |         self.assertIn("created", normal) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_make_api_tokens_grid(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         auth = self.app.get_auth_handler() | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="foo") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.add(user) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         token1 = auth.add_api_token(user, "test1") | 
					
						
							|  |  |  |         token2 = auth.add_api_token(user, "test2") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.commit() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # grid should have 2 records but no tools/actions | 
					
						
							|  |  |  |         grid = view.make_api_tokens_grid(user) | 
					
						
							|  |  |  |         self.assertIsInstance(grid, Grid) | 
					
						
							|  |  |  |         self.assertEqual(len(grid.data), 2) | 
					
						
							|  |  |  |         self.assertEqual(len(grid.tools), 0) | 
					
						
							|  |  |  |         self.assertEqual(len(grid.actions), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # create + delete allowed | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(self.request, "is_root", new=True): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |             grid = view.make_api_tokens_grid(user) | 
					
						
							|  |  |  |             self.assertEqual(len(grid.tools), 1) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertIn("create", grid.tools) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |             self.assertEqual(len(grid.actions), 1) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |             self.assertEqual(grid.actions[0].key, "delete") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_add_api_token(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="foo") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.add(user) | 
					
						
							|  |  |  |         self.session.commit() | 
					
						
							|  |  |  |         self.session.refresh(user) | 
					
						
							|  |  |  |         self.assertEqual(len(user.api_tokens), 0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							|  |  |  |             with patch.object(self.request, "matchdict", new={"uuid": user.uuid}): | 
					
						
							|  |  |  |                 with patch.object( | 
					
						
							|  |  |  |                     self.request, | 
					
						
							|  |  |  |                     "json_body", | 
					
						
							|  |  |  |                     create=True, | 
					
						
							|  |  |  |                     new={"description": "testing"}, | 
					
						
							|  |  |  |                 ): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                     result = view.add_api_token() | 
					
						
							|  |  |  |                     self.assertEqual(len(user.api_tokens), 1) | 
					
						
							|  |  |  |                     token = user.api_tokens[0] | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                     self.assertEqual(result["token_string"], token.token_string) | 
					
						
							|  |  |  |                     self.assertEqual(result["description"], "testing") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |     def test_delete_api_token(self): | 
					
						
							|  |  |  |         model = self.app.model | 
					
						
							|  |  |  |         auth = self.app.get_auth_handler() | 
					
						
							|  |  |  |         view = self.make_view() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         user = model.User(username="foo") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.add(user) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         token1 = auth.add_api_token(user, "test1") | 
					
						
							|  |  |  |         token2 = auth.add_api_token(user, "test2") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |         self.session.commit() | 
					
						
							|  |  |  |         self.session.refresh(user) | 
					
						
							|  |  |  |         self.assertEqual(len(user.api_tokens), 2) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |         with patch.object(view, "Session", return_value=self.session): | 
					
						
							|  |  |  |             with patch.object(self.request, "matchdict", new={"uuid": user.uuid}): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # normal behavior | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 with patch.object( | 
					
						
							|  |  |  |                     self.request, | 
					
						
							|  |  |  |                     "json_body", | 
					
						
							|  |  |  |                     create=True, | 
					
						
							|  |  |  |                     new={"uuid": token1.uuid.hex}, | 
					
						
							|  |  |  |                 ): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                     result = view.delete_api_token() | 
					
						
							|  |  |  |                     self.assertEqual(result, {}) | 
					
						
							|  |  |  |                     self.session.refresh(user) | 
					
						
							|  |  |  |                     self.assertEqual(len(user.api_tokens), 1) | 
					
						
							|  |  |  |                     token = user.api_tokens[0] | 
					
						
							|  |  |  |                     self.assertIs(token, token2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # token for wrong user | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 user2 = model.User(username="bar") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                 self.session.add(user2) | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 token3 = auth.add_api_token(user2, "test3") | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                 self.session.commit() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 with patch.object( | 
					
						
							|  |  |  |                     self.request, | 
					
						
							|  |  |  |                     "json_body", | 
					
						
							|  |  |  |                     create=True, | 
					
						
							|  |  |  |                     new={"uuid": token3.uuid.hex}, | 
					
						
							|  |  |  |                 ): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                     result = view.delete_api_token() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                     self.assertEqual(result, {"error": "API token not found"}) | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  |                 # token not found | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                 with patch.object( | 
					
						
							|  |  |  |                     self.request, | 
					
						
							|  |  |  |                     "json_body", | 
					
						
							|  |  |  |                     create=True, | 
					
						
							|  |  |  |                     new={"uuid": self.app.make_true_uuid().hex}, | 
					
						
							|  |  |  |                 ): | 
					
						
							| 
									
										
										
										
											2025-08-09 09:56:00 -05:00
										 |  |  |                     result = view.delete_api_token() | 
					
						
							| 
									
										
										
										
											2025-08-31 12:26:43 -05:00
										 |  |  |                     self.assertEqual(result, {"error": "API token not found"}) |