diff options
Diffstat (limited to 'mediagoblin/edit')
-rw-r--r-- | mediagoblin/edit/forms.py | 13 | ||||
-rw-r--r-- | mediagoblin/edit/routing.py | 2 | ||||
-rw-r--r-- | mediagoblin/edit/views.py | 123 |
3 files changed, 110 insertions, 28 deletions
diff --git a/mediagoblin/edit/forms.py b/mediagoblin/edit/forms.py index 3b2486de..e0147a0c 100644 --- a/mediagoblin/edit/forms.py +++ b/mediagoblin/edit/forms.py @@ -16,9 +16,11 @@ import wtforms -from mediagoblin.tools.text import tag_length_validator, TOO_LONG_TAG_WARNING +from mediagoblin.tools.text import tag_length_validator from mediagoblin.tools.translate import lazy_pass_to_ugettext as _ from mediagoblin.tools.licenses import licenses_as_choices +from mediagoblin.auth.forms import normalize_user_or_email_field + class EditForm(wtforms.Form): title = wtforms.TextField( @@ -59,6 +61,13 @@ class EditProfileForm(wtforms.Form): class EditAccountForm(wtforms.Form): + new_email = wtforms.TextField( + _('New email address'), + [wtforms.validators.Optional(), + normalize_user_or_email_field(allow_user=False)]) + wants_comment_notification = wtforms.BooleanField( + label='', + description=_("Email me when others comment on my media")) license_preference = wtforms.SelectField( _('License preference'), [ @@ -67,8 +76,6 @@ class EditAccountForm(wtforms.Form): ], choices=licenses_as_choices(), description=_('This will be your default license on upload forms.')) - wants_comment_notification = wtforms.BooleanField( - label=_("Email me when others comment on my media")) class EditAttachmentsForm(wtforms.Form): diff --git a/mediagoblin/edit/routing.py b/mediagoblin/edit/routing.py index 622729ac..3592f708 100644 --- a/mediagoblin/edit/routing.py +++ b/mediagoblin/edit/routing.py @@ -26,3 +26,5 @@ add_route('mediagoblin.edit.delete_account', '/edit/account/delete/', 'mediagoblin.edit.views:delete_account') add_route('mediagoblin.edit.pass', '/edit/password/', 'mediagoblin.edit.views:change_pass') +add_route('mediagoblin.edit.verify_email', '/edit/verify_email/', + 'mediagoblin.edit.views:verify_email') diff --git a/mediagoblin/edit/views.py b/mediagoblin/edit/views.py index 508c380d..25a02446 100644 --- a/mediagoblin/edit/views.py +++ b/mediagoblin/edit/views.py @@ -16,25 +16,31 @@ from datetime import datetime +from itsdangerous import BadSignature from werkzeug.exceptions import Forbidden from werkzeug.utils import secure_filename from mediagoblin import messages from mediagoblin import mg_globals -from mediagoblin.auth import lib as auth_lib +from mediagoblin import auth +from mediagoblin.auth import tools as auth_tools from mediagoblin.edit import forms from mediagoblin.edit.lib import may_edit_media from mediagoblin.decorators import (require_active_login, active_user_from_url, - get_media_entry_by_id, - user_may_alter_collection, get_user_collection) -from mediagoblin.tools.response import render_to_response, \ - redirect, redirect_obj + get_media_entry_by_id, user_may_alter_collection, + get_user_collection) +from mediagoblin.tools.crypto import get_timed_signer_url +from mediagoblin.tools.mail import email_debug_message +from mediagoblin.tools.response import (render_to_response, + redirect, redirect_obj, render_404) from mediagoblin.tools.translate import pass_to_ugettext as _ +from mediagoblin.tools.template import render_template from mediagoblin.tools.text import ( convert_to_tag_list_of_dicts, media_tags_as_string) from mediagoblin.tools.url import slugify from mediagoblin.db.util import check_media_slug_used, check_collection_slug_used +from mediagoblin.db.models import User import mimetypes @@ -212,6 +218,10 @@ def edit_profile(request, url_user=None): {'user': user, 'form': form}) +EMAIL_VERIFICATION_TEMPLATE = ( + u'{uri}?' + u'token={verification_key}') + @require_active_login def edit_account(request): @@ -220,27 +230,45 @@ def edit_account(request): wants_comment_notification=user.wants_comment_notification, license_preference=user.license_preference) - if request.method == 'POST': - form_validated = form.validate() - - if form_validated and \ - form.wants_comment_notification.validate(form): - user.wants_comment_notification = \ - form.wants_comment_notification.data - - if form_validated and \ - form.license_preference.validate(form): - user.license_preference = \ - form.license_preference.data - - if form_validated and not form.errors: + if request.method == 'POST' and form.validate(): + user.wants_comment_notification = form.wants_comment_notification.data + + user.license_preference = form.license_preference.data + + if form.new_email.data: + new_email = form.new_email.data + users_with_email = User.query.filter_by( + email=new_email).count() + if users_with_email: + form.new_email.errors.append( + _('Sorry, a user with that email address' + ' already exists.')) + else: + verification_key = get_timed_signer_url( + 'mail_verification_token').dumps({ + 'user': user.id, + 'email': new_email}) + + rendered_email = render_template( + request, 'mediagoblin/edit/verification.txt', + {'username': user.username, + 'verification_url': EMAIL_VERIFICATION_TEMPLATE.format( + uri=request.urlgen('mediagoblin.edit.verify_email', + qualified=True), + verification_key=verification_key)}) + + email_debug_message(request) + auth_tools.send_verification_email(user, request, new_email, + rendered_email) + + if not form.errors: user.save() messages.add_message(request, - messages.SUCCESS, - _("Account settings saved")) + messages.SUCCESS, + _("Account settings saved")) return redirect(request, - 'mediagoblin.user_pages.user_home', - user=user.username) + 'mediagoblin.user_pages.user_home', + user=user.username) return render_to_response( request, @@ -342,7 +370,7 @@ def change_pass(request): if request.method == 'POST' and form.validate(): - if not auth_lib.bcrypt_check_password( + if not auth.check_password( form.old_password.data, user.pw_hash): form.old_password.errors.append( _('Wrong password')) @@ -354,7 +382,7 @@ def change_pass(request): 'user': user}) # Password matches - user.pw_hash = auth_lib.bcrypt_gen_password_hash( + user.pw_hash = auth.gen_password_hash( form.new_password.data) user.save() @@ -369,3 +397,48 @@ def change_pass(request): 'mediagoblin/edit/change_pass.html', {'form': form, 'user': user}) + + +def verify_email(request): + """ + Email verification view for changing email address + """ + # If no token, we can't do anything + if not 'token' in request.GET: + return render_404(request) + + # Catch error if token is faked or expired + token = None + try: + token = get_timed_signer_url("mail_verification_token") \ + .loads(request.GET['token'], max_age=10*24*3600) + except BadSignature: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) + + return redirect( + request, + 'index') + + user = User.query.filter_by(id=int(token['user'])).first() + + if user: + user.email = token['email'] + user.save() + + messages.add_message( + request, + messages.SUCCESS, + _('Your email address has been verified.')) + + else: + messages.add_message( + request, + messages.ERROR, + _('The verification key or user id is incorrect.')) + + return redirect( + request, 'mediagoblin.user_pages.user_home', + user=user.username) |