]> git.mxchange.org Git - friendica.git/blob - statusnet/statusnet.php
wrapping up 2019.12
[friendica.git] / statusnet / statusnet.php
1 <?php
2
3 /*   StatusNet Plugin for Friendika
4  *
5  *   Author: Tobias Diekershoff
6  *           tobias.diekershoff@gmx.net
7  *
8  *   License:3-clause BSD license (same as Friendika)
9  *
10  *   Configuration:
11  *     To activate the plugin itself add it to the $a->config['system']['addon']
12  *     setting. After this, your user can configure their Twitter account settings
13  *     from "Settings -> Plugin Settings".
14  *
15  *     Requirements: PHP5, curl [Slinky library]
16  *
17  *     Documentation: http://diekershoff.homeunix.net/redmine/wiki/friendikaplugin/StatusNet_Plugin
18  */
19
20 /*   __TODO__
21  *
22  *   - what about multimedia content?
23  *     so far we just strip HTML tags from the message
24  */
25
26
27 /***
28  * We have to alter the TwitterOAuth class a little bit to work with any StatusNet
29  * installation abroad. Basically it's only make the API path variable and be happy.
30  *
31  * Thank you guys for the Twitter compatible API!
32  */
33
34 require_once('library/twitteroauth.php');
35
36 class StatusNetOAuth extends TwitterOAuth {
37     function get_maxlength() {
38         $config = $this->get($this->host . 'statusnet/config.json');
39         return $config->site->textlimit;
40     }
41     function accessTokenURL()  { return $this->host.'oauth/access_token'; }
42     function authenticateURL() { return $this->host.'oauth/authenticate'; } 
43     function authorizeURL() { return $this->host.'oauth/authorize'; }
44     function requestTokenURL() { return $this->host.'oauth/request_token'; }
45     function __construct($apipath, $consumer_key, $consumer_secret, $oauth_token = NULL, $oauth_token_secret = NULL) {
46         parent::__construct($consumer_key, $consumer_secret, $oauth_token, $oauth_token_secret);
47         $this->host = $apipath;
48     }
49 }
50
51 function statusnet_install() {
52         //  we need some hooks, for the configuration and for sending tweets
53         register_hook('plugin_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings'); 
54         register_hook('plugin_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
55         register_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
56         register_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
57
58         logger("installed statusnet");
59 }
60
61
62 function statusnet_uninstall() {
63         unregister_hook('plugin_settings', 'addon/statusnet/statusnet.php', 'statusnet_settings'); 
64         unregister_hook('plugin_settings_post', 'addon/statusnet/statusnet.php', 'statusnet_settings_post');
65         unregister_hook('post_local_end', 'addon/statusnet/statusnet.php', 'statusnet_post_hook');
66         unregister_hook('jot_networks',    'addon/statusnet/statusnet.php', 'statusnet_jot_nets');
67 }
68
69 function statusnet_jot_nets(&$a,&$b) {
70         if(! local_user())
71                 return;
72
73         $statusnet_post = get_pconfig(local_user(),'statusnet','post');
74         if(intval($statusnet_post) == 1) {
75                 $statusnet_defpost = get_pconfig(local_user(),'statusnet','post_by_default');
76                 $selected = ((intval($statusnet_defpost == 1)) ? ' selected="selected" ' : '');
77                 $b .= '<div class="profile-jot-net"><input type="checkbox" name="statusnet_enable"' . $selected . 'value="1" /> ' 
78                         . t('Post to StatusNet') . '</div>';    
79         }
80 }
81
82
83
84
85 function statusnet_settings_post ($a,$post) {
86         if(! local_user())
87             return;
88         if (isset($_POST['statusnet-disconnect'])) {
89             /***
90              * if the statusnet-disconnect checkbox is set, clear the statusnet configuration
91              * TODO can we revoke the access tokens at Twitter and do we need to do so?
92              */
93             del_pconfig( local_user(), 'statusnet', 'consumerkey'  );
94             del_pconfig( local_user(), 'statusnet', 'consumersecret' );
95             del_pconfig( local_user(), 'statusnet', 'post' );
96             del_pconfig( local_user(), 'statusnet', 'oauthtoken' );
97             del_pconfig( local_user(), 'statusnet', 'oauthsecret' );
98             del_pconfig( local_user(), 'statusnet', 'baseapi' );
99         } else {
100         if (isset($_POST['statusnet-consumersecret'])) {
101             set_pconfig(local_user(), 'statusnet', 'consumerkey', $_POST['statusnet-consumerkey']);
102             set_pconfig(local_user(), 'statusnet', 'consumersecret', $_POST['statusnet-consumersecret']);
103             set_pconfig(local_user(), 'statusnet', 'baseapi', $_POST['statusnet-baseapi']);
104             header('Location: '.$a->get_baseurl().'/settings/addon');
105         } else {
106         if (isset($_POST['statusnet-pin'])) {
107             //  if the user supplied us with a PIN from Twitter, let the magic of OAuth happen
108             logger('got a StatusNet security code');
109             $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
110             $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey'  );
111             $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
112             //  the token and secret for which the PIN was generated were hidden in the settings
113             //  form as token and token2, we need a new connection to Twitter using these token
114             //  and secret to request a Access Token with the PIN
115             $connection = new StatusNetOAuth($api, $ckey, $csecret, $_POST['statusnet-token'], $_POST['statusnet-token2']);
116             $token   = $connection->getAccessToken( $_POST['statusnet-pin'] );
117             //  ok, now that we have the Access Token, save them in the user config
118             set_pconfig(local_user(),'statusnet', 'oauthtoken',  $token['oauth_token']);
119             set_pconfig(local_user(),'statusnet', 'oauthsecret', $token['oauth_token_secret']);
120             set_pconfig(local_user(),'statusnet', 'post', 1);
121             //  reload the Addon Settings page, if we don't do it see Bug #42
122             header('Location: '.$a->get_baseurl().'/settings/addon');
123         } else {
124             //  if no PIN is supplied in the POST variables, the user has changed the setting
125             //  to post a tweet for every new __public__ posting to the wall
126             set_pconfig(local_user(),'statusnet','post',intval($_POST['statusnet-enable']));
127         }}}
128 }
129 function statusnet_settings(&$a,&$s) {
130         if(! local_user())
131                 return;
132         $a->page['htmlhead'] .= '<link rel="stylesheet"  type="text/css" href="' . $a->get_baseurl() . '/addon/statusnet/statusnet.css' . '" media="all" />' . "\r\n";
133         /***
134          * 1) Check that we have a base api url and a consumer key & secret
135          * 2) If no OAuthtoken & stuff is present, generate button to get some
136          * 3) Checkbox for "Send public notices (respect size limitation)
137          */
138         $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
139         $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey' );
140         $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
141         $otoken  = get_pconfig(local_user(), 'statusnet', 'oauthtoken'  );
142         $osecret = get_pconfig(local_user(), 'statusnet', 'oauthsecret' );
143         $enabled = get_pconfig(local_user(), 'statusnet', 'post');
144         $checked = (($enabled) ? ' checked="checked" ' : '');
145         $s .= '<div class="settings-block">';
146         $s .= '<h3>'. t('StatusNet Posting Settings').'</h3>';
147
148         if ( (!$ckey) && (!$csecret) ) {
149                 /***
150                  * no consumer keys
151                  */
152                 $s .= '<p>'. t('No consumer key pair for StatusNet found. Register your Friendika Account as an desktop client on your StatusNet account, copy the consumer key pair here and enter the API base root.<br />Before you register your own OAuth key pair ask the administrator if there is already a key pair for this Friendika installation at your favorited StatusNet installation.') .'</p>';
153                 $s .= '<div id="statusnet-consumer-wrapper">';
154                 $s .= '<label id="statusnet-consumerkey-label" for="statusnet-consumerkey">'. t('OAuth Consumer Key') .'</label>';
155                                 $s .= '<input id="statusnet-consumerkey" type="text" name="statusnet-consumerkey" size="35" />';
156                                 $s .= '<div class="clear"></div>';
157                 $s .= '<label id="statusnet-consumersecret-label" for="statusnet-consumersecret">'. t('OAuth Consumer Secret') .'</label>';
158                                 $s .= '<input id="statusnet-consumersecret" type="text" name="statusnet-consumersecret" size="35" />';
159                                 $s .= '<div class="clear"></div>';
160                 $s .= '<label id="statusnet-baseapi-label" for="statusnet-baseapi">'. t("Base API Path \x28remember the trailing /\x29") .'</label>';
161                 $s .= '<input id="statusnet-baseapi" type="text" name="statusnet-baseapi" size="35" />';
162                 $s .= '<div class="clear"></div></div>';
163                 $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
164         } else {
165                 /***
166                  * ok we have a consumer key pair now look into the OAuth stuff
167                  */
168                 if ( (!$otoken) && (!$osecret) ) {
169                         /***
170                          * the user has not yet connected the account to statusnet
171                          * get a temporary OAuth key/secret pair and display a button with
172                          * which the user can request a PIN to connect the account to a
173                          * account at statusnet
174                          */
175                         $connection = new StatusNetOAuth($api, $ckey, $csecret);
176                         $request_token = $connection->getRequestToken('oob');
177                         $token = $request_token['oauth_token'];
178                         /***
179                          *  make some nice form
180                          */
181                         $s .= '<p>'. t('To connect to your StatusNet account click the button below to get a security code from StatusNet which you have to copy into the input box below and submit the form. Only your <strong>public</strong> posts will be posted to StatusNet.') .'</p>';
182                         $s .= '<a href="'.$connection->getAuthorizeURL($token,False).'" target="_statusnet"><img src="addon/statusnet/signinwithstatusnet.png" alt="'. t('Log in with StatusNet') .'"></a>';
183                         $s .= '<div id="statusnet-pin-wrapper">';
184                         $s .= '<label id="statusnet-pin-label" for="statusnet-pin">'. t('Copy the security code from StatusNet here') .'</label>';
185                         $s .= '<input id="statusnet-pin" type="text" name="statusnet-pin" />';
186                         $s .= '<input id="statusnet-token" type="hidden" name="statusnet-token" value="'.$token.'" />';
187                         $s .= '<input id="statusnet-token2" type="hidden" name="statusnet-token2" value="'.$request_token['oauth_token_secret'].'" />';
188                         $s .= '</div><div class="clear"></div>';
189                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="submit" class="settings-submit" value="' . t('Submit') . '" /></div>';
190                 } else {
191                         /***
192                          *  we have an OAuth key / secret pair for the user
193                          *  so let's give a chance to disable the postings to statusnet
194                          */
195                         $connection = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
196                         $details = $connection->get('account/verify_credentials');
197                         $s .= '<div id="statusnet-info" ><img id="statusnet-avatar" src="'.$details->profile_image_url.'" /><p id="statusnet-info-block">'. t('Currently connected to: ') .'<a href="'.$details->statusnet_profile_url.'" target="_statusnet">'.$details->screen_name.'</a><br /><em>'.$details->description.'</em></p></div>';
198                         $s .= '<p>'. t('If enabled all your <strong>public</strong> postings will be posted to the associated StatusNet account as well.') .'</p>';
199                         $s .= '<div id="statusnet-enable-wrapper">';
200                         $s .= '<label id="statusnet-enable-label" for="statusnet-checkbox">'. t('Send public postings to StatusNet') .'</label>';
201                         $s .= '<input id="statusnet-checkbox" type="checkbox" name="statusnet-enable" value="1" ' . $checked . '/>';
202                         $s .= '</div><div class="clear"></div>';
203                         $s .= '<div id="statusnet-disconnect-wrapper">';
204                         $s .= '<label id="statusnet-disconnect-label" for="statusnet-disconnect">'. t('Clear OAuth configuration') .'</label>';
205                         $s .= '<input id="statusnet-disconnect" type="checkbox" name="statusnet-disconnect" value="1" />';
206                         $s .= '</div><div class="clear"></div>';
207                         $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="submit" class="settings-submit" value="' . t('Submit') . '" /></div>'; 
208                 }
209         }
210         $s .= '</div><div class="clear"></div></div>';
211 }
212
213
214 function statusnet_post_hook(&$a,&$b) {
215
216         /**
217          * Post to statusnet
218          */
219
220         logger('StatusNet post invoked');
221
222         if((local_user()) && (local_user() == $b['uid']) && (! $b['private']) && (!$b['parent']) ) {
223
224                 load_pconfig(local_user(), 'statusnet');
225             
226                 $api     = get_pconfig(local_user(), 'statusnet', 'baseapi');
227                 $ckey    = get_pconfig(local_user(), 'statusnet', 'consumerkey'  );
228                 $csecret = get_pconfig(local_user(), 'statusnet', 'consumersecret' );
229                 $otoken  = get_pconfig(local_user(), 'statusnet', 'oauthtoken'  );
230                 $osecret = get_pconfig(local_user(), 'statusnet', 'oauthsecret' );
231
232                 if($ckey && $csecret && $otoken && $osecret) {
233
234                         $statusnet_post = get_pconfig(local_user(),'statusnet','post');
235                         $statusnet_enable = (($statusnet_post && x($_POST,'statusnet_enable')) ? intval($_POST['statusnet_enable']) : 0);
236
237                         if($statusnet_enable && $statusnet_post) {
238                                 require_once('include/bbcode.php');     
239                                 $dent = new StatusNetOAuth($api,$ckey,$csecret,$otoken,$osecret);
240                                 $max_char = $dent->get_maxlength(); // max. length for a dent
241                                 $msg = strip_tags(bbcode($b['body']));
242                                 if ( strlen($msg) > $max_char) {
243                                         $shortlink = "";
244                                         require_once('library/slinky.php');
245                                         // post url = base url + /display/ + owner + post id
246                                         // we construct this from the Owner link and replace
247                                         // profile by display - this will cause an error when
248                                         // /profile/ is in the owner url twice but I don't
249                                         // think this will be very common...
250                                         $posturl = str_replace('/profile/','/display/',$b['owner-link']).'/'.$b['id'];
251                                         $slinky = new Slinky( $posturl );
252                                         // setup a cascade of shortening services
253                                         // try to get a short link from these services
254                                         // in the order ur1.ca, trim, id.gd, tinyurl
255                                         $slinky->set_cascade( array( new Slinky_UR1ca(), new Slinky_Trim(), new Slinky_IsGd(), new Slinky_TinyURL() ) );
256                                         $shortlink = $slinky->short();
257                                         // the new message will be shortened such that "... $shortlink"
258                                         // will fit into the character limit
259                                         $msg = substr($msg, 0, $max_char-strlen($shortlink)-4);
260                                         $msg .= '... ' . $shortlink;
261                                 }
262                                 // and now tweet it :-)
263                                 if(strlen($msg))
264                                         $dent->post('statuses/update', array('status' => $msg));
265                         }
266                 }
267     }
268 }
269