]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/showstream.php
c31bce87aba6bfbb967fcae90766febd2cacba7b
[quix0rs-gnu-social.git] / actions / showstream.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/stream.php');
23
24 define('SUBSCRIPTIONS_PER_ROW', 4);
25 define('SUBSCRIPTIONS', 80);
26
27 class ShowstreamAction extends StreamAction {
28
29     function handle($args)
30     {
31
32         parent::handle($args);
33
34         $nickname_arg = $this->arg('nickname');
35         $nickname = common_canonical_nickname($nickname_arg);
36
37         # Permanent redirect on non-canonical nickname
38
39         if ($nickname_arg != $nickname) {
40             $args = array('nickname' => $nickname);
41             if ($this->arg('page') && $this->arg('page') != 1) {
42                 $args['page'] = $this->arg['page'];
43             }
44             common_redirect(common_local_url('showstream', $args), 301);
45             return;
46         }
47
48         $user = User::staticGet('nickname', $nickname);
49
50         if (!$user) {
51             $this->no_such_user();
52             return;
53         }
54
55         $profile = $user->getProfile();
56
57         if (!$profile) {
58             common_server_error(_('User has no profile.'));
59             return;
60         }
61
62         # Looks like we're good; start output
63
64         # For YADIS discovery, we also have a <meta> tag
65
66         header('X-XRDS-Location: '. common_local_url('xrds', array('nickname' =>
67                                                                    $user->nickname)));
68
69         common_show_header($profile->nickname,
70                            array($this, 'show_header'), $user,
71                            array($this, 'show_top'));
72
73         $this->show_profile($profile);
74
75         $this->show_notices($user);
76
77         common_show_footer();
78     }
79
80     function show_top($user)
81     {
82         $cur = common_current_user();
83
84         if ($cur && $cur->id == $user->id) {
85             common_notice_form('showstream');
86         }
87
88         $this->views_menu();
89
90         $this->show_feeds_list(array(0=>array('href'=>common_local_url('userrss', array('nickname' => $user->nickname)),
91                                               'type' => 'rss',
92                                               'version' => 'RSS 1.0',
93                                               'item' => 'notices'),
94                                      1=>array('href'=>common_local_url('usertimeline', array('nickname' => $user->nickname)),
95                                               'type' => 'atom',
96                                               'version' => 'Atom 1.0',
97                                               'item' => 'usertimeline'),
98
99                                      2=>array('href'=>common_local_url('foaf',array('nickname' => $user->nickname)),
100                                               'type' => 'rdf',
101                                               'version' => 'FOAF',
102                                               'item' => 'foaf')));
103     }
104
105     function show_header($user)
106     {
107         # Feeds
108         common_element('link', array('rel' => 'alternate',
109                                      'href' => common_local_url('api',
110                                                                 array('apiaction' => 'statuses',
111                                                                       'method' => 'user_timeline.rss',
112                                                                       'argument' => $user->nickname)),
113                                      'type' => 'application/rss+xml',
114                                      'title' => sprintf(_('Notice feed for %s'), $user->nickname)));
115         common_element('link', array('rel' => 'alternate feed',
116                                      'href' => common_local_url('api',
117                                                                 array('apiaction' => 'statuses',
118                                                                       'method' => 'user_timeline.atom',
119                                                                       'argument' => $user->nickname)),
120                                      'type' => 'application/atom+xml',
121                                      'title' => sprintf(_('Notice feed for %s'), $user->nickname)));
122         common_element('link', array('rel' => 'alternate',
123                                      'href' => common_local_url('userrss', array('nickname' =>
124                                                                                $user->nickname)),
125                                      'type' => 'application/rdf+xml',
126                                      'title' => sprintf(_('Notice feed for %s'), $user->nickname)));
127         # FOAF
128         common_element('link', array('rel' => 'meta',
129                                      'href' => common_local_url('foaf', array('nickname' =>
130                                                                               $user->nickname)),
131                                      'type' => 'application/rdf+xml',
132                                      'title' => 'FOAF'));
133         # for remote subscriptions etc.
134         common_element('meta', array('http-equiv' => 'X-XRDS-Location',
135                                      'content' => common_local_url('xrds', array('nickname' =>
136                                                                                $user->nickname))));
137         $profile = $user->getProfile();
138         if ($profile->bio) {
139             common_element('meta', array('name' => 'description',
140                                          'content' => $profile->bio));
141         }
142
143         if ($user->emailmicroid && $user->email && $profile->profileurl) {
144             common_element('meta', array('name' => 'microid',
145                                          'content' => "mailto+http:sha1:" . sha1(sha1('mailto:' . $user->email) . sha1($profile->profileurl))));
146         }
147         if ($user->jabbermicroid && $user->jabber && $profile->profileurl) {
148             common_element('meta', array('name' => 'microid',
149                                          'content' => "xmpp+http:sha1:" . sha1(sha1('xmpp:' . $user->jabber) . sha1($profile->profileurl))));
150         }
151
152         # See https://wiki.mozilla.org/Microsummaries
153
154         common_element('link', array('rel' => 'microsummary',
155                                      'href' => common_local_url('microsummary',
156                                                                 array('nickname' => $profile->nickname))));
157     }
158
159     function no_such_user()
160     {
161         $this->client_error(_('No such user.'), 404);
162     }
163
164     function show_profile($profile)
165     {
166
167         common_element_start('div', array('id' => 'profile', 'class' => 'vcard'));
168
169         $this->show_personal($profile);
170
171         $this->show_last_notice($profile);
172
173         $cur = common_current_user();
174
175         $this->show_subscriptions($profile);
176
177         common_element_end('div');
178     }
179
180     function show_personal($profile)
181     {
182
183         $avatar = $profile->getAvatar(AVATAR_PROFILE_SIZE);
184         common_element_start('div', array('id' => 'profile_avatar'));
185         common_element('img', array('src' => ($avatar) ? common_avatar_display_url($avatar) : common_default_avatar(AVATAR_PROFILE_SIZE),
186                                     'class' => 'avatar profile photo',
187                                     'width' => AVATAR_PROFILE_SIZE,
188                                     'height' => AVATAR_PROFILE_SIZE,
189                                     'alt' => $profile->nickname));
190
191         common_element_start('ul', array('id' => 'profile_actions'));
192
193         common_element_start('li', array('id' => 'profile_subscribe'));
194         $cur = common_current_user();
195         if ($cur) {
196             if ($cur->id != $profile->id) {
197                 if ($cur->isSubscribed($profile)) {
198                     common_unsubscribe_form($profile);
199                 } else {
200                     common_subscribe_form($profile);
201                 }
202             }
203         } else {
204             $this->show_remote_subscribe_link($profile);
205         }
206         common_element_end('li');
207
208         $user = User::staticGet('id', $profile->id);
209         common_profile_new_message_nudge($cur, $user, $profile);
210
211         if ($cur && $cur->id != $profile->id) {
212             $blocked = $cur->hasBlocked($profile);
213             common_element_start('li', array('id' => 'profile_block'));
214             if ($blocked) {
215                 common_unblock_form($profile, array('action' => 'showstream',
216                                                     'nickname' => $profile->nickname));
217             } else {
218                 common_block_form($profile, array('action' => 'showstream',
219                                                   'nickname' => $profile->nickname));
220             }
221             common_element_end('li');
222         }
223
224         common_element_end('ul');
225
226         common_element_end('div');
227
228         common_element_start('div', array('id' => 'profile_information'));
229
230         if ($profile->fullname) {
231             common_element('h1', array('class' => 'fn'), $profile->fullname . ' (' . $profile->nickname . ')');
232         } else {
233             common_element('h1', array('class' => 'fn nickname'), $profile->nickname);
234         }
235
236         if ($profile->location) {
237             common_element('p', 'location', $profile->location);
238         }
239         if ($profile->bio) {
240             common_element('p', 'description note', $profile->bio);
241         }
242         if ($profile->homepage) {
243             common_element_start('p', 'website');
244             common_element('a', array('href' => $profile->homepage,
245                                       'rel' => 'me', 'class' => 'url'),
246                            $profile->homepage);
247             common_element_end('p');
248         }
249
250         $this->show_statistics($profile);
251
252         common_element_end('div');
253     }
254
255     function show_remote_subscribe_link($profile)
256     {
257         $url = common_local_url('remotesubscribe',
258                                 array('nickname' => $profile->nickname));
259         common_element('a', array('href' => $url,
260                                   'id' => 'remotesubscribe'),
261                        _('Subscribe'));
262     }
263
264     function show_unsubscribe_form($profile)
265     {
266         common_element_start('form', array('id' => 'unsubscribe', 'method' => 'post',
267                                            'action' => common_local_url('unsubscribe')));
268         common_hidden('token', common_session_token());
269         common_element('input', array('id' => 'unsubscribeto',
270                                       'name' => 'unsubscribeto',
271                                       'type' => 'hidden',
272                                       'value' => $profile->nickname));
273         common_element('input', array('type' => 'submit',
274                                       'class' => 'submit',
275                                       'value' => _('Unsubscribe')));
276         common_element_end('form');
277     }
278
279     function show_subscriptions($profile)
280     {
281         global $config;
282
283         $subs = DB_DataObject::factory('subscription');
284         $subs->subscriber = $profile->id;
285         $subs->whereAdd('subscribed != ' . $profile->id);
286
287         $subs->orderBy('created DESC');
288
289         # We ask for an extra one to know if we need to do another page
290
291         $subs->limit(0, SUBSCRIPTIONS + 1);
292
293         $subs_count = $subs->find();
294
295         common_element_start('div', array('id' => 'subscriptions'));
296
297         common_element('h2', null, _('Subscriptions'));
298
299         if ($subs_count > 0) {
300
301             common_element_start('ul', array('id' => 'subscriptions_avatars'));
302
303             for ($i = 0; $i < min($subs_count, SUBSCRIPTIONS); $i++) {
304
305                 if (!$subs->fetch()) {
306                     common_debug('Weirdly, broke out of subscriptions loop early', __FILE__);
307                     break;
308                 }
309
310                 $other = Profile::staticGet($subs->subscribed);
311
312                 if (!$other) {
313                     common_log_db_error($subs, 'SELECT', __FILE__);
314                     continue;
315                 }
316
317                 common_element_start('li', 'vcard');
318                 common_element_start('a', array('title' => ($other->fullname) ?
319                                                 $other->fullname :
320                                                 $other->nickname,
321                                                 'href' => $other->profileurl,
322                                                 'rel' => 'contact',
323                                                  'class' => 'subscription fn url'));
324                 $avatar = $other->getAvatar(AVATAR_MINI_SIZE);
325                 common_element('img', array('src' => (($avatar) ? common_avatar_display_url($avatar) :  common_default_avatar(AVATAR_MINI_SIZE)),
326                                             'width' => AVATAR_MINI_SIZE,
327                                             'height' => AVATAR_MINI_SIZE,
328                                             'class' => 'avatar mini photo',
329                                             'alt' =>  ($other->fullname) ?
330                                             $other->fullname :
331                                             $other->nickname));
332                 common_element_end('a');
333                 common_element_end('li');
334             }
335
336             common_element_end('ul');
337         }
338
339         if ($subs_count > SUBSCRIPTIONS) {
340             common_element_start('p', array('id' => 'subscriptions_viewall'));
341
342             common_element('a', array('href' => common_local_url('subscriptions',
343                                                                  array('nickname' => $profile->nickname)),
344                                       'class' => 'moresubscriptions'),
345                            _('All subscriptions'));
346             common_element_end('p');
347         }
348
349         common_element_end('div');
350     }
351
352     function show_statistics($profile)
353     {
354
355         // XXX: WORM cache this
356         $subs = DB_DataObject::factory('subscription');
357         $subs->subscriber = $profile->id;
358         $subs_count = (int) $subs->count() - 1;
359
360         $subbed = DB_DataObject::factory('subscription');
361         $subbed->subscribed = $profile->id;
362         $subbed_count = (int) $subbed->count() - 1;
363
364         $notices = DB_DataObject::factory('notice');
365         $notices->profile_id = $profile->id;
366         $notice_count = (int) $notices->count();
367
368         common_element_start('div', 'statistics');
369         common_element('h2', 'statistics', _('Statistics'));
370
371         # Other stats...?
372         common_element_start('dl', 'statistics');
373         common_element('dt', 'membersince', _('Member since'));
374         common_element('dd', 'membersince', date('j M Y',
375                                                  strtotime($profile->created)));
376
377         common_element_start('dt', 'subscriptions');
378         common_element('a', array('href' => common_local_url('subscriptions',
379                                                              array('nickname' => $profile->nickname))),
380                        _('Subscriptions'));
381         common_element_end('dt');
382         common_element('dd', 'subscriptions', (is_int($subs_count)) ? $subs_count : '0');
383         common_element_start('dt', 'subscribers');
384         common_element('a', array('href' => common_local_url('subscribers',
385                                                              array('nickname' => $profile->nickname))),
386                        _('Subscribers'));
387         common_element_end('dt');
388         common_element('dd', 'subscribers', (is_int($subbed_count)) ? $subbed_count : '0');
389         common_element('dt', 'notices', _('Notices'));
390         common_element('dd', 'notices', (is_int($notice_count)) ? $notice_count : '0');
391         # XXX: link these to something
392         common_element('dt', 'tags', _('Tags'));
393         common_element_start('dd', 'tags');
394         $tags = Profile_tag::getTags($profile->id, $profile->id);
395
396         common_element_start('ul', 'tags xoxo');
397         foreach ($tags as $tag) {
398             common_element_start('li');
399             common_element('a', array('rel' => 'bookmark tag',
400                                       'href' => common_local_url('peopletag',
401                                                                  array('tag' => $tag))),
402                            $tag);
403             common_element_end('li');
404         }
405         common_element_end('ul');
406         common_element_end('dd');
407
408         common_element_end('dl');
409
410         common_element_end('div');
411     }
412
413     function show_notices($user)
414     {
415
416         $page = ($this->arg('page')) ? ($this->arg('page')+0) : 1;
417
418         $notice = $user->getNotices(($page-1)*NOTICES_PER_PAGE, NOTICES_PER_PAGE + 1);
419
420         $pnl = new ProfileNoticeList($notice);
421         $cnt = $pnl->show();
422
423         common_pagination($page>1, $cnt>NOTICES_PER_PAGE, $page,
424                           'showstream', array('nickname' => $user->nickname));
425     }
426
427     function show_last_notice($profile)
428     {
429
430         common_element('h2', null, _('Currently'));
431
432         $notice = $profile->getCurrentNotice();
433
434         if ($notice) {
435             # FIXME: URL, image, video, audio
436             common_element_start('p', array('class' => 'notice_current'));
437             if ($notice->rendered) {
438                 common_raw($notice->rendered);
439             } else {
440                 # XXX: may be some uncooked notices in the DB,
441                 # we cook them right now. This can probably disappear in future
442                 # versions (>> 0.4.x)
443                 common_raw(common_render_content($notice->content, $notice));
444             }
445             common_element_end('p');
446         }
447     }
448 }
449
450 # We don't show the author for a profile, since we already know who it is!
451
452 class ProfileNoticeList extends NoticeList {
453     function newListItem($notice)
454     {
455         return new ProfileNoticeListItem($notice);
456     }
457 }
458
459 class ProfileNoticeListItem extends NoticeListItem {
460     function showAuthor()
461     {
462         return;
463     }
464 }