Skip to content

Commit 1502efb

Browse files
committed
Adding self-management page for user profile information
- Legacy-Id: 4705
1 parent 8ff61de commit 1502efb

6 files changed

Lines changed: 304 additions & 14 deletions

File tree

ietf/ietfauth/forms.py

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import subprocess
44

55
from django import forms
6+
from django.forms import ModelForm
67
from django.conf import settings
78
from django.contrib.auth.models import User
89
from django.contrib.sites.models import Site
@@ -155,3 +156,61 @@ def save(self):
155156

156157
class TestEmailForm(forms.Form):
157158
email = forms.EmailField(required=False)
159+
160+
class PersonForm(ModelForm):
161+
request = None
162+
new_emails = []
163+
class Meta:
164+
from ietf.person.models import Person
165+
model = Person
166+
exclude = ('time','user')
167+
168+
def confirm_address(self,email):
169+
person = self.instance
170+
domain = Site.objects.get_current().domain
171+
user = person.user
172+
if len(email) == 0:
173+
return
174+
subject = 'Confirm email address for %s' % person.name
175+
from_email = settings.DEFAULT_FROM_EMAIL
176+
to_email = email
177+
today = datetime.date.today().strftime('%Y%m%d')
178+
auth = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, today, to_email, user)).hexdigest()
179+
context = {
180+
'today': today,
181+
'domain': domain,
182+
'user': user,
183+
'email': email,
184+
'expire': settings.DAYS_TO_EXPIRE_REGISTRATION_LINK,
185+
'auth': auth,
186+
}
187+
send_mail(self.request, to_email, from_email, subject, 'registration/add_email_email.txt', context)
188+
189+
def save(self, force_insert=False, force_update=False, commit=True):
190+
from ietf.group.models import Role
191+
m = super(PersonForm, self).save(commit=False)
192+
self.new_emails = [v for k,v in self.data.items() if k[:10] == u'new_email_' and u'@' in v]
193+
194+
for email in self.new_emails:
195+
self.confirm_address(email)
196+
197+
# Process email active flags
198+
emails = Email.objects.filter(person=self.instance)
199+
for email in emails:
200+
email.active = self.data.__contains__(email.address)
201+
if commit:
202+
email.save()
203+
204+
# Process email for roles
205+
for k,v in self.data.items():
206+
if k[:11] == u'role_email_':
207+
role = Role.objects.get(id=k[11:])
208+
email = Email.objects.get(address = v)
209+
role.email = email
210+
if commit:
211+
role.save()
212+
213+
if commit:
214+
m.save()
215+
return m
216+

ietf/ietfauth/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,6 @@
1717
url(r'^confirm/(?P<username>[\w.@+-]+)/(?P<date>[\d]+)/(?P<realm>[\w]+)/(?P<registration_hash>[a-f0-9]+)/$', 'confirm_account', name='confirm_account'),
1818
url(r'^reset/$', 'password_reset_view', name='password_reset'),
1919
url(r'^reset/confirm/(?P<username>[\w.@+-]+)/(?P<date>[\d]+)/(?P<realm>[\w]+)/(?P<reset_hash>[a-f0-9]+)/$', 'confirm_password_reset', name='confirm_password_reset'),
20+
url(r'^add_email/confirm/(?P<username>[\w.@+-]+)/(?P<date>[\d]+)/(?P<email>[\w.@+-]+)/(?P<hash>[a-f0-9]+)/$', 'confirm_new_email', name='confirm_new_email'),
2021
url(r'^ajax/check_username/$', 'ajax_check_username', name='ajax_check_username'),
2122
)

ietf/ietfauth/views.py

Lines changed: 76 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -79,24 +79,87 @@ def ietf_loggedin(request):
7979

8080
@login_required
8181
def profile(request):
82-
if settings.USE_DB_REDESIGN_PROXY_CLASSES:
83-
from ietf.person.models import Person
84-
from ietf.group.models import Role
82+
from ietf.person.models import Person, Email, Alias
83+
from ietf.group.models import Role
84+
from ietf.ietfauth.forms import PersonForm
8585

86-
roles = []
87-
person = None
86+
roles = []
87+
person = None
88+
try:
89+
person = request.user.get_profile()
90+
except Person.DoesNotExist:
91+
pass
92+
93+
if request.method == 'POST':
94+
form = PersonForm(request.POST, instance=person)
95+
success = False
96+
new_emails = None
97+
error = None
98+
if form.is_valid():
99+
try:
100+
form.save()
101+
success = True
102+
new_emails = form.new_emails
103+
except Exception as e:
104+
error = e
105+
106+
return render_to_response('registration/confirm_profile_update.html',
107+
{ 'success': success, 'new_emails': new_emails, 'error': error} ,
108+
context_instance=RequestContext(request))
109+
else:
110+
roles = Role.objects.filter(person=person).order_by('name__name','group__name')
111+
emails = Email.objects.filter(person=person).order_by('-active','-time')
112+
aliases = Alias.objects.filter(person=person)
113+
114+
person_form = PersonForm(instance=person)
115+
116+
return render_to_response('registration/edit_profile.html',
117+
{ 'user': request.user, 'emails': emails, 'person': person,
118+
'roles': roles, 'person_form': person_form } ,
119+
context_instance=RequestContext(request))
120+
121+
def confirm_new_email(request, username, date, email, hash):
122+
from ietf.person.models import Person, Email, Alias
123+
from django.core.exceptions import ValidationError, NON_FIELD_ERRORS
124+
valid = hashlib.md5('%s%s%s%s' % (settings.SECRET_KEY, date, email, username)).hexdigest() == hash
125+
if not valid:
126+
raise Http404
127+
request_date = datetime.date(int(date[:4]), int(date[4:6]), int(date[6:]))
128+
if datetime.date.today() > (request_date + datetime.timedelta(days=settings.DAYS_TO_EXPIRE_REGISTRATION_LINK)):
129+
raise Http404
130+
success = False
131+
132+
person = None
133+
error = None
134+
new_email = None
135+
136+
try:
137+
# First, check whether this address exists (to give a more sensible
138+
# error when a duplicate is created).
139+
existing_email = Email.objects.get(address=email)
140+
print existing_email
141+
existing_person = existing_email.person
142+
print existing_person
143+
error = {'address': ["Email address '%s' is already assigned to user '%s' (%s)" %
144+
(email, existing_person.user, existing_person.name)]}
145+
except Exception:
88146
try:
89-
person = request.user.get_profile()
90-
roles = Role.objects.filter(person=person)
147+
person = Person.objects.get(user__username=username)
148+
new_email = Email(address=email, person=person, active=True, time=datetime.datetime.now())
149+
new_email.full_clean()
150+
new_email.save()
151+
success = True
91152
except Person.DoesNotExist:
92-
pass
153+
error = {'person': ["No such user: %s" % (username)]}
154+
except ValidationError as e:
155+
error = e.message_dict
93156

94-
return render_to_response('registration/profileREDESIGN.html',
95-
dict(roles=roles,
96-
person=person),
97-
context_instance=RequestContext(request))
157+
return render_to_response('registration/confirm_new_email.html',
158+
{ 'username': username, 'email': email,
159+
'success': success, 'error': error,
160+
'record': new_email},
161+
context_instance=RequestContext(request))
98162

99-
return render_to_response('registration/profile.html', context_instance=RequestContext(request))
100163

101164
def create_account(request):
102165
success = False

ietf/templates/base_leftmenu.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
{% load ietf_filters community_tags %}
3838
<ul>
3939
<li class="sect first">Accounts</li>
40-
<li><a href="{% url account_index %}">New Account</a></li>
40+
<li><a href="{% url account_index %}">{% if request.user.is_authenticated %}Manage Account{% else %}New Account{% endif %}</a></li>
4141
{% if user|in_group:"Area_Director" %}
4242
<li class="sect first">AD Dashboard</li>
4343
<li><a href="{% url doc_search_by_ad name=user.get_profile.person.full_name_as_key %}">My Documents</a></li>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% autoescape off %}
2+
Hello,
3+
4+
We have received a request to add the email address '{{ email }}'
5+
to the user account '{{ user }}' at '{{ domain }}'.
6+
If you requested this change, please confirm that this is your email
7+
address by clicking on following link:
8+
9+
http://{{ domain }}{% url confirm_new_email user today email auth %}
10+
11+
This link will expire in {{ expire }} days.
12+
13+
If you did not request this change, you may safely ignore this email,
14+
as no actions have been taken.
15+
16+
Best regards,
17+
18+
The datatracker login manager service
19+
(for the IETF Secretariat)
20+
{% endautoescape %}
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
{# Copyright The IETF Trust 2007, All Rights Reserved #}
2+
{% extends "base.html" %}
3+
4+
{% block morecss %}
5+
table.userProfile {
6+
text-align: left;
7+
}
8+
th {
9+
vertical-align: top;
10+
text-align: right !important;
11+
font-weight: bold !important;
12+
}
13+
.active {
14+
color: #008000;
15+
color: #008000;
16+
}
17+
.inactive {
18+
color: #800000;
19+
text-decoration: line-through;
20+
}
21+
.even {
22+
background-color: #e0e0ff;
23+
}
24+
.odd {
25+
background-color: #ffffff;
26+
}
27+
{% endblock %}
28+
29+
{% block pagehead %}
30+
<script type="text/javascript">
31+
function init_form()
32+
{
33+
// Make sure emails are styled correctly
34+
var inputs = document.getElementsByTagName("input");
35+
for (var input in inputs)
36+
{
37+
if (inputs[input].type=="checkbox")
38+
{
39+
style_email(inputs[input]);
40+
}
41+
}
42+
}
43+
44+
function style_email(e)
45+
{
46+
var span = document.getElementById(e.id.replace("controller_","span_"));
47+
if (!span) { return; }
48+
if (e.checked)
49+
{
50+
span.className = 'active';
51+
}
52+
else
53+
{
54+
span.className = 'inactive';
55+
}
56+
}
57+
58+
function add_email()
59+
{
60+
var button_row = document.getElementById("add_email_row");
61+
var tr = document.createElement("tr");
62+
tr.appendChild(document.createElement("th"));
63+
tr.appendChild(document.createElement("td"));
64+
var td = document.createElement("td");
65+
var input = document.createElement("input");
66+
input.style.width="100%";
67+
var date = new Date;
68+
input.name = "new_email_"+date.getTime();
69+
td.appendChild(input);
70+
tr.appendChild(td);
71+
button_row.parentNode.insertBefore(tr,button_row);
72+
}
73+
</script>
74+
{% endblock %}
75+
76+
{% block bodyAttrs %}onload='init_form();'{% endblock %}
77+
78+
{% block title %}Profile for {{ user }}{% endblock %}
79+
80+
{% block content %}
81+
<h1>User information for {{ user.username }}</h1>
82+
83+
<form method="post"> {% csrf_token %}
84+
<table class="userProfile">
85+
<tr>
86+
<th>User name:</th>
87+
<td></td>
88+
<td>{{ user.username }}</td>
89+
</tr>
90+
{% for role in roles %}
91+
<tr>
92+
<th>{% if forloop.first %}Roles:{% endif %}</th>
93+
<td></td>
94+
<td class='{% cycle 'even' 'odd'%}'>{{ role.name }} in {{ role.group.acronym|upper }} ({{ role.group.type }})</td>
95+
<td class='{% cycle 'even' 'odd'%}'>
96+
<select name="role_email_{{role.id}}">
97+
{% for email in emails %}<option value="{{email.address}}"{% ifequal email.address role.email.address %} selected="selected"{% endifequal %} class='{% if email.active %}active{% else %}inactive{% endif %}'>{{email}}</option>
98+
{% endfor %}</select></td>
99+
</tr>
100+
{% endfor %}
101+
{% for email in emails %}
102+
<tr>
103+
<th>{% if forloop.first %}Email:{% endif %}</th>
104+
<td></td>
105+
<td colspan="2">
106+
<input type="checkbox" id="controller_{{email.address}}" name="{{email.address}}" {% if email.active %}checked="checked"{% else %}{% endif %} onchange="style_email(this)"/>
107+
<span id="span_{{email.address}}">{{email}}</span></td>
108+
</tr>
109+
{% endfor %}
110+
<tr id="add_email_row">
111+
<th></th>
112+
<td></td>
113+
<td colspan='2'><input type="button" value="Add Email Address" onclick="add_email()"/></td>
114+
</tr>
115+
<tr><td colspan="2"></td><td colspan="2"><i>Note: Email addresses cannot be deleted, only deactivated.</i></td></tr>
116+
<tr>
117+
<th>{{person_form.name.label}}:</th>
118+
<td></td>
119+
<td colspan='2'>{{person_form.name}} - The preferred form of your name</td>
120+
</tr>
121+
<tr>
122+
<th>{{person_form.ascii.label}}:</th>
123+
<td></td>
124+
<td colspan='2'>{{person_form.ascii}} - Your name as rendered in ASCII (Latin, unaccented) characters</td>
125+
</tr>
126+
<tr>
127+
<th>{{person_form.ascii_short.label}}:</th>
128+
<td></td>
129+
<td colspan='2'>{{person_form.ascii_short}} - Short form, if any, of your name as renedered in ASCII (blank is okay)</td>
130+
</tr>
131+
<tr>
132+
<th>{{person_form.affiliation.label}}:</th>
133+
<td></td>
134+
<td colspan='2'>{{person_form.affiliation}} - Employer, university, sponsor, etc.</td>
135+
</tr>
136+
<tr>
137+
<th>Mailing Address:</th>
138+
<td></td>
139+
<td colspan='2'>{{person_form.address}}</td>
140+
</tr>
141+
142+
<td colspan="4"><div width='100%' align='right'><input type="submit" value="Commit Changes" /></div></td></tr>
143+
</table>
144+
145+
146+
</form>
147+
{% endblock %}

0 commit comments

Comments
 (0)