Skip to content

Commit b44a442

Browse files
committed
Add "add email" button to admin user profile
1 parent f7737e8 commit b44a442

5 files changed

Lines changed: 68 additions & 1 deletion

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{% if perms.osf.change_osfuser %}
2+
<a data-toggle="modal" data-target="#addEmailModal" class="btn btn-default">Add email</a>
3+
<div class="modal" id="addEmailModal">
4+
<div class="modal-dialog">
5+
<div class="modal-content">
6+
<form class="well" method="post" action="{% url 'users:add-email' guid=user.guid %}">
7+
<div class="modal-header">
8+
<button type="button" class="close" data-dismiss="modal">x</button>
9+
<h3>Add email to user</h3>
10+
</div>
11+
<div class="modal-body">
12+
<h4>User: {{ user.guid }}</h4>
13+
{% csrf_token %}
14+
<label for="id_new_email">Email address</label>
15+
<input type="email" name="new_email" id="id_new_email" class="form-control" required />
16+
</div>
17+
<div class="modal-footer">
18+
<input class="btn btn-primary" type="submit" value="Add and send confirmation" />
19+
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
20+
</div>
21+
</form>
22+
</div>
23+
</div>
24+
</div>
25+
{% endif %}
26+
27+

admin/templates/users/user.html

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<div class="btn-group" role="group">
2121
<a href="{% url 'users:search' %}" class="btn btn-default"><i class="fa fa-search"></i></a>
2222
{% include "users/reset_password.html" with user=user %}
23+
{% include "users/add_email.html" with user=user %}
2324
{% if perms.osf.change_osfuser %}
2425
<a href="{% url 'users:get-reset-password' guid=user.guid %}" data-toggle="modal" data-target="#getResetModal" class="btn btn-default">Get password reset link</a>
2526
{% if user.confirmed %}

admin/users/forms.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,11 @@ class UserSearchForm(forms.Form):
1919

2020
class MergeUserForm(forms.Form):
2121
user_guid_to_be_merged = forms.CharField(label='user_guid_to_be_merged', min_length=5, max_length=5, required=True) # TODO: Move max to 6 when needed
22+
23+
24+
class AddSystemTagForm(forms.Form):
25+
system_tag_to_add = forms.CharField(label='system_tag_to_add', min_length=1, max_length=1024, required=True)
26+
27+
28+
class AddEmailForm(forms.Form):
29+
new_email = forms.EmailField(label='new_email', required=True)

admin/users/urls.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
re_path(r'^(?P<guid>[a-z0-9]+)/get_reset_password/$', views.GetPasswordResetLink.as_view(), name='get-reset-password'),
2727
re_path(r'^(?P<guid>[a-z0-9]+)/reindex_elastic_user/$', views.UserReindexElastic.as_view(),
2828
name='reindex-elastic-user'),
29+
re_path(r'^(?P<guid>[a-z0-9]+)/add_email/$', views.UserAddEmail.as_view(), name='add-email'),
2930
re_path(r'^(?P<guid>[a-z0-9]+)/reindex_share_user/$', views.UserShareReindex.as_view(),
3031
name='reindex-share-user'),
3132
re_path(r'^(?P<guid>[a-z0-9]+)/merge_accounts/$', views.UserMergeAccounts.as_view(), name='merge-accounts'),

admin/users/views.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
from admin.users.forms import (
4444
EmailResetForm,
4545
UserSearchForm,
46-
MergeUserForm
46+
MergeUserForm,
47+
AddEmailForm
4748
)
4849
from admin.nodes.views import NodeAddSystemTag, NodeRemoveSystemTag
4950
from admin.base.views import GuidView
@@ -396,6 +397,35 @@ class UserRemoveSystemTag(UserMixin, NodeRemoveSystemTag):
396397
permission_required = 'osf.change_osfuser'
397398

398399

400+
class UserAddEmail(UserMixin, FormView):
401+
"""Allows authorized users to add an email to a user's account and trigger confirmation."""
402+
permission_required = 'osf.change_osfuser'
403+
raise_exception = True
404+
form_class = AddEmailForm
405+
406+
def form_valid(self, form):
407+
from osf.exceptions import BlockedEmailError
408+
from django.core.exceptions import ValidationError as DjangoValidationError
409+
from framework.auth.views import send_confirm_email_async
410+
from django.utils import timezone
411+
412+
user = self.get_object()
413+
address = form.cleaned_data['new_email'].strip().lower()
414+
try:
415+
user.add_unconfirmed_email(address)
416+
417+
send_confirm_email_async(user, email=address)
418+
user.email_last_sent = timezone.now()
419+
user.save()
420+
messages.success(self.request, f'Added unconfirmed email {address} and sent confirmation email.')
421+
except (DjangoValidationError, ValueError) as e:
422+
messages.error(self.request, f'Invalid email: {getattr(e, "message", str(e))}')
423+
except BlockedEmailError:
424+
messages.error(self.request, 'This email address domain is blocked.')
425+
426+
return super().form_valid(form)
427+
428+
399429
class UserMergeAccounts(UserMixin, FormView):
400430
""" Allows authorized users to merge a user's accounts using their guid.
401431
"""

0 commit comments

Comments
 (0)