]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Facebook/facebookaction.php
some formatting changes to make inblobs work
[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 . '/lib/noticeform.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 FacebookNoticeForm extends NoticeForm
466 {
467
468     var $post_action = null;
469
470     /**
471      * Constructor
472      *
473      * @param HTMLOutputter $out     output channel
474      * @param string        $action  action to return to, if any
475      * @param string        $content content to pre-fill
476      */
477
478     function __construct($out=null, $action=null, $content=null,
479         $post_action=null, $user=null)
480     {
481         parent::__construct($out, $action, $content, $user);
482         $this->post_action = $post_action;
483     }
484
485     /**
486      * Action of the form
487      *
488      * @return string URL of the action
489      */
490
491     function action()
492     {
493         return $this->post_action;
494     }
495
496 }
497
498 class FacebookNoticeList extends NoticeList
499 {
500
501     /**
502      * constructor
503      *
504      * @param Notice $notice stream of notices from DB_DataObject
505      */
506
507     function __construct($notice, $out=null)
508     {
509         parent::__construct($notice, $out);
510     }
511
512     /**
513      * show the list of notices
514      *
515      * "Uses up" the stream by looping through it. So, probably can't
516      * be called twice on the same list.
517      *
518      * @return int count of notices listed.
519      */
520
521     function show()
522     {
523         $this->out->elementStart('div', array('id' =>'notices_primary'));
524         $this->out->element('h2', null, _m('Notices'));
525         $this->out->elementStart('ul', array('class' => 'notices'));
526
527         $cnt = 0;
528
529         while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
530             $cnt++;
531
532             if ($cnt > NOTICES_PER_PAGE) {
533                 break;
534             }
535
536             $item = $this->newListItem($this->notice);
537             $item->show();
538         }
539
540         $this->out->elementEnd('ul');
541         $this->out->elementEnd('div');
542
543         return $cnt;
544     }
545
546     /**
547      * returns a new list item for the current notice
548      *
549      * Overridden to return a Facebook specific list item.
550      *
551      * @param Notice $notice the current notice
552      *
553      * @return FacebookNoticeListItem a list item for displaying the notice
554      * formatted for display in the Facebook App.
555      */
556
557     function newListItem($notice)
558     {
559         return new FacebookNoticeListItem($notice, $this);
560     }
561
562 }
563
564 class FacebookNoticeListItem extends NoticeListItem
565 {
566
567     /**
568      * constructor
569      *
570      * Also initializes the profile attribute.
571      *
572      * @param Notice $notice The notice we'll display
573      */
574
575     function __construct($notice, $out=null)
576     {
577         parent::__construct($notice, $out);
578     }
579
580     /**
581      * recipe function for displaying a single notice in the Facebook App.
582      *
583      * Overridden to strip out some of the controls that we don't
584      * want to be available.
585      *
586      * @return void
587      */
588
589     function show()
590     {
591         $this->showStart();
592         $this->showNotice();
593         $this->showNoticeInfo();
594
595         // XXX: Need to update to show attachements and controls
596
597         $this->showEnd();
598     }
599
600 }
601
602 class FacebookProfileBoxNotice extends FacebookNoticeListItem
603 {
604
605     /**
606      * constructor
607      *
608      * Also initializes the profile attribute.
609      *
610      * @param Notice $notice The notice we'll display
611      */
612
613     function __construct($notice, $out=null)
614     {
615         parent::__construct($notice, $out);
616     }
617
618     /**
619      * Recipe function for displaying a single notice in the
620      * Facebook App profile notice box
621      *
622      * @return void
623      */
624
625     function show()
626     {
627         $this->showNotice();
628         $this->showNoticeInfo();
629         $this->showAppLink();
630     }
631
632     function showAppLink()
633     {
634
635         $this->facebook = getFacebook();
636
637         $app_props = $this->facebook->api_client->Admin_getAppProperties(
638                 array('canvas_name', 'application_name'));
639
640         $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
641         $this->app_name = $app_props['application_name'];
642
643         $this->out->elementStart('a', array('id' => 'facebook_statusnet_app',
644                                             'href' => $this->app_uri));
645         $this->out->text($this->app_name);
646         $this->out->elementEnd('a');
647     }
648
649 }