]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Facebook/facebookaction.php
1d8b5217b4821e52f128a026d823194baef10584
[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=true, $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' => _('Home')), _('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' => _('Invite')), _('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' => _('Settings')), _('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 = _('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 = _(' 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')), _('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, _('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', _('Nickname'));
269         $this->elementEnd('li');
270         $this->elementStart('li');
271         $this->password('password', _('Password'));
272         $this->elementEnd('li');
273         $this->elementEnd('ul');
274
275         $this->submit('submit', _('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                        _('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('div', array('class' => 'pagination'));
386             $this->elementStart('dl', null);
387             $this->element('dt', null, _('Pagination'));
388             $this->elementStart('dd', null);
389             $this->elementStart('ul', array('class' => 'nav'));
390         }
391         if ($have_before) {
392             $pargs   = array('page' => $page-1);
393             $newargs = $args ? array_merge($args, $pargs) : $pargs;
394             $this->elementStart('li', array('class' => 'nav_prev'));
395             $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'prev'),
396                            _('After'));
397             $this->elementEnd('li');
398         }
399         if ($have_after) {
400             $pargs   = array('page' => $page+1);
401             $newargs = $args ? array_merge($args, $pargs) : $pargs;
402             $this->elementStart('li', array('class' => 'nav_next'));
403             $this->element('a', array('href' => "$this->app_uri/$action?page=$newargs[page]", 'rel' => 'next'),
404                            _('Before'));
405             $this->elementEnd('li');
406         }
407         if ($have_before || $have_after) {
408             $this->elementEnd('ul');
409             $this->elementEnd('dd');
410             $this->elementEnd('dl');
411             $this->elementEnd('div');
412         }
413     }
414
415     function saveNewNotice()
416     {
417
418         $user = $this->flink->getUser();
419
420         $content = $this->trimmed('status_textarea');
421
422         if (!$content) {
423             $this->showPage(_('No notice content!'));
424             return;
425         } else {
426             $content_shortened = common_shorten_links($content);
427
428             if (Notice::contentTooLong($content_shortened)) {
429                 $this->showPage(sprintf(_('That\'s too long. Max notice size is %d chars.'),
430                                         Notice::maxContent()));
431                 return;
432             }
433         }
434
435         $inter = new CommandInterpreter();
436
437         $cmd = $inter->handle_command($user, $content_shortened);
438
439         if ($cmd) {
440
441             // XXX fix this
442
443             $cmd->execute(new WebChannel());
444             return;
445         }
446
447         $replyto = $this->trimmed('inreplyto');
448
449         try {
450             $notice = Notice::saveNew($user->id, $content,
451                                       'web', 1, ($replyto == 'false') ? null : $replyto);
452         } catch (Exception $e) {
453             $this->showPage($e->getMessage());
454             return;
455         }
456
457         common_broadcast_notice($notice);
458
459         // Also update the user's Facebook status
460         facebookBroadcastNotice($notice);
461
462     }
463
464 }
465
466 class FacebookNoticeForm extends NoticeForm
467 {
468
469     var $post_action = null;
470
471     /**
472      * Constructor
473      *
474      * @param HTMLOutputter $out     output channel
475      * @param string        $action  action to return to, if any
476      * @param string        $content content to pre-fill
477      */
478
479     function __construct($out=null, $action=null, $content=null,
480         $post_action=null, $user=null)
481     {
482         parent::__construct($out, $action, $content, $user);
483         $this->post_action = $post_action;
484     }
485
486     /**
487      * Action of the form
488      *
489      * @return string URL of the action
490      */
491
492     function action()
493     {
494         return $this->post_action;
495     }
496
497 }
498
499 class FacebookNoticeList extends NoticeList
500 {
501
502     /**
503      * constructor
504      *
505      * @param Notice $notice stream of notices from DB_DataObject
506      */
507
508     function __construct($notice, $out=null)
509     {
510         parent::__construct($notice, $out);
511     }
512
513     /**
514      * show the list of notices
515      *
516      * "Uses up" the stream by looping through it. So, probably cannot
517      * be called twice on the same list.
518      *
519      * @return int count of notices listed.
520      */
521
522     function show()
523     {
524         $this->out->elementStart('div', array('id' =>'notices_primary'));
525         $this->out->element('h2', null, _('Notices'));
526         $this->out->elementStart('ul', array('class' => 'notices'));
527
528         $cnt = 0;
529
530         while ($this->notice->fetch() && $cnt <= NOTICES_PER_PAGE) {
531             $cnt++;
532
533             if ($cnt > NOTICES_PER_PAGE) {
534                 break;
535             }
536
537             $item = $this->newListItem($this->notice);
538             $item->show();
539         }
540
541         $this->out->elementEnd('ul');
542         $this->out->elementEnd('div');
543
544         return $cnt;
545     }
546
547     /**
548      * returns a new list item for the current notice
549      *
550      * Overridden to return a Facebook specific list item.
551      *
552      * @param Notice $notice the current notice
553      *
554      * @return FacebookNoticeListItem a list item for displaying the notice
555      * formatted for display in the Facebook App.
556      */
557
558     function newListItem($notice)
559     {
560         return new FacebookNoticeListItem($notice, $this);
561     }
562
563 }
564
565 class FacebookNoticeListItem extends NoticeListItem
566 {
567
568     /**
569      * constructor
570      *
571      * Also initializes the profile attribute.
572      *
573      * @param Notice $notice The notice we'll display
574      */
575
576     function __construct($notice, $out=null)
577     {
578         parent::__construct($notice, $out);
579     }
580
581     /**
582      * recipe function for displaying a single notice in the Facebook App.
583      *
584      * Overridden to strip out some of the controls that we don't
585      * want to be available.
586      *
587      * @return void
588      */
589
590     function show()
591     {
592         $this->showStart();
593         $this->showNotice();
594         $this->showNoticeInfo();
595
596         // XXX: Need to update to show attachements and controls
597
598         $this->showEnd();
599     }
600
601 }
602
603 class FacebookProfileBoxNotice extends FacebookNoticeListItem
604 {
605
606     /**
607      * constructor
608      *
609      * Also initializes the profile attribute.
610      *
611      * @param Notice $notice The notice we'll display
612      */
613
614     function __construct($notice, $out=null)
615     {
616         parent::__construct($notice, $out);
617     }
618
619     /**
620      * Recipe function for displaying a single notice in the
621      * Facebook App profile notice box
622      *
623      * @return void
624      */
625
626     function show()
627     {
628         $this->showNotice();
629         $this->showNoticeInfo();
630         $this->showAppLink();
631     }
632
633     function showAppLink()
634     {
635
636         $this->facebook = getFacebook();
637
638         $app_props = $this->facebook->api_client->Admin_getAppProperties(
639                 array('canvas_name', 'application_name'));
640
641         $this->app_uri = 'http://apps.facebook.com/' . $app_props['canvas_name'];
642         $this->app_name = $app_props['application_name'];
643
644         $this->out->elementStart('a', array('id' => 'facebook_statusnet_app',
645                                             'href' => $this->app_uri));
646         $this->out->text($this->app_name);
647         $this->out->elementEnd('a');
648     }
649
650 }