Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ENG-6195] Fix admin confirmation link generation and handling #10734

Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions admin/users/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from osf.models.base import Guid
from osf.models.user import OSFUser
from osf.models.spam import SpamStatus
from osf.utils.users import get_or_refresh_confirmation_link
from framework.auth import get_user
from framework.auth.core import generate_verification_key

Expand Down Expand Up @@ -456,10 +457,10 @@ def get_context_data(self, **kwargs):

class GetUserConfirmationLink(GetUserLink):
def get_link(self, user):
try:
return user.get_confirmation_url(user.username, force=True)
mfraezz marked this conversation as resolved.
Show resolved Hide resolved
except KeyError as e:
return str(e)
result = get_or_refresh_confirmation_link(user._id)
if 'confirmation_link' in result:
return result['confirmation_link']
return result['error']

def get_link_type(self):
return 'User Confirmation'
Expand Down
13 changes: 9 additions & 4 deletions admin_tests/users/test_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -486,9 +486,12 @@ def test_get_user_confirmation_link(self):
view = views.GetUserConfirmationLink()
view = setup_view(view, request, guid=user._id)

user_token = list(user.email_verifications.keys())[0]
ideal_link_path = f'/confirm/{user._id}/{user_token}/'
link = view.get_link(user)

link_furl = furl(link)
generated_token = link_furl.path.segments[-1]

ideal_link_path = f'/confirm/{user._id}/{generated_token}'
link_path = str(furl(link).path)

assert link_path == ideal_link_path
Expand All @@ -504,10 +507,12 @@ def test_get_user_confirmation_link_with_expired_token(self):
user.save()

link = view.get_link(user)
new_user_token = list(user.email_verifications.keys())[0]

link_furl = furl(link)
generated_token = link_furl.path.segments[-1]

ideal_link_path = f'/confirm/{user._id}/{generated_token}'
link_path = str(furl(link).path)
ideal_link_path = f'/confirm/{user._id}/{new_user_token}/'

assert link_path == ideal_link_path

Expand Down
36 changes: 36 additions & 0 deletions osf/utils/users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from django.utils import timezone
from osf.models import OSFUser
from django.core.exceptions import ValidationError
from website.settings import DOMAIN

def get_or_refresh_confirmation_link(uid):
mfraezz marked this conversation as resolved.
Show resolved Hide resolved
u = OSFUser.load(uid)
if u.is_confirmed:
return {'error': f'User {uid} is already confirmed'}

if u.deleted or u.is_merged:
return {'error': f'User {uid} is deleted or merged'}

confirmation_link = None
if u.emails.filter(address=u.username).exists():
for token, data in u.email_verifications.items():
if data['email'] == u.username and data['expiration'] < timezone.now():
u.email_verifications[token]['expiration'] = timezone.now() + timezone.timedelta(days=30)
u.save()
confirmation_link = f'{DOMAIN.rstrip("/")}/confirm/{u._id}/{token}'
mfraezz marked this conversation as resolved.
Show resolved Hide resolved
return {'confirmation_link': confirmation_link}
else:
try:
u.add_unconfirmed_email(u.username)
u.save()
for token, data in u.email_verifications.items():
if data['email'] == u.username:
confirmation_link = f'{DOMAIN.rstrip("/")}/confirm/{u._id}/{token}'
return {'confirmation_link': confirmation_link}
except ValidationError:
return {'error': f'Invalid email for user {uid}'}

if confirmation_link:
return {'confirmation_link': confirmation_link}
else:
return {'error': 'Could not generate or refresh confirmation link'}
Loading