Browse Source

Restructuring some

Alec Nikolas Reiter 7 years ago
parent
commit
059f851226

+ 3 - 4
flaskbb/auth/plugins.py

@@ -3,9 +3,9 @@ from flask_babelplus import gettext as _
 from flask_login import login_user
 from flask_login import login_user
 
 
 from . import impl
 from . import impl
-from ..email import send_activation_token
 from ..user.models import User
 from ..user.models import User
 from ..utils.settings import flaskbb_config
 from ..utils.settings import flaskbb_config
+from .services.factories import account_activator_factory
 
 
 
 
 @impl
 @impl
@@ -13,9 +13,8 @@ def flaskbb_event_user_registered(username):
     user = User.query.filter_by(username=username).first()
     user = User.query.filter_by(username=username).first()
 
 
     if flaskbb_config["ACTIVATE_ACCOUNT"]:
     if flaskbb_config["ACTIVATE_ACCOUNT"]:
-        send_activation_token.delay(
-            user_id=user.id, username=user.username, email=user.email
-        )
+        service = account_activator_factory()
+        service.initiate_account_activation(user.email)
         flash(
         flash(
             _(
             _(
                 "An account activation email has been sent to "
                 "An account activation email has been sent to "

+ 19 - 0
flaskbb/auth/services/__init__.py

@@ -0,0 +1,19 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.auth.services
+    ~~~~~~~~~~~~~~~~~~~~~
+    Public module of implemenations of auth related services
+    in FlaskBB. If you are developing a plugin or extending
+    FlaskBB, you should import from this module rather than
+    submodules.
+
+    :copyright: (c) 2014-2018 the FlaskBB Team.
+    :license: BSD, see LICENSE for more details
+"""
+
+from .activation import AccountActivator
+from .factories import (account_activator_factory,
+                        registration_service_factory, reset_service_factory)
+from .password import ResetPasswordService
+from .registration import (EmailUniquenessValidator, UsernameRequirements,
+                           UsernameUniquenessValidator, UsernameValidator)

+ 62 - 0
flaskbb/auth/services/factories.py

@@ -0,0 +1,62 @@
+# -*- coding: utf-8 -*-
+"""
+    flaskbb.auth.services.factories
+    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    Factory functions for various FlaskBB auth services
+
+    :copyright: 2014-2018 the FlaskBB Team.
+    :license: BSD, see LICENSE for more details
+"""
+from datetime import timedelta
+
+from flask import current_app
+
+from ...extensions import db
+from ...tokens import FlaskBBTokenSerializer
+from ...tokens.verifiers import EmailMatchesUserToken
+from ...user.models import User
+from ...user.repo import UserRepository
+from ...utils.settings import flaskbb_config
+from .activation import AccountActivator
+from .password import ResetPasswordService
+from .registration import (EmailUniquenessValidator, RegistrationService,
+                           UsernameRequirements, UsernameUniquenessValidator,
+                           UsernameValidator)
+
+
+def registration_service_factory():
+    blacklist = [
+        w.strip()
+        for w in flaskbb_config["AUTH_USERNAME_BLACKLIST"].split(",")
+    ]
+
+    requirements = UsernameRequirements(
+        min=flaskbb_config["AUTH_USERNAME_MIN_LENGTH"],
+        max=flaskbb_config["AUTH_USERNAME_MAX_LENGTH"],
+        blacklist=blacklist
+    )
+
+    validators = [
+        EmailUniquenessValidator(User),
+        UsernameUniquenessValidator(User),
+        UsernameValidator(requirements)
+    ]
+
+    return RegistrationService(validators, UserRepository(db))
+
+
+def reset_service_factory():
+    token_serializer = FlaskBBTokenSerializer(
+        current_app.config['SECRET_KEY'], expiry=timedelta(hours=1)
+    )
+    verifiers = [EmailMatchesUserToken(User)]
+    return ResetPasswordService(
+        token_serializer, User, token_verifiers=verifiers
+    )
+
+
+def account_activator_factory():
+    token_serializer = FlaskBBTokenSerializer(
+        current_app.config['SECRET_KEY'], expiry=timedelta(hours=1)
+    )
+    return AccountActivator(token_serializer, User)

+ 23 - 2
flaskbb/auth/services/registration.py

@@ -13,8 +13,8 @@ from collections import namedtuple
 
 
 from sqlalchemy import func
 from sqlalchemy import func
 
 
-from ...core.auth.registration import UserValidator
-from ...core.exceptions import ValidationError
+from ...core.auth.registration import UserValidator, UserRegistrationService
+from ...core.exceptions import ValidationError, StopValidation
 
 
 __all__ = (
 __all__ = (
     "UsernameRequirements", "UsernameValidator", "EmailUniquenessValidator",
     "UsernameRequirements", "UsernameValidator", "EmailUniquenessValidator",
@@ -78,3 +78,24 @@ class EmailUniquenessValidator(UserValidator):
             raise ValidationError(
             raise ValidationError(
                 'email', '{} is already registered'.format(user_info.email)
                 'email', '{} is already registered'.format(user_info.email)
             )
             )
+
+
+class RegistrationService(UserRegistrationService):
+
+    def __init__(self, validators, user_repo):
+        self.validators = validators
+        self.user_repo = user_repo
+
+    def register(self, user_info):
+        failures = []
+
+        for v in self.validators:
+            try:
+                v(user_info)
+            except ValidationError as e:
+                failures.append((e.attribute, e.reason))
+
+        if failures:
+            raise StopValidation(failures)
+
+        self.user_repo.add(user_info)

+ 4 - 44
flaskbb/auth/views.py

@@ -10,7 +10,7 @@
     :license: BSD, see LICENSE for more details.
     :license: BSD, see LICENSE for more details.
 """
 """
 import logging
 import logging
-from datetime import datetime, timedelta
+from datetime import datetime
 
 
 from flask import Blueprint, current_app, flash, g, redirect, request, url_for
 from flask import Blueprint, current_app, flash, g, redirect, request, url_for
 from flask.views import MethodView
 from flask.views import MethodView
@@ -31,16 +31,12 @@ from flaskbb.utils.helpers import (anonymous_required, enforce_recaptcha,
                                    requires_unactivated)
                                    requires_unactivated)
 from flaskbb.utils.settings import flaskbb_config
 from flaskbb.utils.settings import flaskbb_config
 
 
-from ..core.auth.registration import RegistrationService, UserRegistrationInfo
 from ..core.exceptions import StopValidation, ValidationError
 from ..core.exceptions import StopValidation, ValidationError
 from ..core.tokens import TokenError
 from ..core.tokens import TokenError
-from ..tokens import FlaskBBTokenSerializer
-from ..tokens.verifiers import EmailMatchesUserToken
-from ..user.repo import UserRepository
+from ..core.auth.registration import UserRegistrationInfo
 from .plugins import impl
 from .plugins import impl
-from .services import registration
-from .services.activation import AccountActivator
-from .services.password import ResetPasswordService
+from .services import (account_activator_factory, registration_service_factory,
+                       reset_service_factory)
 
 
 logger = logging.getLogger(__name__)
 logger = logging.getLogger(__name__)
 
 
@@ -342,42 +338,6 @@ def flaskbb_load_blueprints(app):
             "errors/too_many_logins.html", timeout=error.description
             "errors/too_many_logins.html", timeout=error.description
         )
         )
 
 
-    def registration_service_factory():
-        with app.app_context():
-            blacklist = [
-                w.strip()
-                for w in flaskbb_config["AUTH_USERNAME_BLACKLIST"].split(",")
-            ]
-
-            requirements = registration.UsernameRequirements(
-                min=flaskbb_config["AUTH_USERNAME_MIN_LENGTH"],
-                max=flaskbb_config["AUTH_USERNAME_MAX_LENGTH"],
-                blacklist=blacklist
-            )
-
-        validators = [
-            registration.EmailUniquenessValidator(User),
-            registration.UsernameUniquenessValidator(User),
-            registration.UsernameValidator(requirements)
-        ]
-
-        return RegistrationService(validators, UserRepository(db))
-
-    def reset_service_factory():
-        token_serializer = FlaskBBTokenSerializer(
-            app.config['SECRET_KEY'], expiry=timedelta(hours=1)
-        )
-        verifiers = [EmailMatchesUserToken(User)]
-        return ResetPasswordService(
-            token_serializer, User, token_verifiers=verifiers
-        )
-
-    def account_activator_factory():
-        token_serializer = FlaskBBTokenSerializer(
-            app.config['SECRET_KEY'], expiry=timedelta(hours=1)
-        )
-        return AccountActivator(token_serializer, User)
-
     # Activate rate limiting on the whole blueprint
     # Activate rate limiting on the whole blueprint
     limiter.limit(
     limiter.limit(
         login_rate_limit, error_message=login_rate_limit_message
         login_rate_limit, error_message=login_rate_limit_message

+ 3 - 17
flaskbb/core/auth/registration.py

@@ -41,21 +41,7 @@ class UserValidator(ABC):
         return self.validate(user_info)
         return self.validate(user_info)
 
 
 
 
-class RegistrationService(object):
-    def __init__(self, validators, user_repo):
-        self.validators = validators
-        self.user_repo = user_repo
-
+class UserRegistrationService(ABC):
+    @abstractmethod
     def register(self, user_info):
     def register(self, user_info):
-        failures = []
-
-        for v in self.validators:
-            try:
-                v(user_info)
-            except ValidationError as e:
-                failures.append((e.attribute, e.reason))
-
-        if failures:
-            raise StopValidation(failures)
-
-        self.user_repo.add(user_info)
+        pass

+ 1 - 2
flaskbb/email.py

@@ -45,14 +45,13 @@ def send_reset_token(token, username, email):
 
 
 
 
 @celery.task
 @celery.task
-def send_activation_token(user_id, username, email):
+def send_activation_token(token, username, email):
     """Sends the activation token to the user's email address.
     """Sends the activation token to the user's email address.
 
 
     :param user_id: The user id. Used to generate the reset token.
     :param user_id: The user id. Used to generate the reset token.
     :param username: The username to whom the email should be sent.
     :param username: The username to whom the email should be sent.
     :param email:  The email address of the user
     :param email:  The email address of the user
     """
     """
-    token = make_token(user_id=user_id, operation="activate_account")
     send_email(
     send_email(
         subject=_("Account Activation"),
         subject=_("Account Activation"),
         recipients=[email],
         recipients=[email],

+ 8 - 10
tests/core/auth/test_registration.py → tests/unit/auth/test_registration.py

@@ -1,5 +1,7 @@
 import pytest
 import pytest
-from flaskbb.core.auth import registration
+
+from flaskbb.auth.services import registration
+from flaskbb.core.auth.registration import UserRegistrationInfo
 from flaskbb.core.exceptions import StopValidation, ValidationError
 from flaskbb.core.exceptions import StopValidation, ValidationError
 from flaskbb.core.user.repo import UserRepository
 from flaskbb.core.user.repo import UserRepository
 
 
@@ -7,20 +9,16 @@ from flaskbb.core.user.repo import UserRepository
 class RaisingValidator(registration.UserValidator):
 class RaisingValidator(registration.UserValidator):
 
 
     def validate(self, user_info):
     def validate(self, user_info):
-        raise ValidationError(
-            'test', 'just a little whoopsie-diddle'
-        )
+        raise ValidationError('test', 'just a little whoopsie-diddle')
 
 
 
 
-def test_doesnt_register_user_if_validator_fails_with_ValidationError(
-        mocker
-):
+def test_doesnt_register_user_if_validator_fails_with_ValidationError(mocker):
     repo = mocker.Mock(UserRepository)
     repo = mocker.Mock(UserRepository)
     service = registration.RegistrationService([RaisingValidator()], repo)
     service = registration.RegistrationService([RaisingValidator()], repo)
 
 
     with pytest.raises(StopValidation):
     with pytest.raises(StopValidation):
         service.register(
         service.register(
-            registration.UserRegistrationInfo(
+            UserRegistrationInfo(
                 username='fred',
                 username='fred',
                 password='lol',
                 password='lol',
                 email='fred@fred.fred',
                 email='fred@fred.fred',
@@ -40,7 +38,7 @@ def test_gathers_up_all_errors_during_registration(mocker):
 
 
     with pytest.raises(StopValidation) as excinfo:
     with pytest.raises(StopValidation) as excinfo:
         service.register(
         service.register(
-            registration.UserRegistrationInfo(
+            UserRegistrationInfo(
                 username='fred',
                 username='fred',
                 password='lol',
                 password='lol',
                 email='fred@fred.fred',
                 email='fred@fred.fred',
@@ -58,7 +56,7 @@ def test_gathers_up_all_errors_during_registration(mocker):
 def test_registers_user_if_no_errors_occurs(mocker):
 def test_registers_user_if_no_errors_occurs(mocker):
     repo = mocker.Mock(UserRepository)
     repo = mocker.Mock(UserRepository)
     service = registration.RegistrationService([], repo)
     service = registration.RegistrationService([], repo)
-    user_info = registration.UserRegistrationInfo(
+    user_info = UserRegistrationInfo(
         username='fred',
         username='fred',
         password='lol',
         password='lol',
         email='fred@fred.fred',
         email='fred@fred.fred',