Added GroupExtResources to the group about page, and added the ability to edit them.
- Legacy-Id: 17685
This commit is contained in:
parent
2de9eb93b5
commit
7587d564d4
|
@ -1135,7 +1135,6 @@ class IndividualInfoFormsTests(TestCase):
|
|||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form textarea[id=id_resources]')),1)
|
||||
|
||||
# AMHERE
|
||||
badlines = (
|
||||
'github_repo https://github3.com/some/repo',
|
||||
'github_notify badaddr',
|
||||
|
|
|
@ -1320,11 +1320,11 @@ def edit_doc_extresources(request, name):
|
|||
value = parts[1]
|
||||
display_name = ' '.join(parts[2:]).strip('()')
|
||||
doc.docextresource_set.create(value=value, name_id=name, display_name=display_name)
|
||||
new_resources = format_resources(doc.docextresource_set.all())
|
||||
e = DocEvent(doc=doc, rev=doc.rev, by=request.user.person, type='changed_document')
|
||||
e.desc = "Changed document external resources from:\n\n%s\n\nto:\n\n%s" % (old_resources, new_resources)
|
||||
e.save()
|
||||
doc.save_with_history([e])
|
||||
new_resources = format_resources(doc.docextresource_set.all())
|
||||
e = DocEvent(doc=doc, rev=doc.rev, by=request.user.person, type='changed_document')
|
||||
e.desc = "Changed document external resources from:\n\n%s\n\nto:\n\n%s" % (old_resources, new_resources)
|
||||
e.save()
|
||||
doc.save_with_history([e])
|
||||
messages.success(request,"Document resources updated.")
|
||||
else:
|
||||
messages.info(request,"No change in Document resources.")
|
||||
|
|
|
@ -13,10 +13,11 @@ import debug # pyflakes:ignore
|
|||
# Django imports
|
||||
from django import forms
|
||||
from django.utils.html import mark_safe # type:ignore
|
||||
from django.core.exceptions import ValidationError, ObjectDoesNotExist
|
||||
|
||||
# IETF imports
|
||||
from ietf.group.models import Group, GroupHistory, GroupStateName
|
||||
from ietf.name.models import ReviewTypeName
|
||||
from ietf.name.models import ReviewTypeName, ExtResourceName
|
||||
from ietf.person.fields import SearchableEmailsField, PersonEmailChoiceField
|
||||
from ietf.person.models import Person
|
||||
from ietf.review.models import ReviewerSettings, UnavailablePeriod, ReviewSecretarySettings
|
||||
|
@ -26,6 +27,7 @@ from ietf.utils.textupload import get_cleaned_text_file_content
|
|||
from ietf.utils.text import strip_suffix
|
||||
#from ietf.utils.ordereddict import insert_after_in_ordered_dict
|
||||
from ietf.utils.fields import DatepickerDateField, MultiEmailField
|
||||
from ietf.utils.validators import validate_external_resource_value
|
||||
|
||||
# --- Constants --------------------------------------------------------
|
||||
|
||||
|
@ -82,6 +84,7 @@ class GroupForm(forms.Form):
|
|||
list_subscribe = forms.CharField(max_length=255, required=False)
|
||||
list_archive = forms.CharField(max_length=255, required=False)
|
||||
urls = forms.CharField(widget=forms.Textarea, label="Additional URLs", help_text="Format: https://site/path (Optional description). Separate multiple entries with newline. Prefer HTTPS URLs where possible.", required=False)
|
||||
resources = forms.CharField(widget=forms.Textarea, label="Additional Resources", help_text="UPDATEME: Format: https://site/path (Optional description). Separate multiple entries with newline. Prefer HTTPS URLs where possible.", required=False)
|
||||
closing_note = forms.CharField(widget=forms.Textarea, label="Closing note", required=False)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -127,6 +130,12 @@ class GroupForm(forms.Form):
|
|||
for f in keys:
|
||||
if f != field and not (f == 'closing_note' and field == 'state'):
|
||||
del self.fields[f]
|
||||
if 'resources' in self.fields:
|
||||
info = "Format: 'tag value (Optional description)'. " \
|
||||
+ "Separate multiple entries with newline. When the value is a URL, use https:// where possible.<br>" \
|
||||
+ "Valid tags: %s" % ', '.join([ o.slug for o in ExtResourceName.objects.all().order_by('slug') ])
|
||||
self.fields['resources'].help_text = mark_safe('<div>'+info+'</div>')
|
||||
|
||||
|
||||
def clean_acronym(self):
|
||||
# Changing the acronym of an already existing group will cause 404s all
|
||||
|
@ -186,6 +195,30 @@ class GroupForm(forms.Form):
|
|||
def clean_urls(self):
|
||||
return [x.strip() for x in self.cleaned_data["urls"].splitlines() if x.strip()]
|
||||
|
||||
def clean_resources(self):
|
||||
lines = [x.strip() for x in self.cleaned_data["resources"].splitlines() if x.strip()]
|
||||
errors = []
|
||||
for l in lines:
|
||||
parts = l.split()
|
||||
if len(parts) == 1:
|
||||
errors.append("Too few fields: Expected at least tag and value: '%s'" % l)
|
||||
elif len(parts) >= 2:
|
||||
name_slug = parts[0]
|
||||
try:
|
||||
name = ExtResourceName.objects.get(slug=name_slug)
|
||||
except ObjectDoesNotExist:
|
||||
errors.append("Bad tag in '%s': Expected one of %s" % (l, ', '.join([ o.slug for o in ExtResourceName.objects.all() ])))
|
||||
continue
|
||||
value = parts[1]
|
||||
try:
|
||||
validate_external_resource_value(name, value)
|
||||
except ValidationError as e:
|
||||
e.message += " : " + value
|
||||
errors.append(e)
|
||||
if errors:
|
||||
raise ValidationError(errors)
|
||||
return lines
|
||||
|
||||
def clean_delegates(self):
|
||||
if len(self.cleaned_data["delegates"]) > MAX_GROUP_DELEGATES:
|
||||
raise forms.ValidationError("At most %s delegates can be appointed at the same time, please remove %s delegates." % (
|
||||
|
|
|
@ -634,6 +634,46 @@ class GroupEditTests(TestCase):
|
|||
self.assertTrue(prefix+'@' in outbox[0]['To'])
|
||||
self.assertTrue(outbox[0].get_payload(decode=True).decode(str(outbox[0].get_charset())).startswith('Sec Retary'))
|
||||
|
||||
def test_edit_extresources(self):
|
||||
group = GroupFactory(acronym='mars',parent=GroupFactory(type_id='area'))
|
||||
CharterFactory(group=group)
|
||||
|
||||
url = urlreverse('ietf.group.views.edit', kwargs=dict(group_type=group.type_id, acronym=group.acronym, action="edit", field="resources"))
|
||||
login_testing_unauthorized(self, "secretary", url)
|
||||
|
||||
r = self.client.get(url)
|
||||
self.assertEqual(r.status_code,200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertEqual(len(q('form textarea[id=id_resources]')),1)
|
||||
|
||||
badlines = (
|
||||
'github_repo https://github3.com/some/repo',
|
||||
'github_notify badaddr',
|
||||
'website /not/a/good/url'
|
||||
'notavalidtag blahblahblah'
|
||||
)
|
||||
|
||||
for line in badlines:
|
||||
r = self.client.post(url, dict(resources=line, submit="1"))
|
||||
self.assertEqual(r.status_code, 200)
|
||||
q = PyQuery(r.content)
|
||||
self.assertTrue(q('.alert-danger'))
|
||||
|
||||
goodlines = """
|
||||
github_repo https://github.com/some/repo Some display text
|
||||
github_notify notify@example.com
|
||||
github_username githubuser
|
||||
website http://example.com/http/is/fine
|
||||
"""
|
||||
|
||||
r = self.client.post(url, dict(resources=goodlines, submit="1"))
|
||||
self.assertEqual(r.status_code,302)
|
||||
group = Group.objects.get(acronym=group.acronym)
|
||||
self.assertEqual(group.latest_event(GroupEvent,type="info_changed").desc[:20], 'Resources changed to')
|
||||
self.assertIn('github_username githubuser', group.latest_event(GroupEvent,type="info_changed").desc)
|
||||
self.assertEqual(group.groupextresource_set.count(), 4)
|
||||
self.assertEqual(group.groupextresource_set.get(name__slug='github_repo').display_name, 'Some display text')
|
||||
|
||||
|
||||
def test_edit_field(self):
|
||||
group = GroupFactory(acronym="mars")
|
||||
|
|
|
@ -880,6 +880,17 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
|
|||
res.append(u.url)
|
||||
return fs.join(res)
|
||||
|
||||
def format_resources(resources, fs="\n"):
|
||||
res = []
|
||||
for r in resources:
|
||||
if r.display_name:
|
||||
res.append("%s %s (%s)" % (r.name.slug, r.value, r.display_name.strip('()')))
|
||||
else:
|
||||
res.append("%s %s" % (r.name.slug, r.value))
|
||||
# TODO: This is likely problematic if value has spaces. How then to delineate value and display_name? Perhaps in the short term move to comma or pipe separation.
|
||||
# Might be better to shift to a formset instead of parsing these lines.
|
||||
return fs.join(res)
|
||||
|
||||
def diff(attr, name):
|
||||
if field and attr != field:
|
||||
return
|
||||
|
@ -933,11 +944,6 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
|
|||
else:
|
||||
save_group_in_history(group)
|
||||
|
||||
|
||||
## XXX Remove after testing
|
||||
# if action == "charter" and not group.charter: # make sure we have a charter
|
||||
# group.charter = get_or_create_initial_charter(group, group_type)
|
||||
|
||||
changes = []
|
||||
|
||||
# update the attributes, keeping track of what we're doing
|
||||
|
@ -1023,6 +1029,19 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
|
|||
url = GroupURL(url=m.group('url'), name='', group=group)
|
||||
url.save()
|
||||
|
||||
if 'resources' in clean:
|
||||
old_resources = sorted(format_resources(group.groupextresource_set.all()).splitlines())
|
||||
new_resources = sorted(clean['resources'])
|
||||
if old_resources != new_resources:
|
||||
group.groupextresource_set.all().delete()
|
||||
for u in new_resources:
|
||||
parts = u.split(None, 2)
|
||||
name = parts[0]
|
||||
value = parts[1]
|
||||
display_name = ' '.join(parts[2:]).strip('()')
|
||||
group.groupextresource_set.create(value=value, name_id=name, display_name=display_name)
|
||||
changes.append(('resources', new_resources, desc('Resources', ", ".join(new_resources), ", ".join(old_resources))))
|
||||
|
||||
group.time = datetime.datetime.now()
|
||||
|
||||
if changes and not new_group:
|
||||
|
@ -1075,6 +1094,7 @@ def edit(request, group_type=None, acronym=None, action="edit", field=None):
|
|||
list_subscribe=group.list_subscribe if group.list_subscribe else None,
|
||||
list_archive=group.list_archive if group.list_archive else None,
|
||||
urls=format_urls(group.groupurl_set.all()),
|
||||
resources=format_resources(group.groupextresource_set.all()),
|
||||
closing_note = closing_note,
|
||||
)
|
||||
|
||||
|
|
|
@ -138,6 +138,36 @@
|
|||
</tr>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
|
||||
{% with group.groupextresource_set.all as resources %}
|
||||
{% if resources or can_edit_group %}
|
||||
<tr>
|
||||
<td></td>
|
||||
<th>Additional Resources</th>
|
||||
<td class="edit">
|
||||
{% if can_edit_group %}
|
||||
<a class="btn btn-default btn-xs" href="{% url 'ietf.group.views.edit' acronym=group.acronym field='resources' %}">Edit</a>
|
||||
{% endif %}
|
||||
</td>
|
||||
<td>
|
||||
{% if resources %}
|
||||
<table class="col-md-12 col-sm-12 col-xs-12">
|
||||
<tbody>
|
||||
{% for resource in resources|dictsort:"display_name" %}
|
||||
{% if resource.name.type.slug == 'url' or resource.name.type.slug == 'email' %}
|
||||
<tr><td> - <a href="{{ resource.value }}" title="{{resource.name.name}}">{% firstof resource.display_name resource.name.name %}</a></td></tr>
|
||||
{# Maybe make how a resource displays itself a method on the class so templates aren't doing this switching #}
|
||||
{% else %}
|
||||
<tr><td> - <span title="{{resource.name.name}}">{% firstof resource.display_name resource.name.name %}: {{resource.value}}</span></td></tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
</tbody>
|
||||
|
||||
<tbody class="meta">
|
||||
|
|
Loading…
Reference in a new issue