usersalmon.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. <?php
  2. /*
  3. * StatusNet - the distributed open-source microblogging tool
  4. * Copyright (C) 2010, StatusNet, Inc.
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. if (!defined('GNUSOCIAL')) { exit(1); }
  20. /**
  21. * @package OStatusPlugin
  22. * @author James Walker <james@status.net>
  23. */
  24. class UsersalmonAction extends SalmonAction
  25. {
  26. protected function prepare(array $args=array())
  27. {
  28. parent::prepare($args);
  29. $this->user = User::getByID($this->trimmed('id'));
  30. $this->target = $this->user->getProfile();
  31. // Notice must either be a) in reply to a notice by this user
  32. // or b) in reply to a notice to the attention of this user
  33. // or c) to the attention of this user
  34. // or d) reference the user as an activity:object
  35. $notice = null;
  36. if (!empty($this->activity->context->replyToID)) {
  37. try {
  38. $notice = Notice::getByUri($this->activity->context->replyToID);
  39. } catch (NoResultException $e) {
  40. $notice = false;
  41. }
  42. }
  43. if ($notice instanceof Notice &&
  44. ($this->target->sameAs($notice->getProfile())
  45. || in_array($this->target->getID(), $notice->getAttentionProfileIDs())
  46. )) {
  47. // In reply to a notice either from or mentioning this user.
  48. common_debug('User is the owner or was in the attention list of thr:in-reply-to activity.');
  49. } elseif (!empty($this->activity->context->attention) &&
  50. array_key_exists($this->target->getUri(), $this->activity->context->attention)) {
  51. // To the attention of this user.
  52. common_debug('User was in attention list of salmon slap.');
  53. } elseif (!empty($this->activity->objects) && $this->activity->objects[0]->id === $this->target->getUri()) {
  54. // The user is the object of this slap (unfollow for example)
  55. common_debug('User URI was the id of the salmon slap object.');
  56. } else {
  57. common_debug('User was NOT found in salmon slap context.');
  58. // TRANS: Client exception.
  59. throw new ClientException(_m('The owner of this salmon endpoint was not in the context of the carried slap.'));
  60. }
  61. return true;
  62. }
  63. /**
  64. * We've gotten a post event on the Salmon backchannel, probably a reply.
  65. *
  66. * @todo validate if we need to handle this post, then call into
  67. * ostatus_profile's general incoming-post handling.
  68. */
  69. function handlePost()
  70. {
  71. common_log(LOG_INFO, "Received post of '{$this->activity->objects[0]->id}' from '{$this->activity->actor->id}'");
  72. // @fixme: process all activity objects?
  73. switch ($this->activity->objects[0]->type) {
  74. case ActivityObject::ARTICLE:
  75. case ActivityObject::BLOGENTRY:
  76. case ActivityObject::NOTE:
  77. case ActivityObject::STATUS:
  78. case ActivityObject::COMMENT:
  79. break;
  80. default:
  81. // TRANS: Client exception thrown when an undefied activity is performed.
  82. throw new ClientException(_m('Cannot handle that kind of post.'));
  83. }
  84. try {
  85. $this->saveNotice();
  86. } catch (AlreadyFulfilledException $e) {
  87. return;
  88. }
  89. }
  90. /**
  91. * We've gotten a follow/subscribe notification from a remote user.
  92. * Save a subscription relationship for them.
  93. */
  94. function handleFollow()
  95. {
  96. common_log(LOG_INFO, sprintf('Setting up subscription from remote %s to local %s', $this->oprofile->getUri(), $this->target->getNickname()));
  97. Subscription::start($this->actor, $this->target);
  98. }
  99. /**
  100. * We've gotten an unfollow/unsubscribe notification from a remote user.
  101. * Check if we have a subscription relationship for them and kill it.
  102. *
  103. * @fixme probably catch exceptions on fail?
  104. */
  105. function handleUnfollow()
  106. {
  107. common_log(LOG_INFO, sprintf('Canceling subscription from remote %s to local %s', $this->oprofile->getUri(), $this->target->getNickname()));
  108. try {
  109. Subscription::cancel($this->actor, $this->target);
  110. } catch (NoProfileException $e) {
  111. common_debug('Could not find profile for Subscription: '.$e->getMessage());
  112. }
  113. }
  114. function handleTag()
  115. {
  116. if ($this->activity->target->type == ActivityObject::_LIST) {
  117. if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
  118. // TRANS: Client exception.
  119. throw new ClientException(_m('Not a person object.'));
  120. }
  121. // this is a peopletag
  122. $tagged = User::getKV('uri', $this->activity->objects[0]->id);
  123. if (!$tagged instanceof User) {
  124. // TRANS: Client exception.
  125. throw new ClientException(_m('Unidentified profile being listed.'));
  126. }
  127. if ($tagged->id !== $this->target->id) {
  128. // TRANS: Client exception.
  129. throw new ClientException(_m('This user is not the one being listed.'));
  130. }
  131. // save the list
  132. $list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
  133. $ptag = $list->localPeopletag();
  134. $result = Profile_tag::setTag($ptag->tagger, $tagged->id, $ptag->tag);
  135. if (!$result) {
  136. // TRANS: Client exception.
  137. throw new ClientException(_m('The listing could not be saved.'));
  138. }
  139. }
  140. }
  141. function handleUntag()
  142. {
  143. if ($this->activity->target->type == ActivityObject::_LIST) {
  144. if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
  145. // TRANS: Client exception.
  146. throw new ClientException(_m('Not a person object.'));
  147. }
  148. // this is a peopletag
  149. $tagged = User::getKV('uri', $this->activity->objects[0]->id);
  150. if (!$tagged instanceof User) {
  151. // TRANS: Client exception.
  152. throw new ClientException(_m('Unidentified profile being unlisted.'));
  153. }
  154. if ($tagged->id !== $this->target->id) {
  155. // TRANS: Client exception.
  156. throw new ClientException(_m('This user is not the one being unlisted.'));
  157. }
  158. // save the list
  159. $list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
  160. $ptag = $list->localPeopletag();
  161. $result = Profile_tag::unTag($ptag->tagger, $tagged->id, $ptag->tag);
  162. if (!$result) {
  163. // TRANS: Client exception.
  164. throw new ClientException(_m('The listing could not be deleted.'));
  165. }
  166. }
  167. }
  168. /**
  169. * @param ActivityObject $object
  170. * @return Notice
  171. * @throws ClientException on invalid input
  172. */
  173. function getNotice(ActivityObject $object)
  174. {
  175. switch ($object->type) {
  176. case ActivityObject::ARTICLE:
  177. case ActivityObject::BLOGENTRY:
  178. case ActivityObject::NOTE:
  179. case ActivityObject::STATUS:
  180. case ActivityObject::COMMENT:
  181. break;
  182. default:
  183. // TRANS: Client exception.
  184. throw new ClientException(_m('Cannot handle that kind of object for liking/faving.'));
  185. }
  186. $notice = Notice::getKV('uri', $object->id);
  187. if (!$notice instanceof Notice) {
  188. // TRANS: Client exception. %s is an object ID.
  189. throw new ClientException(sprintf(_m('Notice with ID %s unknown.'),$object->id));
  190. }
  191. if ($notice->profile_id != $this->target->id) {
  192. // TRANS: Client exception. %1$s is a notice ID, %2$s is a user ID.
  193. throw new ClientException(sprintf(_m('Notice with ID %1$s not posted by %2$s.'), $object->id, $this->target->id));
  194. }
  195. return $notice;
  196. }
  197. }