usersalmon.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. $id = $this->trimmed('id');
  30. if (!$id) {
  31. // TRANS: Client error displayed trying to perform an action without providing an ID.
  32. $this->clientError(_m('No ID.'));
  33. }
  34. $this->user = User::getKV('id', $id);
  35. if (!$this->user instanceof User) {
  36. // TRANS: Client error displayed when referring to a non-existing user.
  37. $this->clientError(_m('No such user.'));
  38. }
  39. $this->target = $this->user->getProfile();
  40. return true;
  41. }
  42. /**
  43. * We've gotten a post event on the Salmon backchannel, probably a reply.
  44. *
  45. * @todo validate if we need to handle this post, then call into
  46. * ostatus_profile's general incoming-post handling.
  47. */
  48. function handlePost()
  49. {
  50. common_log(LOG_INFO, "Received post of '{$this->activity->objects[0]->id}' from '{$this->activity->actor->id}'");
  51. // @fixme: process all activity objects?
  52. switch ($this->activity->objects[0]->type) {
  53. case ActivityObject::ARTICLE:
  54. case ActivityObject::BLOGENTRY:
  55. case ActivityObject::NOTE:
  56. case ActivityObject::STATUS:
  57. case ActivityObject::COMMENT:
  58. break;
  59. default:
  60. // TRANS: Client exception thrown when an undefied activity is performed.
  61. throw new ClientException(_m('Cannot handle that kind of post.'));
  62. }
  63. // Notice must either be a) in reply to a notice by this user
  64. // or b) in reply to a notice to the attention of this user
  65. // or c) to the attention of this user
  66. $context = $this->activity->context;
  67. $notice = false;
  68. if (!empty($context->replyToID)) {
  69. $notice = Notice::getKV('uri', $context->replyToID);
  70. }
  71. if ($notice instanceof Notice &&
  72. ($notice->profile_id == $this->target->id ||
  73. array_key_exists($this->target->id, $notice->getReplies())))
  74. {
  75. // In reply to a notice either from or mentioning this user.
  76. } elseif (!empty($context->attention) &&
  77. array_key_exists($this->target->getUri(), $context->attention)) {
  78. // To the attention of this user.
  79. } else {
  80. // TRANS: Client exception.
  81. throw new ClientException(_m('Not to anyone in reply to anything.'));
  82. }
  83. $existing = Notice::getKV('uri', $this->activity->objects[0]->id);
  84. if ($existing instanceof Notice) {
  85. common_log(LOG_ERR, "Not saving notice with duplicate URI '".$existing->getUri()."' (seems it already exists).");
  86. return;
  87. }
  88. $this->saveNotice();
  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. }