user.py 7.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. # -*- coding: utf-8 -*-
  2. import threading
  3. from smtplib import SMTPException
  4. import transaction
  5. import typing as typing
  6. from tracim.exceptions import NotificationNotSend
  7. from tracim.lib.mail_notifier.notifier import get_email_manager
  8. from sqlalchemy.orm import Session
  9. from tracim import CFG
  10. from tracim.models.auth import User
  11. from tracim.models.auth import Group
  12. from sqlalchemy.orm.exc import NoResultFound
  13. from tracim.exceptions import WrongUserPassword, UserDoesNotExist
  14. from tracim.exceptions import AuthenticationFailed
  15. from tracim.models.context_models import UserInContext
  16. class UserApi(object):
  17. def __init__(
  18. self,
  19. current_user: typing.Optional[User],
  20. session: Session,
  21. config: CFG,
  22. ) -> None:
  23. self._session = session
  24. self._user = current_user
  25. self._config = config
  26. def _base_query(self):
  27. return self._session.query(User)
  28. def get_user_with_context(self, user: User) -> UserInContext:
  29. """
  30. Return UserInContext object from User
  31. """
  32. user = UserInContext(
  33. user=user,
  34. dbsession=self._session,
  35. config=self._config,
  36. )
  37. return user
  38. # Getters
  39. def get_one(self, user_id: int) -> User:
  40. """
  41. Get one user by user id
  42. """
  43. try:
  44. user = self._base_query().filter(User.user_id == user_id).one()
  45. except NoResultFound as exc:
  46. raise UserDoesNotExist('User "{}" not found in database'.format(user_id)) from exc # nopep8
  47. return user
  48. def get_one_by_email(self, email: str) -> User:
  49. """
  50. Get one user by email
  51. :param email: Email of the user
  52. :return: one user
  53. """
  54. try:
  55. user = self._base_query().filter(User.email == email).one()
  56. except NoResultFound as exc:
  57. raise UserDoesNotExist('User "{}" not found in database'.format(email)) from exc # nopep8
  58. return user
  59. # FIXME - G.M - 24-04-2018 - Duplicate method with get_one.
  60. def get_one_by_id(self, id: int) -> User:
  61. return self.get_one(user_id=id)
  62. def get_current_user(self) -> User:
  63. """
  64. Get current_user
  65. """
  66. if not self._user:
  67. raise UserDoesNotExist('There is no current user')
  68. return self._user
  69. def get_all(self) -> typing.Iterable[User]:
  70. return self._session.query(User).order_by(User.display_name).all()
  71. # Check methods
  72. def user_with_email_exists(self, email: str) -> bool:
  73. try:
  74. self.get_one_by_email(email)
  75. return True
  76. # TODO - G.M - 09-04-2018 - Better exception
  77. except:
  78. return False
  79. def authenticate_user(self, email: str, password: str) -> User:
  80. """
  81. Authenticate user with email and password, raise AuthenticationFailed
  82. if uncorrect.
  83. :param email: email of the user
  84. :param password: cleartext password of the user
  85. :return: User who was authenticated.
  86. """
  87. try:
  88. user = self.get_one_by_email(email)
  89. if user.validate_password(password):
  90. return user
  91. else:
  92. raise WrongUserPassword('User "{}" password is incorrect'.format(email)) # nopep8
  93. except (WrongUserPassword, UserDoesNotExist) as exc:
  94. raise AuthenticationFailed('User "{}" authentication failed'.format(email)) from exc # nopep8
  95. # Actions
  96. def update(
  97. self,
  98. user: User,
  99. name: str=None,
  100. email: str=None,
  101. password: str=None,
  102. timezone: str=None,
  103. groups: typing.Optional[typing.List[Group]]=None,
  104. do_save=True,
  105. ) -> User:
  106. if name is not None:
  107. user.display_name = name
  108. if email is not None:
  109. user.email = email
  110. if password is not None:
  111. user.password = password
  112. if timezone is not None:
  113. user.timezone = timezone
  114. if groups is not None:
  115. # INFO - G.M - 2018-07-18 - Delete old groups
  116. for group in user.groups:
  117. if group not in groups:
  118. user.groups.remove(group)
  119. # INFO - G.M - 2018-07-18 - add new groups
  120. for group in groups:
  121. if group not in user.groups:
  122. user.groups.append(group)
  123. if do_save:
  124. self.save(user)
  125. return user
  126. def create_user(
  127. self,
  128. email,
  129. password: str = None,
  130. name: str = None,
  131. timezone: str = '',
  132. groups=[],
  133. do_save: bool=True,
  134. do_notify: bool=True,
  135. ) -> User:
  136. new_user = self.create_minimal_user(email, groups, save_now=False)
  137. self.update(
  138. user=new_user,
  139. name=name,
  140. email=email,
  141. password=password,
  142. timezone=timezone,
  143. do_save=False,
  144. )
  145. if do_notify:
  146. try:
  147. email_manager = get_email_manager(self._config, self._session)
  148. email_manager.notify_created_account(
  149. new_user,
  150. password=password
  151. )
  152. except SMTPException as e:
  153. raise NotificationNotSend()
  154. if do_save:
  155. self.save(new_user)
  156. return new_user
  157. def create_minimal_user(
  158. self,
  159. email,
  160. groups=[],
  161. save_now=False
  162. ) -> User:
  163. """Previous create_user method"""
  164. user = User()
  165. user.email = email
  166. for group in groups:
  167. user.groups.append(group)
  168. self._session.add(user)
  169. if save_now:
  170. self._session.flush()
  171. return user
  172. def enable(self, user: User, do_save=False):
  173. user.is_active = True
  174. if do_save:
  175. self.save(user)
  176. def disable(self, user:User, do_save=False):
  177. user.is_active = False
  178. if do_save:
  179. self.save(user)
  180. def save(self, user: User):
  181. self._session.flush()
  182. def execute_created_user_actions(self, created_user: User) -> None:
  183. """
  184. Execute actions when user just been created
  185. :return:
  186. """
  187. # NOTE: Cyclic import
  188. # TODO - G.M - 28-03-2018 - [Calendar] Reenable Calendar stuff
  189. #from tracim.lib.calendar import CalendarManager
  190. #from tracim.model.organisational import UserCalendar
  191. # TODO - G.M - 04-04-2018 - [auth]
  192. # Check if this is already needed with
  193. # new auth system
  194. created_user.ensure_auth_token(
  195. session=self._session,
  196. validity_seconds=self._config.USER_AUTH_TOKEN_VALIDITY
  197. )
  198. # Ensure database is up-to-date
  199. self._session.flush()
  200. transaction.commit()
  201. # TODO - G.M - 28-03-2018 - [Calendar] Reenable Calendar stuff
  202. # calendar_manager = CalendarManager(created_user)
  203. # calendar_manager.create_then_remove_fake_event(
  204. # calendar_class=UserCalendar,
  205. # related_object_id=created_user.user_id,
  206. # )