This is an automated email from the ASF dual-hosted git repository. kentontaylor pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/allura.git
commit 9f34b77e149de604ec5dc9be51ed4058b397c4f0 Author: Guillermo Cruz <[email protected]> AuthorDate: Mon Sep 8 17:14:01 2025 +0000 [#8584] added missing validate function to formencode validators --- Allura/allura/config/app_cfg.py | 20 ++++++++++++++++---- Allura/allura/controllers/discuss.py | 2 +- Allura/allura/controllers/project.py | 2 +- Allura/allura/lib/validators.py | 2 +- Allura/allura/lib/widgets/forms.py | 16 +++++++++++++++- Allura/allura/lib/widgets/subscriptions.py | 5 +++++ .../test_discussion_moderation_controller.py | 4 ++-- Allura/allura/tests/unit/patches.py | 3 +++ AlluraTest/alluratest/validation.py | 1 + ForgeActivity/forgeactivity/widgets/follow.py | 5 +++++ ForgeBlog/forgeblog/widgets.py | 5 +++++ ForgeDiscussion/forgediscussion/controllers/forum.py | 2 +- ForgeDiscussion/forgediscussion/widgets/admin.py | 2 +- ForgeTracker/forgetracker/widgets/bin_form.py | 5 +++++ ForgeTracker/forgetracker/widgets/ticket_form.py | 5 +++++ 15 files changed, 67 insertions(+), 12 deletions(-) diff --git a/Allura/allura/config/app_cfg.py b/Allura/allura/config/app_cfg.py index 704fdd72f..b545f043c 100644 --- a/Allura/allura/config/app_cfg.py +++ b/Allura/allura/config/app_cfg.py @@ -90,12 +90,14 @@ def __init__(self, root_controller=None): # prevent dispatcher from striping extensions like '.io' from URLs 'disable_request_extensions': True, - 'validation.exceptions': [formencode.Invalid, formencode.api.Invalid], + 'validation.exceptions': [formencode.Invalid, formencode.api.Invalid,], 'validation.validators': { formencode.Schema: lambda schema, params: schema.to_python(params, state=tg.request), - #formencode.FancyValidator: lambda validator, params: validator.to_python(params, state=tg.request), + formencode.FancyValidator: lambda validator, params: validator.to_python(params, state=tg.request), + }, + 'validation.explode': { + formencode.Invalid: self.explode_formencode_invalid, }, - 'validation.explode': {formencode.Invalid: self.explode_formencode_invalid}, # if left to True (default) would use crank.util.default_path_translator to convert all URL punctuation to "_" # which is convenient for /foo-bar to execute a "def foo_bar" method, but is a pretty drastic change for us @@ -106,7 +108,17 @@ def __init__(self, root_controller=None): self.replace(TemplateRenderingConfigurationComponent.id, AlluraTemplateConfig) def explode_formencode_invalid(self, err): - return {"errors": err.error_dict, "values": err.value} + errors = {} + if getattr(err, 'error_dict', None): + for k, v in getattr(err, 'error_dict', {}).items(): + if isinstance(v, formencode.Invalid): + errors[k] = v.msg + else: + errors[k] = v + else: + errors = err.msg + values = {str(k): v for k, v in getattr(err, 'value', {}).items()} if hasattr(err, 'value') and isinstance(err.value, dict) else {} + return {"errors": errors, "values": values} class AlluraTemplateConfig(TemplateRenderingConfigurationComponent): diff --git a/Allura/allura/controllers/discuss.py b/Allura/allura/controllers/discuss.py index e5ed81f87..c890696e7 100644 --- a/Allura/allura/controllers/discuss.py +++ b/Allura/allura/controllers/discuss.py @@ -52,7 +52,7 @@ class pass_validator: - def validate(self, v, s): + def validate(self, v, s=None): return v diff --git a/Allura/allura/controllers/project.py b/Allura/allura/controllers/project.py index 86ba0a7b4..cf521e59c 100644 --- a/Allura/allura/controllers/project.py +++ b/Allura/allura/controllers/project.py @@ -151,7 +151,7 @@ def index(self, sort='alpha', limit=25, page=0, **kw): def add_project(self, **form_data): with h.login_overlay(): require_access(self.neighborhood, 'register') - verify = request.validation.errors == {'_the_form': 'phone-verification'} + verify = 'phone-verification' in request.validation.errors c.show_phone_verification_overlay = verify c.add_project = W.add_project form_data.setdefault('tools', W.add_project.default_tools) diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py index 1a949d7e0..08586706f 100644 --- a/Allura/allura/lib/validators.py +++ b/Allura/allura/lib/validators.py @@ -153,7 +153,7 @@ def to_python(self, value, state): def from_python(self, value, state): return value - def validate(self, value, state): + def validate(self, value, state=None): return value diff --git a/Allura/allura/lib/widgets/forms.py b/Allura/allura/lib/widgets/forms.py index 51e42a55f..032a7c69d 100644 --- a/Allura/allura/lib/widgets/forms.py +++ b/Allura/allura/lib/widgets/forms.py @@ -117,6 +117,10 @@ def display_field(self, field, ignore_errors=False): display += Markup("<div class='error'>{}</div>").format(ctx['errors']) return display + def validate(self, value, state=None): + state = getattr(tg, 'request', None) + return super().validate(value, state) + class ForgeFormResponsive(ForgeForm): def __init__(self): @@ -808,6 +812,10 @@ def resources(self): class AdminForm(ForgeForm): template = 'jinja:allura:templates/widgets/admin_form.html' + def validate(self, value, state=None): + state = tg.request if hasattr(state, 'request') else state + return super().validate(value, state) + class AdminFormResponsive(ForgeForm): def __init__(self): @@ -982,10 +990,11 @@ def fields(self): @ew_core.core.validator def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state value = super().validate(value, state) provider = plugin.ProjectRegistrationProvider.get() if not provider.phone_verified(c.user, c.project.neighborhood): - raise formencode.Invalid('phone-verification', value, None) + raise formencode.Invalid('phone-verification', value, None, error_dict={'phone-verification': 'verification required'}) return value def resources(self): @@ -1118,6 +1127,11 @@ def context_for(self, field): ctx['value'] = tg.request.cookies.get('_csrf_token') or tg.request.environ['_csrf_token'] return ctx + def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state + return super().validate(value, state) + + class AwardGrantForm(ForgeForm): diff --git a/Allura/allura/lib/widgets/subscriptions.py b/Allura/allura/lib/widgets/subscriptions.py index 64bc33c9f..64ee11e05 100644 --- a/Allura/allura/lib/widgets/subscriptions.py +++ b/Allura/allura/lib/widgets/subscriptions.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. +import tg import ew as ew_core import ew.jinja2_ew as ew from tg import tmpl_context as c @@ -90,3 +91,7 @@ def resources(self): yield from super().resources() if not c.user.is_anonymous(): yield ew.JSLink('js/subscriptions.js', location='body_js_tail') # location, to force after react js files + + def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state + return super().validate(value, state) \ No newline at end of file diff --git a/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py b/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py index 2b9a01fff..8faef962d 100644 --- a/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py +++ b/Allura/allura/tests/unit/controllers/test_discussion_moderation_controller.py @@ -73,7 +73,7 @@ def get_post(self): class TestIndexWithNoPosts(WithDatabase): - patches = [patches.fake_app_patch] + patches = [patches.fake_app_patch, patches.fake_form_request_patch] def test_that_it_returns_no_posts(self): discussion = create_discussion() @@ -82,7 +82,7 @@ def test_that_it_returns_no_posts(self): class TestIndexWithAPostInTheDiscussion(WithDatabase): - patches = [patches.fake_app_patch] + patches = [patches.fake_app_patch, patches.fake_form_request_patch] def setup_method(self, method): super().setup_method(method) diff --git a/Allura/allura/tests/unit/patches.py b/Allura/allura/tests/unit/patches.py index 630beeccf..ddb92ff00 100644 --- a/Allura/allura/tests/unit/patches.py +++ b/Allura/allura/tests/unit/patches.py @@ -17,6 +17,7 @@ from mock import Mock, patch, MagicMock from tg import tmpl_context as c +import tg from allura.tests.unit.factories import ( create_project, @@ -62,3 +63,5 @@ def fake_request_patch(test_case): MagicMock( referer='.' )) +def fake_form_request_patch(test_case): + return patch('tg.request', MagicMock(referer='.')) diff --git a/AlluraTest/alluratest/validation.py b/AlluraTest/alluratest/validation.py index 2a13b9eb4..78d9fced4 100644 --- a/AlluraTest/alluratest/validation.py +++ b/AlluraTest/alluratest/validation.py @@ -27,6 +27,7 @@ import re import importlib.resources +import tg import webtest from webtest import TestApp, TestResponse from ming.utils import LazyProperty diff --git a/ForgeActivity/forgeactivity/widgets/follow.py b/ForgeActivity/forgeactivity/widgets/follow.py index 6a81ede1f..d2aa0f665 100644 --- a/ForgeActivity/forgeactivity/widgets/follow.py +++ b/ForgeActivity/forgeactivity/widgets/follow.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. +import tg from tg import tmpl_context as c from formencode import validators as fev import ew as ew_core @@ -55,3 +56,7 @@ def success_message(self, following): action=context['action_label'], thing=context['thing'], ) + + def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state + return super().validate(value, state) diff --git a/ForgeBlog/forgeblog/widgets.py b/ForgeBlog/forgeblog/widgets.py index c0445369c..4cde920f9 100644 --- a/ForgeBlog/forgeblog/widgets.py +++ b/ForgeBlog/forgeblog/widgets.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. +import tg import ew as ew_core import ew.jinja2_ew as ew @@ -68,6 +69,10 @@ def resources(self): }); ''') + def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state + return super().validate(value, state) + class NewPostForm(BlogPostForm): diff --git a/ForgeDiscussion/forgediscussion/controllers/forum.py b/ForgeDiscussion/forgediscussion/controllers/forum.py index b7f3e0761..a6d472aae 100644 --- a/ForgeDiscussion/forgediscussion/controllers/forum.py +++ b/ForgeDiscussion/forgediscussion/controllers/forum.py @@ -44,7 +44,7 @@ class pass_validator: - def validate(self, v, s): + def validate(self, v, s=None): return v diff --git a/ForgeDiscussion/forgediscussion/widgets/admin.py b/ForgeDiscussion/forgediscussion/widgets/admin.py index eba27dcd7..990697d40 100644 --- a/ForgeDiscussion/forgediscussion/widgets/admin.py +++ b/ForgeDiscussion/forgediscussion/widgets/admin.py @@ -14,7 +14,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. - +import tg from formencode import validators as fev from formencode import All import formencode diff --git a/ForgeTracker/forgetracker/widgets/bin_form.py b/ForgeTracker/forgetracker/widgets/bin_form.py index 7040ff392..fa08f6402 100644 --- a/ForgeTracker/forgetracker/widgets/bin_form.py +++ b/ForgeTracker/forgetracker/widgets/bin_form.py @@ -15,6 +15,7 @@ # specific language governing permissions and limitations # under the License. +import tg import ew from ew import jinja2_ew from allura.lib import validators as v @@ -39,3 +40,7 @@ class fields(ew.NameList): terms = jinja2_ew.TextField( label='Search Terms', validator=v.UnicodeString(not_empty=True)) + + def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state + return super().validate(value, state) diff --git a/ForgeTracker/forgetracker/widgets/ticket_form.py b/ForgeTracker/forgetracker/widgets/ticket_form.py index fc19fb94e..b53bfdafc 100644 --- a/ForgeTracker/forgetracker/widgets/ticket_form.py +++ b/ForgeTracker/forgetracker/widgets/ticket_form.py @@ -16,6 +16,7 @@ # under the License. +import tg from tg import tmpl_context as c from formencode import validators as fev from markupsafe import Markup @@ -140,6 +141,10 @@ def fields(self): break return ew_core.NameList(fields) + def validate(self, value, state=None): + state = tg.request if hasattr(tg, 'request') else state + return super().validate(value, state) + class TicketForm(GenericTicketForm): template = 'jinja:forgetracker:templates/tracker_widgets/ticket_form.html'
