diff --git a/tailbone/api/auth.py b/tailbone/api/auth.py index 867c15a8..1b347b21 100644 --- a/tailbone/api/auth.py +++ b/tailbone/api/auth.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,8 +24,6 @@ Tailbone Web API - Auth Views """ -from __future__ import unicode_literals, absolute_import - from rattail.db.auth import set_user_password from cornice import Service @@ -168,6 +166,9 @@ class AuthenticationView(APIView): if not self.request.user: raise self.forbidden() + if self.request.user.prevent_password_change and not self.request.is_root: + raise self.forbidden() + data = self.request.json_body # first make sure "current" password is accurate diff --git a/tailbone/api/users.py b/tailbone/api/users.py index 2b6476a2..a6bcad57 100644 --- a/tailbone/api/users.py +++ b/tailbone/api/users.py @@ -2,7 +2,7 @@ ################################################################################ # # Rattail -- Retail Software Framework -# Copyright © 2010-2022 Lance Edgar +# Copyright © 2010-2023 Lance Edgar # # This file is part of Rattail. # @@ -24,8 +24,6 @@ Tailbone Web API - User Views """ -from __future__ import unicode_literals, absolute_import - from rattail.db import model from tailbone.api import APIMasterView @@ -57,6 +55,10 @@ class UserView(APIMasterView): query = query.outerjoin(model.Person) return query + def update_object(self, user, data): + # TODO: should ensure prevent_password_change is respected + return super(UserView, self).update_object(user, data) + def defaults(config, **kwargs): base = globals() diff --git a/tailbone/templates/base.mako b/tailbone/templates/base.mako index df4451c6..91589990 100644 --- a/tailbone/templates/base.mako +++ b/tailbone/templates/base.mako @@ -607,7 +607,9 @@ % if messaging_enabled: ${h.link_to("Messages{}".format(" ({})".format(inbox_count) if inbox_count else ''), url('messages.inbox'), class_='navbar-item')} % endif - ${h.link_to("Change Password", url('change_password'), class_='navbar-item')} + % if request.is_root or not request.user.prevent_password_change: + ${h.link_to("Change Password", url('change_password'), class_='navbar-item')} + % endif ${h.link_to("Edit Preferences", url('my.preferences'), class_='navbar-item')} ${h.link_to("Logout", url('logout'), class_='navbar-item')} diff --git a/tailbone/views/auth.py b/tailbone/views/auth.py index 9bcb644f..fbae397b 100644 --- a/tailbone/views/auth.py +++ b/tailbone/views/auth.py @@ -175,8 +175,12 @@ class AuthenticationView(View): if not self.request.user: return self.redirect(self.request.route_url('home')) - if self.user_is_protected(self.request.user) and not self.request.is_root: - self.request.session.flash("Cannot change password for user: {}".format(self.request.user)) + if ((self.request.user.prevent_password_change + or self.user_is_protected(self.request.user)) + and not self.request.is_root): + + self.request.session.flash("Cannot change password for user: {}".format( + self.request.user)) return self.redirect(self.request.get_referrer()) schema = ChangePassword().bind(user=self.request.user, request=self.request) diff --git a/tailbone/views/users.py b/tailbone/views/users.py index 4f3a0070..ff614460 100644 --- a/tailbone/views/users.py +++ b/tailbone/views/users.py @@ -67,6 +67,7 @@ class UserView(PrincipalMasterView): 'active', 'active_sticky', 'set_password', + 'prevent_password_change', 'roles', 'permissions', ] @@ -210,7 +211,10 @@ class UserView(PrincipalMasterView): f.set_renderer('display_name_', self.render_person_name) # set_password - f.set_widget('set_password', dfwidget.CheckedPasswordWidget()) + if self.editing and user.prevent_password_change and not self.request.is_root: + f.remove('set_password') + else: + f.set_widget('set_password', dfwidget.CheckedPasswordWidget()) # if self.creating: # f.set_required('password') @@ -316,7 +320,7 @@ class UserView(PrincipalMasterView): user.person.local_only = True # maybe set user password - if data['set_password']: + if 'set_password' in form and data['set_password']: set_user_password(user, data['set_password']) # update roles for user