feat: add first-time setup page to create admin user
This commit is contained in:
parent
bc49392140
commit
675b51cac2
6 changed files with 241 additions and 79 deletions
20
src/wuttaweb/templates/setup.mako
Normal file
20
src/wuttaweb/templates/setup.mako
Normal file
|
@ -0,0 +1,20 @@
|
|||
## -*- coding: utf-8; -*-
|
||||
<%inherit file="/form.mako" />
|
||||
|
||||
<%def name="title()">First-Time Setup</%def>
|
||||
|
||||
<%def name="page_content()">
|
||||
<b-notification type="is-success">
|
||||
<p class="block">
|
||||
The app is running okay!
|
||||
</p>
|
||||
<p class="block">
|
||||
Please setup the first Administrator account below.
|
||||
</p>
|
||||
</b-notification>
|
||||
|
||||
${parent.page_content()}
|
||||
</%def>
|
||||
|
||||
|
||||
${parent.body()}
|
|
@ -47,10 +47,16 @@ class AuthView(View):
|
|||
* route: ``login``
|
||||
* template: ``/auth/login.mako``
|
||||
"""
|
||||
model = self.app.model
|
||||
session = session or Session()
|
||||
auth = self.app.get_auth_handler()
|
||||
|
||||
# TODO: should call request.get_referrer()
|
||||
referrer = self.request.route_url('home')
|
||||
# nb. redirect to /setup if no users exist
|
||||
user = session.query(model.User).first()
|
||||
if not user:
|
||||
return self.redirect(self.request.route_url('setup'))
|
||||
|
||||
referrer = self.request.get_referrer()
|
||||
|
||||
# redirect if already logged in
|
||||
if self.request.user:
|
||||
|
@ -69,7 +75,6 @@ class AuthView(View):
|
|||
if data:
|
||||
|
||||
# truly validate user credentials
|
||||
session = session or Session()
|
||||
user = auth.authenticate_user(session, data['username'], data['password'])
|
||||
if user:
|
||||
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
Common Views
|
||||
"""
|
||||
|
||||
import colander
|
||||
|
||||
from wuttaweb.views import View
|
||||
from wuttaweb.forms import widgets
|
||||
from wuttaweb.db import Session
|
||||
|
||||
|
||||
class CommonView(View):
|
||||
|
@ -32,7 +36,7 @@ class CommonView(View):
|
|||
Common views shared by all apps.
|
||||
"""
|
||||
|
||||
def home(self):
|
||||
def home(self, session=None):
|
||||
"""
|
||||
Home page view.
|
||||
|
||||
|
@ -40,12 +44,88 @@ class CommonView(View):
|
|||
|
||||
This is normally the view shown when a user navigates to the
|
||||
root URL for the web app.
|
||||
|
||||
"""
|
||||
model = self.app.model
|
||||
session = session or Session()
|
||||
|
||||
# nb. redirect to /setup if no users exist
|
||||
user = session.query(model.User).first()
|
||||
if not user:
|
||||
return self.redirect(self.request.route_url('setup'))
|
||||
|
||||
return {
|
||||
'index_title': self.app.get_title(),
|
||||
}
|
||||
|
||||
def setup(self, session=None):
|
||||
"""
|
||||
View for first-time app setup, to create admin user.
|
||||
|
||||
Template: ``/setup.mako``
|
||||
|
||||
This page is only meant for one-time use. As such, if the app
|
||||
DB contains any users, this page will always redirect to the
|
||||
home page.
|
||||
|
||||
However if no users exist yet, this will show a form which may
|
||||
be used to create the first admin user. When finished, user
|
||||
will be redirected to the login page.
|
||||
|
||||
.. note::
|
||||
|
||||
As long as there are no users in the DB, both the home and
|
||||
login pages will automatically redirect to this one.
|
||||
"""
|
||||
model = self.app.model
|
||||
session = session or Session()
|
||||
|
||||
# nb. this view only available until first user is created
|
||||
user = session.query(model.User).first()
|
||||
if user:
|
||||
return self.redirect(self.request.route_url('home'))
|
||||
|
||||
form = self.make_form(fields=['username', 'password', 'first_name', 'last_name'],
|
||||
show_button_cancel=False,
|
||||
show_button_reset=True)
|
||||
form.set_widget('password', widgets.CheckedPasswordWidget())
|
||||
form.set_required('first_name', False)
|
||||
form.set_required('last_name', False)
|
||||
|
||||
if form.validate():
|
||||
auth = self.app.get_auth_handler()
|
||||
data = form.validated
|
||||
|
||||
# make user
|
||||
user = auth.make_user(session=session, username=data['username'])
|
||||
auth.set_user_password(user, data['password'])
|
||||
|
||||
# assign admin role
|
||||
admin = auth.get_role_administrator(session)
|
||||
user.roles.append(admin)
|
||||
|
||||
# ensure all built-in roles exist
|
||||
auth.get_role_authenticated(session)
|
||||
auth.get_role_anonymous(session)
|
||||
|
||||
# maybe make person
|
||||
if data['first_name'] or data['last_name']:
|
||||
first = data['first_name']
|
||||
last = data['last_name']
|
||||
person = model.Person(first_name=first,
|
||||
last_name=last,
|
||||
full_name=(f"{first} {last}").strip())
|
||||
session.add(person)
|
||||
user.person = person
|
||||
|
||||
# send user to /login
|
||||
self.request.session.flash("Account created! Please login below.")
|
||||
return self.redirect(self.request.route_url('login'))
|
||||
|
||||
return {
|
||||
'index_title': self.app.get_title(),
|
||||
'form': form,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def defaults(cls, config):
|
||||
cls._defaults(config)
|
||||
|
@ -62,6 +142,12 @@ class CommonView(View):
|
|||
route_name='home',
|
||||
renderer='/home.mako')
|
||||
|
||||
# setup
|
||||
config.add_route('setup', '/setup')
|
||||
config.add_view(cls, attr='setup',
|
||||
route_name='setup',
|
||||
renderer='/setup.mako')
|
||||
|
||||
|
||||
def defaults(config, **kwargs):
|
||||
base = globals()
|
||||
|
|
|
@ -75,12 +75,12 @@ class RoleView(MasterView):
|
|||
auth = self.app.get_auth_handler()
|
||||
|
||||
# prevent delete for built-in roles
|
||||
if role is auth.get_role_administrator(session):
|
||||
return False
|
||||
if role is auth.get_role_authenticated(session):
|
||||
return False
|
||||
if role is auth.get_role_anonymous(session):
|
||||
return False
|
||||
if role is auth.get_role_administrator(session):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue