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.users.exceptions import (
InvalidEmailException,
UserCreationException,
UserNotFoundException,
)
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
class TestUserManagerService:
class TestUserManagerServiceUserUpdate:
def test_it_raises_exception_if_user_does_not_exist(
self, app: Flask
) -> None:
@ -190,6 +191,155 @@ class TestUserManagerService:
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:
@pytest.mark.parametrize(
('input_email',),

View File

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

View File

@ -1,11 +1,18 @@
import secrets
from typing import Optional, Tuple
from sqlalchemy import func
from fittrackee import db
from ..exceptions import InvalidEmailException, UserNotFoundException
from ..exceptions import (
InvalidEmailException,
UserControlsException,
UserCreationException,
UserNotFoundException,
)
from ..models import User
from ..utils.controls import is_valid_email
from ..utils.controls import is_valid_email, register_controls
class UserManagerService:
@ -80,3 +87,62 @@ class UserManagerService:
db.session.commit()
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