4 use Digest
::MD5 qw
/md5_base64/;
6 # loads a page stat tracker
11 conf
=> \
%LJ::PAGESTATS_PLUGIN_CONF
,
19 # render JS output for embedding in pages
20 # ctx can be "journal" or "app". defaults to "app".
23 my ($self, $params) = @_;
25 my $ctx = $self->get_context;
27 return '' unless $self->should_do_pagestats;
30 foreach my $plugin ($self->get_active_plugins) {
31 my $class = "LJ::PageStats::$plugin";
32 eval "use $class; 1;";
33 die "Error loading PageStats '$plugin': $@" if $@
;
34 my $plugin_obj = $class->new;
35 next unless $plugin_obj->should_render;
36 $output .= $plugin_obj->render(conf
=> $self->{conf
}->{$plugin}, params
=> (ref($params) eq 'HASH' ?
$params : {}) );
40 return "<div id='hello-world' style='text-align: left; font-size:0; line-height:0; height:0; overflow:hidden;'>$output</div>";
43 # method on root object (LJ::PageStats instance) to decide if user has optted-out of page
44 # stats tracking, or if it's a bad idea to show one to this user (underage). but
45 # this isn't pagestat-specific logic. that's in the "should_render" method.
46 sub should_do_pagestats
{
49 my $u = $self->get_user;
51 # Make sure the user isn't underage or said no to tracking
52 return 0 if $u && $u->underage;
53 return 0 if $u && $u->prop('opt_exclude_stats');
57 # decide if tracker should be embedded in page
61 my $ctx = $self->get_context;
62 return 0 unless ($ctx && $ctx =~ /^(app|journal)$/);
64 LJ
::Request
->is_inited or return 0;
66 # Make sure we don't exclude tracking from this page or path
67 return 0 if grep { LJ
::Request
->uri =~ /$_/ } @
{ $LJ::PAGESTATS_EXCLUDE
{'uripath'} };
68 return 0 if grep { LJ
::Request
->notes('codepath') eq $_ } @
{ $LJ::PAGESTATS_EXCLUDE
{'codepath'} };
70 # Turned off. AMyshkin
71 # See if their ljuniq cookie has the PageStats flag
72 # if ($BML::COOKIE{'ljuniq'} =~ /[a-zA-Z0-9]{15}:\d+:pgstats([01])/) {
73 # return 0 unless $1; # Don't serve PageStats if it is "pgstats:0"
75 # return 0; # They don't have it set this request, but will for the next one
84 return $self->get_journal() ?
'journal' : 'app';
90 return LJ
::get_remote
();
93 # return Apache request
97 return LJ
::Request
->r;
103 return $LJ::IS_SSL ?
$LJ::SSLROOT
: $LJ::SITEROOT
;
106 sub get_active_plugins
{
109 my $conf = $self->get_conf;
111 return () unless $conf;
113 return @
{$conf->{_active
} || []};
119 return $self->{conf
};
122 sub get_plugin_conf
{
125 my $plugin = ref $self; $plugin =~ s/^LJ::PageStats:://;
127 return $LJ::PAGESTATS_PLUGIN_CONF
{$plugin};
133 my $filename = LJ
::Request
->uri;
141 my $codepath = LJ
::Request
->notes('codepath');
142 # remove 's2.' or 's1.' prefix from codepath
143 $codepath =~ s/^[Ss]\d{1}\.(.*)$/$1/;
145 # map some s1 codepath names to s2
147 'bml.talkpost' => "reply",
148 'bml.talkread' => "entry",
149 'bml.view.index' => "calendar",
152 foreach my $s1code (keys %s1_map) {
153 $codepath = $s1_map{$s1code} if ($codepath =~ /^$s1code$/);
164 if ($self->is_journal_ctx) {
165 $pagename = $self->codepath;
167 $pagename = $self->filename;
176 my $j = LJ
::get_active_journal
();
179 # Now try to determine active_journal from base request if it is requests chain.
180 # Cache it in $self->{active_journal}.
181 # This code is necessary for getting active_journal in 'error-page.bml'.
183 return $self->{active_journal
} if exists $self->{active_journal
};
185 $self->{active_journal
} = undef;
187 if (!LJ
::Request
->is_initial_req())
189 my $request = LJ
::Request
->prev();
190 my $host = $request->header_in('Host');
191 my $uri = $request->uri;
193 if (($LJ::USER_VHOSTS
|| $LJ::ONLY_USER_VHOSTS
) &&
194 $host =~ /^([\w\-]{1,15})\.\Q$LJ::USER_DOMAIN\E$/ &&
199 my $func = $LJ::SUBDOMAIN_FUNCTION
{$user};
201 if ($func eq 'journal' && $uri =~ m!^/(\w{1,15})(/.*)?$!) {
209 my $u = LJ
::load_user
($user);
210 $self->{active_journal
} = $u if $u;
215 return $self->{active_journal
};
221 my $j = $self->get_journal;
223 return $j->journaltype_readable;
229 my $j = $self->get_journal;
231 return $j->journal_base;
236 my $ctx = $self->get_context;
238 return 1 if ($ctx eq 'journal');
242 # not implemented for livejournal
252 my $scheme = BML
::get_scheme
();
253 $scheme = (LJ
::site_schemes
())[0]->{'scheme'} unless $scheme;
261 my $lang = LJ
::Lang
::get_effective_lang
();
269 my $loggedin = $self->get_user ?
'1' : '0';
274 sub campaign_tracking
{
275 my ($self, $opts) = @_;
277 return '' unless $self->should_do_pagestats;
280 foreach my $plugin ($self->get_active_plugins) {
281 my $class = "LJ::PageStats::$plugin";
282 eval "use $class; 1;";
283 die "Error loading PageStats '$plugin': $@" if $@
;
284 my $plugin_obj = $class->new;
285 next unless $plugin_obj->should_render;
286 next unless ($plugin_obj->can('campaign_track_html'));
287 $output .= $plugin_obj->campaign_track_html($opts);
301 if (LJ
::get_cap
($u, 'paid')) {
302 if ($u->in_class('perm')) {
304 } elsif ($u->in_class('sponsored')) {
305 $level = 'sponsored';
309 } elsif ($u->in_class('plus')) {
321 my ($self, $journal) = @_;
323 return 'undef' unless $journal;
324 return LJ
::Request
->notes('codepath') =~ m/^([sS]\d)\./ ?
lc($1) : 'undef';
328 my ($self, $journal) = @_;
330 return 'undef' unless $journal;
332 my $style_system = $self->style_system($journal);
334 if ($style_system eq 's1') {
335 $style_layout = $journal->{'_s1styleid'} && LJ
::S1
::get_style
($journal->{'_s1styleid'})->{'styledes'} || 'own_style';
336 } elsif ($style_system eq 's2') {
337 $style_layout = 'own_style';
338 if ($journal->{'_s2styleid'}) {
339 my %style = LJ
::S2
::get_style
($journal->{'_s2styleid'});
340 $style_layout = defined $style{'layout'} && S2
::get_layer_info
($style{'layout'}, 'name');
341 unless ($style_layout) {
342 LJ
::S2
::load_layers
($style{'layout'});
343 $style_layout = S2
::get_layer_info
($style{'layout'}, 'name') || 'own_style';
344 S2
::unregister_layer
($style{'layout'});
346 } elsif (defined $journal->{'_s2styleid'}) {
347 $style_layout = 'default';
350 $style_layout = 'undef';
353 return $style_layout;
357 my ($self, $journal) = @_;
359 return 'undef' unless $journal;
361 my $remote = LJ
::get_remote
();
362 my $style = LJ
::Request
->get_param('style');
363 my $format = LJ
::Request
->get_param('format') || '';
364 my $stylemine = ($style && $style eq 'mine') ?
1 : 0;
365 my $style_u = $journal;
367 my $comments_style = 's1';
369 my ($stylesys, $styleid);
371 if ($remote && ($stylemine || $remote->opt_stylealwaysmine || $remote->opt_commentsstylemine)) {
375 LJ
::load_user_props
($journal, ("stylesys", "s2_style"));
379 LJ
::run_hooks
("force_s1", $journal, \
$forceflag);
381 if ( not $forceflag and $journal->{'stylesys'} and $journal->{'stylesys'} == 2 ) {
383 $styleid = $journal->{'s2_style'};
389 if ( $stylesys == 2 ) {
390 my $style = LJ
::Customize
->verify_and_load_style ($journal);
391 my $prop_value = undef;
393 my $ctx = LJ
::S2
::s2_context
('UNUSED', $styleid);
394 $LJ::S2
::CURR_CTX
= $ctx;
395 $prop_value = $ctx->[S2
::PROPS
]->{'view_entry_disabled'};
396 warn "Style probably corrupted. User: " . $journal->username;
398 $prop_value = LJ
::MemCache
::get_or_set
(
399 [$journal->userid, "s2prop:".$journal->userid.":view_entry_disabled"],
400 sub { return LJ
::Customize
->get_s2_prop_values ("view_entry_disabled", $journal, $style); },
405 $comments_style = 's2'
406 if (not $prop_value and LJ
::get_cap
($journal, "s2viewentry")) || $LJ::JOURNALS_WITH_FIXED_STYLE
{$journal->user};
409 if ( $format eq 'light' ) {
410 $comments_style = 's1';
413 return $comments_style;
417 return LJ
::Request
->current_page_url() =~ m{^$LJ::SITEROOT(?:/welcome/?|/latest/?|/editors/?|/category/\w+/?)?/?$} ?
1 : 0;
420 sub homepage_category
{
423 my $url = LJ
::Request
->current_page_url();
425 if (my ($cat_pretty_name) = $url =~ m{^$LJ::SITEROOT/category/(\w+)/?$}) {
426 for (@
{LJ
::HomePage
::Category
->get_all_categories}) {
427 return $cat_pretty_name
428 if $cat_pretty_name eq $_->{'pretty_name'};
438 my $remote = LJ
::get_remote
();
441 geotargeting
=> LJ
::PersonalStats
::Ratings
->get_rating_country() || 'undef',
442 unique_items
=> LJ
::User
::HomePage
->homepage_flag ($remote, 'show_unique_items') ?
'show' : 'hide',
443 from_friends
=> LJ
::User
::HomePage
->homepage_flag ($remote, 'show_from_friends') ?
'show' : 'hide',
444 hidden_items
=> LJ
::User
::HomePage
->homepage_flag ($remote, 'show_hidden_items') ?
'show' : 'hide',
451 my $req = !LJ
::Request
->is_initial_req && LJ
::Request
->prev || LJ
::Request
->request;
453 my $host = $req->header_in('Host');
455 my $args = $req->args;
457 $args = "?$args" if $args;
459 # Special requirement from ATI:
460 # The character „&“ should not be used, or encoded two times. O_O
461 $args =~ s/(&)/LJ::eurl($1)/eg;
463 my $url = LJ
::eurl
("$host$uri$args");
467 my $journaltype = $u->journaltype_readable;
468 my $journal_user = $u->user;
470 if ($journaltype eq 'redirect' && (my $renamedto = LJ
::load_user
($u->prop('renamedto')))) {
471 $journaltype = $renamedto->journaltype_readable;
475 userid
=> $u->userid(),
476 stylealwaysmine
=> $u->opt_stylealwaysmine ?
'yes' : 'no',
477 login_service
=> $u->identity ?
$u->identity->short_code : 'lj',
478 sup_enabled
=> LJ
::SUP
->is_sup_enabled($u) ?
'Cyr' : 'nonCyr',
479 premium_package
=> $u->get_cap('perm') ?
'perm' : $u->get_cap('paid') ?
'paid' : 'no',
480 account_level
=> $self->account_level($u),
481 page_params
=> "journal::$journaltype\:\:$journal_user\:\:$url",
482 adult_content
=> $u->adult_content_calculated,
483 early_adopter
=> LJ
::get_cap
($u, 'early') ?
'yes' : 'no',
484 user_md5_base64
=> md5_base64
($u->user, 0, 8),
485 user
=> $journal_user,
486 journaltype
=> $journaltype,
491 my $ip_class = LJ
::GeoLocation
->ip_class();
495 stylealwaysmine
=> 'undef',
496 login_service
=> 'undef',
497 sup_enabled
=> LJ
::SUP
->is_sup_ip_class($ip_class) ?
'Cyr' : 'nonCyr',
498 premium_package
=> 'undef',
499 account_level
=> 'undef',
500 page_params
=> "service::undef::undef::$url",
501 adult_content
=> 'undef',
502 early_adopter
=> 'undef',
503 user_md5_base64
=> 'undef',
505 journaltype
=> 'undef',