LJSUP-17669: Login.bml form refactoring
[livejournal.git] / cgi-bin / LJ / SiteScheme.pm
blobb9d03d8cb3aabdd47cfdd7b0fe66fa32c08227df
1 package LJ::SiteScheme;
3 use strict;
4 use warnings;
6 # Internal modules
7 use LJ::Lang qw( ml );
8 use LJ::Auth::Challenge;
9 use LJ::Widget::SGMessages;
10 use LJ::User::FriendInvites;
12 my %CODE_TO_CLASS_MAP;
14 ### PARENT CLASS FUNCTIONS ###
15 sub render_page {
16 my ( $class, $args ) = @_;
18 my $handler;
20 if ( $class eq __PACKAGE__ ) {
21 $handler = $class->find_handler;
22 } else {
23 $handler = $class;
26 $handler->need_res;
28 my $filename = "$ENV{'LJHOME'}/templates/SiteScheme/"
29 . $handler->template_filename . '.tmpl';
31 LJ::need_var( 'scheme' => $handler->code );
33 # cast all keys to lowercase because uppercase everywhere is creepy
34 my $args_normalized = {};
35 foreach my $k ( keys %$args ) {
36 $args_normalized->{ lc $k } = $args->{$k};
39 my $params = $handler->template_params($args_normalized);
41 if ( LJ::is_web_context() ) {
42 LJ::Request->notes ( using_site_scheme => 1 );
43 $params->{'lj_res_in_bottom'} = $args->{'lj_res_in_bottom'} || (LJ::Request->get_param('res_bottom') ? 1 : 0);
44 $params->{'lj_res_includes'} = LJ::res_includes({ no_sitewide_css => $params->{'no_sitewide_css'} });
45 $params->{'lj_res_includes_basic'} = LJ::res_includes({ only_needed => 1 });
46 $params->{'lj_res_templates'} = LJ::res_includes({ only_needed => 1, only_tmpl => 1 });
47 $params->{'lj_res_includes_css'} = LJ::res_includes({ only_css => 1, no_sitewide_css => $params->{'no_sitewide_css'} });
48 $params->{'lj_res_includes_js'} = LJ::res_includes({ only_js => 1, no_sitewide_css => $params->{'no_sitewide_css'} });
51 my $template = LJ::HTML::Template->new( { 'use_expr' => 1 },
52 'filename' => $filename, );
54 $template->param(%$params);
56 return $template->output;
59 sub find_handler {
60 my ($class) = @_;
62 my $usescheme = LJ::Request->get_param('usescheme');
64 return $class->handler_from_code('schemius')
65 if LJ::is_enabled('schemius');
67 return $class->handler_from_code($usescheme) || $class->handler_from_code('schemius')
68 if LJ::is_enabled('schemius_with_usescheme');
70 my @candidate_codes = (
71 LJ::Request->notes('bml_use_scheme'),
72 LJ::run_hook('force_scheme'),
73 $usescheme,
74 LJ::Request->cookie('BMLschemepref'),
75 LJ::run_hook('default_scheme'),
76 'lynx',
79 foreach my $code (@candidate_codes) {
80 next unless defined $code;
82 my $handler = $class->handler_from_code($code);
83 next unless defined $handler;
85 return $handler;
88 # this shouldn never happen because we always have lynx
89 die 'no scheme found';
92 sub handler_from_code {
93 my ( $class, $code ) = @_;
95 return undef unless $code;
96 return $CODE_TO_CLASS_MAP{$code};
99 ### PARENT CLASS UTILITY FUNCTIONS ###
101 sub template_param_breadcrumbs {
102 my ($class) = @_;
104 my @crumbs = LJ::get_crumb_path();
105 return [] unless @crumbs;
107 my @ret;
108 my $count = 0;
109 foreach my $crumb (@crumbs) {
110 my ( $name, $link, $parent, $type ) = @$crumb;
112 # put crumbs together
113 next unless $type; # no blank crumbs
114 if ( $type eq 'dynamic' ) {
115 unshift @ret, { 'is_dynamic' => 1, 'name' => $name };
116 } else {
117 unshift @ret, { 'name' => ml("crumb.$type"), 'link' => $link };
121 return \@ret;
124 sub show_mobile_link {
125 return 0 if LJ::Request->cookie ('hide_mobile_link');
126 return 1 if LJ::is_enabled('view_mobile_link_always');
127 return 1 if Apache::WURFL->is_mobile;
128 return 0;
131 sub lentaru_branding {
132 return 1 if LJ::is_enabled('show_olympic_games_widget_2014');
133 my $time_start = 1391868000; # 08.02.2014 00:00 MSK
134 my $time_end = 1393164000; # 23.02.2014 23:59 MSK
136 return unless time > $time_start && time < $time_end;
138 if ( LJ::get_remote() ) {
139 return LJ::SUP->is_remote_sup();
142 # no remote here
143 my $country = LJ::GeoLocation->get_country_info_by_ip();
145 return unless $country;
146 return $country eq 'RU' || $country eq 'UA' || $country eq 'BY';
149 sub common_template_params {
150 my ( $class, $args ) = @_;
152 my $remote = LJ::get_remote();
153 my $uri = LJ::Request->uri;
155 my $remote_username = '';
156 if ($remote) {
157 $remote_username = $remote->username;
160 my $lj_home = $LJ::SITEROOT;
162 my $favicon = '';
163 if ( my $journal = LJ::get_active_journal() ) {
164 if ( $journal->is_personal ) {
165 ($favicon) = $journal->userhead;
166 $favicon = $LJ::IMGPREFIX . "/" . $favicon
167 unless $favicon =~ m{^http://};
169 if ( $journal->username() eq 'lj_singapore') {
170 $lj_home = 'http://www.livejournal.sg';
174 my $ie8_ie7_compatible = 1;
175 if ( defined $args->{'ie8_ie7_compatible'} &&
176 ! $args->{'ie8_ie7_compatible'} )
178 $ie8_ie7_compatible = 0;
181 my $additional_head_content = '';
182 LJ::run_hooks( 'head_content', \$additional_head_content );
184 my $current_lang = LJ::Lang::current_language();
185 my $html_lang = $LJ::LANG_TO_HTML_LANG{$current_lang} || $current_lang;
187 my @error_list = ();
188 if ( my @errors = @BMLCodeBlock::errors ) {
189 @error_list = map {
190 my $err = LJ::errobj($_);
191 $err->log;
192 my $errstr = $err->as_bullets;
193 { error => $errstr }
194 } grep { $_ } @errors;
197 my $warning_list = '';
198 if ( my @warnings = @BMLCodeBlock::warnings ) {
199 $warning_list = LJ::warning_list(@warnings);
202 my $chalresp_js = '';
203 if ( !LJ::get_remote()
204 && !$LJ::IS_SSL
205 && !$LJ::USE_SSL_LOGIN
206 && !$LJ::REQ_HEAD_HAS{'chalresp_js'}++ )
208 $chalresp_js = $LJ::COMMON_CODE{'chalresp_js'};
211 my $after_bml_title = LJ::run_hook('insert_after_bml_title') || '';
213 my $show_mobile_link = $class->show_mobile_link;
214 my $ml_mobile_link = '';
215 if ($show_mobile_link) {
216 my $uri = '';
218 $uri .= $LJ::IS_SSL ? 'https://' : 'http://';
219 $uri .= LJ::Request->hostname;
220 $uri .= LJ::Request->uri;
222 if ( my $args = LJ::Request->args ) {
223 $uri .= '?' . $args;
226 my $mobile_uri =
227 "http://m.$LJ::DOMAIN/redirect?from=" . LJ::eurl($uri);
229 $ml_mobile_link =
230 ml( 'link.mobile', { 'href' => "href='$mobile_uri'" }, );
233 my $initial_body_html = LJ::initial_body_html();
235 my $site_messages_html = '';
236 if ( LJ::Widget::SiteMessages->should_render ) {
237 $site_messages_html = LJ::Widget::SiteMessages->render;
240 my @navbar = LJ::Nav->navbar($remote);
242 # apparently our HTML::Template doesn't support __index__,
243 # let's provide one ourselves; lanzelot requires this for
244 # drop-downs to work
245 $navbar[$_]->{'idx'} = $_ foreach ( 0 .. $#navbar );
247 my $expresslane_html_comment =
248 LJ::LJcom::expresslane_html_comment($remote);
250 my $remote_logged_in = $remote ? 1 : 0;
251 my $remote_personal = 0;
252 my $remote_identity = 0;
253 my $remote_paid = 0;
254 my $remote_sees_ads = 0;
255 my $logout_link = '';
256 my $remote_sessid = 0;
257 my $remote_userpic_url = '';
258 my $remote_ljuser_display = '';
259 my $remote_display_name = '';
260 my $remote_profile_url = '';
261 my $remote_recent_url = '';
262 my $remote_friends_url = '';
263 my $remote_can_use_esn = 0;
264 my $remote_unread_count = 0;
265 my $remote_wallet_link = 0;
266 my $remote_ljphoto_url = '';
267 my $remote_can_use_ljphoto = 0;
268 my $remote_is_sup = 0;
269 my $remote_invites_count = 0;
270 my $remote_usermsg_count = 0;
272 if ($remote) {
273 my $username = $remote->username;
275 if ( my $session = $remote->session ) {
276 $remote_sessid = $session->id;
277 $logout_link =
278 "$LJ::SITEROOT/logout.bml?user=$username&sessid=$remote_sessid";
279 } else {
280 $logout_link = "$LJ::SITEROOT/logout.bml?user=$username";
283 if ( my $upi = $remote->userpic ) {
284 $remote_userpic_url = $upi->url;
287 my $inbox = $remote->notification_inbox;
289 $remote_personal = $remote->is_personal;
290 $remote_identity = $remote->is_identity;
291 $remote_paid = $remote->get_cap('paid');
292 $remote_sees_ads = $remote->get_cap('ads');
293 $remote_ljuser_display = $remote->ljuser_display;
294 $remote_display_name = $remote->display_name;
295 $remote_profile_url = $remote->profile_url;
296 $remote_recent_url = $remote->journal_base . '/';
297 $remote_friends_url = $remote->journal_base . '/friends/';
298 $remote_can_use_esn = $remote->can_use_esn;
299 $remote_unread_count = $inbox->unread_count;
300 $remote_usermsg_count = $inbox->unread_message_count;
301 $remote_wallet_link = LJ::Pay::Wallet->get_wallet_link($remote);
302 $remote_ljphoto_url = $remote->journal_base . '/pics/';
303 $remote_can_use_ljphoto = $remote->can_use_ljphoto ? 1 : 0;
304 $remote_is_sup = LJ::SUP->is_remote_sup();
305 $remote_invites_count = LJ::User::FriendInvites->count_recv_invites($remote);
308 my $need_loginform = 0;
310 my $loginform_returnto = '';
311 my $loginform_root = '';
312 my $loginform_challenge = '';
313 my $loginform_need_extra_fields = 0;
314 my $loginform_onclick = '';
316 unless ( $remote || $uri eq '/login.bml' || $uri eq '/logout.bml' ) {
317 $need_loginform = 1;
320 # lanzelot doesn't respect need_loginform; i. e. it renders it on
321 # login.bml and logout.bml as well
322 unless ($remote) {
323 $loginform_returnto = LJ::Request->get_param('returnto') || '';
325 if ($LJ::USE_SSL_LOGIN) {
326 $loginform_root = $LJ::SSLROOT;
327 } else {
328 $loginform_root = $LJ::SITEROOT;
329 $loginform_challenge = LJ::Auth::Challenge->generate(300);
330 $loginform_need_extra_fields = 1;
331 $loginform_onclick = "onclick='return sendForm()'";
335 my $dev_banner = '';
336 if ($LJ::IS_DEV_SERVER) {
337 $dev_banner = $LJ::DEV_BANNER;
340 my $pagestats_obj = LJ::pagestats_obj();
341 my $pagestats_html = $pagestats_obj->render;
343 my $before_body_close = '';
344 if ( LJ::get_active_journal() ) {
345 LJ::run_hooks( 'insert_html_before_journalctx_body_close',
346 \$before_body_close, );
349 my $final_body_html = LJ::final_body_html();
351 # ad stuff
352 my ( $ad_beforecrumbs, $ad_aftertitle, $ad_bottom, $ad_beforetitle ) =
353 ( '', '', '', '' );
355 unless ($LJ::IS_SSL) {
356 $ad_beforecrumbs =
357 LJ::get_ads( { 'location' => 'look.top.beforecrumbs' } );
359 $ad_aftertitle =
360 LJ::get_ads( { 'location' => 'look.top.aftertitle' } );
362 $ad_bottom = LJ::get_ads( { 'location' => 'look.bottom' } );
364 $ad_beforetitle =
365 LJ::get_ads( { 'location' => 'look.top.beforetitle' } );
368 # footer stuff
369 my $uri_tos = LJ::run_hook("get_tos_uri")
370 || "$LJ::SITEROOT/legal/tos.bml";
372 my $uri_privacy = LJ::run_hook("get_privacy_uri")
373 || "$LJ::SITEROOT/legal/privacy.bml";
375 my $uri_advertising = LJ::run_hook("get_advertising_url") || "#";
377 my $uri_policy = LJ::run_hook('get_policy_uri')
378 || "$LJ::SITEROOT/abuse/policy.bml";
380 my $uri_volunteer = $LJ::HELPURL{'how_to_help'};
382 my $uri_developers = do {
383 my $lj_dev = LJ::load_user('lj_dev');
384 $lj_dev ? $lj_dev->url : '';
387 my $uri_merchandise = LJ::run_hook('get_merchandise_link')
388 || 'https://www.zazzle.com/livejournal*';
390 my $ml_ljlabs_header = ml(
391 'horizon.footer.ljlabs.header',
392 { 'sitenameabbrev' => $LJ::SITENAMEABBREV },
395 my $ml_ljlabs_aqua =
396 ml( 'horizon.footer.ljlabs.aqua',
397 { 'sitenameabbrev' => $LJ::SITENAMEABBREV },
400 my $ml_ljlabs_dashboard = ml(
401 'horizon.footer.ljlabs.dashboard',
402 { 'sitenameabbrev' => $LJ::SITENAMEABBREV },
405 my $version = LJ::run_hook('current_version_html');
406 my $ml_copyright_header = ml(
407 'horizon.footer.copyright.header_current',
408 { 'current_year' => $LJ::CURRENT_YEAR },
411 ## service page branding (optional)
412 ## see also cgi-bin/LJ/Hooks/Homepage.pm
413 my $branding = LJ::run_hook("service_page_branding", { scheme => $class->code });
415 my $lentaru_branding = lentaru_branding();
416 if ($lentaru_branding) {
417 LJ::need_res(qw{
418 js/jquery/jquery.lj.lentaRu.js
421 LJ::need_string('olympics.widget.full.standings');
422 LJ::need_res_group('popupus');
424 my $json = LJ::API::LentaRu->get_olympics();
425 LJ::need_var(lentaRu => $json->{'result'});
427 $lentaru_branding = 0
428 if ref $json->{'result'}->{'result'}->{'team'} ne 'ARRAY';
431 return {
432 'html_lang' => $html_lang,
433 'pretitle' => $args->{'pretitle'},
434 'title' => $args->{'title'},
435 'windowtitle' => $args->{'windowtitle'} || $args->{'title'},
436 'meta' => $args->{'meta'},
437 'appstore_meta' => $args->{'appstore_meta'},
438 'head' => $args->{'head'},
439 'bodyopts' => $args->{'bodyopts'},
440 'body' => $args->{'body'},
441 'page_is_ssl' => $LJ::IS_SSL ? 1 : 0,
442 'error_list' => \@error_list,
443 'warning_list' => $warning_list,
444 'breadcrumbs' => $class->template_param_breadcrumbs,
445 'index_page' => $args->{'index_page'},
446 'chalresp_js' => $chalresp_js,
447 'after_bml_title' => $after_bml_title,
448 'show_mobile_link' => $show_mobile_link,
449 'ml_mobile_link' => $ml_mobile_link,
450 'initial_body_html' => $initial_body_html,
451 'site_messages_html' => $site_messages_html,
452 'navbar' => \@navbar,
453 'navbar_max_idx' => $#navbar,
454 'server_signature' => $LJ::SERVER_SIGNATURE_BODY,
455 'dev_banner' => $dev_banner,
456 'pagestats_html' => $pagestats_html,
457 'before_body_close' => $before_body_close,
458 'final_body_html' => $final_body_html,
460 'remote_logged_in' => $remote_logged_in,
461 'remote_personal' => $remote_personal,
462 'remote_identity' => $remote_identity,
463 'remote_paid' => $remote_paid,
464 'remote_sees_ads' => $remote_sees_ads,
465 'remote_username' => $remote_username,
466 'remote_sessid' => $remote_sessid,
467 'logout_link' => $logout_link,
468 'remote_userpic_url' => $remote_userpic_url,
469 'remote_ljuser_display' => $remote_ljuser_display,
470 'remote_display_name' => $remote_display_name,
471 'remote_profile_url' => $remote_profile_url,
472 'remote_recent_url' => $remote_recent_url,
473 'remote_friends_url' => $remote_friends_url,
474 'remote_can_use_esn' => $remote_can_use_esn,
475 'remote_unread_count' => $remote_unread_count,
476 'remote_usermsg_count' => $remote_usermsg_count,
477 'remote_wallet_link' => $remote_wallet_link,
478 'remote_ljphoto_url' => $remote_ljphoto_url,
479 'remote_can_use_ljphoto' => $remote_can_use_ljphoto,
480 'remote_is_sup' => $remote_is_sup,
481 'remote_invites_count' => $remote_invites_count,
483 'need_loginform' => $need_loginform,
484 'loginform_returnto' => $loginform_returnto,
485 'loginform_root' => $loginform_root,
486 'loginform_challenge' => $loginform_challenge,
487 'loginform_need_extra_fields' => $loginform_need_extra_fields,
488 'loginform_onclick' => $loginform_onclick,
490 'ie8_ie7_compatible' => $ie8_ie7_compatible,
491 'additional_head_content' => $additional_head_content,
492 'expresslane_html_comment' => $expresslane_html_comment,
493 'server_signature_title' => $LJ::SERVER_SIGNATURE_TITLE || '',
495 'ad_beforecrumbs' => $ad_beforecrumbs,
496 'ad_aftertitle' => $ad_aftertitle,
497 'ad_bottom' => $ad_bottom,
498 'ad_beforetitle' => $ad_beforetitle,
500 'favicon' => $favicon,
502 'uri_tos' => $uri_tos,
503 'uri_privacy' => $uri_privacy,
504 'uri_advertising' => $uri_advertising,
505 'uri_policy' => $uri_policy,
506 'uri_volunteer' => $uri_volunteer,
507 'uri_developers' => $uri_developers,
508 'uri_merchandise' => $uri_merchandise,
509 'ml_ljlabs_header' => $ml_ljlabs_header,
510 'ml_ljlabs_aqua' => $ml_ljlabs_aqua,
511 'ml_ljlabs_dashboard' => $ml_ljlabs_dashboard,
512 'version' => $version,
513 'ml_copyright_header' => $ml_copyright_header,
515 'branding' => $branding,
516 'lentaru_branding' => $lentaru_branding,
517 'random_value' => int(rand(999999999)),
519 'lj_home' => $lj_home,
521 'lj_domain' => $LJ::DOMAIN,
523 'banner_top' => LJ::get_ads({location => 'common.banner'}) || '',
527 ### OVERRIDABLE FUNCTIONS ###
529 sub template_filename {
530 my ($class) = @_;
531 return $class->code;
534 sub code { die 'abstract method'; }
535 sub need_res { die 'abstract method'; }
536 sub template_params { die 'abstract method'; }
538 BEGIN {
539 require LJ::Config;
540 LJ::Config->load;
542 foreach my $class (@LJ::SUPPORTED_SCHEMES_LIST) {
543 my $filename = $class;
544 $filename =~ s{::}{/}g;
545 $filename .= '.pm';
547 require $filename;
548 $CODE_TO_CLASS_MAP{ $class->code } = $class;