This is an automated email from the ASF dual-hosted git repository.
gcruz pushed a commit to branch gc/8484
in repository https://gitbox.apache.org/repos/asf/allura.git
The following commit(s) were added to refs/heads/gc/8484 by this push:
new 1eadc7269 [#8484] improvements to validation and fixed project
features duplication bug
1eadc7269 is described below
commit 1eadc726922fa9d4514e3e22cbacec17a3bd8804
Author: Guillermo Cruz <[email protected]>
AuthorDate: Tue Jan 3 17:05:41 2023 -0600
[#8484] improvements to validation and fixed project features duplication
bug
---
Allura/allura/controllers/auth.py | 2 +-
Allura/allura/ext/admin/widgets.py | 16 +++++----
.../user_profile/templates/sections/social.html | 2 +-
Allura/allura/lib/validators.py | 18 ++++++++--
.../templates/widgets/sortable_repeated_field.html | 17 +++++++--
Allura/allura/tests/functional/test_admin.py | 40 ++++++++++++++++++++++
6 files changed, 81 insertions(+), 14 deletions(-)
diff --git a/Allura/allura/controllers/auth.py
b/Allura/allura/controllers/auth.py
index 5086701d8..177b95209 100644
--- a/Allura/allura/controllers/auth.py
+++ b/Allura/allura/controllers/auth.py
@@ -1054,7 +1054,7 @@ class UserContactsController(BaseController):
require_authenticated()
if kw['socialnetwork'] == 'Twitter' and not
kw['accounturl'].startswith('http'):
- kw['accounturl'] = 'http://twitter.com/%s' %
kw['accounturl'].replace('@', '')
+ kw['accounturl'] =
f"http://twitter.com/{kw['accounturl'].replace('@', '')}"
c.user.add_multivalue_pref('socialnetworks',
{'socialnetwork': kw['socialnetwork'],
'accounturl': kw['accounturl']})
diff --git a/Allura/allura/ext/admin/widgets.py
b/Allura/allura/ext/admin/widgets.py
index 7af817d0b..0ce7e4b15 100644
--- a/Allura/allura/ext/admin/widgets.py
+++ b/Allura/allura/ext/admin/widgets.py
@@ -164,10 +164,11 @@ class MetadataAdmin(ff.AdminForm):
defaults = dict(
ff.AdminForm.defaults,
enctype='multipart/form-data')
- allowed_social_domains = aslist(tg.config.get('allowed_social_domains',
- ['facebook', 'instagram',
'linkedin', 'twitter']),
- ',')
+
class fields(ew_core.NameList):
+ allowed_social_domains = aslist(tg.config.get('allowed_social_domains',
+ ['facebook',
'instagram', 'linkedin', 'twitter']),
+ ',')
name = ew.InputField(field_type='text',
label='Name',
validator=formencode.All(
@@ -224,14 +225,17 @@ class MetadataAdmin(ff.AdminForm):
field_type="text", label="Google Analytics ID",
attrs=(dict(placeholder='UA-123456-0',
pattern='UA-[0-9]+-[0-9]+')))
twitter_handle = ew.InputField(
- field_type="text", label='Twitter Handle',
validator=V.SocialDomainValidator('twitter.com'))
+ field_type="text", label='Twitter Handle',
validator=formencode.All(fev.URL(add_http=True, if_empty=''),
+
V.SocialDomainValidator('twitter.com')))
facebook_page = ew.InputField(field_type="text", label='Facebook page',
-
validator=formencode.All(fev.URL(add_http=True),
V.SocialDomainValidator('facebook.com')) )
+
validator=formencode.All(fev.URL(add_http=True),
+
V.SocialDomainValidator('facebook.com')) )
instagram_page = ew.InputField(
field_type="text", label='Instagram page',
validator=formencode.All(fev.URL(add_http=True),
V.SocialDomainValidator('instagram.com')))
+
fediverse_address = ew.InputField(field_type="text", label="Mastodon
address",
-
validator=V.FediverseAddressValidator)
+
validator=V.SocialDomainValidator(domains=allowed_social_domains))
diff --git a/Allura/allura/ext/user_profile/templates/sections/social.html
b/Allura/allura/ext/user_profile/templates/sections/social.html
index d94f0bf48..ba9feb4a2 100644
--- a/Allura/allura/ext/user_profile/templates/sections/social.html
+++ b/Allura/allura/ext/user_profile/templates/sections/social.html
@@ -34,7 +34,7 @@
<dl>
{% for contact in user.get_pref('socialnetworks') %}
{% if contact.socialnetwork == 'Mastodon' %}
- <dt>{{ contact.socialnetwork }}</dt><dd><a href="{{
h.parse_fediverse_address(contact.accounturl) }}" rel="me nofollow">{{
contact.accounturl }}</a></dd>
+ <dt>{{ contact.socialnetwork }}</dt><dd><a href="{{
h.parse_fediverse_address(contact.accounturl) }}" rel="me nofollow"
target="_blank">{{ contact.accounturl }}</a></dd>
{% else %}
<dt>{{ contact.socialnetwork }}</dt><dd>{{
contact.accounturl|urlize(nofollow=True) }}</dd>
{% endif %}
diff --git a/Allura/allura/lib/validators.py b/Allura/allura/lib/validators.py
index aa0488705..231f6312f 100644
--- a/Allura/allura/lib/validators.py
+++ b/Allura/allura/lib/validators.py
@@ -488,7 +488,7 @@ class IconValidator(fev.FancyValidator):
return value
-FEDIVERSE_REGEX = r'^@[a-zA-Z_]*@[a-zA-Z_]*\.{1}[A-Za-z]{0,10}$'
+FEDIVERSE_REGEX = r'^@[a-zA-Z_]*@[a-zA-Z_.]*$'
class FediverseAddressValidator(fev.FancyValidator):
@@ -508,9 +508,21 @@ class SocialDomainValidator(fev.FancyValidator):
self.domains = kw.get('domains')
def _to_python(self, value, state):
- if value.startswith('@') and not re.match(FEDIVERSE_REGEX , value):
- value = f'https://twitter.com/{value.replace("@","")}'
url = urlsplit(value)
+ state_values = state.full_dict
+ if value.startswith('@') and not re.match(FEDIVERSE_REGEX , value):
+ if state_values.get('socialnetwork','') == 'Twitter' or
state_values.get('twitter_handle',''):
+ value = f'https://twitter.com/{value.replace("@","")}'
+ elif state_values.get('socialnetwork','') == 'Instagram' or
state_values.get('instagram_page',''):
+ value = f'https://instagram.com/{value.replace("@", "")}'
+ url = urlsplit(value)
+ if (state_values.get('socialnetwork','') == 'Mastodon' and
state_values.get('accounturl','').startswith('http'))\
+ or state_values.get('fediverse_address','').startswith('http'):
+ fediverse_url = f'{url.path.replace("/", "")}@{url.netloc}'
+ if re.match(FEDIVERSE_REGEX, fediverse_url):
+ return fediverse_url
+ if value.startswith('@') and re.match(FEDIVERSE_REGEX, value) and
state_values.get('socialnetwork','') != 'Mastodon':
+ raise fe.Invalid('Invalid domain for this field', value, state)
if not re.match(FEDIVERSE_REGEX , value):
if self.domain and not self.domain ==
url.netloc.replace('www.',''):
raise fe.Invalid('Invalid domain for this field', value, state)
diff --git a/Allura/allura/templates/widgets/sortable_repeated_field.html
b/Allura/allura/templates/widgets/sortable_repeated_field.html
index e81249fb0..8390d0e22 100644
--- a/Allura/allura/templates/widgets/sortable_repeated_field.html
+++ b/Allura/allura/templates/widgets/sortable_repeated_field.html
@@ -26,13 +26,24 @@
{% if show_button %}{{ widget.button.display() }}{% endif %}
<br style="clear:both"/>
<div class="{{ flist_cls }}">
+ {% set id = 0 %}
{% for i in range(repetitions) %}
{% set ctx = widget.context_for(i) %}
- {{ widget.field.display(css_class=field_cls, **ctx) }}
+ {% if c.form_values %}
+ {% if 'features-' ~ i ~ '.feature' in c.form_values %}
+ {% set ctx = widget.context_for(i) %}
+ {% do ctx.update({'value': {'feature':
c.form_values.get('features-' ~ i ~ '.feature')} }) %}
+ {{ widget.field.display(css_class=field_cls, **ctx) }}
+ {% endif %}
+ {% else %}
+ {{ widget.field.display(css_class=field_cls, **ctx) }}
+ {% endif %}
{% endfor %}
{% if extra_field_on_focus_name %}
- {% set ctx = widget.context_for(repetitions) %}
- {{ widget.field.display(css_class=field_cls, **ctx) }}
+ {% if not c.form_values %}
+ {% set ctx = widget.context_for(repetitions) %}
+ {{ widget.field.display(css_class=field_cls, **ctx) }}
+ {% endif %}
{% endif %}
{{ widget.field.display(name=name+'#', css_class=stub_cls) }}
</div>
diff --git a/Allura/allura/tests/functional/test_admin.py
b/Allura/allura/tests/functional/test_admin.py
index c1d71bd72..7a017b710 100644
--- a/Allura/allura/tests/functional/test_admin.py
+++ b/Allura/allura/tests/functional/test_admin.py
@@ -956,6 +956,46 @@ class TestProjectAdmin(TestController):
r = self.app.get('/admin/invitations')
r.mustcontain('Neighborhood Invitation(s) for test')
+ def test_social_networks(self):
+ #Invalid Twitter
+ resp = self.app.post('/admin/update',
params={'twitter_handle':'https://twit.com/tests'})
+ assert resp.status_int == 200
+ resp = self.app.post('/admin/update', params={'twitter_handle':
'https://google.com'})
+ assert resp.status_int == 200
+ #invalid Facebook
+ resp = self.app.post('/admin/update', params={'facebook_page':
'https://facebok.com'})
+ assert resp.status_int == 200
+ resp = self.app.post('/admin/update', params={'facebook_page':
'https://spam.com'})
+ assert resp.status_int == 200
+ errors = resp.html.findAll('div', attrs={'class': 'error'})
+ assert errors[0].text == 'Invalid domain for this field'
+ #invalid instagram
+ resp = self.app.post('/admin/update', params={'instagram_page':
'https://instagrams.com'})
+ assert resp.status_int == 200
+ #invalid fediverse
+ resp = self.app.post('/admin/update', params={'fediverse_address':
'@[email protected]'})
+ assert resp.status_int == 200
+
+ #valid Twitter
+ resp = self.app.post('/admin/update', params={'twitter_handle':
'https://twitter.com/sourceforge'})
+ assert resp.status_int == 302
+ resp = self.app.post('/admin/update', params={'twitter_handle':
'@sourceforge'})
+ assert resp.status_int == 302
+ #valid Facebook
+ resp = self.app.post('/admin/update', params={'facebook_page':
'https://www.facebook.com/sourceforgenet/'})
+ assert resp.status_int == 302
+ #valid instagram
+ resp = self.app.post('/admin/update', params={'instagram_page':
'https://instagram.com/test'})
+ assert resp.status_int == 302
+ resp = self.app.post('/admin/update', params={'instagram_page':
'@test'})
+ assert resp.status_int == 302
+ # valid fediverse
+ resp = self.app.post('/admin/update', params={'fediverse_address':
'@[email protected]'})
+ assert resp.status_int == 302
+ resp = self.app.post('/admin/update', params={'fediverse_address':
'https://indieweb.social/@test'})
+ assert resp.status_int == 302
+
+
class TestExport(TestController):