]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - lib/accountmover.php
normalize accounts and check for return in HTTP for moving
[quix0rs-gnu-social.git] / lib / accountmover.php
1 <?php
2 /**
3  * StatusNet - the distributed open-source microblogging tool
4  * Copyright (C) 2010, StatusNet, Inc.
5  *
6  * A class for moving an account to a new server
7  * 
8  * PHP version 5
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU Affero General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Affero General Public License for more details.
19  *
20  * You should have received a copy of the GNU Affero General Public License
21  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
22  *
23  * @category  Account
24  * @package   StatusNet
25  * @author    Evan Prodromou <evan@status.net>
26  * @copyright 2010 StatusNet, Inc.
27  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
28  * @link      http://status.net/
29  */
30
31 if (!defined('STATUSNET')) {
32     // This check helps protect against security problems;
33     // your code file can't be executed directly from the web.
34     exit(1);
35 }
36
37 /**
38  * Moves an account from this server to another
39  *
40  * @category  Account
41  * @package   StatusNet
42  * @author    Evan Prodromou <evan@status.net>
43  * @copyright 2010 StatusNet, Inc.
44  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0
45  * @link      http://status.net/
46  */
47
48 class AccountMover
49 {
50     private $_user    = null;
51     private $_profile = null;
52     private $_remote  = null;
53     private $_sink    = null;
54     
55     function __construct($user, $remote, $password)
56     {
57         $this->_user    = $user;
58         $this->_profile = $user->getProfile();
59
60         $remote = Discovery::normalize($remote);
61
62         $oprofile = Ostatus_profile::ensureProfileURI($remote);
63
64         if (empty($oprofile)) {
65             throw new Exception("Can't locate account {$remote}");
66         }
67
68         $this->_remote = $oprofile->localProfile();
69
70         list($svcDocUrl, $username) = self::getServiceDocument($remote);
71
72         $this->_sink = new ActivitySink($svcDocUrl, $username, $password);
73     }
74
75     static function getServiceDocument($remote)
76     {
77         $discovery = new Discovery();
78
79         $xrd = $discovery->lookup($remote);
80
81         if (empty($xrd)) {
82             throw new Exception("Can't find XRD for $remote");
83         } 
84
85         $svcDocUrl = null;
86         $username  = null;
87
88         foreach ($xrd->links as $link) {
89             if ($link['rel'] == 'http://apinamespace.org/atom' &&
90                 $link['type'] == 'application/atomsvc+xml') {
91                 $svcDocUrl = $link['href'];
92                 if (!empty($link['property'])) {
93                     foreach ($link['property'] as $property) {
94                         if ($property['type'] == 'http://apinamespace.org/atom/username') {
95                             $username = $property['value'];
96                             break;
97                         }
98                     }
99                 }
100                 break;
101             }
102         }
103
104         if (empty($svcDocUrl)) {
105             throw new Exception("No AtomPub API service for $remote.");
106         }
107
108         return array($svcDocUrl, $username);
109     }
110
111     function move()
112     {
113         $stream = new UserActivityStream($this->_user);
114
115         $acts = array_reverse($stream->activities);
116
117         // Reverse activities to run in correct chron order
118
119         foreach ($acts as $act) {
120             $this->_moveActivity($act);
121         }
122     }
123
124     private function _moveActivity($act)
125     {
126         switch ($act->verb) {
127         case ActivityVerb::FAVORITE:
128             // push it, then delete local
129             $this->_sink->postActivity($act);
130             $notice = Notice::staticGet('uri', $act->objects[0]->id);
131             if (!empty($notice)) {
132                 $fave = Fave::pkeyGet(array('user_id' => $this->_user->id,
133                                             'notice_id' => $notice->id));
134                 $fave->delete();
135             }
136             break;
137         case ActivityVerb::POST:
138             // XXX: send a reshare, not a post
139             common_log(LOG_INFO, "Pushing notice {$act->objects[0]->id} to {$this->_remote->getURI()}");
140             $this->_sink->postActivity($act);
141             $notice = Notice::staticGet('uri', $act->objects[0]->id);
142             if (!empty($notice)) {
143                 $notice->delete();
144             }
145             break;
146         case ActivityVerb::JOIN:
147             $this->_sink->postActivity($act);
148             $group = User_group::staticGet('uri', $act->objects[0]->id);
149             if (!empty($group)) {
150                 Group_member::leave($group->id, $this->_user->id);
151             }
152             break;
153         case ActivityVerb::FOLLOW:
154             if ($act->actor->id == $this->_user->uri) {
155                 $this->_sink->postActivity($act);
156                 $other = Profile::fromURI($act->objects[0]->id);
157                 if (!empty($other)) {
158                     Subscription::cancel($this->_profile, $other);
159                 }
160             } else {
161                 $otherUser = User::staticGet('uri', $act->actor->id);
162                 if (!empty($otherUser)) {
163                     $otherProfile = $otherUser->getProfile();
164                     Subscription::start($otherProfile, $this->_remote);
165                     Subscription::cancel($otherProfile, $this->_user->getProfile());
166                 } else {
167                     // It's a remote subscription. Do something here!
168                 }
169             }
170             break;
171         }
172     }
173 }