An ebook/comic library service and web client
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

176 lines
4.8 KiB

  1. """Service to handle user operations."""
  2. import logging
  3. import random
  4. import string
  5. from datetime import datetime
  6. from typing import Optional, Dict, Callable, Any
  7. from atheneum import errors
  8. from atheneum.db import db
  9. from atheneum.model import User
  10. from atheneum.service.role_service import Role
  11. from atheneum.service.transformation_service import (
  12. BaseTransformer,
  13. register_transformer
  14. )
  15. from atheneum.utility import authentication_utility
  16. LOGGER = logging.getLogger(__name__)
  17. @register_transformer
  18. class UserTransformer(BaseTransformer):
  19. """Serialize User model."""
  20. type = User
  21. def _deserializers(
  22. self) -> Dict[str, Callable[[User, Any], None]]:
  23. """Define the fields and the accompanying deserializer factory."""
  24. return {
  25. 'name': self.deserialize_name,
  26. 'creationTime': self.deserialize_creation_time,
  27. 'lastLoginTime': self.deserialize_last_login_time,
  28. 'version': self.deserialize_version,
  29. 'role': self.deserialize_role,
  30. }
  31. def _serializers(self) -> Dict[str, Callable[[], Any]]:
  32. """Define the fields and the accompanying serializer factory."""
  33. return {
  34. 'name': self.serialize_name,
  35. 'creationTime': self.serialize_creation_time,
  36. 'lastLoginTime': self.serialize_last_login_time,
  37. 'version': self.serialize_version,
  38. 'role': self.serialize_role,
  39. }
  40. def serialize_name(self) -> str:
  41. """User name."""
  42. return self.model.name
  43. @staticmethod
  44. def deserialize_name(model: User, name: str) -> None:
  45. """User name."""
  46. model.name = name
  47. def serialize_creation_time(self) -> datetime:
  48. """User creation time."""
  49. return self.model.creation_time
  50. @staticmethod
  51. def deserialize_creation_time(
  52. model: User, creation_time: datetime) -> None:
  53. """User creation time."""
  54. model.creation_time = creation_time
  55. def serialize_last_login_time(self) -> datetime:
  56. """User last login time."""
  57. return self.model.last_login_time
  58. @staticmethod
  59. def deserialize_last_login_time(
  60. model: User, last_login_time: datetime) -> None:
  61. """User last login time."""
  62. model.last_login_time = last_login_time
  63. def serialize_version(self) -> int:
  64. """User version."""
  65. return self.model.version
  66. @staticmethod
  67. def deserialize_version(model: User, version: int) -> None:
  68. """User version."""
  69. model.version = version
  70. def serialize_role(self) -> str:
  71. """User role."""
  72. return self.model.role.value
  73. @staticmethod
  74. def deserialize_role(model: User, role_value: str) -> None:
  75. """User role."""
  76. model.role = Role(role_value)
  77. def find_by_name(name: str) -> Optional[User]:
  78. """
  79. Find a user by name.
  80. :param name:
  81. :return:
  82. """
  83. return User.query.filter_by(name=name).first()
  84. def register(name: str, password: Optional[str], role: Optional[str]) -> User:
  85. """
  86. Register a new user.
  87. :param name: Desired user name. Must be unique and not already registered
  88. :param password: Password to be hashed and stored for the user
  89. :param role: Role to assign the user [ROLE_USER, ROLE_ADMIN]
  90. :return:
  91. """
  92. password = password if password is not None else ''.join(
  93. random.choices(string.ascii_letters + string.digits, k=32))
  94. role = role if role is not None else User.ROLE_USER
  95. if find_by_name(name=name) is not None:
  96. raise errors.ValidationError('User name is already taken.')
  97. pw_hash, pw_revision = authentication_utility.get_password_hash(password)
  98. new_user = User(
  99. name=name,
  100. role=role,
  101. password_hash=pw_hash,
  102. password_revision=pw_revision,
  103. creation_time=datetime.now(),
  104. version=0)
  105. db.session.add(new_user)
  106. db.session.commit()
  107. LOGGER.info('Registered new user: %s with role: %s', name, role)
  108. return new_user
  109. def delete(user: User) -> bool:
  110. """
  111. Delete a user.
  112. :param user:
  113. :return:
  114. """
  115. existing_user = db.session.delete(user)
  116. if existing_user is None:
  117. db.session.commit()
  118. return True
  119. return False
  120. def update_last_login_time(user: User) -> None:
  121. """
  122. Bump the last login time for the user.
  123. :param user:
  124. :return:
  125. """
  126. if user is not None:
  127. user.last_login_time = datetime.now()
  128. db.session.commit()
  129. def update_password(user: User, password: str) -> None:
  130. """
  131. Change the user password.
  132. :param user:
  133. :param password:
  134. :return:
  135. """
  136. pw_hash, pw_revision = authentication_utility.get_password_hash(
  137. password)
  138. user.password_hash = pw_hash
  139. user.password_revision = pw_revision
  140. db.session.commit()