CLI - init user creation command

This commit is contained in:
Sam 2023-03-12 11:09:04 +01:00
parent 141b345e45
commit 01ae44c68b
3 changed files with 227 additions and 3 deletions

View File

@ -13,6 +13,7 @@ from flask import Flask
from fittrackee import bcrypt, db from fittrackee import bcrypt, db
from fittrackee.users.exceptions import ( from fittrackee.users.exceptions import (
InvalidEmailException, InvalidEmailException,
UserCreationException,
UserNotFoundException, UserNotFoundException,
) )
from fittrackee.users.models import BlacklistedToken, User from fittrackee.users.models import BlacklistedToken, User
@ -32,7 +33,7 @@ from fittrackee.users.utils.token import (
from ..utils import random_email, random_int, random_string from ..utils import random_email, random_int, random_string
class TestUserManagerService: class TestUserManagerServiceUserUpdate:
def test_it_raises_exception_if_user_does_not_exist( def test_it_raises_exception_if_user_does_not_exist(
self, app: Flask self, app: Flask
) -> None: ) -> None:
@ -190,6 +191,155 @@ class TestUserManagerService:
assert user_1.confirmation_token is None assert user_1.confirmation_token is None
class TestUserManagerServiceUserCreation:
def test_it_raises_exception_if_provided_username_is_invalid(
self, app: Flask
) -> None:
user_manager_service = UserManagerService(username='.admin')
with pytest.raises(
UserCreationException,
match=(
'username: only alphanumeric characters and '
'the underscore character "_" allowed\n'
),
):
user_manager_service.create(email=random_email())
def test_it_raises_exception_if_a_user_exists_with_same_username(
self, app: Flask, user_1: User
) -> None:
user_manager_service = UserManagerService(username=user_1.username)
with pytest.raises(
UserCreationException,
match='sorry, that username is already taken',
):
user_manager_service.create(email=random_email())
def test_it_raises_exception_if_provided_email_is_invalid(
self, app: Flask
) -> None:
user_manager_service = UserManagerService(username=random_string())
with pytest.raises(
UserCreationException, match='valid email must be provided'
):
user_manager_service.create(email=random_string())
def test_it_raises_exception_if_a_user_exists_with_same_email(
self, app: Flask, user_1: User
) -> None:
user_manager_service = UserManagerService(username=random_string())
with pytest.raises(
UserCreationException,
match='This user already exists. No action done.',
):
user_manager_service.create(email=user_1.email)
def test_it_creates_user_with_provided_password(self, app: Flask) -> None:
username = random_string()
email = random_email()
password = random_string()
user_manager_service = UserManagerService(username=username)
new_user, user_password = user_manager_service.create(email, password)
assert new_user
assert new_user.username == username
assert new_user.email == email
assert bcrypt.check_password_hash(new_user.password, password)
assert user_password == password
def test_it_creates_user_when_password_is_not_provided(
self, app: Flask
) -> None:
username = random_string()
email = random_email()
user_manager_service = UserManagerService(username=username)
new_user, user_password = user_manager_service.create(email)
assert new_user
assert new_user.username == username
assert new_user.email == email
assert bcrypt.check_password_hash(new_user.password, user_password)
def test_it_creates_when_registration_is_not_enabled(
self,
app_with_3_users_max: Flask,
user_1: User,
user_2: User,
user_3: User,
) -> None:
username = random_string()
email = random_email()
user_manager_service = UserManagerService(username=username)
new_user, user_password = user_manager_service.create(email)
assert new_user
assert new_user.username == username
assert new_user.email == email
assert bcrypt.check_password_hash(new_user.password, user_password)
def test_created_user_is_inactive(self, app: Flask) -> None:
username = random_string()
user_manager_service = UserManagerService(username=username)
new_user, _ = user_manager_service.create(email=random_email())
assert new_user
assert new_user.is_active is False
assert new_user.confirmation_token is not None
def test_created_user_has_no_admin_rights(self, app: Flask) -> None:
username = random_string()
user_manager_service = UserManagerService(username=username)
new_user, _ = user_manager_service.create(email=random_email())
assert new_user
assert new_user.admin is False
def test_created_user_does_not_accept_privacy_policy(
self, app: Flask
) -> None:
username = random_string()
user_manager_service = UserManagerService(username=username)
new_user, _ = user_manager_service.create(email=random_email())
assert new_user
assert new_user.accepted_policy_date is None
def test_created_user_timezone_is_europe_paris(self, app: Flask) -> None:
username = random_string()
user_manager_service = UserManagerService(username=username)
new_user, _ = user_manager_service.create(email=random_email())
assert new_user
assert new_user.timezone == 'Europe/Paris'
def test_created_user_date_format_is_MM_dd_yyyy( # noqa
self, app: Flask
) -> None:
username = random_string()
user_manager_service = UserManagerService(username=username)
new_user, _ = user_manager_service.create(email=random_email())
assert new_user
assert new_user.date_format == 'MM/dd/yyyy'
def test_created_user_language_is_en(self, app: Flask) -> None:
username = random_string()
user_manager_service = UserManagerService(username=username)
new_user, _ = user_manager_service.create(email=random_email())
assert new_user
assert new_user.language == 'en'
class TestIsValidEmail: class TestIsValidEmail:
@pytest.mark.parametrize( @pytest.mark.parametrize(
('input_email',), ('input_email',),

View File

@ -2,5 +2,13 @@ class InvalidEmailException(Exception):
... ...
class UserControlsException(Exception):
...
class UserCreationException(Exception):
...
class UserNotFoundException(Exception): class UserNotFoundException(Exception):
... ...

View File

@ -1,11 +1,18 @@
import secrets import secrets
from typing import Optional, Tuple from typing import Optional, Tuple
from sqlalchemy import func
from fittrackee import db from fittrackee import db
from ..exceptions import InvalidEmailException, UserNotFoundException from ..exceptions import (
InvalidEmailException,
UserControlsException,
UserCreationException,
UserNotFoundException,
)
from ..models import User from ..models import User
from ..utils.controls import is_valid_email from ..utils.controls import is_valid_email, register_controls
class UserManagerService: class UserManagerService:
@ -80,3 +87,62 @@ class UserManagerService:
db.session.commit() db.session.commit()
return user, user_updated, new_password return user, user_updated, new_password
def create_user(
self,
email: str,
password: Optional[str] = None,
check_email: bool = False,
) -> Tuple[Optional[User], Optional[str]]:
if not password:
password = secrets.token_urlsafe(30)
ret = register_controls(self.username, email, password)
if ret != '':
raise UserControlsException(ret)
user = User.query.filter(
func.lower(User.username) == func.lower(self.username)
).first()
if user:
raise UserCreationException(
'sorry, that username is already taken'
)
# if a user exists with same email address, no error is returned
# since a user has to confirm his email to activate his account
user = User.query.filter(
func.lower(User.email) == func.lower(email)
).first()
if user:
if check_email:
raise UserCreationException(
'This user already exists. No action done.'
)
return None, None
new_user = User(username=self.username, email=email, password=password)
new_user.timezone = 'Europe/Paris'
new_user.date_format = 'MM/dd/yyyy'
new_user.confirmation_token = secrets.token_urlsafe(30)
db.session.add(new_user)
db.session.flush()
return new_user, password
def create(
self,
email: str,
password: Optional[str] = None,
) -> Tuple[Optional[User], Optional[str]]:
try:
new_user, password = self.create_user(
email, password, check_email=True
)
if new_user:
new_user.language = 'en'
db.session.commit()
except UserControlsException as e:
raise UserCreationException(str(e))
return new_user, password