]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OStatus/actions/usersalmon.php
Merge commit 'refs/merge-requests/164' of git://gitorious.org/statusnet/mainline...
[quix0rs-gnu-social.git] / plugins / OStatus / actions / usersalmon.php
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
20 if (!defined('STATUSNET')) {
21     exit(1);
22 }
23
24 /**
25  * @package OStatusPlugin
26  * @author James Walker <james@status.net>
27  */
28 class UsersalmonAction extends SalmonAction
29 {
30     function prepare($args)
31     {
32         parent::prepare($args);
33
34         $id = $this->trimmed('id');
35
36         if (!$id) {
37             // TRANS: Client error displayed trying to perform an action without providing an ID.
38             $this->clientError(_m('No ID.'));
39         }
40
41         $this->user = User::staticGet('id', $id);
42
43         if (empty($this->user)) {
44             // TRANS: Client error displayed when referring to a non-existing user.
45             $this->clientError(_m('No such user.'));
46         }
47
48         $this->target = $this->user;
49
50         return true;
51     }
52
53     /**
54      * We've gotten a post event on the Salmon backchannel, probably a reply.
55      *
56      * @todo validate if we need to handle this post, then call into
57      * ostatus_profile's general incoming-post handling.
58      */
59     function handlePost()
60     {
61         common_log(LOG_INFO, "Received post of '{$this->activity->objects[0]->id}' from '{$this->activity->actor->id}'");
62
63         // @fixme: process all activity objects?
64         switch ($this->activity->objects[0]->type) {
65         case ActivityObject::ARTICLE:
66         case ActivityObject::BLOGENTRY:
67         case ActivityObject::NOTE:
68         case ActivityObject::STATUS:
69         case ActivityObject::COMMENT:
70             break;
71         default:
72             // TRANS: Client exception thrown when an undefied activity is performed.
73             throw new ClientException(_m('Cannot handle that kind of post.'));
74         }
75
76         // Notice must either be a) in reply to a notice by this user
77         // or b) to the attention of this user
78         // or c) in reply to a notice to the attention of this user
79
80         $context = $this->activity->context;
81
82         if (!empty($context->replyToID)) {
83             $notice = Notice::staticGet('uri', $context->replyToID);
84             if (empty($notice)) {
85                 // TRANS: Client exception.
86                 throw new ClientException(_m('In reply to unknown notice.'));
87             }
88             if ($notice->profile_id != $this->user->id &&
89                 !in_array($this->user->id, $notice->getReplies())) {
90                 // TRANS: Client exception.
91                 throw new ClientException(_m('In reply to a notice not by this user and not mentioning this user.'));
92             }
93         } else if (!empty($context->attention)) {
94             if (!in_array($this->user->uri, $context->attention) &&
95                 !in_array(common_profile_url($this->user->nickname), $context->attention)) {
96                 common_log(LOG_ERR, "{$this->user->uri} not in attention list (".implode(',', $context->attention).")");
97                 // TRANS: Client exception.
98                 throw new ClientException(_m('To the attention of user(s), not including this one.'));
99             }
100         } else {
101             // TRANS: Client exception.
102             throw new ClientException(_m('Not to anyone in reply to anything.'));
103         }
104
105         $existing = Notice::staticGet('uri', $this->activity->objects[0]->id);
106
107         if (!empty($existing)) {
108             common_log(LOG_ERR, "Not saving notice '{$existing->uri}'; already exists.");
109             return;
110         }
111
112         $this->saveNotice();
113     }
114
115     /**
116      * We've gotten a follow/subscribe notification from a remote user.
117      * Save a subscription relationship for them.
118      */
119     function handleFollow()
120     {
121         $oprofile = $this->ensureProfile();
122         if ($oprofile) {
123             common_log(LOG_INFO, "Setting up subscription from remote {$oprofile->uri} to local {$this->user->nickname}");
124             Subscription::start($oprofile->localProfile(),
125                                 $this->user->getProfile());
126         } else {
127             common_log(LOG_INFO, "Can't set up subscription from remote; missing profile.");
128         }
129     }
130
131     /**
132      * We've gotten an unfollow/unsubscribe notification from a remote user.
133      * Check if we have a subscription relationship for them and kill it.
134      *
135      * @fixme probably catch exceptions on fail?
136      */
137     function handleUnfollow()
138     {
139         $oprofile = $this->ensureProfile();
140         if ($oprofile) {
141             common_log(LOG_INFO, "Canceling subscription from remote {$oprofile->uri} to local {$this->user->nickname}");
142             Subscription::cancel($oprofile->localProfile(), $this->user->getProfile());
143         } else {
144             common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile");
145         }
146     }
147
148     /**
149      * Remote user likes one of our posts.
150      * Confirm the post is ours, and save a local favorite event.
151      */
152
153     function handleFavorite()
154     {
155         $notice = $this->getNotice($this->activity->objects[0]);
156         $profile = $this->ensureProfile()->localProfile();
157
158         $old = Fave::pkeyGet(array('user_id' => $profile->id,
159                                    'notice_id' => $notice->id));
160
161         if (!empty($old)) {
162             // TRANS: Client exception.
163             throw new ClientException(_m('This is already a favorite.'));
164         }
165
166         if (!Fave::addNew($profile, $notice)) {
167            // TRANS: Client exception.
168            throw new ClientException(_m('Could not save new favorite.'));
169         }
170     }
171
172     /**
173      * Remote user doesn't like one of our posts after all!
174      * Confirm the post is ours, and save a local favorite event.
175      */
176     function handleUnfavorite()
177     {
178         $notice = $this->getNotice($this->activity->objects[0]);
179         $profile = $this->ensureProfile()->localProfile();
180
181         $fave = Fave::pkeyGet(array('user_id' => $profile->id,
182                                    'notice_id' => $notice->id));
183         if (empty($fave)) {
184             // TRANS: Client exception.
185             throw new ClientException(_m('Notice was not favorited!'));
186         }
187
188         $fave->delete();
189     }
190
191     function handleTag()
192     {
193         if ($this->activity->target->type == ActivityObject::_LIST) {
194             if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
195                 // TRANS: Client exception.
196                 throw new ClientException(_m('Not a person object.'));
197                 return false;
198             }
199             // this is a peopletag
200             $tagged = User::staticGet('uri', $this->activity->objects[0]->id);
201
202             if (empty($tagged)) {
203                 // TRANS: Client exception.
204                 throw new ClientException(_m('Unidentified profile being listed.'));
205             }
206
207             if ($tagged->id !== $this->user->id) {
208                 // TRANS: Client exception.
209                 throw new ClientException(_m('This user is not the one being listed.'));
210             }
211
212             // save the list
213             $tagger = $this->ensureProfile();
214             $list   = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
215
216             $ptag = $list->localPeopletag();
217             $result = Profile_tag::setTag($ptag->tagger, $tagged->id, $ptag->tag);
218             if (!$result) {
219                 // TRANS: Client exception.
220                 throw new ClientException(_m('The listing could not be saved.'));
221             }
222         }
223     }
224
225     function handleUntag()
226     {
227         if ($this->activity->target->type == ActivityObject::_LIST) {
228             if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
229                 // TRANS: Client exception.
230                 throw new ClientException(_m('Not a person object.'));
231                 return false;
232             }
233             // this is a peopletag
234             $tagged = User::staticGet('uri', $this->activity->objects[0]->id);
235
236             if (empty($tagged)) {
237                 // TRANS: Client exception.
238                 throw new ClientException(_m('Unidentified profile being unlisted.'));
239             }
240
241             if ($tagged->id !== $this->user->id) {
242                 // TRANS: Client exception.
243                 throw new ClientException(_m('This user is not the one being unlisted.'));
244             }
245
246             // save the list
247             $tagger = $this->ensureProfile();
248             $list   = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
249
250             $ptag = $list->localPeopletag();
251             $result = Profile_tag::unTag($ptag->tagger, $tagged->id, $ptag->tag);
252
253             if (!$result) {
254                 // TRANS: Client exception.
255                 throw new ClientException(_m('The listing could not be deleted.'));
256             }
257         }
258     }
259
260     /**
261      * @param ActivityObject $object
262      * @return Notice
263      * @throws ClientException on invalid input
264      */
265     function getNotice($object)
266     {
267         if (!$object) {
268             // TRANS: Client exception.
269             throw new ClientException(_m('Cannot favorite/unfavorite without an object.'));
270         }
271
272         switch ($object->type) {
273         case ActivityObject::ARTICLE:
274         case ActivityObject::BLOGENTRY:
275         case ActivityObject::NOTE:
276         case ActivityObject::STATUS:
277         case ActivityObject::COMMENT:
278             break;
279         default:
280             // TRANS: Client exception.
281             throw new ClientException(_m('Cannot handle that kind of object for liking/faving.'));
282         }
283
284         $notice = Notice::staticGet('uri', $object->id);
285
286         if (empty($notice)) {
287             // TRANS: Client exception. %s is an object ID.
288             throw new ClientException(sprintf(_m('Notice with ID %s unknown.'),$object->id));
289         }
290
291         if ($notice->profile_id != $this->user->id) {
292             // TRANS: Client exception. %1$s is a notice ID, %2$s is a user ID.
293             throw new ClientException(sprintf(_m('Notice with ID %1$s not posted by %2$s.'),$object->id,$this->user->id));
294         }
295
296         return $notice;
297     }
298 }