profile.py 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. # -*- coding: utf-8 -*-
  2. # Copyright 2014-2016 OpenMarket Ltd
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. from twisted.internet import defer
  16. from synapse.api.errors import SynapseError, AuthError, CodeMessageException
  17. from synapse.types import UserID, Requester
  18. from ._base import BaseHandler
  19. import logging
  20. logger = logging.getLogger(__name__)
  21. class ProfileHandler(BaseHandler):
  22. def __init__(self, hs):
  23. super(ProfileHandler, self).__init__(hs)
  24. self.federation = hs.get_replication_layer()
  25. self.federation.register_query_handler(
  26. "profile", self.on_profile_query
  27. )
  28. distributor = hs.get_distributor()
  29. distributor.observe("registered_user", self.registered_user)
  30. def registered_user(self, user):
  31. return self.store.create_profile(user.localpart)
  32. @defer.inlineCallbacks
  33. def get_displayname(self, target_user):
  34. if self.hs.is_mine(target_user):
  35. displayname = yield self.store.get_profile_displayname(
  36. target_user.localpart
  37. )
  38. defer.returnValue(displayname)
  39. else:
  40. try:
  41. result = yield self.federation.make_query(
  42. destination=target_user.domain,
  43. query_type="profile",
  44. args={
  45. "user_id": target_user.to_string(),
  46. "field": "displayname",
  47. }
  48. )
  49. except CodeMessageException as e:
  50. if e.code != 404:
  51. logger.exception("Failed to get displayname")
  52. raise
  53. except:
  54. logger.exception("Failed to get displayname")
  55. else:
  56. defer.returnValue(result["displayname"])
  57. @defer.inlineCallbacks
  58. def set_displayname(self, target_user, requester, new_displayname):
  59. """target_user is the user whose displayname is to be changed;
  60. auth_user is the user attempting to make this change."""
  61. if not self.hs.is_mine(target_user):
  62. raise SynapseError(400, "User is not hosted on this Home Server")
  63. if target_user != requester.user:
  64. raise AuthError(400, "Cannot set another user's displayname")
  65. if new_displayname == '':
  66. new_displayname = None
  67. yield self.store.set_profile_displayname(
  68. target_user.localpart, new_displayname
  69. )
  70. yield self._update_join_states(requester)
  71. @defer.inlineCallbacks
  72. def get_avatar_url(self, target_user):
  73. if self.hs.is_mine(target_user):
  74. avatar_url = yield self.store.get_profile_avatar_url(
  75. target_user.localpart
  76. )
  77. defer.returnValue(avatar_url)
  78. else:
  79. try:
  80. result = yield self.federation.make_query(
  81. destination=target_user.domain,
  82. query_type="profile",
  83. args={
  84. "user_id": target_user.to_string(),
  85. "field": "avatar_url",
  86. }
  87. )
  88. except CodeMessageException as e:
  89. if e.code != 404:
  90. logger.exception("Failed to get avatar_url")
  91. raise
  92. except:
  93. logger.exception("Failed to get avatar_url")
  94. defer.returnValue(result["avatar_url"])
  95. @defer.inlineCallbacks
  96. def set_avatar_url(self, target_user, requester, new_avatar_url):
  97. """target_user is the user whose avatar_url is to be changed;
  98. auth_user is the user attempting to make this change."""
  99. if not self.hs.is_mine(target_user):
  100. raise SynapseError(400, "User is not hosted on this Home Server")
  101. if target_user != requester.user:
  102. raise AuthError(400, "Cannot set another user's avatar_url")
  103. yield self.store.set_profile_avatar_url(
  104. target_user.localpart, new_avatar_url
  105. )
  106. yield self._update_join_states(requester)
  107. @defer.inlineCallbacks
  108. def on_profile_query(self, args):
  109. user = UserID.from_string(args["user_id"])
  110. if not self.hs.is_mine(user):
  111. raise SynapseError(400, "User is not hosted on this Home Server")
  112. just_field = args.get("field", None)
  113. response = {}
  114. if just_field is None or just_field == "displayname":
  115. response["displayname"] = yield self.store.get_profile_displayname(
  116. user.localpart
  117. )
  118. if just_field is None or just_field == "avatar_url":
  119. response["avatar_url"] = yield self.store.get_profile_avatar_url(
  120. user.localpart
  121. )
  122. defer.returnValue(response)
  123. @defer.inlineCallbacks
  124. def _update_join_states(self, requester):
  125. user = requester.user
  126. if not self.hs.is_mine(user):
  127. return
  128. self.ratelimit(requester)
  129. joins = yield self.store.get_rooms_for_user(
  130. user.to_string(),
  131. )
  132. for j in joins:
  133. handler = self.hs.get_handlers().room_member_handler
  134. try:
  135. # Assume the user isn't a guest because we don't let guests set
  136. # profile or avatar data.
  137. requester = Requester(user, "", False)
  138. yield handler.update_membership(
  139. requester,
  140. user,
  141. j.room_id,
  142. "join", # We treat a profile update like a join.
  143. ratelimit=False, # Try to hide that these events aren't atomic.
  144. )
  145. except Exception as e:
  146. logger.warn(
  147. "Failed to update join event for room %s - %s",
  148. j.room_id, str(e.message)
  149. )