user.py 8.0KB

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