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("API key usage", mail['subject'])
|
||||||
self.assertIn(" %s times" % count, body)
|
self.assertIn(" %s times" % count, body)
|
||||||
self.assertIn(date, 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'^logout/$', logout),
|
||||||
url(r'^password/$', views.change_password),
|
url(r'^password/$', views.change_password),
|
||||||
url(r'^profile/$', views.profile),
|
url(r'^profile/$', views.profile),
|
||||||
|
url(r'^editexternalresources/$', views.edit_person_externalresources),
|
||||||
url(r'^reset/$', views.password_reset),
|
url(r'^reset/$', views.password_reset),
|
||||||
url(r'^reset/confirm/(?P<auth>[^/]+)/$', views.confirm_password_reset),
|
url(r'^reset/confirm/(?P<auth>[^/]+)/$', views.confirm_password_reset),
|
||||||
url(r'^review/$', views.review_overview),
|
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.htpasswd import update_htpasswd_file
|
||||||
from ietf.ietfauth.utils import role_required, has_role
|
from ietf.ietfauth.utils import role_required, has_role
|
||||||
from ietf.mailinglists.models import Subscribed, Whitelisted
|
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.person.models import Person, Email, Alias, PersonalApiKey, PERSON_API_KEY_VALUES
|
||||||
from ietf.review.models import ReviewerSettings, ReviewWish, ReviewAssignment
|
from ietf.review.models import ReviewerSettings, ReviewWish, ReviewAssignment
|
||||||
from ietf.review.utils import unavailable_periods_to_list, get_default_filter_re
|
from ietf.review.utils import unavailable_periods_to_list, get_default_filter_re
|
||||||
from ietf.doc.fields import SearchableDocumentField
|
from ietf.doc.fields import SearchableDocumentField
|
||||||
from ietf.utils.decorators import person_required
|
from ietf.utils.decorators import person_required
|
||||||
from ietf.utils.mail import send_mail
|
from ietf.utils.mail import send_mail
|
||||||
|
from ietf.utils.validators import validate_external_resource_value
|
||||||
|
|
||||||
|
|
||||||
def index(request):
|
def index(request):
|
||||||
return render(request, 'registration/index.html')
|
return render(request, 'registration/index.html')
|
||||||
|
@ -286,6 +289,79 @@ def profile(request):
|
||||||
'settings':settings,
|
'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):
|
def confirm_new_email(request, auth):
|
||||||
try:
|
try:
|
||||||
username, email = django.core.signing.loads(auth, salt="add_email", max_age=settings.DAYS_TO_EXPIRE_REGISTRATION_LINK * 24 * 60 * 60)
|
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>
|
</div>
|
||||||
{% endif %}
|
{% 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">
|
<div class="col-md-6">
|
||||||
<h2 id="rfcs">RFCs</h2>
|
<h2 id="rfcs">RFCs</h2>
|
||||||
|
|
|
@ -94,7 +94,7 @@
|
||||||
<label class="col-sm-2 control-label">Nomcom Eligible</label>
|
<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-1 form-control-static">{{person|is_nomcom_eligible|yesno:'Yes,No,No'}}</div>
|
||||||
<div class="col-sm-9">
|
<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/>
|
This calculation is EXPERIMENTAL.<br/>
|
||||||
|
|
||||||
If you believe it is incorrect, make sure you've added all the
|
If you believe it is incorrect, make sure you've added all the
|
||||||
|
@ -111,6 +111,22 @@
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div class="form-group">
|
||||||
<label class="col-sm-2 control-label">Email addresses</label>
|
<label class="col-sm-2 control-label">Email addresses</label>
|
||||||
<div class="col-sm-10">
|
<div class="col-sm-10">
|
||||||
|
|
Loading…
Reference in a new issue