added ways to see and edit PersonExtResources.
- Legacy-Id: 17869
This commit is contained in:
parent
38ba0f401d
commit
b7f45dba05
|
@ -647,4 +647,44 @@ class IetfAuthTests(TestCase):
|
|||
self.assertIn("API key usage", mail['subject'])
|
||||
self.assertIn(" %s times" % count, body)
|
||||
self.assertIn(date, body)
|
||||
|
||||
def test_edit_person_extresources(self):
|
||||
url = urlreverse('ietf.ietfauth.views.edit_person_externalresources')
|
||||
person = PersonFactory()
|
||||
|
||||
r = self.client.get(url)
|
||||
self.assertNotEqual(r.status_code, 200)
|
||||
|
||||
self.client.login(username=person.user.username,password=person.user.username+'+password')
|
||||
|
||||
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)
|
||||
self.assertEqual(person.personextresource_set.count(), 4)
|
||||
self.assertEqual(person.personextresource_set.get(name__slug='github_repo').display_name, 'Some display text')
|
||||
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ urlpatterns = [
|
|||
url(r'^logout/$', logout),
|
||||
url(r'^password/$', views.change_password),
|
||||
url(r'^profile/$', views.profile),
|
||||
url(r'^editexternalresources/$', views.edit_person_externalresources),
|
||||
url(r'^reset/$', views.password_reset),
|
||||
url(r'^reset/confirm/(?P<auth>[^/]+)/$', views.confirm_password_reset),
|
||||
url(r'^review/$', views.review_overview),
|
||||
|
|
|
@ -67,12 +67,15 @@ from ietf.ietfauth.forms import ( RegistrationForm, PasswordForm, ResetPasswordF
|
|||
from ietf.ietfauth.htpasswd import update_htpasswd_file
|
||||
from ietf.ietfauth.utils import role_required, has_role
|
||||
from ietf.mailinglists.models import Subscribed, Whitelisted
|
||||
from ietf.name.models import ExtResourceName
|
||||
from ietf.person.models import Person, Email, Alias, PersonalApiKey, PERSON_API_KEY_VALUES
|
||||
from ietf.review.models import ReviewerSettings, ReviewWish, ReviewAssignment
|
||||
from ietf.review.utils import unavailable_periods_to_list, get_default_filter_re
|
||||
from ietf.doc.fields import SearchableDocumentField
|
||||
from ietf.utils.decorators import person_required
|
||||
from ietf.utils.mail import send_mail
|
||||
from ietf.utils.validators import validate_external_resource_value
|
||||
|
||||
|
||||
def index(request):
|
||||
return render(request, 'registration/index.html')
|
||||
|
@ -286,6 +289,79 @@ def profile(request):
|
|||
'settings':settings,
|
||||
})
|
||||
|
||||
@login_required
|
||||
@person_required
|
||||
def edit_person_externalresources(request):
|
||||
class PersonExtResourceForm(forms.Form):
|
||||
resources = forms.CharField(widget=forms.Textarea, label="Additional Resources", required=False,
|
||||
help_text=("Format: 'tag value (Optional description)'."
|
||||
" Separate multiple entries with newline. When the value is a URL, use https:// where possible.") )
|
||||
|
||||
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 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)
|
||||
|
||||
person = request.user.person
|
||||
|
||||
old_resources = format_resources(person.personextresource_set.all())
|
||||
|
||||
if request.method == 'POST':
|
||||
form = PersonExtResourceForm(request.POST)
|
||||
if form.is_valid():
|
||||
old_resources = sorted(old_resources.splitlines())
|
||||
new_resources = sorted(form.cleaned_data['resources'])
|
||||
if old_resources != new_resources:
|
||||
person.personextresource_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('()')
|
||||
person.personextresource_set.create(value=value, name_id=name, display_name=display_name)
|
||||
new_resources = format_resources(person.personextresource_set.all())
|
||||
messages.success(request,"Person resources updated.")
|
||||
else:
|
||||
messages.info(request,"No change in Person resources.")
|
||||
return redirect('ietf.ietfauth.views.profile')
|
||||
else:
|
||||
form = PersonExtResourceForm(initial={'resources': old_resources, })
|
||||
|
||||
info = "Valid tags:<br><br> %s" % ', '.join([ o.slug for o in ExtResourceName.objects.all().order_by('slug') ])
|
||||
# May need to explain the tags more - probably more reason to move to a formset.
|
||||
title = "Additional person resources"
|
||||
return render(request, 'ietfauth/edit_field.html',dict(person=person, form=form, title=title, info=info) )
|
||||
|
||||
def confirm_new_email(request, auth):
|
||||
try:
|
||||
username, email = django.core.signing.loads(auth, salt="add_email", max_age=settings.DAYS_TO_EXPIRE_REGISTRATION_LINK * 24 * 60 * 60)
|
||||
|
|
33
ietf/templates/ietfauth/edit_field.html
Normal file
33
ietf/templates/ietfauth/edit_field.html
Normal file
|
@ -0,0 +1,33 @@
|
|||
{% extends "base.html" %}
|
||||
{# Copyright The IETF Trust 2015, All Rights Reserved #}
|
||||
{% load origin %}
|
||||
|
||||
{% load bootstrap3 %}
|
||||
|
||||
{% block title %}
|
||||
{{ title }} {{ person.plain_name }}
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
{% origin %}
|
||||
<h1>{{ title }}<br><small>{{ person.plain_name }}</small></h1>
|
||||
|
||||
<p>
|
||||
<b>
|
||||
{{ info|safe }}
|
||||
</b>
|
||||
</p>
|
||||
|
||||
|
||||
<form enctype="multipart/form-data" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form %}
|
||||
|
||||
{% buttons %}
|
||||
<!-- Regarding placement of buttons: https://www.lukew.com/ff/entry.asp?571 -->
|
||||
<button type="submit" class="btn btn-primary" name="submit" value="Save">Submit</button>
|
||||
<a class="btn btn-default pull-right" href="{% url "ietf.ietfauth.views.profile" %}">Back</a>
|
||||
{% endbuttons %}
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
|
@ -57,7 +57,19 @@
|
|||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
{% if person.personextresource_set.exists %}
|
||||
<div class="col-md-12">
|
||||
<h2 id="extresources">External Resources</h2>
|
||||
<table class="table">
|
||||
{% for extres in person.personextresource_set.all %}
|
||||
<tr>
|
||||
<td class="col-md-1"><span title="{{ extres.name.name }}">{% firstof extres.display_name extres.name.name %}</span></td>
|
||||
<td class="col-md-11">{{extres.value}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="col-md-6">
|
||||
<h2 id="rfcs">RFCs</h2>
|
||||
|
|
|
@ -94,7 +94,7 @@
|
|||
<label class="col-sm-2 control-label">Nomcom Eligible</label>
|
||||
<div class="col-sm-1 form-control-static">{{person|is_nomcom_eligible|yesno:'Yes,No,No'}}</div>
|
||||
<div class="col-sm-9">
|
||||
<p class="alert alert-info form-control-static ">
|
||||
<p class="alert alert-info form-control-static">
|
||||
This calculation is EXPERIMENTAL.<br/>
|
||||
|
||||
If you believe it is incorrect, make sure you've added all the
|
||||
|
@ -111,6 +111,22 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">External Resources</label>
|
||||
<div class="col-sm-10 form-control-static">
|
||||
{% for extres in person.personextresource_set.all %}
|
||||
<div class="row">
|
||||
<div class="col-sm-1"><span title="{{ extres.name.name}}">{% firstof extres.display_name extres.name.name %}</span></div>
|
||||
<div class="col-sm-11">{{extres.value}}
|
||||
{% if forloop.first %} <a href="{% url 'ietf.ietfauth.views.edit_person_externalresources' %}"><span class="fa fa-pencil"></span></a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="row"><div class="col-sm-1">None <a href="{% url 'ietf.ietfauth.views.edit_person_externalresources' %}"><span class="fa fa-pencil"></span></a></div></div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Email addresses</label>
|
||||
<div class="col-sm-10">
|
||||
|
|
Loading…
Reference in a new issue