]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/twittersettings.php
bf8827958a75786a557998323d519c6def47e392
[quix0rs-gnu-social.git] / actions / twittersettings.php
1 <?php
2 /*
3  * Laconica - a distributed open-source microblogging tool
4  * Copyright (C) 2008, Controlez-Vous, 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('LACONICA')) { exit(1); }
21
22 require_once(INSTALLDIR.'/lib/settingsaction.php');
23
24 define('SUBSCRIPTIONS', 80);
25
26 class TwittersettingsAction extends SettingsAction {
27
28         var $twit_id;
29         var $twit_username;
30         var $twit_password;
31         var $friends_count = 0;
32         var $noticesync;
33         var $repliessync;
34         var $friendsync;
35
36         function get_instructions() {
37                 return _('Add your Twitter account to automatically send your notices to Twitter, ' .
38                         'and subscribe to Twitter friends already here.');
39         }
40
41         function show_form($msg=NULL, $success=false) {
42                 $user = common_current_user();
43                 $profile = $user->getProfile();
44                 $fuser = NULL;
45                 $flink = Foreign_link::getByUserID($user->id, 1); // 1 == Twitter
46
47                 if ($flink) {
48                         $fuser = $flink->getForeignUser();
49                 }
50
51                 $this->form_header(_('Twitter settings'), $msg, $success);
52                 common_element_start('form', array('method' => 'post',
53                                                                                    'id' => 'twittersettings',
54                                                                                    'action' =>
55                                                                                    common_local_url('twittersettings')));
56                 common_hidden('token', common_session_token());
57
58                 common_element('h2', NULL, _('Twitter Account'));
59
60                 if ($fuser) {
61                         common_element_start('p');
62
63                         common_element('span', 'twitter_user', $fuser->nickname);
64                         common_element('a', array('href' => $fuser->uri),  $fuser->uri);
65                         common_element('span', 'input_instructions',
66                                        _('Current verified Twitter account.'));
67                         common_hidden('flink_foreign_id', $flink->foreign_id);
68                         common_element_end('p');
69                         common_submit('remove', _('Remove'));
70                 } else {
71                         common_input('twitter_username', _('Twitter Username'),
72                                                  ($this->arg('twitter_username')) ? $this->arg('twitter_username') : $profile->nickname,
73                                                  _('No spaces, please.')); // hey, it's what Twitter says
74
75                         common_password('twitter_password', _('Twitter Password'));
76                 }
77
78                 common_element('h2', NULL, _('Preferences'));
79
80                 common_checkbox('noticesync', _('Automatically send my notices to Twitter.'),
81                                                 ($flink) ? ($flink->noticesync & FOREIGN_NOTICE_SEND) : true);
82
83                 common_checkbox('replysync', _('Send local "@" replies to Twitter.'),
84                                                 ($flink) ? ($flink->noticesync & FOREIGN_NOTICE_SEND_REPLY) : true);
85
86                 common_checkbox('friendsync', _('Subscribe to my Twitter friends here.'),
87                                                 ($flink) ? ($flink->friendsync & FOREIGN_FRIEND_RECV) : true);
88
89                 if ($flink) {
90                         common_submit('save', _('Save'));
91                 } else {
92                         common_submit('add', _('Add'));
93                 }
94
95                 
96                 $this->show_twitter_subscriptions();
97
98                 common_element_end('form');
99                 
100                 common_show_footer();
101         }
102         
103         function subscribed_twitter_users() {
104
105                 $current_user = common_current_user();
106                 
107                 $qry = 'SELECT user.* ' .
108                         'FROM subscription ' . 
109                         'JOIN user ON subscription.subscribed = user.id ' .
110                         'JOIN foreign_link ON foreign_link.user_id = user.id ' . 
111                         'WHERE subscriber = %d ' . 
112                         'ORDER BY user.nickname';
113
114                 $user = new User();
115                 
116                 $user->query(sprintf($qry, $current_user->id));
117
118                 $users = array();
119
120                 while ($user->fetch()) {
121                         $users[] = clone($user);
122                 }
123                 
124                 return $users;
125         }
126         
127         
128         function show_twitter_subscriptions() {
129         
130                 common_debug('show twitter subs');
131                 $friends = $this->subscribed_twitter_users();
132
133                 $friends_count = count($friends);
134
135                 common_debug("friends count = $friends_count");
136
137                 if ($friends_count > 0) {
138
139                         common_element('h3', NULL, _('Twitter Friends'));
140                         common_element_start('div', array('id' => 'subscriptions'));
141                         common_element_start('ul', array('id' => 'subscriptions_avatars'));
142
143                         for ($i = 0; $i < min($friends_count, SUBSCRIPTIONS); $i++) {
144
145                                 $other = Profile::staticGet($friends[$i]->id);
146
147                                 if (!$other) {
148                                         common_log_db_error($subs, 'SELECT', __FILE__);
149                                         continue;
150                                 }
151                                 
152                                 common_element_start('li');
153                                 common_element_start('a', array('title' => ($other->fullname) ?
154                                                                                                 $other->fullname :
155                                                                                                 $other->nickname,
156                                                                                                 'href' => $other->profileurl,
157                                                                                                 'rel' => 'contact',
158                                                                                                 'class' => 'subscription'));
159                                 $avatar = $other->getAvatar(AVATAR_MINI_SIZE);
160                                 common_element('img', array('src' => (($avatar) ? common_avatar_display_url($avatar) :  common_default_avatar(AVATAR_MINI_SIZE)),
161                                                                                         'width' => AVATAR_MINI_SIZE,
162                                                                                         'height' => AVATAR_MINI_SIZE,
163                                                                                         'class' => 'avatar mini',
164                                                                                         'alt' =>  ($other->fullname) ?
165                                                                                         $other->fullname :
166                                                                                         $other->nickname));
167                                 common_element_end('a');
168                                 common_element_end('li');
169                 
170                         }
171
172                         common_element_end('ul');
173                         common_element_end('div');
174
175                 }
176
177                 // XXX Figure out a way to show all Twitter friends...
178                 
179                 /*
180                 if ($subs_count > SUBSCRIPTIONS) {
181                         common_element_start('p', array('id' => 'subscriptions_viewall'));
182
183                         common_element('a', array('href' => common_local_url('subscriptions',
184                                                                                                                                  array('nickname' => $profile->nickname)),
185                                                                           'class' => 'moresubscriptions'),
186                                                    _('All subscriptions'));
187                         common_element_end('p');
188                 }
189                 */
190
191         }
192         
193         
194
195         function handle_post() {
196
197                 # CSRF protection
198                 $token = $this->trimmed('token');
199                 if (!$token || $token != common_session_token()) {
200                         $this->show_form(_('There was a problem with your session token. Try again, please.'));
201                         return;
202                 }
203
204                 if ($this->arg('save')) {
205                         $this->save_preferences();
206                 } else if ($this->arg('add')) {
207                         $this->add_twitter_acct();
208                 } else if ($this->arg('remove')) {
209                         $this->remove_twitter_acct();
210                 } else {
211                         $this->show_form(_('Unexpected form submission.'));
212                 }
213         }
214
215         function add_twitter_acct() {
216
217                 $this->twit_username = $this->trimmed('twitter_username');
218                 $this->twit_password = $this->trimmed('twitter_password');
219                 $this->noticesync = $this->boolean('noticesync');
220                 $this->replysync = $this->boolean('replysync');
221                 $this->friendsync = $this->boolean('friendsync');
222
223                 if (!Validate::string($this->twit_username, array('min_length' => 1,
224                                                                                                            'max_length' => 15,
225                                                                                                            'format' => VALIDATE_NUM . VALIDATE_ALPHA . '_'))) {
226                         $this->show_form(_('Username must have only numbers, upper- and lowercase letters, and underscore (_). 15 chars max.'));
227                         return;
228                 }
229
230                 // Verify this is a real Twitter user.
231                 if (!$this->verify_credentials()) {
232                         $this->show_form(_('Could not verify your Twitter credentials!'));
233                         return;
234                 }
235
236                 if (!$this->twitter_user_info()) {
237                         $this->show_form(sprintf(_('Unable to retrieve account information for "%s" from Twitter.'),
238                                 $twitter_username));
239                         return;
240                 }
241
242                 $fuser_id = $this->update_twitter_user($this->twit_id, $this->twit_username);
243
244                 if (!$fuser_id) {
245                         $this->show_form(_('Unable to save your Twitter settings!'));
246                         return;
247                 }
248
249                 $user = common_current_user();
250
251                 $flink = DB_DataObject::factory('foreign_link');
252                 $flink->user_id = $user->id;
253                 $flink->foreign_id = $fuser_id;
254                 $flink->service = 1; // Twitter
255                 $flink->credentials = $this->twit_password;
256                 $flink->created = common_sql_now();
257
258                 $this->set_flags($flink, $this->noticesync, $this->replysync, $this->friendsync);
259
260                 $flink_id = $flink->insert();
261
262                 if (!$flink_id) {
263                         common_log_db_error($flink, 'INSERT', __FILE__);
264                         $this->show_form(_('Unable to save your Twitter settings!'));
265                         return;
266                 }
267
268                 if ($this->friendsync) {
269                         $this->save_friends();
270                 }
271
272                 $this->show_form(_('Twitter settings saved.'), true);
273         }
274
275         function remove_twitter_acct() {
276                 $user = common_current_user();
277
278                 // For now we assume one Twitter acct per Laconica acct
279                 $flink = Foreign_link::getByUserID($user->id, 1);
280                 $flink_foreign_id = $this->arg('flink_foreign_id');
281
282                 if (!$flink) {
283                         common_debug("couldn't get flink");
284                 }
285
286                 # Maybe an old tab open...?
287                 if ($flink->foreign_id != $flink_foreign_id) {
288                         common_debug("flink user_id = " . $flink->user_id);
289                     $this->show_form(_('That is not your Twitter account.'));
290                     return;
291                 }
292
293                 $result = $flink->delete();
294
295                 if (!$result) {
296                         common_log_db_error($flink, 'DELETE', __FILE__);
297                         common_server_error(_('Couldn\'t remove Twitter user.'));
298                         return;
299                 }
300
301                 $this->show_form(_('Twitter account removed.'), TRUE);
302         }
303
304         function save_preferences() {
305                 $this->noticesync = $this->boolean('noticesync');
306                 $this->friendsync = $this->boolean('friendsync');
307                 $this->replysync = $this->boolean('replysync');
308
309                 $user = common_current_user();
310                 $flink = Foreign_link::getByUserID($user->id, 1);
311
312                 if (!$flink) {
313                         common_log_db_error($flink, 'SELECT', __FILE__);
314                         $this->show_form(_('Couldn\'t save Twitter preferences.'));
315                         return;
316                 }
317
318                 $this->twit_id = $flink->foreign_id;
319                 $this->twit_password = $flink->credentials;
320
321                 $fuser = $flink->getForeignUser();
322
323                 if (!$fuser) {
324                         common_log_db_error($fuser, 'SELECT', __FILE__);
325                         $this->show_form(_('Couldn\'t save Twitter preferences.'));
326                         return;
327                 }
328
329                 $this->twit_username = $fuser->nickname;
330
331                 $original = clone($flink);
332                 $this->set_flags($flink, $this->noticesync, $this->replysync, $this->friendsync);
333                 $result = $flink->update($original);
334
335                 if ($result === FALSE) {
336                         common_log_db_error($flink, 'UPDATE', __FILE__);
337                         $this->show_form(_('Couldn\'t save Twitter preferences.'));
338                         return;
339                 }
340
341                 if ($this->friendsync) {
342                         $this->save_friends();
343                 }
344
345                 $this->show_form(_('Twitter preferences saved.'));
346         }
347
348         function twitter_user_info() {
349                 $uri = "http://twitter.com/users/show/$this->twit_username.json";
350                 $data = $this->get_twitter_data($uri);
351
352                 if (!$data) {
353                         return false;
354                 }
355
356                 $twit_user = json_decode($data);
357
358                 if (!$twit_user) {
359                         return false;
360                 }
361
362                 $this->friends_count = $twit_user->friends_count;
363                 $this->twit_id = $twit_user->id;
364
365                 common_debug("Twitter_id = $this->twit_id");
366                 common_debug("Friends_count = $this->friends_count");
367
368                 return true;
369         }
370
371         function verify_credentials() {
372                 $uri = 'http://twitter.com/account/verify_credentials.json';
373                 $data = $this->get_twitter_data($uri);
374
375                 if (!$data) {
376                         return false;
377                 }
378
379                 $creds = json_decode($data);
380
381                 if (!$creds) {
382                         return false;
383                 }
384
385                 if ($creds->authorized == 1) {
386                         return true;
387                 }
388
389                 return false;
390         }
391
392         function get_twitter_data($uri) {
393
394                 $options = array(
395                                 CURLOPT_USERPWD => sprintf("%s:%s", $this->twit_username, $this->twit_password),
396                                 CURLOPT_RETURNTRANSFER  => true,
397                                 CURLOPT_FAILONERROR             => true,
398                                 CURLOPT_HEADER                  => false,
399                                 CURLOPT_FOLLOWLOCATION  => true,
400                                 // CURLOPT_USERAGENT            => "identi.ca",
401                                 CURLOPT_CONNECTTIMEOUT  => 120,
402                                 CURLOPT_TIMEOUT                 => 120
403                 );
404
405
406                 $ch = curl_init($uri);
407             curl_setopt_array($ch, $options);
408             $data = curl_exec($ch);
409             $errmsg = curl_error($ch);
410
411                 if ($errmsg) {
412                         common_debug("cURL error: $errmsg - trying to load: $uri with user $this->twit_user.",
413                                 __FILE__);
414                 }
415
416                 curl_close($ch);
417
418                 return $data;
419         }
420
421         function set_flags(&$flink, $noticesync, $replysync, $friendsync) {
422                 if ($noticesync) {
423                         $flink->noticesync |= FOREIGN_NOTICE_SEND;
424                 } else {
425                         $flink->noticesync &= ~FOREIGN_NOTICE_SEND;
426                 }
427
428                 if ($replysync) {
429                         $flink->noticesync |= FOREIGN_NOTICE_SEND_REPLY;
430                 } else {
431                         $flink->noticesync &= ~FOREIGN_NOTICE_SEND_REPLY;
432                 }
433
434                 if ($friendsync) {
435                         $flink->friendsync |= FOREIGN_FRIEND_RECV;
436                 } else {
437                         $flink->friendsync &= ~FOREIGN_FRIEND_RECV;
438                 }
439
440                 $flink->profilesync = 0; // XXX: leave as default?
441         }
442
443         function save_friends() {
444
445                 $uri = 'http://twitter.com/statuses/friends.json?page=';
446
447                 $this->twitter_user_info();
448
449                 // Calculate how many pages to get...
450                 $pages = ceil($this->friends_count / 100);
451
452                 common_debug("number of pages to get: $pages");
453
454                 $friends = array();
455
456                 for ($i = 1; $i <= $pages; $i++) {
457
458                         $data = $this->get_twitter_data($uri . $i);
459
460                         common_debug("fetching " . $uri . $i);
461
462                         if (!$data) {
463                                 return false;
464                         }
465
466                         common_debug("got data");
467                 
468                         $more_friends = json_decode($data);
469                         
470                         if (!$more_friends) {
471                                 return false;
472                         }
473
474                         $friends = array_merge($friends, $more_friends);
475
476                 }
477                 
478                 common_debug("number of friends =" + count($friends));
479
480                 $user = common_current_user();
481
482             foreach ($friends as $friend) {
483                 
484                         $friend_name = $friend->screen_name;
485                         $friend_id = $friend->id;
486
487                         // Update or create the Foreign_user record
488                         $this->update_twitter_user($friend_id, $friend_name);
489                         
490                         // Check to see if there's a related local user
491                         $flink = Foreign_link::getByForeignID($friend_id, 1);
492                                                 
493                         if ($flink) {
494                                 
495                                 // Get associated user
496                                 $friend_user = User::staticGet('id', $flink->user_id);                          
497                                 subs_subscribe_to($user, $friend_user);
498                                 
499                         }
500                 }
501                 
502         }
503
504         // Creates or Updates a Twitter user
505         function update_twitter_user($twitter_id, $screen_name) {
506
507                 $fuser = null;
508
509                 $uri = "http://twitter.com/$screen_name";
510
511                 // Check to see whether the Twitter user is already in the system,
512                 // and update its screen name and uri if so.
513                 $fuser = Foreign_User::getForeignUser($twitter_id, 1);
514
515                 if ($fuser) {
516
517                         // Only update if Twitter screen name has changed
518                         if ($fuser->nickname != $screen_name) {
519
520                                 $original = clone($fuser);
521                                 $fuser->nickname = $screen_name;
522                                 $fuser->uri = $uri;
523                                 $result = $fuser->updateKeys($original);
524
525                                 if (!$result) {
526                                         common_log_db_error($fuser, 'UPDATE', __FILE__);
527                                         return null;
528                                 }
529
530                                 common_debug(
531                                         sprintf('Updated Twitter user %, screen name was: %, now: %s.',
532                                                 $twitter_id, $original->nickname, $screen_name));
533                         }
534
535                         common_debug("No update for $screen_name needed.");
536
537                 } else {
538
539                                 // Otherwise, create a new Twitter user
540                                 $fuser = DB_DataObject::factory('foreign_user');
541
542                                 $fuser->nickname = $screen_name;
543                                 $fuser->uri = $uri;
544                                 $fuser->id = $twitter_id;
545                                 $fuser->service = 1; // Twitter
546                                 $fuser->created = common_sql_now();
547                                 $result = $fuser->insert();
548
549                                 if (!$result) {
550                                         common_debug("Failed to add new Twitter user: $twitter_id - $screen_name.");
551                                         common_log_db_error($fuser, 'INSERT', __FILE__);
552                                         return null;
553                                 }
554
555                                 common_debug("Added new Twitter user: $twitter_id - $screen_name.");
556
557                                 //      common_debug(print_r($friend, true));
558                 }
559
560                 return $fuser->id;
561
562         }
563
564 }