IndexPlWalkthroughNotes: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
| (2 intermediate revisions by the same user not shown) | |||
| Line 1: | Line 1: | ||
[[CssWork]]<br> | [[CssWork]]<br> | ||
[[SlashDocumentationIndex]] | [[SlashDocumentationIndex]] | ||
* Subroutines in index.pl | |||
** sub main | |||
** sub redirect_home_if_necessary | |||
** sub getDispModesForStories | |||
** sub getDispModeForStory | |||
** sub getSidFromRemark | |||
** sub do_rss | |||
** sub saveUserBoxes | |||
** sub upBid | |||
** sub dnBid | |||
** sub rmBid | |||
** sub displayStories | |||
<h2>index.pl</h2> | <h2>index.pl</h2> | ||
| Line 20: | Line 33: | ||
sub main { | sub main { | ||
my $start_time = Time::HiRes::time; | my $start_time = Time::HiRes::time; | ||
my $constants = getCurrentStatic(); | my $constants = getCurrentStatic(); [in slash utility - Environment.pm] | ||
my $user = getCurrentUser(); | my $user = getCurrentUser(); [in slash utility - Environment.pm] | ||
my $form = getCurrentForm(); | my $form = getCurrentForm(); [in slash utility - Environment.pm] | ||
my $slashdb = getCurrentDB(); | my $slashdb = getCurrentDB(); [in slash utility - Environment.pm] | ||
my $reader = getObject('Slash::DB', { db_type => 'reader' }); | my $reader = getObject('Slash::DB', { db_type => 'reader' }); [in slash utility - Environment.pm] | ||
return if redirect_home_if_necessary(); | return if redirect_home_if_necessary(); [subroutine below.] | ||
my($stories, $Stories); # could this be MORE confusing please? kthx | my($stories, $Stories); # could this be MORE confusing please? kthx | ||
# why is this commented out? -- pudge | # why is this commented out? -- pudge | ||
| Line 38: | Line 51: | ||
elsif ($form->{op} eq 'd') { dnBid($form->{bid}) } | elsif ($form->{op} eq 'd') { dnBid($form->{bid}) } | ||
else { rmBid($form->{bid}) } | else { rmBid($form->{bid}) } | ||
redirect($ENV{HTTP_REFERER} || $ENV{SCRIPT_NAME}); | redirect($ENV{HTTP_REFERER} || $ENV{SCRIPT_NAME}); [redirect is in Utility Anchor.pm] | ||
return; | return; | ||
} | } | ||
| Line 409: | Line 422: | ||
@$stories = grep { getDispModeForStory($_, $stories_data_cache->{$_->{stoid}}, \%mp_dispmode_nexus, \%sec_dispmode_nexus, \@story_always_topic, $story_to_dispmode_hr) ne "none" } @$stories; | @$stories = grep { getDispModeForStory($_, $stories_data_cache->{$_->{stoid}}, \%mp_dispmode_nexus, \%sec_dispmode_nexus, \@story_always_topic, $story_to_dispmode_hr) ne "none" } @$stories; | ||
} | } | ||
sub getDispModeForStory { | sub getDispModeForStory { | ||
| Line 460: | Line 472: | ||
} | } | ||
sub getSidFromRemark { | sub getSidFromRemark { | ||
my($remark) = @_; | my($remark) = @_; | ||
Latest revision as of 22:17, 5 March 2014
CssWork
SlashDocumentationIndex
- Subroutines in index.pl
- sub main
- sub redirect_home_if_necessary
- sub getDispModesForStories
- sub getDispModeForStory
- sub getSidFromRemark
- sub do_rss
- sub saveUserBoxes
- sub upBid
- sub dnBid
- sub rmBid
- sub displayStories
index.pl
#!/usr/bin/perl -w
# This code is a part of Slash, and is released under the GPL.
# Copyright 1997-2005 by Open Source Technology Group. See README
# and COPYING for more information, or see http://slashcode.com/.
# $Id$
use strict; [strict type checking ?]
use Slash; [These are the modules whose routines we will use]
use Slash::Display;
use Slash::Utility;
use Slash::XML;
use Time::HiRes;
use Slash::Slashboxes;
sub main {
my $start_time = Time::HiRes::time;
my $constants = getCurrentStatic(); [in slash utility - Environment.pm]
my $user = getCurrentUser(); [in slash utility - Environment.pm]
my $form = getCurrentForm(); [in slash utility - Environment.pm]
my $slashdb = getCurrentDB(); [in slash utility - Environment.pm]
my $reader = getObject('Slash::DB', { db_type => 'reader' }); [in slash utility - Environment.pm]
return if redirect_home_if_necessary(); [subroutine below.]
my($stories, $Stories); # could this be MORE confusing please? kthx
# why is this commented out? -- pudge
# $form->{mode} = $user->{mode} = "dynamic" if $ENV{SCRIPT_NAME};
# Handle moving a block up or down, or removing it.
if ($form->{bid} && $form->{op} && $form->{op} =~ /^[udx]$/) {
if ($form->{op} eq 'u') { upBid($form->{bid}) }
elsif ($form->{op} eq 'd') { dnBid($form->{bid}) }
else { rmBid($form->{bid}) }
redirect($ENV{HTTP_REFERER} || $ENV{SCRIPT_NAME}); [redirect is in Utility Anchor.pm]
return;
}
my $rss = $constants->{rss_allow_index}
&& $form->{content_type} && $form->{content_type} =~ $constants->{feed_types}
&& (
$user->{is_admin}
|| ($constants->{rss_allow_index} > 1 && $user->{is_subscriber})
|| ($constants->{rss_allow_index} > 2 && !$user->{is_anon})
);
# $form->{logtoken} is only allowed if using rss
if ($form->{logtoken} && !$rss) {
redirect($ENV{SCRIPT_NAME});
}
my $skin_name = $form->{section};
my $skid = $skin_name
? $reader->getSkidFromName($skin_name)
: determineCurrentSkin();
setCurrentSkin($skid);
my $gSkin = getCurrentSkin();
$skin_name = $gSkin->{name};
# XXXSKIN I'm turning custom numbers of maxstories off for now, so all
# users get the same number. This will improve query cache hit rates and
# right now we need all the edge we can get. Hopefully we can get this
# back on soon. - Jamie 2004/07/17
# my $user_maxstories = $user->{maxstories};
# my $user_maxstories = getCurrentAnonymousCoward("maxstories");
# Decide what our issue is going to be.
my $limit;
my $issue = $form->{issue} || '';
$issue = '' if $issue !~ /^\d{8}$/;
# if ($issue) {
# if ($user->{is_anon}) {
# $limit = $gSkin->{artcount_max} * 3;
# } else {
# $limit = $user_maxstories * 7;
# }
# } elsif ($user->{is_anon}) {
# $limit = $gSkin->{artcount_max};
# } else {
# $limit = $user_maxstories;
# }
my $gse_hr = { };
# Set the characteristics that stories can be in to appear. This
# is a simple list: the current skin's nexus, and then if the
# current skin is the mainpage, add in the list of nexuses that
# the mainpage needs the user's story_always_topic
# and story_always_nexus tids.
# It's pretty ugly that this duplicates some of the effect of
# getDispModesForStories(). This code really should be
# simplified and consolidated.
$gse_hr->{tid} = [ $gSkin->{nexus} ];
if ($gSkin->{skid} == $constants->{mainpage_skid}) {
# This may or may not be necessary; gSE() should
# already know to do this. But it should not hurt
# to add the tids here.
if ($constants->{brief_sectional_mainpage}) {
my $nexus_children = $reader->getMainpageDisplayableNexuses();
push @{$gse_hr->{tid}}, @$nexus_children;
}
my @extra_tids = split ",", $user->{story_always_topic};
push @extra_tids, split ",", $user->{story_always_nexus};
# Let gse know that we're asking for extra tids beyond
# those expected by default.
if (@extra_tids) {
$gse_hr->{tid_extras} = 1;
push @{$gse_hr->{tid}}, @extra_tids;
}
# Eliminate duplicates and sort.
my %tids = ( map { ($_, 1) } @{$gse_hr->{tid}} );
$gse_hr->{tid} = [ keys %tids ];
}
@{ $gse_hr->{tid} } = sort { $a <=> $b } @{ $gse_hr->{tid} };
# Now exclude characteristics. One tricky thing here is that
# we never exclude the nexus for the current skin -- if the user
# went to foo.sitename.com explicitly, then they're going to see
# stories about foo, regardless of their prefs. Another tricky
# thing is that story_never_topic doesn't get used unless a var
# and/or this user's subscriber status are set a particular way.
my @never_tids = split /,/, $user->{story_never_nexus};
if ($constants->{story_never_topic_allow} == 2
|| ($user->{is_subscriber} && $constants->{story_never_topic_allow} == 1)
) {
push @never_tids, split /,/, $user->{story_never_topic};
}
@never_tids =
grep { /^'?\d+'?$/ && $_ != $gSkin->{nexus} }
@never_tids;
$gse_hr->{tid_exclude} = [ @never_tids ] if @never_tids;
$gse_hr->{uid_exclude} = [ split /,/, $user->{story_never_author} ]
if $user->{story_never_author};
# For now, all users get the same number of maxstories.
# $gse_hr->{limit} = $user_maxstories if $user_maxstories;
$gse_hr->{issue} = $issue if $issue;
my $gse_db = rand(1) < $constants->{index_gse_backup_prob} ? $reader : $slashdb;
$stories = $gse_db->getStoriesEssentials($gse_hr);
# Workaround for a bug in saving/updating. Sometimes a story
# will be saved with neverdisplay=1 but with an incorrect
# story_topics_rendered row that places it in a nexus as well.
# Until we figure out why, there's additional logic here to
# make sure we screen out neverdisplay stories. -Jamie 2007-08-06
my $stoid_in_str = join(',', map { $_->{stoid} } @$stories);
my $nd_hr = { };
if ($stoid_in_str) {
$nd_hr = $gse_db->sqlSelectAllKeyValue('stoid, value',
'story_param',
qq{stoid IN ($stoid_in_str) AND name='neverdisplay' AND value != 0});
if (keys %$nd_hr) {
for my $story_hr (@$stories) {
$story_hr->{neverdisplay} = 1 if $nd_hr->{ $story_hr->{stoid} };
}
}
}
if (grep { $_->{neverdisplay} } @$stories) {
require Data::Dumper; $Data::Dumper::Sortkeys = 1;
my @nd_ids = map { $_->{stoid} } grep { $_->{neverdisplay} } @$stories;
my $gse_str = Data::Dumper::Dumper($gse_hr); $gse_str =~ s/\s+/ /g;
print STDERR scalar(gmtime) . " index.pl ND story '@nd_ids' returned by gSE called with params: '$gse_str'\n";
$stories = [ grep { !$_->{neverdisplay} } @$stories ];
}
# A kludge to keep Politics stories off the mainpage. The
# proper fix would be to redesign story_topics_rendered to
# include a weight in the (stoid,nexus_tid) tuple, and to
# have gSE only select stories from its nexus list with that
# weight or higher. Instead I've been asked to hardcode
# an "offmainpage" boolean at story save time which will be
# checked at story display time. -Jamie 2008-01-25
if ($gSkin->{skid} == $constants->{mainpage_skid}) {
my $om_hr = { };
if ($stoid_in_str) {
$om_hr = $gse_db->sqlSelectAllKeyValue('stoid, value',
'story_param',
qq{stoid IN ($stoid_in_str) AND name='offmainpage' AND value != 0});
if (keys %$om_hr) {
for my $story_hr (@$stories) {
$story_hr->{offmainpage} = 1 if $om_hr->{ $story_hr->{stoid} };
}
}
}
# XXX should only grep a story out if the story has
# NO nexuses that the user has requested appear in
# full on the mainpage
$stories = [ grep { !$_->{offmainpage} } @$stories ];
}
#my $last_mainpage_view;
#$last_mainpage_view = $slashdb->getTime() if $gSkin->{nexus} == $constants->{mainpage_skid} && !$user->{is_anon};
#use Data::Dumper;
#print STDERR "index.pl gse_hr: " . Dumper($gse_hr);
#print STDERR "index.pl gSE stories: " . Dumper($stories);
# We may, in this listing, have a story from the Mysterious Future.
# If so, there are three possibilities:
# 1) This user is a subscriber, in which case they see it (and its
# timestamp gets altered to the MystFu text)
# 2) This user is not a subscriber, but is logged-in, and logged-in
# non-subscribers are allowed to *know* that there is such a
# story without being able to see it, so we make them aware.
# 3) This user is not a subscriber, and non-subscribers are not
# to be made aware of this story's existence, so ignore it.
my $future_plug = 0;
# Is there a story in the Mysterious Future?
my $is_future_story = 0;
$is_future_story = 1 if @$stories # damn you, autovivification!
&& $stories->[0]{is_future};
# Do we want to display the plug saying "there's a future story,
# subscribe and you can see it"? Yes if the user is logged-in
# but not a subscriber, but only if the first story is actually
# in the future. If the user has a daypass, they don't get this
# either. Just check the first story; they're in order.
if ($is_future_story
&& !$user->{is_subscriber}
&& !$user->{has_daypass}
&& !$user->{is_anon}
&& $constants->{subscribe_future_plug}) {
$future_plug = 1;
}
return do_rss($reader, $constants, $user, $form, $stories, $skin_name) if $rss;
# Do we want to display the plug offering the user a daypass?
my $daypass_plug_text = '';
if ($constants->{daypass}) {
# If this var is set, only offer a daypass when there
# is a future story available.
if (!$constants->{daypass_offer_onlywhentmf}
|| $is_future_story) {
my $daypass_db = getObject('Slash::Daypass', { db_type => 'reader' });
my $do_offer = $daypass_db->doOfferDaypass();
if ($do_offer) {
$daypass_plug_text = $daypass_db->getOfferText();
# On days where a daypass is being offered, for
# users who are eligible, we give them that
# message instead of (not in addition to) the
# "please subscribe" message.
$future_plug = 0;
}
}
}
# # See comment in plugins/Journal/journal.pl for its call of
# # getSkinColors() as well.
# $user->{currentSection} = $section->{section};
Slash::Utility::Anchor::getSkinColors();
# displayStories() pops stories off the front of the @$stories array.
# Whatever's left is fed to displaySlashboxes for use in the
# index_more block (aka Older Stuff).
# We really should make displayStories() _return_ the leftover
# stories as well, instead of modifying $stories in place to just
# suddenly mean something else.
my $linkrel = {};
$Stories = displayStories($stories, $linkrel);
# damn you, autovivification!
my($first_date, $last_date);
if (@$stories) {
($first_date, $last_date) = ($stories->[0]{time}, $stories->[-1]{time});
$first_date =~ s/(\d\d\d\d)-(\d\d)-(\d\d).*$/$1$2$3/;
$last_date =~ s/(\d\d\d\d)-(\d\d)-(\d\d).*$/$1$2$3/;
}
my $StandardBlocks = displaySlashboxes($gSkin, $stories,
{ first_date => $first_date, last_date => $last_date }
);
my $title = getData('head', { skin => $skin_name });
header({ title => $title, link => $linkrel }) or return;
if ($form->{remark}
&& $user->{is_subscriber}
&& $form->{sid})
{
my $sid = $form->{sid};
my $story = $slashdb->getStory($sid);
my $remark = $form->{remark};
# If what's pasted in contains a substring that looks
# like a sid, yank it out and just use that.
my $targetsid = getSidFromRemark($remark);
$remark = $targetsid if $targetsid;
if ($story) {
my $remarks = getObject('Slash::Remarks');
$remarks->createRemark($remark, {
uid => $user->{uid},
stoid => $story->{stoid}
});
print getData('remark_thanks');
}
}
my $metamod_elig = 0;
if ($constants->{m2}) {
my $metamod_reader = getObject('Slash::Metamod', { db_type => 'reader' });
$metamod_elig = $metamod_reader->metamodEligible($user);
}
slashDisplay('index', {
metamod_elig => $metamod_elig,
future_plug => $future_plug,
daypass_plug_text => $daypass_plug_text,
stories => $Stories,
boxes => $StandardBlocks,
});
footer();
#$slashdb->setUser($user->{uid}, { 'last_mainpage_view' => $last_mainpage_view }) if $last_mainpage_view;
writeLog($skin_name);
# {
# use Proc::ProcessTable;
# my $t = new Proc::ProcessTable;
# my $procs = $t->table();
# PROC: for my $proc (@$procs) {
# my $pid = $proc->pid();
# next unless $pid == $$;
# my $size = $proc->size();
#
# if ($size > 10_000_000) {
# my $mb = sprintf("%.2f", $size/1_000_000);
# print STDERR "pid $$ VSZ $mb MB: just finished op '$form->{op}' sid '$form->{sid}' issue '$form->{issue}' skid '$gSkin->{skid}' uid '$user->{uid}'\n";
# last PROC;
# }
# }
# }
}
# Slash::Apache::User can turn a "/" request into an index.pl request
# if the user has index_classic set or the user-agent is MSIE 6.
# So, since this already is index.pl, be sure not to redirect to
# "/" if either of those things is true, since that would be an
# infinite redirection loop.
sub redirect_home_if_necessary {
my $user = getCurrentUser();
my $form = getCurrentForm();
my $script = '';
if (!$user->{is_anon} && defined $form->{usebeta}) {
my $usebeta = $form->{usebeta} eq '1';
my $index_classic = $usebeta ? undef : 1;
if ($user->{index_classic} xor $index_classic) {
my $slashdb = getCurrentDB();
$slashdb->setUser($user->{uid}, { index_classic => $index_classic });
$user->{index_classic} = $index_classic;
}
$script = '/' if $usebeta
&& !$form->{content_type}
&& $ENV{HTTP_USER_AGENT} !~ /MSIE [2-6]/;
}
if ( $form->{op} && $form->{op} eq 'userlogin' && !$user->{is_anon}
|| $form->{upasswd}
|| $form->{unickname}
) {
# Any login attempt, successful or not, gets
# redirected to the homepage, to avoid keeping
# the password or nickname in the query_string of
# the URL (this is a security risk via "Referer").
# (If we've determined the user needs to go to
# index2.pl, send them there.) Note that
# $form->{returnto} is processed by
# Slash::Apache::User::handler, which for reasons
# of a mysterious bug defers the actual redirect
# to be handled by this script.
$script = $form->{returnto} || '/';
}
if ($script) {
redirect($script);
return 1;
}
return 0;
}
sub getDispModesForStories {
my($stories, $stories_data_cache, $user, $modes, $story_to_dispmode_hr) = @_;
my @story_always_topic = split (',', $user->{story_always_topic});
my @story_always_nexus = split (',', $user->{story_always_nexus});
my @story_full_brief_nexus = split (',', $user->{story_full_brief_nexus});
my @story_brief_always_nexus = split (',', $user->{story_brief_always_nexus});
my @story_full_best_nexus = split (',', $user->{story_full_best_nexus});
my @story_brief_best_nexus = split (',', $user->{story_brief_best_nexus});
my(%mp_dispmode_nexus, %sec_dispmode_nexus);
$mp_dispmode_nexus{$_} = $modes->[0] foreach (@story_always_nexus, @story_full_brief_nexus, @story_full_best_nexus);
$mp_dispmode_nexus{$_} = $modes->[1] foreach (@story_brief_best_nexus, @story_brief_always_nexus);
$sec_dispmode_nexus{$_} = $modes->[2] foreach (@story_always_nexus);
$sec_dispmode_nexus{$_} = $modes->[3] foreach (@story_full_brief_nexus, @story_brief_always_nexus);
$sec_dispmode_nexus{$_} = $modes->[4] foreach (@story_full_best_nexus, @story_brief_best_nexus);
$story_to_dispmode_hr ||= {};
# Filter out any story we're planning on skipping up front
@$stories = grep { getDispModeForStory($_, $stories_data_cache->{$_->{stoid}}, \%mp_dispmode_nexus, \%sec_dispmode_nexus, \@story_always_topic, $story_to_dispmode_hr) ne "none" } @$stories;
}
sub getDispModeForStory {
my($story, $story_data, $mp_dispmode_nexus_hr, $sec_dispmode_nexus_hr, $always_topic_ar, $dispmode_hr) = @_;
my $constants = getCurrentStatic();
my $gSkin = getCurrentSkin();
my $slashdb = getCurrentDB();
my $skins = $slashdb->getSkins();
my $dispmode;
# sometimes this is uninit ...
my $ps_nexus = $skins->{$story->{primaryskid}}->{nexus};
if ($gSkin->{nexus} != $constants->{mainpage_nexus_tid}) {
$dispmode_hr->{$story->{stoid}} = "full" if $dispmode_hr;
return "full";
}
# XXXNEWINDEX : Right now we do our best to handle this -- there is no user pref
# to select whether a user wants to see this in brief vs full mode. For
# now we just return "full" (individual non-nexus topic selection isn't used on
# Slashdot currently)
foreach (@$always_topic_ar) {
$dispmode_hr->{$story->{stoid}} = "full" if $dispmode_hr;
return "full" if $story_data->{story_topics_rendered}{$_};
}
if ($story_data->{story_topics_rendered}{$constants->{mainpage_nexus_tid}}) {
$dispmode = $mp_dispmode_nexus_hr->{$ps_nexus};
$dispmode_hr->{$story->{stoid}} = $dispmode if $dispmode_hr && $dispmode;
return $dispmode if $dispmode;
$dispmode_hr->{$story->{stoid}} = "full" if $dispmode_hr;
return "full";
}
# Sectional Story -- decide what we should do with it
$dispmode = $sec_dispmode_nexus_hr->{$ps_nexus};
$dispmode_hr->{$story->{stoid}} = $dispmode if $dispmode_hr && $dispmode;
return $dispmode if $dispmode;
# preference for sectional not defined -- go with default for site
if ($constants->{brief_sectional_mainpage}) {
$dispmode_hr->{$story->{stoid}} = "brief" if $dispmode_hr;
return "brief";
} else {
$dispmode_hr->{$story->{stoid}} = "none" if $dispmode_hr;
return "none";
}
}
sub getSidFromRemark {
my($remark) = @_;
my $regex = regexSid();
my($sid) = $remark =~ $regex;
return $sid || '';
}
sub do_rss {
my($reader, $constants, $user, $form, $stories, $skin_name) = @_;
my $gSkin = getCurrentSkin();
my @rss_stories;
my @stoids_for_cache =
map { $_->{stoid} }
@$stories;
my $stories_data_cache;
$stories_data_cache = $reader->getStoriesData(\@stoids_for_cache)
if @stoids_for_cache;
getDispModesForStories($stories, $stories_data_cache, $user, [qw(full none full none none)]);
for (@$stories) {
my $story = $reader->getStory($_->{sid});
$story->{introtext} = parseSlashizedLinks($story->{introtext});
$story->{introtext} = processSlashTags($story->{introtext});
$story->{introtext} =~ s{(HREF|SRC)\s*=\s*"(//[^/]+)}
{$1 . '="' . url2abs($2)}sieg;
push @rss_stories, { story => $story };
}
my $title = getData('rsshead', { skin => $skin_name });
my $name = lc($gSkin->{basedomain}) . '.' . $form->{content_type};
xmlDisplay($form->{content_type} => {
channel => {
title => $title,
},
version => $form->{rss_version},
image => 1,
items => \@rss_stories,
rdfitemdesc => 1,
rdfitemdesc_html => 1,
}, {
filename => $name,
});
writeLog($skin_name);
return;
}
#################################################################
# Should this method be in the DB library?
# absolutely. we should hide the details there. but this is in a lot of
# places (modules, index, users); let's come back to it later. -- pudge
sub saveUserBoxes {
my(@slashboxes) = @_;
my $slashdb = getCurrentDB();
my $user = getCurrentUser();
return if $user->{is_anon};
$user->{slashboxes} = join ",", @slashboxes;
$slashdb->setUser($user->{uid},
{ slashboxes => $user->{slashboxes} });
}
#################################################################
sub upBid {
my($bid) = @_;
my @a = getUserSlashboxes();
# Build the %order hash with the order in the values.
my %order = ( );
for my $i (0..$#a) {
$order{$a[$i]} = $i;
}
# Reduce the value of the block that's reordered.
$order{$bid} -= 1.5;
# Resort back into the new order.
@a = sort { $order{$a} <=> $order{$b} } keys %order;
saveUserBoxes(@a);
}
#################################################################
sub dnBid {
my($bid) = @_;
my @a = getUserSlashboxes();
# Build the %order hash with the order in the values.
my %order = ( );
for my $i (0..$#a) {
$order{$a[$i]} = $i;
}
# Increase the value of the block that's reordered.
$order{$bid} += 1.5;
# Resort back into the new order.
@a = sort { $order{$a} <=> $order{$b} } keys %order;
saveUserBoxes(@a);
}
#################################################################
sub rmBid {
my($bid) = @_;
my @a = getUserSlashboxes();
@a = grep { $_ ne $bid } @a;
saveUserBoxes(@a);
}
#################################################################
# pass it how many, and what.
sub displayStories {
my($stories, $linkrel) = @_;
my $reader = getObject('Slash::DB', { db_type => 'reader' });
my $constants = getCurrentStatic();
my $form = getCurrentForm();
my $user = getCurrentUser();
my $gSkin = getCurrentSkin();
my $ls_other = { user => $user, reader => $reader, constants => $constants };
my($today, $x) = ('', 0);
# XXXSKIN I'm turning custom numbers of maxstories off for now, so all
# users get the same number. This will improve query cache hit rates and
# right now we need all the edge we can get. Hopefully we can get this
# back on soon. - Jamie 2004/07/17
# my $user_maxstories = $user->{maxstories};
# Here, maxstories should come from the skin, and $cnt should be
# named minstories and that should come from the skin too.
my $user_maxstories = getCurrentAnonymousCoward("maxstories");
my $cnt = $gSkin->{artcount_min};
my($return, $counter);
# get some of our constant messages but do it just once instead
# of for every story
my $msg;
$msg->{readmore} = getData('readmore');
if ($constants->{body_bytes}) {
$msg->{bytes} = getData('bytes');
} else {
$msg->{words} = getData('words');
}
# Pull the story data we'll be needing into a cache all at once,
# to avoid making multiple calls to the DB.
# my $n_future_stories = scalar grep { $_->{is_future} } @$stories;
# my $n_for_cache = $cnt + $n_future_stories;
# $n_for_cache = scalar(@$stories) if $n_for_cache > scalar(@$stories);
my @stoids_for_cache =
map { $_->{stoid} }
@$stories;
# @stoids_for_cache = @stoids_for_cache[0..$n_for_cache-1]
# if $#stoids_for_cache > $n_for_cache;
my $stories_data_cache;
$stories_data_cache = $reader->getStoriesData(\@stoids_for_cache)
if @stoids_for_cache;
my $dispmodelast = "";
my $story_to_dispmode_hr = {};
getDispModesForStories($stories, $stories_data_cache, $user, [qw(full brief full brief none)], $story_to_dispmode_hr);
# Shift them off, so we do not display them in the Older Stuff block
# later (this simulates the old cursor-based method from circa 1997
# which was actually not all that smart, but umpteen layers of caching
# makes it quite tolerable here in 2004 :)
my $story;
STORIES_DISPLAY: while ($story = shift @$stories) {
my($tmpreturn, $other, @links);
$other->{dispmode} = $story_to_dispmode_hr->{$story->{stoid}};
# This user may not be authorized to see future stories; if so,
# skip them.
if ($story->{is_future}) {
# If subscribers are allowed to see 0 seconds into the
# future, future stories are off-limits.
next if !$constants->{subscribe_future_secs};
# If the user is a subscriber or has a daypass, the
# is_subscriber field will be set. If that field is
# not set, future stories are off-limits.
next if !$user->{is_subscriber} && !$user->{has_daypass};
# If the user is only an honorary subscriber because
# they have a daypass, and honorary subscribers don't
# get to see The Mysterious Future, future stories are
# off-limits.
next if !$user->{is_subscriber} && $user->{has_daypass}
&& !$constants->{daypass_seetmf};
}
# Check the day this story was posted (in the user's timezone).
# Compare it to what we believe "today" is (which will be the
# first eligible story in this list). If this story's day is
# not "today", and if we've already displayed enough stories
# to sufficiently fill the homepage (typically 10), then we're
# done -- put the story back on the list (so it'll correctly
# appear in the Older Stuff box) and exit.
my $day = timeCalc($story->{time}, '%A %B %d');
my($w) = join ' ', (split / /, $day)[0 .. 2];
$today ||= $w;
if (++$x > $cnt && $today ne $w) {
unshift @$stories, $story;
last;
}
my @threshComments = split /,/, $story->{hitparade}; # posts in each threshold
$other->{is_future} = 1 if $story->{is_future};
#$other->{dispoptions}{new} = 1 if !$user->{is_anon} && $user->{last_mainpage_view} && $gSkin->{nexus} == $constants->{mainpage_skid} && $user->{last_mainpage_view} lt $story->{time};
my $story_data = $stories_data_cache->{$story->{stoid}};
$tmpreturn .= getData("briefarticles_begin")
if $other->{dispmode} && $other->{dispmode} eq "brief"
&& $dispmodelast ne "brief";
$tmpreturn .= getData("briefarticles_end")
if $dispmodelast eq "brief"
&& !( $other->{dispmode} && $other->{dispmode} eq "brief" );
$story->{commentcount} = $threshComments[0] if $story->{commentcount};
$other->{thresh_commentcount} = $user->{threshold} > -1
? $threshComments[$user->{threshold} + 1]
: $story->{commentcount};
$tmpreturn .= displayStory($story->{sid}, '', $other, $stories_data_cache);
if ($other->{dispmode} eq "full") {
my $readmore = $msg->{readmore};
if ($constants->{index_readmore_with_bytes}) {
my $readmore_data = {};
if ($story->{body_length}) {
if ($constants->{body_bytes}) {
$readmore_data->{bytes} = $story->{body_length};
} else {
$readmore_data->{words} = $story->{word_count};
}
$readmore = getData('readmore_with_bytes', $readmore_data );
}
}
push @links, linkStory({
'link' => $readmore,
sid => $story->{sid},
tid => $story->{tid},
skin => $story->{primaryskid},
class => 'more'
}, '', $ls_other);
my $link;
if ($constants->{body_bytes}) {
$link = "$story->{body_length} $msg->{bytes}";
} else {
$link = "$story->{word_count} $msg->{words}";
}
if (!$constants->{index_readmore_with_bytes}) {
push @links, linkStory({
'link' => $link,
sid => $story->{sid},
tid => $story->{tid},
mode => 'nocomment',
skin => $story->{primaryskid},
}, '', $ls_other) if $story->{body_length};
}
my @commentcount_link;
my $thresh = $threshComments[1]; # threshold == 0
$commentcount_link[1] = linkStory({
sid => $story->{sid},
tid => $story->{tid},
'link' => $story->{commentcount} || 0,
skin => $story->{primaryskid}
}, '', $ls_other);
push @commentcount_link, $thresh, ($story->{commentcount} || 0);
push @links, getData('comments', { cc => \@commentcount_link });
if ($story->{primaryskid} != $constants->{mainpage_skid} && $gSkin->{skid} == $constants->{mainpage_skid}) {
my $skin = $reader->getSkin($story->{primaryskid});
my $url;
if ($skin->{rootdir}) {
$url = $skin->{rootdir} . '/';
} elsif ($user->{is_anon}) {
$url = $gSkin->{rootdir} . '/' . $story->{name} . '/';
} else {
$url = $gSkin->{rootdir} . '/' . $gSkin->{index_handler} . '?section=' . $skin->{name};
}
push @links, [ $url, $skin->{hostname} || $skin->{title}, '', 'section'];
}
if ($user->{seclev} >= 100) {
push @links, [ "$gSkin->{rootdir}/admin.pl?op=edit&sid=$story->{sid}", getData('edit'), '', 'edit' ];
if ($constants->{plugin}{Ajax}) {
my $signoff = slashDisplay("signoff", { stoid => $story->{stoid}, storylink => 1 }, { Return => 1 } );
push @links, $signoff;
}
}
# I added sid so that you could set up replies from the front page -Brian
$tmpreturn .= slashDisplay('storylink', {
links => \@links,
sid => $story->{sid},
}, { Return => 1 });
}
$return .= $tmpreturn;
$dispmodelast = $other->{dispmode};
}
$return .= getData("briefarticles_end") if $dispmodelast eq "brief";
unless ($constants->{index_no_prev_next_day}) {
my($today, $tomorrow, $yesterday, $week_ago) = getOlderDays($form->{issue});
$return .= slashDisplay('next_prev_issue', {
today => $today,
tomorrow => $tomorrow,
yesterday => $yesterday,
week_ago => $week_ago,
linkrel => $linkrel,
}, { Return => 1 });
}
# limit number of stories leftover for older stories if desired
$#$stories = ($gSkin->{older_stories_max} - 1) if
($gSkin->{older_stories_max} < @$stories)
&&
($gSkin->{older_stories_max} > 0);
return $return;
}
#################################################################
createEnvironment();
main();
1;