]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/OStatus/actions/usersalmon.php
Code cleanup and enabling User object's etc. getUri()
[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::getKV('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::getKV('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 (!array_key_exists($this->user->getUri(), $context->attention) &&
95                 !array_key_exists(common_profile_url($this->user->nickname), $context->attention)) {
96                 common_log(LOG_ERR, $this->user->getUri() . "not in attention list (".implode(',', array_keys($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::getKV('uri', $this->activity->objects[0]->id);
106         if ($existing instanceof Notice) {
107             common_log(LOG_ERR, "Not saving notice '".$existing->getUri()."'; already exists.");
108             return;
109         }
110
111         $this->saveNotice();
112     }
113
114     /**
115      * We've gotten a follow/subscribe notification from a remote user.
116      * Save a subscription relationship for them.
117      */
118     function handleFollow()
119     {
120         $oprofile = $this->ensureProfile();
121         if ($oprofile) {
122             common_log(LOG_INFO, sprintf('Setting up subscription from remote %s to local %s', $oprofile->getUri(), $this->user->getNickname()));
123             Subscription::start($oprofile->localProfile(),
124                                 $this->user->getProfile());
125         } else {
126             common_log(LOG_INFO, "Can't set up subscription from remote; missing profile.");
127         }
128     }
129
130     /**
131      * We've gotten an unfollow/unsubscribe notification from a remote user.
132      * Check if we have a subscription relationship for them and kill it.
133      *
134      * @fixme probably catch exceptions on fail?
135      */
136     function handleUnfollow()
137     {
138         $oprofile = $this->ensureProfile();
139         if ($oprofile) {
140             common_log(LOG_INFO, sprintf('Canceling subscription from remote %s to local %s', $oprofile->getUri(), $this->user->getNickname()));
141             Subscription::cancel($oprofile->localProfile(), $this->user->getProfile());
142         } else {
143             common_log(LOG_ERR, "Can't cancel subscription from remote, didn't find the profile");
144         }
145     }
146
147     /**
148      * Remote user likes one of our posts.
149      * Confirm the post is ours, and save a local favorite event.
150      */
151
152     function handleFavorite()
153     {
154         $notice = $this->getNotice($this->activity->objects[0]);
155         $profile = $this->ensureProfile()->localProfile();
156
157         $old = Fave::pkeyGet(array('user_id' => $profile->id,
158                                    'notice_id' => $notice->id));
159
160         if (!empty($old)) {
161             // TRANS: Client exception.
162             throw new ClientException(_m('This is already a favorite.'));
163         }
164
165         if (!Fave::addNew($profile, $notice)) {
166            // TRANS: Client exception.
167            throw new ClientException(_m('Could not save new favorite.'));
168         }
169     }
170
171     /**
172      * Remote user doesn't like one of our posts after all!
173      * Confirm the post is ours, and save a local favorite event.
174      */
175     function handleUnfavorite()
176     {
177         $notice = $this->getNotice($this->activity->objects[0]);
178         $profile = $this->ensureProfile()->localProfile();
179
180         $fave = Fave::pkeyGet(array('user_id' => $profile->id,
181                                    'notice_id' => $notice->id));
182         if (empty($fave)) {
183             // TRANS: Client exception.
184             throw new ClientException(_m('Notice was not favorited!'));
185         }
186
187         $fave->delete();
188     }
189
190     function handleTag()
191     {
192         if ($this->activity->target->type == ActivityObject::_LIST) {
193             if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
194                 // TRANS: Client exception.
195                 throw new ClientException(_m('Not a person object.'));
196                 return false;
197             }
198             // this is a peopletag
199             $tagged = User::getKV('uri', $this->activity->objects[0]->id);
200
201             if (empty($tagged)) {
202                 // TRANS: Client exception.
203                 throw new ClientException(_m('Unidentified profile being listed.'));
204             }
205
206             if ($tagged->id !== $this->user->id) {
207                 // TRANS: Client exception.
208                 throw new ClientException(_m('This user is not the one being listed.'));
209             }
210
211             // save the list
212             $tagger = $this->ensureProfile();
213             $list   = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
214
215             $ptag = $list->localPeopletag();
216             $result = Profile_tag::setTag($ptag->tagger, $tagged->id, $ptag->tag);
217             if (!$result) {
218                 // TRANS: Client exception.
219                 throw new ClientException(_m('The listing could not be saved.'));
220             }
221         }
222     }
223
224     function handleUntag()
225     {
226         if ($this->activity->target->type == ActivityObject::_LIST) {
227             if ($this->activity->objects[0]->type != ActivityObject::PERSON) {
228                 // TRANS: Client exception.
229                 throw new ClientException(_m('Not a person object.'));
230                 return false;
231             }
232             // this is a peopletag
233             $tagged = User::getKV('uri', $this->activity->objects[0]->id);
234
235             if (empty($tagged)) {
236                 // TRANS: Client exception.
237                 throw new ClientException(_m('Unidentified profile being unlisted.'));
238             }
239
240             if ($tagged->id !== $this->user->id) {
241                 // TRANS: Client exception.
242                 throw new ClientException(_m('This user is not the one being unlisted.'));
243             }
244
245             // save the list
246             $tagger = $this->ensureProfile();
247             $list   = Ostatus_profile::ensureActivityObjectProfile($this->activity->target);
248
249             $ptag = $list->localPeopletag();
250             $result = Profile_tag::unTag($ptag->tagger, $tagged->id, $ptag->tag);
251
252             if (!$result) {
253                 // TRANS: Client exception.
254                 throw new ClientException(_m('The listing could not be deleted.'));
255             }
256         }
257     }
258
259     /**
260      * @param ActivityObject $object
261      * @return Notice
262      * @throws ClientException on invalid input
263      */
264     function getNotice($object)
265     {
266         if (!$object) {
267             // TRANS: Client exception.
268             throw new ClientException(_m('Cannot favorite/unfavorite without an object.'));
269         }
270
271         switch ($object->type) {
272         case ActivityObject::ARTICLE:
273         case ActivityObject::BLOGENTRY:
274         case ActivityObject::NOTE:
275         case ActivityObject::STATUS:
276         case ActivityObject::COMMENT:
277             break;
278         default:
279             // TRANS: Client exception.
280             throw new ClientException(_m('Cannot handle that kind of object for liking/faving.'));
281         }
282
283         $notice = Notice::getKV('uri', $object->id);
284
285         if (empty($notice)) {
286             // TRANS: Client exception. %s is an object ID.
287             throw new ClientException(sprintf(_m('Notice with ID %s unknown.'),$object->id));
288         }
289
290         if ($notice->profile_id != $this->user->id) {
291             // TRANS: Client exception. %1$s is a notice ID, %2$s is a user ID.
292             throw new ClientException(sprintf(_m('Notice with ID %1$s not posted by %2$s.'),$object->id,$this->user->id));
293         }
294
295         return $notice;
296     }
297 }