usersalmon.php 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  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. common_debug('Referenced Notice object found with URI: '.$notice->getUri());
  40. } catch (NoResultException $e) {
  41. common_debug('Referenced Notice object NOT found with URI: '.$this->activity->context->replyToID);
  42. $notice = false;
  43. }
  44. }
  45. if ($notice instanceof Notice &&
  46. ($this->target->sameAs($notice->getProfile())
  47. || in_array($this->target->getID(), $notice->getAttentionProfileIDs())
  48. )) {
  49. // In reply to a notice either from or mentioning this user.
  50. common_debug('User is the owner or was in the attention list of thr:in-reply-to activity.');
  51. } elseif (!empty($this->activity->context->attention) &&
  52. array_key_exists($this->target->getUri(), $this->activity->context->attention)) {
  53. // To the attention of this user.
  54. common_debug('User was in attention list of salmon slap.');
  55. } elseif (!empty($this->activity->objects) && $this->activity->objects[0]->id === $this->target->getUri()) {
  56. // The user is the object of this slap (unfollow for example)
  57. common_debug('User URI was the id of the salmon slap object.');
  58. } else {
  59. common_debug('User was NOT found in salmon slap context.');
  60. // TRANS: Client exception.
  61. throw new ClientException(_m('The owner of this salmon endpoint was not in the context of the carried slap.'));
  62. }
  63. return true;
  64. }
  65. /**
  66. * We've gotten a post event on the Salmon backchannel, probably a reply.
  67. *
  68. * @todo validate if we need to handle this post, then call into
  69. * ostatus_profile's general incoming-post handling.
  70. */
  71. function handlePost()
  72. {
  73. common_log(LOG_INFO, "Received post of '{$this->activity->objects[0]->id}' from '{$this->activity->actor->id}'");
  74. // @fixme: process all activity objects?
  75. switch ($this->activity->objects[0]->type) {
  76. case ActivityObject::ARTICLE:
  77. case ActivityObject::BLOGENTRY:
  78. case ActivityObject::NOTE:
  79. case ActivityObject::STATUS:
  80. case ActivityObject::COMMENT:
  81. break;
  82. default:
  83. // TRANS: Client exception thrown when an undefied activity is performed.
  84. throw new ClientException(_m('Cannot handle that kind of post.'));
  85. }
  86. try {
  87. $this->saveNotice();
  88. } catch (AlreadyFulfilledException $e) {
  89. return;
  90. }
  91. }
  92. /**
  93. * We've gotten a follow/subscribe notification from a remote user.
  94. * Save a subscription relationship for them.
  95. */
  96. function handleFollow()
  97. {
  98. common_log(LOG_INFO, sprintf('Setting up subscription from remote %s to local %s', $this->oprofile->getUri(), $this->target->getNickname()));
  99. Subscription::start($this->actor, $this->target);
  100. }
  101. /**
  102. * We've gotten an unfollow/unsubscribe notification from a remote user.
  103. * Check if we have a subscription relationship for them and kill it.
  104. *
  105. * @fixme probably catch exceptions on fail?
  106. */
  107. function handleUnfollow()
  108. {
  109. common_log(LOG_INFO, sprintf('Canceling subscription from remote %s to local %s', $this->oprofile->getUri(), $this->target->getNickname()));
  110. try {
  111. Subscription::cancel($this->actor, $this->target);
  112. } catch (NoProfileException $e) {
  113. common_debug('Could not find profile for Subscription: '.$e->getMessage());
  114. }
  115. }
  116. function handleTag()
  117. {
  118. if ($this->activity->target->type == ActivityObject::_LIST) {
  119. if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
  120. // TRANS: Client exception.
  121. throw new ClientException(_m('Not a person object.'));
  122. }
  123. // this is a peopletag
  124. $tagged = User::getKV('uri', $this->activity->objects[0]->id);
  125. if (!$tagged instanceof User) {
  126. // TRANS: Client exception.
  127. throw new ClientException(_m('Unidentified profile being listed.'));
  128. }
  129. if ($tagged->id !== $this->target->id) {
  130. // TRANS: Client exception.
  131. throw new ClientException(_m('This user is not the one being listed.'));
  132. }
  133. // save the list
  134. $list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
  135. $ptag = $list->localPeopletag();
  136. $result = Profile_tag::setTag($ptag->tagger, $tagged->id, $ptag->tag);
  137. if (!$result) {
  138. // TRANS: Client exception.
  139. throw new ClientException(_m('The listing could not be saved.'));
  140. }
  141. }
  142. }
  143. function handleUntag()
  144. {
  145. if ($this->activity->target->type == ActivityObject::_LIST) {
  146. if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
  147. // TRANS: Client exception.
  148. throw new ClientException(_m('Not a person object.'));
  149. }
  150. // this is a peopletag
  151. $tagged = User::getKV('uri', $this->activity->objects[0]->id);
  152. if (!$tagged instanceof User) {
  153. // TRANS: Client exception.
  154. throw new ClientException(_m('Unidentified profile being unlisted.'));
  155. }
  156. if ($tagged->id !== $this->target->id) {
  157. // TRANS: Client exception.
  158. throw new ClientException(_m('This user is not the one being unlisted.'));
  159. }
  160. // save the list
  161. $list = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
  162. $ptag = $list->localPeopletag();
  163. $result = Profile_tag::unTag($ptag->tagger, $tagged->id, $ptag->tag);
  164. if (!$result) {
  165. // TRANS: Client exception.
  166. throw new ClientException(_m('The listing could not be deleted.'));
  167. }
  168. }
  169. }
  170. /**
  171. * @param ActivityObject $object
  172. * @return Notice
  173. * @throws ClientException on invalid input
  174. */
  175. function getNotice(ActivityObject $object)
  176. {
  177. switch ($object->type) {
  178. case ActivityObject::ARTICLE:
  179. case ActivityObject::BLOGENTRY:
  180. case ActivityObject::NOTE:
  181. case ActivityObject::STATUS:
  182. case ActivityObject::COMMENT:
  183. break;
  184. default:
  185. // TRANS: Client exception.
  186. throw new ClientException(_m('Cannot handle that kind of object for liking/faving.'));
  187. }
  188. $notice = Notice::getKV('uri', $object->id);
  189. if (!$notice instanceof Notice) {
  190. // TRANS: Client exception. %s is an object ID.
  191. throw new ClientException(sprintf(_m('Notice with ID %s unknown.'),$object->id));
  192. }
  193. if ($notice->profile_id != $this->target->id) {
  194. // TRANS: Client exception. %1$s is a notice ID, %2$s is a user ID.
  195. throw new ClientException(sprintf(_m('Notice with ID %1$s not posted by %2$s.'), $object->id, $this->target->id));
  196. }
  197. return $notice;
  198. }
  199. }