diff --git a/tailbone/templates/poser/reports/view.mako b/tailbone/templates/poser/reports/view.mako
index 990a35af..cb6490cd 100644
--- a/tailbone/templates/poser/reports/view.mako
+++ b/tailbone/templates/poser/reports/view.mako
@@ -3,10 +3,12 @@
<%def name="render_form_buttons()">
+ % if master.has_perm('replace'):
+ @click="showUploadForm = true">
Upload Replacement Module
+ % endif
+ % if master.has_perm('replace'):
${h.form(master.get_action_url('replace', instance), enctype='multipart/form-data', **{'@submit': 'uploadSubmitting = true'})}
${h.csrf_token(request)}
@@ -55,10 +58,12 @@
${h.end_form()}
+ % endif
%def>
<%def name="modify_this_page_vars()">
${parent.modify_this_page_vars()}
+ % if master.has_perm('replace'):
+ % endif
%def>
${parent.body()}
diff --git a/tailbone/views/auth.py b/tailbone/views/auth.py
index efe2794d..406b8add 100644
--- a/tailbone/views/auth.py
+++ b/tailbone/views/auth.py
@@ -2,7 +2,7 @@
################################################################################
#
# Rattail -- Retail Software Framework
-# Copyright © 2010-2021 Lance Edgar
+# Copyright © 2010-2022 Lance Edgar
#
# This file is part of Rattail.
#
@@ -87,7 +87,7 @@ class AuthenticationView(View):
# Store current URL in session, for smarter redirect after login.
self.request.session['next_url'] = self.request.current_route_url()
next_url = self.request.route_url('login')
- self.request.session.flash(msg, allow_duplicate=False)
+ self.request.session.flash(msg, 'warning', allow_duplicate=False)
return self.redirect(next_url)
def login(self, **kwargs):
diff --git a/tailbone/views/poser/reports.py b/tailbone/views/poser/reports.py
index 146398f8..8098e1f9 100644
--- a/tailbone/views/poser/reports.py
+++ b/tailbone/views/poser/reports.py
@@ -252,22 +252,26 @@ class PoserReportView(MasterView):
@classmethod
def defaults(cls, config):
- cls._poser_report_defaults(config)
cls._defaults(config)
+ cls._poser_report_defaults(config)
@classmethod
def _poser_report_defaults(cls, config):
route_prefix = cls.get_route_prefix()
+ permission_prefix = cls.get_permission_prefix()
instance_url_prefix = cls.get_instance_url_prefix()
+ model_title = cls.get_model_title()
# replace module
+ config.add_tailbone_permission(permission_prefix,
+ '{}.replace'.format(permission_prefix),
+ "Upload replacement module for {}".format(model_title))
config.add_route('{}.replace'.format(route_prefix),
'{}/replace'.format(instance_url_prefix),
request_method='POST')
config.add_view(cls, attr='replace',
route_name='{}.replace'.format(route_prefix),
- # TODO: requires root, should add custom permission?
- permission='admin')
+ permission='{}.replace'.format(permission_prefix))
class PoserReportSchema(colander.MappingSchema):