user.py 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # -*- coding: utf-8 -*-
  2. from webob.exc import HTTPForbidden
  3. from tracim import model as pm
  4. from sprox.tablebase import TableBase
  5. from sprox.formbase import EditableForm, AddRecordForm
  6. from sprox.fillerbase import TableFiller, EditFormFiller
  7. from tw2 import forms as tw2f
  8. import tg
  9. from tg import tmpl_context
  10. from tg.i18n import ugettext as _, lazy_ugettext as l_
  11. from sprox.widgets import PropertyMultipleSelectField
  12. from sprox._compat import unicode_text
  13. from formencode import Schema
  14. from formencode.validators import FieldsMatch
  15. from tracim.controllers import TIMRestController
  16. from tracim.lib import helpers as h
  17. from tracim.lib.user import UserApi
  18. from tracim.lib.group import GroupApi
  19. from tracim.lib.user import UserStaticApi
  20. from tracim.lib.userworkspace import RoleApi
  21. from tracim.lib.workspace import WorkspaceApi
  22. from tracim.model import DBSession
  23. from tracim.model.auth import Group, User
  24. from tracim.model.serializers import Context, CTX, DictLikeClass
  25. class UserWorkspaceRestController(TIMRestController):
  26. def _before(self, *args, **kw):
  27. """
  28. Instantiate the current workspace in tg.tmpl_context
  29. :param args:
  30. :param kw:
  31. :return:
  32. """
  33. super(self.__class__, self)._before(args, kw)
  34. api = UserApi(tg.tmpl_context.current_user)
  35. user_id = tmpl_context.current_user_id
  36. user = tmpl_context.current_user
  37. @tg.expose()
  38. def enable_notifications(self, workspace_id, next_url=None):
  39. workspace_id = int(workspace_id)
  40. api = WorkspaceApi(tg.tmpl_context.current_user)
  41. workspace = api.get_one(workspace_id)
  42. api.enable_notifications(tg.tmpl_context.current_user, workspace)
  43. tg.flash(_('Notification enabled for workspace {}').format(workspace.label))
  44. if next_url:
  45. tg.redirect(tg.url(next_url))
  46. tg.redirect(self.parent_controller.url(None, 'me'))
  47. @tg.expose()
  48. def disable_notifications(self, workspace_id, next_url=None):
  49. workspace_id = int(workspace_id)
  50. api = WorkspaceApi(tg.tmpl_context.current_user)
  51. workspace = api.get_one(workspace_id)
  52. api.disable_notifications(tg.tmpl_context.current_user, workspace)
  53. tg.flash(_('Notification disabled for workspace {}').format(workspace.label))
  54. if next_url:
  55. tg.redirect(tg.url(next_url))
  56. tg.redirect(self.parent_controller.url(None, 'me'))
  57. class UserPasswordRestController(TIMRestController):
  58. """
  59. CRUD Controller allowing to manage password of a given user
  60. TODO: do not duplicate this controller between admin and "standard user" interfaces
  61. """
  62. def _before(self, *args, **kw):
  63. """
  64. Instantiate the current workspace in tg.tmpl_context
  65. :param args:
  66. :param kw:
  67. :return:
  68. """
  69. super(self.__class__, self)._before(args, kw)
  70. api = UserApi(tg.tmpl_context.current_user)
  71. user_id = tmpl_context.current_user_id
  72. user = tmpl_context.current_user
  73. @tg.expose('tracim.templates.user_password_edit_me')
  74. def edit(self):
  75. if not tg.config.get('auth_is_internal'):
  76. raise HTTPForbidden()
  77. dictified_user = Context(CTX.USER).toDict(tmpl_context.current_user, 'user')
  78. return DictLikeClass(result = dictified_user)
  79. @tg.expose()
  80. def put(self, current_password, new_password1, new_password2):
  81. if not tg.config.get('auth_is_internal'):
  82. raise HTTPForbidden()
  83. # FIXME - Allow only self password or operation for managers
  84. current_user = tmpl_context.current_user
  85. redirect_url = tg.lurl('/home')
  86. if not current_password or not new_password1 or not new_password2:
  87. tg.flash(_('Empty password is not allowed.'))
  88. tg.redirect(redirect_url)
  89. if current_user.validate_password(current_password) is False:
  90. tg.flash(_('The current password you typed is wrong'))
  91. tg.redirect(redirect_url)
  92. if new_password1!=new_password2:
  93. tg.flash(_('New passwords do not match.'))
  94. tg.redirect(redirect_url)
  95. current_user.password = new_password1
  96. pm.DBSession.flush()
  97. tg.flash(_('Your password has been changed'))
  98. tg.redirect(redirect_url)
  99. class UserRestController(TIMRestController):
  100. """
  101. CRUD Controller allowing to manage Users
  102. """
  103. password = UserPasswordRestController()
  104. workspaces = UserWorkspaceRestController()
  105. @classmethod
  106. def current_item_id_key_in_context(cls):
  107. return 'user_id'
  108. @tg.expose('tracim.templates.user_get_all')
  109. def get_all(self, *args, **kw):
  110. tg.redirect(self.url(None, 'me'))
  111. pass
  112. @tg.expose()
  113. def post(self, name, email, password, is_tracim_manager='off', is_pod_admin='off'):
  114. pass
  115. @tg.expose('tracim.templates.user_get_me')
  116. def get_one(self, user_id):
  117. user_id = tmpl_context.current_user.user_id
  118. current_user = tmpl_context.current_user
  119. assert user_id==current_user.user_id
  120. api = UserApi(current_user)
  121. current_user = api.get_one(current_user.user_id)
  122. dictified_user = Context(CTX.USER).toDict(current_user, 'user')
  123. current_user_content = Context(CTX.CURRENT_USER).toDict(tmpl_context.current_user)
  124. fake_api_content = DictLikeClass(current_user=current_user_content)
  125. fake_api = Context(CTX.WORKSPACE).toDict(fake_api_content)
  126. return DictLikeClass(result=dictified_user, fake_api=fake_api)
  127. @tg.expose('tracim.templates.user_edit_me')
  128. def edit(self, id, next_url=None):
  129. id = tmpl_context.current_user.user_id
  130. current_user = tmpl_context.current_user
  131. assert id==current_user.user_id
  132. dictified_user = Context(CTX.USER).toDict(current_user, 'user')
  133. fake_api = DictLikeClass(next_url=next_url)
  134. return DictLikeClass(result=dictified_user, fake_api=fake_api)
  135. @tg.expose('tracim.templates.workspace.edit')
  136. def put(self, user_id, name, email, next_url=None):
  137. user_id = tmpl_context.current_user.user_id
  138. current_user = tmpl_context.current_user
  139. assert user_id==current_user.user_id
  140. # Only keep allowed field update
  141. updated_fields = self._clean_update_fields({
  142. 'name': name,
  143. 'email': email
  144. })
  145. api = UserApi(tmpl_context.current_user)
  146. api.update(current_user, do_save=True, **updated_fields)
  147. tg.flash(_('profile updated.'))
  148. if next_url:
  149. tg.redirect(tg.url(next_url))
  150. tg.redirect(self.url())
  151. def _clean_update_fields(self, fields: dict):
  152. """
  153. Remove field key who are not allowed to be updated
  154. :param fields: dict with field name key to be cleaned
  155. :rtype fields: dict
  156. :return:
  157. """
  158. auth_instance = tg.config.get('auth_instance')
  159. if not auth_instance.is_internal:
  160. externalized_fields_names = auth_instance.managed_fields
  161. for externalized_field_name in externalized_fields_names:
  162. if externalized_field_name in fields:
  163. fields.pop(externalized_field_name)
  164. return fields