From 42c99034be468f6968274700cd6c5abbd7da40ff Mon Sep 17 00:00:00 2001 From: Daniel Schadt Date: Tue, 30 May 2023 19:45:09 +0200 Subject: de-duplicate verification token code --- fietsboek/actions.py | 43 ++++++++++++++++++++++++++++++++++++++++++- fietsboek/views/account.py | 23 ++--------------------- fietsboek/views/default.py | 27 +++++---------------------- 3 files changed, 49 insertions(+), 44 deletions(-) diff --git a/fietsboek/actions.py b/fietsboek/actions.py index b9221c3..395843f 100644 --- a/fietsboek/actions.py +++ b/fietsboek/actions.py @@ -12,15 +12,17 @@ from typing import List, Optional import brotli import gpxpy +from pyramid.i18n import TranslationString as _ from pyramid.request import Request from sqlalchemy import select from sqlalchemy.orm.session import Session -from . import models +from . import email, models from . import transformers as mod_transformers from . import util from .data import DataManager, TrackDataDir from .models.track import TrackType, Visibility +from .models.user import TokenType LOGGER = logging.getLogger(__name__) @@ -219,3 +221,42 @@ def execute_transformers(request: Request, track: models.Track) -> Optional[gpxp track.ensure_cache(gpx) request.dbsession.add(track.cache) return gpx + + +def send_verification_token(request: Request, user: models.User): + """Creates a verification token and sends it to the user. + + If no verification token exists yet, a fresh one is created. + + If a token already exists, a fresh one is still created. The old token + stays valid until its expiry date. + + Note that this function does not provide the user with feedback other than + the email. You may want to show a flash message or similar to show that + something has happened. + + :param request: The request. + :param user: The user who to generate a verification token for. + """ + # Some of this code appears in the password reset form as well, but that's + # fine for now. + # pylint: disable=duplicate-code + token = models.Token.generate(user, TokenType.VERIFY_EMAIL) + request.dbsession.add(token) + + message = email.prepare_message( + request.config.email_from, + user.email, + request.localizer.translate(_("email.verify_mail.subject")), + ) + message.set_content( + request.localizer.translate(_("email.verify.text")).format( + request.route_url("use-token", uuid=token.uuid) + ) + ) + email.send_message( + request.config.email_smtp_url, + request.config.email_username, + request.config.email_password.get_secret_value(), + message, + ) diff --git a/fietsboek/views/account.py b/fietsboek/views/account.py index 39a62e5..5400f0a 100644 --- a/fietsboek/views/account.py +++ b/fietsboek/views/account.py @@ -3,8 +3,7 @@ from pyramid.httpexceptions import HTTPForbidden, HTTPFound from pyramid.i18n import TranslationString as _ from pyramid.view import view_config -from .. import email, models, util -from ..models.user import TokenType +from .. import actions, models, util @view_config( @@ -63,25 +62,7 @@ def do_create_account(request): user.set_password(password) request.dbsession.add(user) - token = models.Token.generate(user, TokenType.VERIFY_EMAIL) - request.dbsession.add(token) - - message = email.prepare_message( - request.config.email_from, - user.email, - request.localizer.translate(_("email.verify_mail.subject")), - ) - message.set_content( - request.localizer.translate(_("email.verify.text")).format( - request.route_url("use-token", uuid=token.uuid) - ) - ) - email.send_message( - request.config.email_smtp_url, - request.config.email_username, - request.config.email_password.get_secret_value(), - message, - ) + actions.send_verification_token(request, user) request.session.flash(request.localizer.translate(_("flash.a_confirmation_link_has_been_sent"))) return HTTPFound(request.route_url("login")) diff --git a/fietsboek/views/default.py b/fietsboek/views/default.py index b3cad40..f9942c3 100644 --- a/fietsboek/views/default.py +++ b/fietsboek/views/default.py @@ -12,7 +12,7 @@ from sqlalchemy import select from sqlalchemy.exc import NoResultFound from sqlalchemy.orm import aliased -from .. import email, models, summaries, util +from .. import actions, email, models, summaries, util from ..models.track import TrackType, TrackWithMetadata from ..models.user import TOKEN_LIFETIME, PasswordMismatch, TokenType @@ -201,7 +201,7 @@ def do_password_reset(request: Request) -> Response: request_method="GET", renderer="fietsboek:templates/resend_verification.jinja2", ) -def resend_verification(request: Request) -> Response: +def resend_verification(_request: Request) -> Response: """Form to request a new verification mail. :param request: The Pyramid request. @@ -221,30 +221,13 @@ def do_resend_verification(request: Request) -> Response: user = request.dbsession.execute(query).scalar_one_or_none() if user is None or user.is_verified: request.session.flash( - request.localizer.translate(_("flash.resend_verification_email_fail"))) + request.localizer.translate(_("flash.resend_verification_email_fail")) + ) return HTTPFound(request.route_url("resend-verification")) - token = models.Token.generate(user, TokenType.VERIFY_EMAIL) - request.dbsession.add(token) + actions.send_verification_token(request, user) request.session.flash(request.localizer.translate(_("flash.verification_token_generated"))) - mail = email.prepare_message( - request.config.email_from, - user.email, - request.localizer.translate(_("email.verify_mail.subject")), - ) - mail.set_content( - request.localizer.translate(_("email.verify.text")).format( - request.route_url("use-token", uuid=token.uuid) - ) - ) - email.send_message( - request.config.email_smtp_url, - request.config.email_username, - request.config.email_password.get_secret_value(), - mail, - ) - return HTTPFound(request.route_url("login")) -- cgit v1.2.3