user.py 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. # -*- coding: utf-8 -*-
  2. import transaction
  3. from sqlalchemy.exc import IntegrityError
  4. from tg import config
  5. from tracim.command import AppContextCommand
  6. from tracim.command import Extender
  7. from tracim.lib.auth.ldap import LDAPAuth
  8. from tracim.lib.daemons import DaemonsManager
  9. from tracim.lib.daemons import RadicaleDaemon
  10. from tracim.lib.email import get_email_manager
  11. from tracim.lib.exception import AlreadyExistError
  12. from tracim.lib.exception import CommandAbortedError
  13. from tracim.lib.group import GroupApi
  14. from tracim.lib.user import UserApi
  15. from tracim.model import DBSession
  16. from tracim.model import User
  17. class UserCommand(AppContextCommand):
  18. ACTION_CREATE = 'create'
  19. ACTION_UPDATE = 'update'
  20. action = NotImplemented
  21. def __init__(self, *args, **kwargs):
  22. super().__init__(*args, **kwargs)
  23. self._session = DBSession
  24. self._transaction = transaction
  25. self._user_api = UserApi(None)
  26. self._group_api = GroupApi(None)
  27. def get_description(self):
  28. return '''Create or update user.'''
  29. def get_parser(self, prog_name):
  30. parser = super().get_parser(prog_name)
  31. parser.add_argument(
  32. "-l",
  33. "--login",
  34. help='User login (email)',
  35. dest='login',
  36. required=True
  37. )
  38. parser.add_argument(
  39. "-p",
  40. "--password",
  41. help='User password',
  42. dest='password',
  43. required=False,
  44. default=None
  45. )
  46. parser.add_argument(
  47. "-g",
  48. "--add-to-group",
  49. help='Add user to group',
  50. dest='add_to_group',
  51. nargs='*',
  52. action=Extender,
  53. default=[],
  54. )
  55. parser.add_argument(
  56. "-rmg",
  57. "--remove-from-group",
  58. help='Remove user from group',
  59. dest='remove_from_group',
  60. nargs='*',
  61. action=Extender,
  62. default=[],
  63. )
  64. parser.add_argument(
  65. "--send-email",
  66. help='Send mail to user',
  67. dest='send_email',
  68. required=False,
  69. action='store_true',
  70. default=False,
  71. )
  72. return parser
  73. def _user_exist(self, login):
  74. return self._user_api.user_with_email_exists(login)
  75. def _get_group(self, name):
  76. return self._group_api.get_one_with_name(name)
  77. def _add_user_to_named_group(self, user, group_name):
  78. group = self._get_group(group_name)
  79. if user not in group.users:
  80. group.users.append(user)
  81. self._session.flush()
  82. def _remove_user_from_named_group(self, user, group_name):
  83. group = self._get_group(group_name)
  84. if user in group.users:
  85. group.users.remove(user)
  86. self._session.flush()
  87. def _create_user(self, login, password, **kwargs):
  88. if not password:
  89. if self._password_required():
  90. raise CommandAbortedError("You must provide -p/--password parameter")
  91. password = ''
  92. try:
  93. user = User(email=login, password=password, **kwargs)
  94. self._session.add(user)
  95. self._session.flush()
  96. # We need to enable radicale if it not already done
  97. daemons = DaemonsManager()
  98. daemons.run('radicale', RadicaleDaemon)
  99. user_api = UserApi(user)
  100. user_api.execute_created_user_actions(user)
  101. except IntegrityError:
  102. self._session.rollback()
  103. raise AlreadyExistError()
  104. return user
  105. def _update_password_for_login(self, login, password):
  106. user = self._user_api.get_one_by_email(login)
  107. user.password = password
  108. self._session.flush()
  109. transaction.commit()
  110. def take_action(self, parsed_args):
  111. super().take_action(parsed_args)
  112. user = self._proceed_user(parsed_args)
  113. self._proceed_groups(user, parsed_args)
  114. print("User created/updated")
  115. def _proceed_user(self, parsed_args):
  116. self._check_context(parsed_args)
  117. if self.action == self.ACTION_CREATE:
  118. try:
  119. user = self._create_user(login=parsed_args.login, password=parsed_args.password)
  120. except AlreadyExistError:
  121. raise CommandAbortedError("Error: User already exist (use `user update` command instead)")
  122. if parsed_args.send_email:
  123. email_manager = get_email_manager()
  124. email_manager.notify_created_account(
  125. user=user,
  126. password=parsed_args.password,
  127. )
  128. else:
  129. if parsed_args.password:
  130. self._update_password_for_login(login=parsed_args.login, password=parsed_args.password)
  131. user = self._user_api.get_one_by_email(parsed_args.login)
  132. return user
  133. def _proceed_groups(self, user, parsed_args):
  134. # User always in "users" group
  135. self._add_user_to_named_group(user, 'users')
  136. for group_name in parsed_args.add_to_group:
  137. self._add_user_to_named_group(user, group_name)
  138. for group_name in parsed_args.remove_from_group:
  139. self._remove_user_from_named_group(user, group_name)
  140. def _password_required(self):
  141. if config.get('auth_type') == LDAPAuth.name:
  142. return False
  143. return True
  144. def _check_context(self, parsed_args):
  145. if config.get('auth_type') == LDAPAuth.name:
  146. auth_instance = config.get('auth_instance')
  147. if not auth_instance.ldap_auth.user_exist(parsed_args.login):
  148. raise LDAPUserUnknown(
  149. "LDAP is enabled and user with login/email \"%s\" not found in LDAP" % parsed_args.login
  150. )
  151. class CreateUserCommand(UserCommand):
  152. action = UserCommand.ACTION_CREATE
  153. class UpdateUserCommand(UserCommand):
  154. action = UserCommand.ACTION_UPDATE
  155. class LDAPUserUnknown(CommandAbortedError):
  156. pass