#!/usr/bin/perl -w # This code is a part of Slash, and is released under the GPL. # Copyright 1997-2001 by Open Source Development Network. See README # and COPYING for more information, or see http://slashcode.com/. # $Id: admin.pl,v 1.2.2.91 2001/11/25 17:30:27 jamie Exp $ use strict; use Image::Size; use POSIX qw(O_RDWR O_CREAT O_EXCL tmpnam); use Slash; use Slash::Display; use Slash::Utility; sub main { my $user = getCurrentUser(); my $form = getCurrentForm(); my $slashdb = getCurrentDB(); my $constants = getCurrentStatic(); my $postflag = $user->{state}{post}; # lc just in case my $op = lc($form->{op}); my($tbtitle); my $ops = { edit_keyword => { function => \&editKeyword, seclev => 10000, }, save => { function => \&saveStory, seclev => 100, }, update => { function => \&updateStory, seclev => 100, }, list => { function => \&listStories, seclev => 100, }, default => { function => \&listStories, seclev => 100, }, 'delete' => { function => \&listStories, seclev => 10000, }, preview => { function => \&editStory, seclev => 100, }, edit => { function => \&editStory, seclev => 100, }, blocks => { # blockdelete_cancel,blockdelete_confirm, # blockdelete1,blockdelete2,blocksave, # blockrevert,blocksavedef,blockdelete,blocknew, function => \&blockEdit, seclev => 500, }, colors => { # colored,colorpreview,colorsave,colorrevert, # colororig,colorsavedef, function => \&colorEdit, seclev => 10000, }, listfilters => { function => \&listFilters, # listfilters seclev => 100, }, editfilter => { function => \&editFilter, # newfilter,updatefilter,deletefilter, seclev => 100, }, siteinfo => { function => \&siteInfo, seclev => 10000, }, templates => { # templatedelete_confirm,templatesection, # templatedelete_cancel, # templatepage,templateed,templatedelete, # templatenew,templatesave, function => \&templateEdit, seclev => 500, }, topics => { # topiced,topicnew,topicsave,topicdelete function => \&topicEdit, seclev => 10000, }, vars => { # varsave, varedit function => \&varEdit, seclev => 10000, }, }; # admin.pl is not for regular users if ($user->{seclev} < 100) { my $rootdir = getCurrentStatic('rootdir'); redirect("$rootdir/users.pl"); return; } # non suadmin users can't perform suadmin ops unless ($ops->{$op}) { $op = 'default'; } $op = 'list' if $user->{seclev} < $ops->{$op}{seclev}; $op ||= 'list'; if (($form->{op} =~ /^preview|edit$/) && $form->{title}) { # Show submission/article title on browser's titlebar. $tbtitle = $form->{title}; $tbtitle =~ s/"/'/g; $tbtitle = " - \"$tbtitle\""; # Undef the form title value if we have SID defined, since the editor # will have to get this information from the database anyways. undef $form->{title} if ($form->{sid} && $form->{op} eq 'edit'); } my $db_time = $slashdb->getTime(); my $gmt_ts = timeCalc($db_time, "%T", 0); my $local_ts = timeCalc($db_time, "%T"); my $time_remark = (length $tbtitle > 10) ? " $gmt_ts" : " $local_ts $user->{tzcode} = $gmt_ts GMT"; # "backSlash" needs to be in a template or something -- pudge header("backSlash$time_remark$tbtitle", 'admin'); # Admin Menu print "

 

" unless $user->{seclev}; # it'd be nice to have a legit retval my $retval = $ops->{$op}{function}->($form, $slashdb, $user, $constants); # Display who is logged in right now. footer(); writeLog($user->{uid}, $op, $form->{sid}); } ################################################################## # Variables Editor sub varEdit { my($form, $slashdb, $user, $constants) = @_; if ($form->{varsave}) { varSave(@_); } my $name = $form->{name}; my $varsref; my $vars = $slashdb->getDescriptions('vars', '', 1); $vars->{""} = ""; my $vars_select = createSelect('name', $vars, $name, 1); if ($name) { $varsref = $slashdb->getVar($name); } slashDisplay('varEdit', { title => getTitle('varEdit-title', { name => $name }), vars_select => $vars_select, varsref => $varsref, }); } ################################################################## sub varSave { my($form, $slashdb, $user, $constants) = @_; if ($form->{thisname}) { my $value = $slashdb->getVar($form->{thisname}); if ($value) { $slashdb->setVar($form->{thisname}, { value => $form->{value}, description => $form->{desc} }); } else { $slashdb->createVar($form->{thisname}, $form->{value}, $form->{desc}); } if ($form->{desc}) { print getData('varSave-message'); } else { # please don't delete this by just removing comment, # since we don't even warn the admin this will happen. # $slashdb->deleteVar($form->{thisname}); # print getData('varDelete-message'); } } } ################################################################## sub siteInfo { my($form, $slashdb, $user, $constants) = @_; my $plugins = $slashdb->getDescriptions('plugins'); my $site_info = $slashdb->getDescriptions('site_info'); slashDisplay('siteInfo', { plugins => $plugins, site_info => $site_info, }); } ################################################################## sub pageEdit { my($seclev, $page) = @_; my $slashdb = getCurrentDB(); my $form = getCurrentForm(); my $pages = $slashdb->getPages(); my $pageselect = createSelect('page', $pages, $page, 1); slashDisplay('pageEdit', { page => $page }); } ################################################################## # OK, here's the template editor # @my_names = grep /^$foo-/, @all_names; sub templateEdit { my($form, $slashdb, $user, $constants) = @_; my($seclev, $tpid, $page, $section); my $seclev_flag = 1; my($title, $templateref, $template_select, $page_select, $section_select, $savepage_select, $savesection_select); my($templatedelete_flag, $templateedit_flag, $templateform_flag) = 0; my $pagehashref = {}; $title = getTitle('templateEdit-title', {}, 1); if ($form->{templatenew} || $form->{templatepage} || $form->{templatesection}) { $tpid = ''; $page = $form->{page}; $section = $form->{section}; } elsif ($form->{templatesave} || $form->{templatesavedef}) { if ($form->{save_new}) { $section = $form->{newS} ? $form->{newsection} : $form->{section}; $page = $form->{newP} ? $form->{newpage} : $form->{page}; } else { $section = $form->{newS} ? $form->{newsection} : $form->{savesection}; $page = $form->{newP} ? $form->{newpage} : $form->{savepage}; } my $templateref = $slashdb->getTemplate($form->{thistpid}, '', 1); if ( $templateref->{seclev} <= $user->{seclev}) { templateSave($form->{thistpid}, $form->{name}, $page, $section); } else { print getData('seclev-message', { name => $form->{name}, tpid => $form->{thistpid} }); } $tpid = $form->{thistpid}; } elsif ($form->{templatedelete_confirm}) { my $templateref = $slashdb->getTemplate($form->{deletetpid}, '', 1); if ($templateref->{seclev} <= $user->{seclev}) { templateDelete($form->{deletename}, $form->{deletetpid}); print getData('templateDelete-message', { name => $form->{deletename}, tpid => $form->{deletepid} }); } else { print getData('seclev-message', { name => $form->{deletename}, tpid => $form->{deletepid} }); } } else { $tpid = $form->{tpid}; $page = $form->{page}; $section = $form->{section}; } $page ||= 'misc'; $section ||= 'default'; $templateref = $slashdb->getTemplate($tpid, '', 1) if $tpid; $seclev_flag = 0 if $templateref->{seclev} > $user->{seclev}; if ($form->{templatedelete}) { $templatedelete_flag = 1; } else { my $templates = {}; if ($form->{templatesection}) { if ($section eq 'All') { $templates = $slashdb->getTemplateList('', $page); } else { $templates = $slashdb->getTemplateList($section); } } else { if ($page eq 'All') { $templates = $slashdb->getTemplateList(); } else { $templates = $slashdb->getTemplateList('', $page); } } my $pages = $slashdb->getDescriptions('pages', $page, 1); my $sections = $slashdb->getDescriptions('templatesections', $section, 1); $pages->{All} = 'All'; $pages->{misc} = 'misc'; $sections->{default} = 'default'; $sections->{All} = 'All'; # put these in alpha order by label, and add tpid to label my @ordered; for (sort { $templates->{$a} cmp $templates->{$b} } keys %$templates) { push @ordered, $_; $templates->{$_} = $templates->{$_} . " ($_)"; } $page_select = createSelect('page', $pages, $page, 1); $savepage_select = createSelect('savepage', $pages, $templateref->{page}, 1) if $templateref->{tpid}; $template_select = createSelect('tpid', $templates, $tpid, 1, 0, \@ordered); $section_select = createSelect('section', $sections, $section, 1); $savesection_select = createSelect('savesection', $sections, $templateref->{section}, 1) if $templateref->{tpid}; } if (!$form->{templatenew} && $tpid && $templateref->{tpid}) { $templateedit_flag = 1; } $templateform_flag = 1 if ((! $form->{templatedelete_confirm} && $tpid) || $form->{templatenew}); slashDisplay('templateEdit', { tpid => $tpid, title => $title, templateref => $templateref, seclev_flag => $seclev_flag, templateedit_flag => $templateedit_flag, templatedelete_flag => $templatedelete_flag, template_select => $template_select, templateform_flag => $templateform_flag, page_select => $page_select, savepage_select => $savepage_select, section_select => $section_select, savesection_select => $savesection_select, }); } ################################################################## sub templateSave { my($tpid, $name, $page, $section) = @_; my $user = getCurrentUser(); my $form = getCurrentForm(); my $slashdb = getCurrentDB(); my $constants = getCurrentStatic(); $form->{seclev} ||= 500; my $id = $slashdb->getTemplate($tpid, '', 1); my $temp = $slashdb->getTemplateByName($name, [ 'section', 'page', 'name', 'tpid', 'seclev' ], 1 , $page, $section); return if $temp->{seclev} > $user->{seclev}; my $exists = 0; $exists = 1 if ($name eq $temp->{name} && $section eq $temp->{section} && $page eq $temp->{page}); if ($form->{save_new}) { if ($id->{tpid} || $exists) { print getData('templateSave-exists-message', { tpid => $tpid, name => $name }); return; } else { print "trying to insert $name
\n"; ($tpid) = ($form->{thistpid}) = $slashdb->createTemplate({ name => $name, template => $form->{template}, title => $form->{title}, description => $form->{description}, seclev => $form->{seclev}, page => $page, section => $section }); print getData('templateSave-inserted-message', { tpid => $tpid , name => $name}); } } else { $slashdb->setTemplate($tpid, { name => $name, template => $form->{template}, description => $form->{description}, title => $form->{title}, seclev => $form->{seclev}, page => $page, section => $section }); print getData('templateSave-saved-message', { tpid => $tpid, name => $name }); } } ################################################################## sub templateDelete { my($name, $tpid) = @_; my $slashdb = getCurrentDB(); return if getCurrentUser('seclev') < 500; $slashdb->deleteTemplate($tpid); } ################################################################## sub blockEdit { my($form, $slashdb, $user, $constants) = @_; my($bid); if ($form->{blocksave} || $form->{blocksavedef}) { blockSave($form->{thisbid}); $bid = $form->{thisbid}; print getData('blockSave-saved-message', { bid => $bid }); } elsif ($form->{blockrevert}) { $slashdb->revertBlock($form->{thisbid}); $bid = $form->{thisbid}; } elsif ($form->{blockdelete}) { $bid = $form->{thisbid}; } elsif ($form->{blockdelete1} || $form->{blocked1}) { $bid = $form->{bid1}; } elsif ($form->{blockdelete2} || $form->{blocked2}) { $bid = $form->{bid2}; } elsif ($form->{blockdelete_confirm}) { blockDelete($form->{deletebid}); print getData('blockDelete-message', { bid => $form->{deletebid} }); } my($blockref, $saveflag, $block_select, $retrieve_checked, $portal_checked, $block_select1, $block_select2); my($blockedit_flag, $blockdelete_flag, $blockform_flag) = (0, 0, 0); $blockref = {}; if ($bid) { $blockref = $slashdb->getBlock($bid, '', 1); } my $sectionbid = $blockref->{section}; if ($form->{blockdelete} || $form->{blockdelete1} || $form->{blockdelete2}) { $blockdelete_flag = 1; } else { # get the static blocks my $blocks = $slashdb->getDescriptions('static_block', $user->{seclev}, 1); $block_select1 = createSelect('bid1', $blocks, $bid, 1); $blocks = $slashdb->getDescriptions('portald_block', $user->{seclev}, 1); $block_select2 = createSelect('bid2', $blocks, $bid, 1); } my $blocktype = $slashdb->getDescriptions('blocktype', '', 1); my $blocktype_select = createSelect('type', $blocktype, $blockref->{type}, 1); # if the pulldown has been selected and submitted # or this is a block save and the block is a portald block # or this is a block edit via sections.pl if (! $form->{blocknew} && $bid) { if ($blockref->{bid}) { $blockedit_flag = 1; $blockref->{ordernum} = "NA" if $blockref->{ordernum} eq ''; $retrieve_checked = "CHECKED" if $blockref->{retrieve} == 1; $portal_checked = "CHECKED" if $blockref->{portal} == 1; } } $blockform_flag = 1 if ((! $form->{blockdelete_confirm} && $bid) || $form->{blocknew}); my $title = getTitle('blockEdit-title', { bid => $bid }, 1); slashDisplay('blockEdit', { bid => $bid, title => $title, blockref => $blockref, blockedit_flag => $blockedit_flag, blockdelete_flag => $blockdelete_flag, block_select1 => $block_select1, block_select2 => $block_select2, blockform_flag => $blockform_flag, portal_checked => $portal_checked, retrieve_checked => $retrieve_checked, blocktype_select => $blocktype_select, sectionbid => $sectionbid, }); } ################################################################## sub blockSave { my($bid) = @_; my $slashdb = getCurrentDB(); return unless $bid; my $saved = $slashdb->saveBlock($bid); if (getCurrentForm('save_new') && $saved > 0) { print getData('blockSave-exists-message', { bid => $bid }); return; } if ($saved == 0) { print getData('blockSave-inserted-message', { bid => $bid }); } } ################################################################## sub blockDelete { my($bid) = @_; my $slashdb = getCurrentDB(); $slashdb->deleteBlock($bid); } ################################################################## sub colorEdit { my($form, $slashdb, $user, $constants) = @_; my($color_select, $block, $colorblock_clean, $title, @colors); # return if $user->{'seclev'} < 500; if ($form->{colorsave} || $form->{colorsavedef} || $form->{colororig}) { colorSave(); } my $colorblock; $form->{color_block} ||= 'colors'; if ($form->{colorpreview} || $form->{colorsave}) { $colorblock_clean = $colorblock = join ',', @{$form}{qw[fg0 fg1 fg2 fg3 fg4 bg0 bg1 bg2 bg3 bg4]}; # the #s will break the url $colorblock_clean =~ s/#//g; } else { $colorblock = $slashdb->getBlock($form->{color_block}, 'block'); } @colors = split m/,/, $colorblock; $user->{fg} = [@colors[0..4]]; $user->{bg} = [@colors[5..9]]; $title = getTitle('colorEdit-title'); $block = $slashdb->getDescriptions('color_block', '', 1); $color_select = createSelect('color_block', $block, $form->{color_block}, 1); slashDisplay('colorEdit', { title => $title, colorblock_clean => $colorblock_clean, colors => \@colors, color_select => $color_select, }); } ################################################################## sub colorSave { my $slashdb = getCurrentDB(); my $form = getCurrentForm(); my $colorblock = join ',', @{$form}{qw[fg0 fg1 fg2 fg3 fg4 bg0 bg1 bg2 bg3 bg4]}; $slashdb->saveColorBlock($colorblock); } ################################################################## # Keyword Editor sub editKeyword { my($form, $slashdb, $user, $constants) = @_; if ($form->{keywordnew}) { $form->{id} = ''; saveKeyword(@_); } deleteKeyword(@_) if $form->{keyworddelete}; saveKeyword(@_) if $form->{keywordsave}; my($keywords_menu, $keywords_select); $keywords_menu = $slashdb->getDescriptions('keywords', '', 1); $keywords_select = createSelect('id', $keywords_menu, $form->{id}, 1, '', 1); my $keyword = $slashdb->getRelatedLink($form->{id}) if $form->{id}; slashDisplay('keywordEdit', { keywords_select => $keywords_select, keyword => $keyword, }); } ################################################################## sub deleteKeyword { my($form, $slashdb, $user, $constants) = @_; print getData('keywordDelete-message'); $slashdb->deleteRelatedLink($form->{id}); $form->{id} = ''; } ################################################################## sub saveKeyword { my($form, $slashdb, $user, $constants) = @_; my $basedir = $constants->{'basedir'}; return if getCurrentUser('seclev') < 500; if ($form->{id}) { $slashdb->setRelatedLink($form->{id}, { keyword => $form->{keyword}, name => $form->{name}, 'link' => $form->{'link'} }); } else { $form->{id} = $slashdb->createRelatedLink({ keyword => $form->{keyword}, name => $form->{name}, 'link' => $form->{'link'} }); } print getData('keywordSave-message'); } ################################################################## # Topic Editor sub topicEdit { my($form, $slashdb, $user, $constants) = @_; my $basedir = $constants->{basedir}; my($image, $image2); my($topic, $topics_menu, $topics_select); my $available_images = {}; my $image_select = ""; if ($form->{topicdelete}) { topicDelete($form->{tid}); print getData('topicDelete-message', { tid => $form->{tid} }); } elsif ($form->{topicsave}) { topicSave(@_); print getData('topicSave-message'); } my($imageseen_flag, $images_flag) = (0, 0); local *DIR; opendir(DIR, "$basedir/images/topics"); # this should be a preference at some point, image # extensions ... -- pudge $available_images = { map { ($_, $_) } grep /\.(?:gif|jpe?g|png)$/, readdir DIR }; closedir(DIR); $topics_menu = $slashdb->getDescriptions('topics_all', '', 1); $topics_select = createSelect('nexttid', $topics_menu, $form->{nexttid} ? $form->{nexttid} : $constants->{defaulttopic}, 1); my $sections = $slashdb->getDescriptions('sections-all', '', 1); my $section_topics = $slashdb->getDescriptions('topic-sections', $form->{nexttid}, 1); my $sectionref; while (my($section, $title) = each %$sections) { $sectionref->{$section}{checked} = ($section_topics->{$section}) ? ' CHECKED' : ''; $sectionref->{$section}{title} = $title; } if (!$form->{topicdelete}) { if (!$form->{topicnew} && $form->{nexttid}) { $topic = $slashdb->getTopic($form->{nexttid}); } else { $topic = {}; } } if ($available_images) { $images_flag = 1; $image_select = createSelect('image', $available_images, $topic->{image}, 1); } # we can change topic->{image} because it's cached and it'll hose it sitewide $image = $topic->{image}; if ($image =~ /^\w+\.\w+$/) { $image = "$constants->{imagedir}/topics/$image"; } else { $image2 = $image; } my $topicname = $topic->{name} || ''; slashDisplay('topicEdit', { title => getTitle('editTopic-title', { tname => $topicname }), images_flag => $images_flag, image => $image2 ? $image2 : $image, image2 => $image2, topic => $topic, topics_select => $topics_select, image_select => $image_select, sectionref => $sectionref }); } ################################################################## sub topicDelete { my($tid) = @_; my $slashdb = getCurrentDB(); my $form = getCurrentForm(); $tid ||= $form->{tid}; $slashdb->deleteTopic($tid); $slashdb->deleteSectionTopicsByTopic($form->{tid}); $form->{tid} = ''; } ################################################################## sub topicSave { my($form, $slashdb, $user, $constants) = @_; my $basedir = $constants->{basedir}; if (!$form->{width} && !$form->{height} && ! $form->{image2}) { @{ $form }{'width', 'height'} = imgsize("$basedir/images/topics/$form->{image}"); } $form->{tid} = $slashdb->saveTopic($form); # The next few lines need to be wrapped in a transaction -Brian $slashdb->deleteSectionTopicsByTopic($form->{tid}); for my $item (keys %$form) { if ($item =~ /^exsect_(.*)/) { $slashdb->createSectionTopic($1, $form->{tid}); } } $form->{nexttid} = $form->{tid}; } ################################################################## # hmmm, what do we want to do with this sub ? PMG 10/18/00 sub importImage { # Check for a file upload my $section = $_[0]; my $rootdir = getCurrentStatic('rootdir'); my $filename = getCurrentForm('importme'); my $tf = getsiddir() . $filename; $tf =~ s|/|~|g; $tf = "$section~$tf"; if ($filename) { local *IMAGE; system("mkdir /tmp/slash"); open(IMAGE, ">>/tmp/slash/$tf"); my $buffer; while (read $filename, $buffer, 1024) { print IMAGE $buffer; } close IMAGE; } else { return ""; } my($w, $h) = imgsize("/tmp/slash/$tf"); return qq[$section]; } ################################################################## sub importFile { # Check for a file upload my $section = $_[0]; my $rootdir = getCurrentStatic('rootdir'); my $filename = getCurrentForm('importme'); my $tf = getsiddir() . $filename; $tf =~ s|/|~|g; $tf = "$section~$tf"; if ($filename) { system("mkdir /tmp/slash"); open(IMAGE, ">>/tmp/slash/$tf"); my $buffer; while (read $filename, $buffer, 1024) { print IMAGE $buffer; } close IMAGE; } else { return ""; } return qq[Attachment]; } ######################################################## # Returns the directory (eg YY/MM/DD/) that stories are being written in today sub getsiddir { my($mday, $mon, $year) = (localtime)[3, 4, 5]; $year = $year % 100; my $sid = sprintf('%02d/%02d/%02d/', $year, $mon+1, $mday); return $sid; } ################################################################## sub importText { # Check for a file upload my $filename = getCurrentForm('importme'); my($r, $buffer); if ($filename) { while (read $filename, $buffer, 1024) { $r .= $buffer; } } return $r; } ################################################################## # Generated the 'Related Links' for Stories sub getRelated { my($story_content) = @_; my $slashdb = getCurrentDB(); my $related_links = $slashdb->getRelatedLinks(); my $related_text; if ($related_links) { for my $key (values %$related_links) { if ($story_content =~ /\b$key->{keyword}\b/i) { my $str = qq[
  • $key->{name}
  • \n]; $related_text .= $str unless $related_text =~ /\Q$str\E/; } } } # And slurp in all the URLs just for good measure while ($story_content =~ m|(.*?)|sgi) { my($url, $label) = ($1, $2); $label =~ s/(\S{30})/$1 /g; my $str = qq[
  • $label
  • \n]; $related_text .= $str unless $related_text =~ /\Q$str\E/ || $label eq "?" || $label eq "[?]"; } return $related_text; } ################################################################## sub otherLinks { my($aid, $tid, $uid) = @_; my $slashdb = getCurrentDB(); my $topic = $slashdb->getTopic($tid); return slashDisplay('otherLinks', { uid => $uid, aid => $aid, tid => $tid, topic => $topic, }, { Return => 1, Nocomm => 1 }); } ################################################################## # Story Editing sub editStory { my($form, $slashdb, $user, $constants) = @_; my($sid, $storylinks, $authorbox); if ($form->{op} eq 'edit') { $sid = $form->{sid}; } my($authoredit_flag, $extracolumn_flag) = (0, 0); my($storyref, $story, $author, $topic, $storycontent, $storybox, $locktest, $sections, $topic_select, $section_select, $author_select, $extracolumns, $displaystatus_select, $commentstatus_select, $description); my $extracolref = {}; my($fixquotes_check, $autonode_check, $fastforward_check, $shortcuts_check) = qw(off off off off); for (keys %{$form}) { $storyref->{$_} = $form->{$_} } my $newarticle = 1 if (!$sid && !$form->{sid}); if ($form->{title}) { $extracolumns = $slashdb->getSectionExtras($storyref->{section}) || [ ]; $storyref->{writestatus} = "dirty"; $storyref->{displaystatus} = $slashdb->getVar('defaultdisplaystatus', 'value'); $storyref->{commentstatus} = $slashdb->getVar('defaultcommentstatus', 'value'); $storyref->{uid} ||= $user->{uid}; $storyref->{section} = $form->{section}; $storyref->{writestatus} = $form->{writestatus} if exists $form->{writestatus}; $storyref->{displaystatus} = $form->{displaystatus} if exists $form->{displaystatus}; $storyref->{commentstatus} = $form->{commentstatus} if exists $form->{commentstatus}; $storyref->{dept} =~ s/[-\s]+/-/g; $storyref->{dept} =~ s/^-//; $storyref->{dept} =~ s/-$//; $storyref->{introtext} = $slashdb->autoUrl( $form->{section}, $storyref->{introtext} ); $storyref->{bodytext} = $slashdb->autoUrl( $form->{section}, $storyref->{bodytext} ); $topic = $slashdb->getTopic($storyref->{tid}); $form->{uid} ||= $user->{uid}; $author = $slashdb->getAuthor($form->{uid}); $sid = $form->{sid}; if (!$form->{'time'} || $form->{fastforward}) { $storyref->{'time'} = $slashdb->getTime(); } else { $storyref->{'time'} = $form->{'time'}; } my $tmp = $user->{currentSection}; $user->{currentSection} = $storyref->{section}; $storycontent = dispStory($storyref, $author, $topic, 'Full'); $user->{currentSection} = $tmp; $storyref->{relatedtext} = getRelated("$storyref->{title} $storyref->{bodytext} $storyref->{introtext}") . otherLinks($slashdb->getAuthor($storyref->{uid}, 'nickname'), $storyref->{tid}, $storyref->{uid}); $storybox = fancybox($constants->{fancyboxwidth}, 'Related Links', $storyref->{relatedtext}, 0, 1); } elsif (defined $sid) { # Loading an existing SID my $tmp = $user->{currentSection}; $user->{currentSection} = $slashdb->getStory($sid, 'section', 1); ($story, $storyref, $author, $topic) = displayStory($sid, 'Full'); $extracolumns = $slashdb->getSectionExtras($user->{currentSection}) || [ ]; $user->{currentSection} = $tmp; $storybox = fancybox($constants->{fancyboxwidth}, 'Related Links', $storyref->{relatedtext}, 0, 1); } else { # New Story $extracolumns = $slashdb->getSectionExtras($storyref->{section}) || [ ]; $storyref->{displaystatus} = $slashdb->getVar('defaultdisplaystatus', 'value'); $storyref->{commentstatus} = $slashdb->getVar('defaultcommentstatus', 'value'); $storyref->{tid} = $slashdb->getVar('defaulttopic', 'value'); $storyref->{section} = $slashdb->getVar('defaultsection', 'value'); $storyref->{'time'} = $slashdb->getTime(); $storyref->{uid} = $user->{uid}; $storyref->{writestatus} = "dirty"; } for (@{$extracolumns}) { my $key = $_->[1]; $storyref->{$key} = $form->{$key} || $storyref->{$key}; } my $newestthree = $slashdb->getBlock('newestthree','block'); my $nextthree = $slashdb->getNextThree($storyref->{time}); my $nextstories = {}; for (@$nextthree) { my $tmpstory = $slashdb->getStory($_->[0], ['title', 'uid', 'time']); my $author = $slashdb->getUser($tmpstory->{uid},'nickname'); $nextstories->{$_->[0]}{title} = $tmpstory->{title}; } my $nextblock = slashDisplay('three', { stories => $nextstories }, { Return => 1, Page => 'misc', Section => 'default' }); $storylinks = $newestthree . $nextblock; $sections = $slashdb->getDescriptions('sections'); $topic_select = selectTopic('tid', $storyref->{tid}, $storyref->{section}, 1); $section_select = selectSection('section', $storyref->{section}, $sections, 1) unless $user->{section}; if ($user->{seclev} >= 100) { $authoredit_flag = 1; my $authors = $slashdb->getDescriptions('authors', '', 1); $author_select = createSelect('uid', $authors, $storyref->{uid}, 1); } $storyref->{dept} =~ s/ /-/gi; $locktest = lockTest($storyref->{title}); unless ($user->{section}) { $description = $slashdb->getDescriptions('displaycodes'); $displaystatus_select = createSelect('displaystatus', $description, $storyref->{displaystatus}, 1); } $description = $slashdb->getDescriptions('commentcodes'); $commentstatus_select = createSelect('commentstatus', $description, $storyref->{commentstatus}, 1); $fixquotes_check = 'on' if $form->{fixquotes}; $autonode_check = 'on' if $form->{autonode}; $fastforward_check = 'on' if $form->{fastforward}; $shortcuts_check = 'on' if $form->{shortcuts}; $slashdb->setSession($user->{uid}, { lasttitle => $storyref->{title} }); my $ispell_comments = { introtext => get_ispell_comments($storyref->{introtext}), bodytext => get_ispell_comments($storyref->{bodytext}), }; $authorbox = fancybox($constants->{fancyboxwidth}, 'Story admin', $storylinks, 0, 1); slashDisplay('editStory', { storyref => $storyref, story => $story, storycontent => $storycontent, storybox => $storybox, sid => $sid, authorbox => $authorbox, newarticle => $newarticle, topic_select => $topic_select, section_select => $section_select, author_select => $author_select, locktest => $locktest, displaystatus_select => $displaystatus_select, commentstatus_select => $commentstatus_select, fixquotes_check => $fixquotes_check, autonode_check => $autonode_check, fastforward_check => $fastforward_check, shortcuts_check => $shortcuts_check, user => $user, authoredit_flag => $authoredit_flag, ispell_comments => $ispell_comments, extras => $extracolumns, }); } ################################################################## sub write_to_temp_file { my($data) = @_; local *TMP; my $tmp; do { # Note: don't mount /tmp over NFS, it's a security risk # See Camel3, p. 574 $tmp = tmpnam(); } until sysopen(TMP, $tmp, O_RDWR|O_CREAT|O_EXCL, 0600); print TMP $data; close TMP; $tmp; } ################################################################## sub get_ispell_comments { my($text) = @_; $text = strip_nohtml($text); # don't split to scalar context, it clobbers @_ my $n_text_words = scalar(my @junk = split /\W+/, $text); my $slashdb = getCurrentDB(); my $ispell = $slashdb->getVar("ispell", "value"); return "" if !$ispell; return "bad ispell var '$ispell'" unless $ispell eq 'ispell' or $ispell =~ /^\//; return "insecure ispell var '$ispell'" if $ispell =~ /\s/; if ($ispell ne 'ispell') { return "no file, not readable, or not executable '$ispell'" if !-e $ispell or !-f _ or !-r _ or !-x _; } # That last "1" means to ignore errors my $ok = $slashdb->getTemplateByName('ispellok', '', 1, '', '', 1); $ok = $ok ? ($ok->{template} || "") : ""; $ok =~ s/\s+/\n/g; local *ISPELL; my $tmptext = write_to_temp_file(lc($text)); my $tmpok = ""; $tmpok = write_to_temp_file(lc($ok)) if $ok; my $tmpok_flag = ""; $tmpok_flag = " -p $tmpok" if $tmpok; if (!open(ISPELL, "$ispell -a -B -S -W 3$tmpok_flag < $tmptext 2> /dev/null |")) { errorLog("could not pipe to $ispell from $tmptext, $!"); return "could not pipe to $ispell from $tmptext, $!"; } my %w; while (defined(my $line = )) { # Grab all ispell's flagged words and put them in the hash $w{$1}++ if $line =~ /^[#?&]\s+(\S+)/; } close ISPELL; unlink $tmptext, $tmpok; my $comm = ''; for my $word (sort {lc($a) cmp lc($b) or $a cmp $b} keys %w) { # if it's a repeated error, ignore it next if $w{$word} >= 2 and $w{$word} > $n_text_words*0.002; # a misspelling; report it $comm = "ispell doesn't recognize:" if !$comm; $comm .= " $word"; } return $comm; } ################################################################## sub listStories { my($form, $slashdb, $user, $constants) = @_; my($first_story, $num_stories) = ($form->{'next'} || 0, 40); my($count, $storylist) = $slashdb->getStoryList($first_story, $num_stories); my $storylistref = []; my($sectionflag); my($i, $canedit) = (0, 0); if ($form->{op} eq 'delete') { rmStory($form->{sid}); titlebar('100%', getTitle('rmStory-title', {sid => $form->{sid}})); } else { titlebar('100%', getTitle('listStories-title')); } for (@$storylist) { my($hits, $comments, $sid, $title, $aid, $time_plain, $topic, $section, $displaystatus, $writestatus) = @$_; my $time = timeCalc($time_plain, '%H:%M', 0); my $td = timeCalc($time_plain, '%A %B %d', 0); my $td2 = timeCalc($time_plain, '%m/%d', 0); $title = substr($title, 0, 50) . '...' if (length $title > 55); my $tbtitle = fixparam($title); if ($user->{uid} eq $aid || $user->{seclev} >= 100) { $canedit = 1; } $storylistref->[$i] = { 'x' => $i + $first_story + 1, hits => $hits, comments => $comments, sid => $sid, title => $title, aid => $slashdb->getAuthor($aid, 'nickname'), 'time' => $time, canedit => $canedit, topic => $topic, section => $section, td => $td, td2 => $td2, writestatus => $writestatus, displaystatus => $displaystatus, tbtitle => $tbtitle, }; $i++; } $sectionflag = 1 unless ($user->{section} || $form->{section}); slashDisplay('listStories', { sectionflag => $sectionflag, storylistref => $storylistref, 'x' => $i + $first_story, left => $count - ($i + $first_story), }); } ################################################################## sub rmStory { my($sid) = @_; my $slashdb = getCurrentDB(); my $constants = getCurrentStatic(); $slashdb->deleteStory($sid); } ################################################################## sub listFilters { my($form, $slashdb, $user, $constants) = @_; my $formname = $form->{formname}; my $title = getTitle('listFilters-title'); my $filter_ref = $slashdb->getContentFilters($formname); my $form_list = $slashdb->getDescriptions('forms'); my $form_select = createSelect('formname', $form_list, $formname, 1); slashDisplay('listFilters', { title => $title, form_select => $form_select, filter_ref => $filter_ref }); } ################################################################## sub editFilter { my($form, $slashdb, $user, $constants) = @_; my($filter_id); my $formname = $form->{formname}; if ($form->{newfilter}) { $filter_id = $slashdb->createContentFilter($formname); titlebar("100%", getTitle('updateFilter-new-title', { filter_id => $filter_id })); } elsif ($form->{updatefilter}) { if (!$form->{regex}) { print getData('updateFilter-message'); } else { $slashdb->setContentFilter(); } $filter_id = $form->{filter_id}; titlebar("100%", getTitle('updateFilter-update-title')); } elsif ($form->{deletefilter}) { $slashdb->deleteContentFilter($form->{filter_id}); titlebar("100%", getTitle('updateFilter-delete-title')); listFilters($formname); return(); } $filter_id ||= $form->{filter_id}; my @values = qw(regex form modifier field ratio minimum_match minimum_length err_message); my $filter = $slashdb->getContentFilter($filter_id, \@values, 1); my $form_list = $slashdb->getDescriptions('forms'); my $form_select = createSelect('formname', $form_list, $filter->{form}, 1); # this has to be here - it really screws up the block editor $filter->{err_message} = strip_literal($filter->{'err_message'}); slashDisplay('editFilter', { form_select => $form_select, filter => $filter, filter_id => $filter_id }); } ################################################################## sub updateStory { my($form, $slashdb, $user, $constants) = @_; # Some users can only post to a fixed section if (my $section = getCurrentUser('section')) { $form->{section} = $section; $form->{displaystatus} = 1; } $form->{dept} =~ s/ /-/g; $form->{aid} = $slashdb->getStory($form->{sid}, 'aid', 1) unless $form->{aid}; $form->{relatedtext} = getRelated("$form->{title} $form->{bodytext} $form->{introtext}") . otherLinks($slashdb->getAuthor($form->{uid}, 'nickname'), $form->{tid}, $form->{uid}); $slashdb->updateStory(); titlebar('100%', getTitle('updateStory-title')); # make sure you pass it the goods listStories(@_); } ################################################################## sub saveStory { my($form, $slashdb, $user, $constants) = @_; my $edituser = $slashdb->getUser($form->{uid}); my $rootdir = getCurrentStatic('rootdir'); # In the previous form of this, a section only # editor could assign a story to a different user # and bypass their own restrictions for what section # they could post to. -Brian $form->{displaystatus} ||= 1 if ($user->{section} || $edituser->{section}); if ($user->{section} || $edituser->{section}) { $form->{section} = $user->{section} ? $user->{section} : $edituser->{section}; } $form->{dept} =~ s/ /-/g; $form->{relatedtext} = getRelated( "$form->{title} $form->{bodytext} $form->{introtext}" ) . otherLinks($edituser->{nickname}, $form->{tid}, $edituser->{uid}); my $sid = $slashdb->createStory($form); if ($sid) { my $id = $slashdb->createDiscussion( { title => $form->{title}, section => $form->{section}, topic => $form->{tid}, url => "$rootdir/article.pl?sid=$sid", sid => $sid, ts => $form->{'time'} }); if ($id) { $slashdb->setStory($sid, { discussion => $id }); } else { # Probably should be a warning sent to the browser # for this error, though it should be rare. errorLog("could not create discussion for story '$sid'"); } } else { titlebar('100%', getData('story_creation_failed')); listStories(@_); return; } my $newestthree = $slashdb->getNewestThree(); my $newstories = {}; for (@$newestthree) { my $tmpstory = $slashdb->getStory($_->[0], ['title' ]); $newstories->{$_->[0]}{title} = $tmpstory->{title}; } my $newblock = slashDisplay('three', { stories => $newstories }, { Return => 1, Page => 'misc', Section => 'default' } ); $slashdb->sqlUpdate('blocks', { block => $newblock, }, "bid='newestthree'" ); titlebar('100%', getTitle('saveStory-title')); listStories(@_); } ################################################################## sub getTitle { my($value, $hashref, $nocomm) = @_; $hashref ||= {}; $hashref->{value} = $value; return slashDisplay('titles', $hashref, { Return => 1, Nocomm => $nocomm }); } ################################################################## sub getLinks { # huh? who did this? } createEnvironment(); main(); 1;