IndexPlWalkthroughNotes: Difference between revisions
Jump to navigation
Jump to search
No edit summary |
No edit summary |
||
Line 3: | Line 3: | ||
<h2>index.pl</h2> | <h2>index.pl</h2> | ||
<pre> | |||
#!/usr/bin/perl -w | #!/usr/bin/perl -w | ||
# This code is a part of Slash, and is released under the GPL. | # This code is a part of Slash, and is released under the GPL. |
Revision as of 20:37, 5 March 2014
CssWork
SlashDocumentationIndex
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; use Slash; 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(); my $user = getCurrentUser(); my $form = getCurrentForm(); my $slashdb = getCurrentDB(); my $reader = getObject('Slash::DB', { db_type => 'reader' }); return if redirect_home_if_necessary(); 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}); 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;