]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Facebook/facebookaction.php
86d6647b5ff773c6f78214616202d78ba4f0def8
[quix0rs-gnu-social.git] / plugins / Facebook / facebookaction.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * Base Facebook Action
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Faceboook
23  * @package   StatusNet
24  * @author    Zach Copley <zach@status.net>
25  * @copyright 2008-2009 StatusNet, Inc.
26  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
27  * @link      http://status.net/
28  */
29
30 if (!defined('STATUSNET') && !defined('LACONICA')) {
31     exit(1);
32 }
33
34 require_once INSTALLDIR . '/plugins/Facebook/facebookutil.php';
35 require_once INSTALLDIR . '/plugins/Facebook/facebooknoticeform.php';
36
37 class FacebookAction extends Action
38 {
39
40     var $facebook = null;
41     var $fbuid    = null;
42     var $flink    = null;
43     var $action   = null;
44     var $app_uri  = null;
45     var $app_name = null;
46
47     function __construct($output='php://output', $indent=null, $facebook=null, $flink=null)
48     {
49         parent::__construct($output, $indent);
50
51         $this->facebook = $facebook;
52         $this->flink = $flink;
53
54         if ($this->flink) {
55             $this->fbuid = $flink->foreign_id;
56             $this->user = $flink->getUser();
57         }
58
59         $this->args = array();
60     }
61
62     function prepare($argarray)
63     {
64         parent::prepare($argarray);
65
66         $this->facebook = getFacebook();
67         $this->fbuid = $this->facebook->require_login();
68
69         $this->action = $this->trimmed('action');
70
71         $app_props = $this->facebook->api_client->Admin_getAppProperties(
72                 array('canvas_name', 'application_name'));
73
74         $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
75         $this->app_name = $app_props['application_name'];
76
77         $this->flink = Foreign_link::getByForeignID($this->fbuid, FACEBOOK_SERVICE);
78
79         return true;
80
81     }
82
83     function showStylesheets()
84     {
85         $this->cssLink('css/display.css', 'base');
86         $this->cssLink('css/display.css', null, 'screen, projection, tv');
87         $this->cssLink('plugins/Facebook/facebookapp.css');
88     }
89
90     function showScripts()
91     {
92         $this->script('js/facebookapp.js');
93     }
94
95     /**
96      * Start an Facebook ready HTML document
97      *
98      * For Facebook we don't want to actually output any headers,
99      * DTD info, etc.  Just Stylesheet and JavaScript links.
100      *
101      * @param string $type MIME type to use; default is to do negotation.
102      *
103      * @return void
104      */
105
106     function startHTML($type=null)
107     {
108         $this->showStylesheets();
109         $this->showScripts();
110
111         $this->elementStart('div', array('class' => 'facebook-page'));
112     }
113
114     /**
115     *  Ends a Facebook ready HTML document
116     *
117     *  @return void
118     */
119     function endHTML()
120     {
121         $this->elementEnd('div');
122         $this->endXML();
123     }
124
125     /**
126      * Show notice form.
127      *
128      * @return nothing
129      */
130     function showNoticeForm()
131     {
132         // don't do it for most of the Facebook pages
133     }
134
135     function showBody()
136     {
137         $this->elementStart('div', array('id' => 'wrap'));
138         $this->showHeader();
139         $this->showCore();
140         $this->showFooter();
141         $this->elementEnd('div');
142     }
143
144     function showHead($error, $success)
145     {
146
147         if ($error) {
148             $this->element("h1", null, $error);
149         }
150
151         if ($success) {
152             $this->element("h1", null, $success);
153         }
154
155         $this->elementStart('fb:if-section-not-added', array('section' => 'profile'));
156         $this->elementStart('span', array('id' => 'add_to_profile'));
157         $this->element('fb:add-section-button', array('section' => 'profile'));
158         $this->elementEnd('span');
159         $this->elementEnd('fb:if-section-not-added');
160
161     }
162
163     // Make this into a widget later
164     function showLocalNav()
165     {
166         $this->elementStart('ul', array('class' => 'nav'));
167
168         $this->elementStart('li', array('class' =>
169             ($this->action == 'facebookhome') ? 'current' : 'facebook_home'));
170         $this->element('a',
171             array('href' => 'index.php', 'title' => _m('Home')), _m('Home'));
172         $this->elementEnd('li');
173
174         if (common_config('invite', 'enabled')) {
175             $this->elementStart('li',
176                 array('class' =>
177                     ($this->action == 'facebookinvite') ? 'current' : 'facebook_invite'));
178             $this->element('a',
179                 array('href' => 'invite.php', 'title' => _m('Invite')), _m('Invite'));
180             $this->elementEnd('li');
181         }
182
183         $this->elementStart('li',
184             array('class' =>
185                 ($this->action == 'facebooksettings') ? 'current' : 'facebook_settings'));
186         $this->element('a',
187             array('href' => 'settings.php',
188                 'title' => _m('Settings')), _m('Settings'));
189         $this->elementEnd('li');
190
191         $this->elementEnd('ul');
192     }
193
194     /**
195      * Show header of the page.
196      *
197      * @return nothing
198      */
199     function showHeader()
200     {
201         $this->elementStart('div', array('id' => 'header'));
202         $this->showLogo();
203         $this->showNoticeForm();
204         $this->elementEnd('div');
205     }
206
207     /**
208      * Show page, a template method.
209      *
210      * @return nothing
211      */
212     function showPage($error = null, $success = null)
213     {
214         $this->startHTML();
215         $this->showHead($error, $success);
216         $this->showBody();
217         $this->endHTML();
218     }
219
220     function showInstructions()
221     {
222
223         $this->elementStart('div', array('class' => 'facebook_guide'));
224
225         $this->elementStart('dl', array('class' => 'system_notice'));
226         $this->element('dt', null, 'Page Notice');
227
228         $loginmsg_part1 = _m('To use the %s Facebook Application you need to login ' .
229             'with your username and password. Don\'t have a username yet? ');
230         $loginmsg_part2 = _m(' a new account.');
231
232         $this->elementStart('dd');
233         $this->elementStart('p');
234         $this->text(sprintf($loginmsg_part1, common_config('site', 'name')));
235         $this->element('a',
236             array('href' => common_local_url('register')), _m('Register'));
237         $this->text($loginmsg_part2);
238         $this->elementEnd('p');
239         $this->elementEnd('dd');
240
241         $this->elementEnd('dl');
242         $this->elementEnd('div');
243     }
244
245     function showLoginForm($msg = null)
246     {
247
248         $this->elementStart('div', array('id' => 'content'));
249         $this->element('h1', null, _m('Login'));
250
251         if ($msg) {
252              $this->element('fb:error', array('message' => $msg));
253         }
254
255         $this->showInstructions();
256
257         $this->elementStart('div', array('id' => 'content_inner'));
258
259         $this->elementStart('form', array('method' => 'post',
260                                                'class' => 'form_settings',
261                                                'id' => 'login',
262                                                'action' => 'index.php'));
263
264         $this->elementStart('fieldset');
265
266         $this->elementStart('ul', array('class' => 'form_datas'));
267         $this->elementStart('li');
268         $this->input('nickname', _m('Nickname'));
269         $this->elementEnd('li');
270         $this->elementStart('li');
271         $this->password('password', _m('Password'));
272         $this->elementEnd('li');
273         $this->elementEnd('ul');
274
275         $this->submit('submit', _m('Login'));
276         $this->elementEnd('fieldset');
277         $this->elementEnd('form');
278
279         $this->elementStart('p');
280         $this->element('a', array('href' => common_local_url('recoverpassword')),
281                        _m('Lost or forgotten password?'));
282         $this->elementEnd('p');
283
284         $this->elementEnd('div');
285         $this->elementEnd('div');
286
287     }
288
289     function updateProfileBox($notice)
290     {
291
292         // Need to include inline CSS for styling the Profile box
293
294         $app_props = $this->facebook->api_client->Admin_getAppProperties(array('icon_url'));
295         $icon_url = $app_props['icon_url'];
296
297         $style = '<style>
298      .entry-title *,
299      .entry-content * {
300      font-size:14px;
301      font-family:"Lucida Sans Unicode", "Lucida Grande", sans-serif;
302      }
303      .entry-title a,
304      .entry-content a {
305      color:#002E6E;
306      }
307
308          .entry-title .vcard .photo {
309          float:left;
310          display:inline;
311      margin-right:11px;
312      margin-bottom:11px
313          }
314      .entry-title {
315      margin-bottom:11px;
316      }
317          .entry-title p.entry-content {
318          display:inline;
319      margin-left:5px;
320          }
321
322      div.entry-content {
323      clear:both;
324      }
325          div.entry-content dl,
326          div.entry-content dt,
327          div.entry-content dd {
328          display:inline;
329      text-transform:lowercase;
330          }
331
332          div.entry-content dd,
333      div.entry-content .device dt {
334      margin-left:0;
335      margin-right:5px;
336          }
337          div.entry-content dl.timestamp dt,
338      div.entry-content dl.response dt {
339          display:none;
340          }
341          div.entry-content dd a {
342          display:inline-block;
343          }
344
345      #facebook_statusnet_app {
346      text-indent:-9999px;
347      height:16px;
348      width:16px;
349      display:block;
350      background:url('.$icon_url.') no-repeat 0 0;
351      float:right;
352      }
353          </style>';
354
355         $this->xw->openMemory();
356
357         $item = new FacebookProfileBoxNotice($notice, $this);
358         $item->show();
359
360         $fbml = "<fb:wide>$style " . $this->xw->outputMemory(false) . "</fb:wide>";
361         $fbml .= "<fb:narrow>$style " . $this->xw->outputMemory(false) . "</fb:narrow>";
362
363         $fbml_main = "<fb:narrow>$style " . $this->xw->outputMemory(false) . "</fb:narrow>";
364
365         $this->facebook->api_client->profile_setFBML(null, $this->fbuid, $fbml, null, null, $fbml_main);
366
367         $this->xw->openURI('php://output');
368     }
369
370     /**
371      * Generate pagination links
372      *
373      * @param boolean $have_before is there something before?
374      * @param boolean $have_after  is there something after?
375      * @param integer $page        current page
376      * @param string  $action      current action
377      * @param array   $args        rest of query arguments
378      *
379      * @return nothing
380      */
381     function pagination($have_before, $have_after, $page, $action, $args=null)
382     {
383         // Does a little before-after block for next/prev page
384         if ($have_before || $have_after) {
385             $this->elementStart('dl', 'pagination');
386             $this->element('dt', null, _m('Pagination'));
387             $this->elementStart('dd', null);
388             $this->elementStart('ul', array('class' => 'nav'));
389         }
390         if ($have_before) {
391             $pargs   = array('page' => $page-1);
392             $newargs = $args ? array_merge($args, $pargs) : $pargs;
393             $this->elementStart('li', array('class' => 'nav_prev'));
394             $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'prev'),
395                            _m('After'));
396             $this->elementEnd('li');
397         }
398         if ($have_after) {
399             $pargs   = array('page' => $page+1);
400             $newargs = $args ? array_merge($args, $pargs) : $pargs;
401             $this->elementStart('li', array('class' => 'nav_next'));
402             $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'next'),
403                            _m('Before'));
404             $this->elementEnd('li');
405         }
406         if ($have_before || $have_after) {
407             $this->elementEnd('ul');
408             $this->elementEnd('dd');
409             $this->elementEnd('dl');
410         }
411     }
412
413     function saveNewNotice()
414     {
415
416         $user = $this->flink->getUser();
417
418         $content = $this->trimmed('status_textarea');
419
420         if (!$content) {
421             $this->showPage(_m('No notice content!'));
422             return;
423         } else {
424             $content_shortened = common_shorten_links($content);
425
426             if (Notice::contentTooLong($content_shortened)) {
427                 $this->showPage(sprintf(_m('That\'s too long. Max notice size is %d chars.'),
428                                         Notice::maxContent()));
429                 return;
430             }
431         }
432
433         $inter = new CommandInterpreter();
434
435         $cmd = $inter->handle_command($user, $content_shortened);
436
437         if ($cmd) {
438
439             // XXX fix this
440
441             $cmd->execute(new WebChannel());
442             return;
443         }
444
445         $replyto = $this->trimmed('inreplyto');
446
447         try {
448             $notice = Notice::saveNew($user->id, $content, 'web',
449                                       array('reply_to' => ($replyto == 'false') ? null : $replyto));
450
451         } catch (Exception $e) {
452             $this->showPage($e->getMessage());
453             return;
454         }
455
456         common_broadcast_notice($notice);
457
458         // Also update the user's Facebook status
459         facebookBroadcastNotice($notice);
460
461     }
462
463 }
464
465 class FacebookNoticeList extends NoticeList
466 {
467
468     /**
469      * constructor
470      *
471      * @param Notice $notice stream of notices from DB_DataObject
472      */
473
474     function __construct($notice, $out=null)
475     {
476         parent::__construct($notice, $out);
477     }
478
479     /**
480      * show the list of notices
481      *
482      * "Uses up" the stream by looping through it. So, probably can't
483      * be called twice on the same list.
484      *
485      * @return int count of notices listed.
486      */
487
488     function show()
489     {
490         $this->out->elementStart('div', array('id' =>'notices_primary'));
491         $this->out->element('h2', null, _m('Notices'));
492         $this->out->elementStart('ul', array('class' => 'notices'));
493
494         $cnt = 0;
495
496         while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
497             $cnt++;
498
499             if ($cnt > NOTICES_PER_PAGE) {
500                 break;
501             }
502
503             $item = $this->newListItem($this->notice);
504             $item->show();
505         }
506
507         $this->out->elementEnd('ul');
508         $this->out->elementEnd('div');
509
510         return $cnt;
511     }
512
513     /**
514      * returns a new list item for the current notice
515      *
516      * Overridden to return a Facebook specific list item.
517      *
518      * @param Notice $notice the current notice
519      *
520      * @return FacebookNoticeListItem a list item for displaying the notice
521      * formatted for display in the Facebook App.
522      */
523
524     function newListItem($notice)
525     {
526         return new FacebookNoticeListItem($notice, $this);
527     }
528
529 }
530
531 class FacebookNoticeListItem extends NoticeListItem
532 {
533
534     /**
535      * constructor
536      *
537      * Also initializes the profile attribute.
538      *
539      * @param Notice $notice The notice we'll display
540      */
541
542     function __construct($notice, $out=null)
543     {
544         parent::__construct($notice, $out);
545     }
546
547     /**
548      * recipe function for displaying a single notice in the Facebook App.
549      *
550      * Overridden to strip out some of the controls that we don't
551      * want to be available.
552      *
553      * @return void
554      */
555
556     function show()
557     {
558         $this->showStart();
559         $this->showNotice();
560         $this->showNoticeInfo();
561
562         // XXX: Need to update to show attachements and controls
563
564         $this->showEnd();
565     }
566
567 }
568
569 class FacebookProfileBoxNotice extends FacebookNoticeListItem
570 {
571
572     /**
573      * constructor
574      *
575      * Also initializes the profile attribute.
576      *
577      * @param Notice $notice The notice we'll display
578      */
579
580     function __construct($notice, $out=null)
581     {
582         parent::__construct($notice, $out);
583     }
584
585     /**
586      * Recipe function for displaying a single notice in the
587      * Facebook App profile notice box
588      *
589      * @return void
590      */
591
592     function show()
593     {
594         $this->showNotice();
595         $this->showNoticeInfo();
596         $this->showAppLink();
597     }
598
599     function showAppLink()
600     {
601
602         $this->facebook = getFacebook();
603
604         $app_props = $this->facebook->api_client->Admin_getAppProperties(
605                 array('canvas_name', 'application_name'));
606
607         $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
608         $this->app_name = $app_props['application_name'];
609
610         $this->out->elementStart('a', array('id' => 'facebook_statusnet_app',
611                                             'href' => $this->app_uri));
612         $this->out->text($this->app_name);
613         $this->out->elementEnd('a');
614     }
615
616 }