user.py 8.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. # -*- coding: utf-8 -*-
  2. import argparse
  3. from pyramid.scripting import AppEnvironment
  4. import transaction
  5. from sqlalchemy.exc import IntegrityError
  6. from sqlalchemy.orm.exc import NoResultFound
  7. from tracim_backend import CFG
  8. from tracim_backend.command import AppContextCommand
  9. from tracim_backend.command import Extender
  10. from tracim_backend.exceptions import UserAlreadyExistError
  11. from tracim_backend.exceptions import GroupDoesNotExist
  12. from tracim_backend.exceptions import NotificationNotSend
  13. from tracim_backend.exceptions import BadCommandError
  14. from tracim_backend.lib.core.group import GroupApi
  15. from tracim_backend.lib.core.user import UserApi
  16. from tracim_backend.models import User
  17. from tracim_backend.models import Group
  18. class UserCommand(AppContextCommand):
  19. ACTION_CREATE = 'create'
  20. ACTION_UPDATE = 'update'
  21. action = NotImplemented
  22. def get_description(self) -> str:
  23. return '''Create or update user.'''
  24. def get_parser(self, prog_name: str) -> argparse.ArgumentParser:
  25. parser = super().get_parser(prog_name)
  26. parser.add_argument(
  27. "-l",
  28. "--login",
  29. help='User login (email)',
  30. dest='login',
  31. required=True
  32. )
  33. parser.add_argument(
  34. "-p",
  35. "--password",
  36. help='User password',
  37. dest='password',
  38. required=False,
  39. default=None
  40. )
  41. parser.add_argument(
  42. "-g",
  43. "--add-to-group",
  44. help='Add user to group',
  45. dest='add_to_group',
  46. nargs='*',
  47. action=Extender,
  48. default=[],
  49. )
  50. parser.add_argument(
  51. "-rmg",
  52. "--remove-from-group",
  53. help='Remove user from group',
  54. dest='remove_from_group',
  55. nargs='*',
  56. action=Extender,
  57. default=[],
  58. )
  59. parser.add_argument(
  60. "--send-email",
  61. help='Send mail to user',
  62. dest='send_email',
  63. required=False,
  64. action='store_true',
  65. default=False,
  66. )
  67. return parser
  68. def _user_exist(self, login: str) -> User:
  69. return self._user_api.user_with_email_exists(login)
  70. def _get_group(self, name: str) -> Group:
  71. groups_availables = [group.group_name
  72. for group in self._group_api.get_all()]
  73. if name not in groups_availables:
  74. msg = "Group '{}' does not exist, choose a group name in : ".format(name) # nopep8
  75. for group in groups_availables:
  76. msg+= "'{}',".format(group)
  77. self._session.rollback()
  78. raise GroupDoesNotExist(msg)
  79. return self._group_api.get_one_with_name(name)
  80. def _add_user_to_named_group(
  81. self,
  82. user: str,
  83. group_name: str
  84. ) -> None:
  85. group = self._get_group(group_name)
  86. if user not in group.users:
  87. group.users.append(user)
  88. self._session.flush()
  89. def _remove_user_from_named_group(
  90. self,
  91. user: User,
  92. group_name: str
  93. ) -> None:
  94. group = self._get_group(group_name)
  95. if user in group.users:
  96. group.users.remove(user)
  97. self._session.flush()
  98. def _create_user(
  99. self,
  100. login: str,
  101. password: str,
  102. do_notify: bool,
  103. **kwargs
  104. ) -> User:
  105. if not password:
  106. if self._password_required():
  107. raise BadCommandError(
  108. "You must provide -p/--password parameter"
  109. )
  110. password = ''
  111. if self._user_api.check_email_already_in_db(login):
  112. raise UserAlreadyExistError()
  113. try:
  114. user = self._user_api.create_user(
  115. email=login,
  116. password=password,
  117. do_save=True,
  118. do_notify=do_notify,
  119. )
  120. # TODO - G.M - 04-04-2018 - [Caldav] Check this code
  121. # # We need to enable radicale if it not already done
  122. # daemons = DaemonsManager()
  123. # daemons.run('radicale', RadicaleDaemon)
  124. self._user_api.execute_created_user_actions(user)
  125. except IntegrityError as exception:
  126. self._session.rollback()
  127. raise UserAlreadyExistError() from exception
  128. except NotificationNotSend as exception:
  129. self._session.rollback()
  130. raise exception from exception
  131. return user
  132. def _update_password_for_login(self, login: str, password: str) -> None:
  133. user = self._user_api.get_one_by_email(login)
  134. user.password = password
  135. self._session.flush()
  136. transaction.commit()
  137. def take_app_action(
  138. self,
  139. parsed_args: argparse.Namespace,
  140. app_context: AppEnvironment
  141. ) -> None:
  142. # TODO - G.M - 05-04-2018 -Refactor this in order
  143. # to not setup object var outside of __init__ .
  144. self._session = app_context['request'].dbsession
  145. self._app_config = app_context['registry'].settings['CFG']
  146. self._user_api = UserApi(
  147. current_user=None,
  148. session=self._session,
  149. config=self._app_config,
  150. )
  151. self._group_api = GroupApi(
  152. current_user=None,
  153. session=self._session,
  154. config=self._app_config,
  155. )
  156. user = self._proceed_user(parsed_args)
  157. self._proceed_groups(user, parsed_args)
  158. print("User created/updated")
  159. def _proceed_user(self, parsed_args: argparse.Namespace) -> User:
  160. self._check_context(parsed_args)
  161. if self.action == self.ACTION_CREATE:
  162. try:
  163. user = self._create_user(
  164. login=parsed_args.login,
  165. password=parsed_args.password,
  166. do_notify=parsed_args.send_email,
  167. )
  168. except UserAlreadyExistError:
  169. raise UserAlreadyExistError("Error: User already exist (use `user update` command instead)")
  170. except NotificationNotSend:
  171. raise NotificationNotSend("Error: Cannot send email notification, user not created.")
  172. # TODO - G.M - 04-04-2018 - [Email] Check this code
  173. # if parsed_args.send_email:
  174. # email_manager = get_email_manager()
  175. # email_manager.notify_created_account(
  176. # user=user,
  177. # password=parsed_args.password,
  178. # )
  179. else:
  180. if parsed_args.password:
  181. self._update_password_for_login(
  182. login=parsed_args.login,
  183. password=parsed_args.password
  184. )
  185. user = self._user_api.get_one_by_email(parsed_args.login)
  186. return user
  187. def _proceed_groups(
  188. self,
  189. user: User,
  190. parsed_args: argparse.Namespace
  191. ) -> None:
  192. # User always in "users" group
  193. self._add_user_to_named_group(user, 'users')
  194. for group_name in parsed_args.add_to_group:
  195. self._add_user_to_named_group(user, group_name)
  196. for group_name in parsed_args.remove_from_group:
  197. self._remove_user_from_named_group(user, group_name)
  198. def _password_required(self) -> bool:
  199. # TODO - G.M - 04-04-2018 - [LDAP] Check this code
  200. # if config.get('auth_type') == LDAPAuth.name:
  201. # return False
  202. return True
  203. def _check_context(self, parsed_args: argparse.Namespace) -> None:
  204. # TODO - G.M - 04-04-2018 - [LDAP] Check this code
  205. # if config.get('auth_type') == LDAPAuth.name:
  206. # auth_instance = config.get('auth_instance')
  207. # if not auth_instance.ldap_auth.user_exist(parsed_args.login):
  208. # raise LDAPUserUnknown(
  209. # "LDAP is enabled and user with login/email \"%s\" not found in LDAP" % parsed_args.login
  210. # )
  211. pass
  212. class CreateUserCommand(UserCommand):
  213. action = UserCommand.ACTION_CREATE
  214. class UpdateUserCommand(UserCommand):
  215. action = UserCommand.ACTION_UPDATE
  216. class LDAPUserUnknown(BadCommandError):
  217. pass