3
0
Fork 0

feat: add first-time setup page to create admin user

This commit is contained in:
Lance Edgar 2024-08-14 18:29:08 -05:00
parent bc49392140
commit 675b51cac2
6 changed files with 241 additions and 79 deletions

View file

@ -1,90 +1,88 @@
# -*- coding: utf-8; -*-
from unittest import TestCase
from unittest.mock import MagicMock
from unittest.mock import MagicMock, patch
from pyramid import testing
from pyramid.httpexceptions import HTTPFound, HTTPForbidden
from wuttjamaican.conf import WuttaConfig
from wuttaweb.views import auth as mod
from wuttaweb.auth import WuttaSecurityPolicy
from wuttaweb.subscribers import new_request
from tests.util import WebTestCase
class TestAuthView(TestCase):
class TestAuthView(WebTestCase):
def setUp(self):
self.config = WuttaConfig(defaults={
'wutta.db.default.url': 'sqlite://',
})
self.request = testing.DummyRequest(wutta_config=self.config, user=None)
self.pyramid_config = testing.setUp(request=self.request, settings={
'wutta_config': self.config,
})
self.app = self.config.get_app()
auth = self.app.get_auth_handler()
model = self.app.model
model.Base.metadata.create_all(bind=self.config.appdb_engine)
self.session = self.app.make_session()
self.user = model.User(username='barney')
self.session.add(self.user)
auth.set_user_password(self.user, 'testpass')
self.session.commit()
self.pyramid_config.set_security_policy(WuttaSecurityPolicy(db_session=self.session))
self.pyramid_config.include('wuttaweb.views.auth')
self.setup_web()
self.pyramid_config.include('wuttaweb.views.common')
def tearDown(self):
testing.tearDown()
def make_view(self):
return mod.AuthView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.auth')
def test_login(self):
view = mod.AuthView(self.request)
context = view.login()
model = self.app.model
auth = self.app.get_auth_handler()
view = self.make_view()
# until user exists, will redirect
self.assertEqual(self.session.query(model.User).count(), 0)
response = view.login(session=self.session)
self.assertEqual(response.status_code, 302)
# make a user
barney = model.User(username='barney')
auth.set_user_password(barney, 'testpass')
self.session.add(barney)
self.session.commit()
# now since user exists, form will display
context = view.login(session=self.session)
self.assertIn('form', context)
# redirect if user already logged in
self.request.user = self.user
view = mod.AuthView(self.request)
redirect = view.login(session=self.session)
self.assertIsInstance(redirect, HTTPFound)
with patch.object(self.request, 'user', new=barney):
view = self.make_view()
response = view.login(session=self.session)
self.assertEqual(response.status_code, 302)
# login fails w/ wrong password
self.request.user = None
self.request.method = 'POST'
self.request.POST = {'username': 'barney', 'password': 'WRONG'}
view = mod.AuthView(self.request)
view = self.make_view()
context = view.login(session=self.session)
self.assertIn('form', context)
# redirect if login succeeds
self.request.method = 'POST'
self.request.POST = {'username': 'barney', 'password': 'testpass'}
view = mod.AuthView(self.request)
redirect = view.login(session=self.session)
self.assertIsInstance(redirect, HTTPFound)
view = self.make_view()
response = view.login(session=self.session)
self.assertEqual(response.status_code, 302)
def test_logout(self):
view = mod.AuthView(self.request)
self.pyramid_config.add_route('login', '/login')
view = self.make_view()
self.request.session.delete = MagicMock()
redirect = view.logout()
response = view.logout()
self.request.session.delete.assert_called_once_with()
self.assertIsInstance(redirect, HTTPFound)
self.assertEqual(response.status_code, 302)
def test_change_password(self):
view = mod.AuthView(self.request)
model = self.app.model
auth = self.app.get_auth_handler()
barney = model.User(username='barney')
self.session.add(barney)
self.session.commit()
view = self.make_view()
# unauthenticated user is redirected
redirect = view.change_password()
self.assertIsInstance(redirect, HTTPFound)
# now "login" the user, and set initial password
self.request.user = self.user
auth.set_user_password(self.user, 'foo')
self.request.user = barney
auth.set_user_password(barney, 'foo')
self.session.commit()
# view should now return context w/ form
@ -105,9 +103,8 @@ class TestAuthView(TestCase):
redirect = view.change_password()
self.assertIsInstance(redirect, HTTPFound)
self.session.commit()
self.session.refresh(self.user)
self.assertFalse(auth.check_user_password(self.user, 'foo'))
self.assertTrue(auth.check_user_password(self.user, 'bar'))
self.assertFalse(auth.check_user_password(barney, 'foo'))
self.assertTrue(auth.check_user_password(barney, 'bar'))
# at this point 'foo' is the password, now let's submit some
# invalid forms and make sure we get back a context w/ form
@ -147,8 +144,6 @@ class TestAuthView(TestCase):
self.assertEqual(dform['new_password'].errormsg, "New password must be different from old password.")
def test_become_root(self):
event = MagicMock(request=self.request)
new_request(event) # add request.get_referrer()
view = mod.AuthView(self.request)
# GET not allowed
@ -168,8 +163,6 @@ class TestAuthView(TestCase):
self.assertTrue(self.request.session['is_root'])
def test_stop_root(self):
event = MagicMock(request=self.request)
new_request(event) # add request.get_referrer()
view = mod.AuthView(self.request)
# GET not allowed

View file

@ -1,27 +1,85 @@
# -*- coding: utf-8; -*-
from unittest import TestCase
from pyramid import testing
from wuttjamaican.conf import WuttaConfig
from wuttaweb.views import common
from wuttaweb.views import common as mod
from tests.util import WebTestCase
class TestCommonView(TestCase):
class TestCommonView(WebTestCase):
def setUp(self):
self.config = WuttaConfig()
self.app = self.config.get_app()
self.request = testing.DummyRequest()
self.request.wutta_config = self.config
self.pyramid_config = testing.setUp(request=self.request)
def make_view(self):
return mod.CommonView(self.request)
def test_includeme(self):
self.pyramid_config.include('wuttaweb.views.common')
def tearDown(self):
testing.tearDown()
def test_home(self):
view = common.CommonView(self.request)
context = view.home()
self.pyramid_config.add_route('setup', '/setup')
model = self.app.model
view = self.make_view()
# if no users then home page will redirect
response = view.home(session=self.session)
self.assertEqual(response.status_code, 302)
# so add a user
user = model.User(username='foo')
self.session.add(user)
self.session.commit()
# now we see the home page
context = view.home(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
def test_setup(self):
self.pyramid_config.add_route('home', '/')
self.pyramid_config.add_route('login', '/login')
model = self.app.model
auth = self.app.get_auth_handler()
view = self.make_view()
# at first, can see the setup page
self.assertEqual(self.session.query(model.User).count(), 0)
context = view.setup(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
# so add a user
user = model.User(username='foo')
self.session.add(user)
self.session.commit()
# once user exists it will always redirect
response = view.setup(session=self.session)
self.assertEqual(response.status_code, 302)
# delete that user
self.session.delete(user)
self.session.commit()
# so we can see the setup page again
context = view.setup(session=self.session)
self.assertEqual(context['index_title'], self.app.get_title())
# and finally, post data to create admin user
self.request.method = 'POST'
self.request.POST = {
'username': 'barney',
'__start__': 'password:mapping',
'password': 'testpass',
'password-confirm': 'testpass',
'__end__': 'password:mapping',
'first_name': "Barney",
'last_name': "Rubble",
}
response = view.setup(session=self.session)
# nb. redirects on success
self.assertEqual(response.status_code, 302)
barney = self.session.query(model.User).one()
self.assertEqual(barney.username, 'barney')
self.assertTrue(auth.check_user_password(barney, 'testpass'))
admin = auth.get_role_administrator(self.session)
self.assertIn(admin, barney.roles)
self.assertIsNotNone(barney.person)
person = barney.person
self.assertEqual(person.first_name, "Barney")
self.assertEqual(person.last_name, "Rubble")
self.assertEqual(person.full_name, "Barney Rubble")