]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/YammerImport/lib/yammerrunner.php
Yammer import (work run via background queues) now can be started from the admin...
[quix0rs-gnu-social.git] / plugins / YammerImport / lib / yammerrunner.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  * State machine for running through Yammer import.
26  *
27  * @package YammerImportPlugin
28  * @author Brion Vibber <brion@status.net>
29  */
30 class YammerRunner
31 {
32     private $state;
33     private $client;
34     private $importer;
35
36     /**
37      * Normalize our singleton state and give us a YammerRunner object to play with!
38      *
39      * @return YammerRunner
40      */
41     public static function init()
42     {
43         $state = Yammer_state::staticGet('id', 1);
44         if (!$state) {
45             $state = self::initState();
46         }
47         return new YammerRunner($state);
48     }
49
50     private static function initState()
51     {
52         $state = new Yammer_state();
53         $state->id = 1;
54         $state->state = 'init';
55         $state->created = common_sql_now();
56         $state->modified = common_sql_now();
57         $state->insert();
58         return $state;
59     }
60
61     private function __construct($state)
62     {
63         $this->state = $state;
64
65         $this->client = new SN_YammerClient(
66             common_config('yammer', 'consumer_key'),
67             common_config('yammer', 'consumer_secret'),
68             $this->state->oauth_token,
69             $this->state->oauth_secret);
70
71         $this->importer = new YammerImporter($this->client);
72     }
73
74     /**
75      * Check which state we're in
76      *
77      * @return string
78      */
79     public function state()
80     {
81         return $this->state->state;
82     }
83
84     /**
85      * Is the import done, finished, complete, finito?
86      *
87      * @return boolean
88      */
89     public function isDone()
90     {
91         $workStates = array('import-users', 'import-groups', 'fetch-messages', 'save-messages');
92         return ($this->state() == 'done');
93     }
94
95     /**
96      * Check if we have work to do in iterate().
97      *
98      * @return boolean
99      */
100     public function hasWork()
101     {
102         $workStates = array('import-users', 'import-groups', 'fetch-messages', 'save-messages');
103         return in_array($this->state(), $workStates);
104     }
105
106     /**
107      * Blow away any current state!
108      */
109     public function reset()
110     {
111         $this->state->delete();
112         $this->state = self::initState();
113     }
114
115     /**
116      * Start the authentication process! If all goes well, we'll get back a URL.
117      * Have the user visit that URL, log in on Yammer and verify the importer's
118      * permissions. They'll get back a verification code, which needs to be passed
119      * on to saveAuthToken().
120      *
121      * @return string URL
122      */
123     public function requestAuth()
124     {
125         if ($this->state->state != 'init') {
126             throw new ServerException("Cannot request Yammer auth; already there!");
127         }
128
129         $data = $this->client->requestToken();
130
131         $old = clone($this->state);
132         $this->state->state = 'requesting-auth';
133         $this->state->oauth_token = $data['oauth_token'];
134         $this->state->oauth_secret = $data['oauth_token_secret'];
135         $this->state->modified = common_sql_now();
136         $this->state->update($old);
137
138         return $this->getAuthUrl();
139     }
140
141     /**
142      * When already in requesting-auth state, grab the URL to send the user to
143      * to complete OAuth setup.
144      *
145      * @return string URL
146      */
147     function getAuthUrl()
148     {
149         if ($this->state() == 'requesting-auth') {
150             return $this->client->authorizeUrl($this->state->oauth_token);
151         } else {
152             throw new ServerException('Cannot get Yammer auth URL when not in requesting-auth state!');
153         }
154     }
155
156     /**
157      * Now that the user's given us this verification code from Yammer, we can
158      * request a final OAuth token/secret pair which we can use to access the
159      * API.
160      *
161      * After success here, we'll be ready to move on and run through iterate()
162      * until the import is complete.
163      *
164      * @param string $verifier
165      * @return boolean success
166      */
167     public function saveAuthToken($verifier)
168     {
169         if ($this->state->state != 'requesting-auth') {
170             throw new ServerException("Cannot save auth token in Yammer import state {$this->state->state}");
171         }
172
173         $data = $this->client->accessToken($verifier);
174
175         $old = clone($this->state);
176         $this->state->state = 'import-users';
177         $this->state->oauth_token = $data['oauth_token'];
178         $this->state->oauth_secret = $data['oauth_token_secret'];
179         $this->state->modified = common_sql_now();
180         $this->state->update($old);
181
182         return true;
183     }
184
185     /**
186      * Once authentication is complete, we need to call iterate() a bunch of times
187      * until state() returns 'done'.
188      *
189      * @return boolean success
190      */
191     public function iterate()
192     {
193         switch($this->state())
194         {
195             case 'init':
196             case 'requesting-auth':
197                 // Neither of these should reach our background state!
198                 common_log(LOG_ERR, "Non-background YammerImport state '$state->state' during import run!");
199                 return false;
200             case 'import-users':
201                 return $this->iterateUsers();
202             case 'import-groups':
203                 return $this->iterateGroups();
204             case 'fetch-messages':
205                 return $this->iterateFetchMessages();
206             case 'save-messages':
207                 return $this->iterateSaveMessages();
208             default:
209                 common_log(LOG_ERR, "Invalid YammerImport state '$state->state' during import run!");
210                 return false;
211         }
212     }
213
214     /**
215      * Trundle through one 'page' return of up to 50 user accounts retrieved
216      * from the Yammer API, importing them as we go.
217      *
218      * When we run out of users, move on to groups.
219      *
220      * @return boolean success
221      */
222     private function iterateUsers()
223     {
224         $old = clone($this->state);
225
226         $page = intval($this->state->users_page) + 1;
227         $data = $this->client->users(array('page' => $page));
228
229         if (count($data) == 0) {
230             common_log(LOG_INFO, "Finished importing Yammer users; moving on to groups.");
231             $this->state->state = 'import-groups';
232         } else {
233             foreach ($data as $item) {
234                 $user = $this->importer->importUser($item);
235                 common_log(LOG_INFO, "Imported Yammer user " . $item['id'] . " as $user->nickname ($user->id)");
236             }
237             $this->state->users_page = $page;
238         }
239         $this->state->modified = common_sql_now();
240         $this->state->update($old);
241         return true;
242     }
243
244     /**
245      * Trundle through one 'page' return of up to 20 user groups retrieved
246      * from the Yammer API, importing them as we go.
247      *
248      * When we run out of groups, move on to messages.
249      *
250      * @return boolean success
251      */
252     private function iterateGroups()
253     {
254         $old = clone($this->state);
255
256         $page = intval($this->state->groups_page) + 1;
257         $data = $this->client->groups(array('page' => $page));
258
259         if (count($data) == 0) {
260             common_log(LOG_INFO, "Finished importing Yammer groups; moving on to messages.");
261             $this->state->state = 'fetch-messages';
262         } else {
263             foreach ($data as $item) {
264                 $group = $this->importer->importGroup($item);
265                 common_log(LOG_INFO, "Imported Yammer group " . $item['id'] . " as $group->nickname ($group->id)");
266             }
267             $this->state->groups_page = $page;
268         }
269         $this->state->modified = common_sql_now();
270         $this->state->update($old);
271         return true;
272     }
273
274     /**
275      * Trundle through one 'page' return of up to 20 public messages retrieved
276      * from the Yammer API, saving them to our stub table for future import in
277      * correct chronological order.
278      *
279      * When we run out of messages to fetch, move on to saving the messages.
280      *
281      * @return boolean success
282      */
283     private function iterateFetchMessages()
284     {
285         $old = clone($this->state);
286
287         $oldest = intval($this->state->messages_oldest);
288         if ($oldest) {
289             $params = array('older_than' => $oldest);
290         } else {
291             $params = array();
292         }
293         $data = $this->client->messages($params);
294         $messages = $data['messages'];
295
296         if (count($messages) == 0) {
297             common_log(LOG_INFO, "Finished fetching Yammer messages; moving on to save messages.");
298             $this->state->state = 'save-messages';
299         } else {
300             foreach ($messages as $item) {
301                 Yammer_notice_stub::record($item['id'], $item);
302                 $oldest = $item['id'];
303             }
304             $this->state->messages_oldest = $oldest;
305         }
306         $this->state->modified = common_sql_now();
307         $this->state->update($old);
308         return true;
309     }
310
311     private function iterateSaveMessages()
312     {
313         $old = clone($this->state);
314
315         $newest = intval($this->state->messages_newest);
316
317         $stub = new Yammer_notice_stub();
318         if ($newest) {
319             $stub->whereAdd('id > ' . $newest);
320         }
321         $stub->limit(20);
322         $stub->orderBy('id');
323         $stub->find();
324         
325         if ($stub->N == 0) {
326             common_log(LOG_INFO, "Finished saving Yammer messages; import complete!");
327             $this->state->state = 'done';
328         } else {
329             while ($stub->fetch()) {
330                 $item = $stub->getData();
331                 $notice = $this->importer->importNotice($item);
332                 common_log(LOG_INFO, "Imported Yammer notice " . $item['id'] . " as $notice->id");
333                 $newest = $item['id'];
334             }
335             $this->state->messages_newest = $newest;
336         }
337         $this->state->modified = common_sql_now();
338         $this->state->update($old);
339         return true;
340     }
341
342     /**
343      * Count the number of Yammer users we've mapped into our system!
344      *
345      * @return int
346      */
347     public function countUsers()
348     {
349         $map = new Yammer_user();
350         return $map->count();
351     }
352
353
354     /**
355      * Count the number of Yammer groups we've mapped into our system!
356      *
357      * @return int
358      */
359     public function countGroups()
360     {
361         $map = new Yammer_group();
362         return $map->count();
363     }
364
365
366     /**
367      * Count the number of Yammer notices we've pulled down for pending import...
368      *
369      * @return int
370      */
371     public function countFetchedNotices()
372     {
373         $map = new Yammer_notice_stub();
374         return $map->count();
375     }
376
377
378     /**
379      * Count the number of Yammer notices we've mapped into our system!
380      *
381      * @return int
382      */
383     public function countSavedNotices()
384     {
385         $map = new Yammer_notice();
386         return $map->count();
387     }
388
389     /**
390      * Start running import work in the background queues...
391      */
392     public function startBackgroundImport()
393     {
394         $qm = QueueManager::get();
395         $qm->enqueue('YammerImport', 'yammer');
396     }
397
398 }