#!/usr/bin/perl # TmNetWiki version 0.4 (September 11, 2002) # Copyright (C) 2002 Adam Brate # # Based on the GPLed UseModWiki 0.92 # Copyright (C) 2000-2001 Clifford A. Adams # or # Based on the GPLed AtisWiki 0.3 (C) 1998 Markus Denker # # ...which was based on # the LGPLed CVWiki CVS-patches (C) 1997 Peter Merel # and The Original WikiWikiWeb (C) Ward Cunningham # (code reused with permission) # Email and ThinLine options by Jim Mahoney # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the # Free Software Foundation, Inc. # 59 Temple Place, Suite 330 # Boston, MA 02111-1307 USA package Wiki::edit; use strict; # needs subs Wiki::user: UserCanEdit, UserIsBanned # Wiki::template: GetHeader, GetCommonFooter, # GetHiddenValue, GetTextArea, GetPageLink, GetFormStart, # GetGotoBar, GetMinimumFooter, GetHistoryLink # Wiki::page: OpenPage, # Wiki::text: OpenDefaultText, # Wiki::utility: GetParam, QuoteHtml, # Wiki::keep: OpenKeptRevisions, OpenKeptRevision, # Wiki::wiki: WikiToHTML, # Wiki::calc: TimeToText # Wiki::translate: T, Ts # Wiki::lock: RequestLock, ReleaseLock # Wiki::diff: UpdateDiffs # Wiki::rc: WriteRcLog # Wiki::browse: ReBrowsePage # needs consts $HomePage, $SiteName, $EmailNotify # needs vars %KeptRevisions, %Section, %Text, $q, $MainPage use base 'Exporter'; use Wiki::consts; use Wiki::wiki; use Wiki::browse; use Wiki::rc; use Wiki::user; use Wiki::page; use Wiki::text; use Wiki::category; use Wiki::keep; use Wiki::lock; use Wiki::diff; use Wiki::utility; use Wiki::template; use Wiki::calc; use Wiki::translate; #if ($^V and $^V gt v5.6.0) { # our @EXPORT; #else { use vars qw(@EXPORT); #} @EXPORT = qw( DoEdit DoPost ); sub DoEdit { my ($id, $isError, $oldTime, $newText, $preview) = @_; my ($header, $editRows, $editCols, $userName, $revision, $oldText); my ($summary, $category, $isEdit, $pageTime); if (!&UserCanEdit($id, 1)) { print &GetHeader("", T('Editing Denied'), ""); if (&UserIsBanned()) { print T('Editing not allowed: user, ip, or network is blocked.'); print "

"; print T('Contact the wiki administrator for more information.'); } else { print Ts('Editing not allowed: %s is read-only.', $SiteName); } print &GetCommonFooter(); return; } # Consider sending a new user-ID cookie if user does not have one &OpenPage($id); &OpenDefaultText(); $pageTime = $Section{'ts'}; $header = Ts('Editing %s', $id); # Old revision handling $revision = &GetParam('revision', ''); $revision =~ s/\D//g; # Remove non-numeric chars if ($revision ne '') { &OpenKeptRevisions('text_default'); if (!defined($KeptRevisions{$revision})) { $revision = ''; # Later look for better solution, like error message? } else { &OpenKeptRevision($revision); $header = Ts('Editing revision %s of', $revision) . " $id"; } } $oldText = $Text{'text'}; if ($preview && $isError !~ /conflict/) { $oldText = $newText; } if ($isError eq 'summary') { $oldText = $newText; } $editRows = &GetParam("editrows", 20); $editCols = &GetParam("editcols", 65); print &GetHeader('', &QuoteHtml($header), ''); if ($revision ne '') { print "\n" . Ts('Editing old revision %s.', $revision) . " " . T('Saving this page will replace the latest revision with this text.') . '
' } if ($isError eq 'summary') { # we don't have to use numerical values... print "\n

".T('Summary required for major edits.')."

\n"; } elsif ($isError =~ /conflict/) { $editRows -= 10 if ($editRows > 19); print "\n

" . T('Edit Conflict!') . "

\n"; if ($isError eq 'newconflict') { # The main purpose of a new warning is to display more text # and move the save button down from its old location. print "\n

" . T('(This is a new conflict)') . "

\n"; } print "

", T('Someone saved this page after you started editing.'), " ", T('The top textbox contains the saved text.'), " ", T('Only the text in the top textbox will be saved.'), "
\n", T('Scroll down to see your edited text.'), "
\n"; print T('Last save time:'), ' ', &TimeToText($oldTime), " (", T('Current time is:'), ' ', &TimeToText($Now), ")
\n"; } print &GetFormStart(); print &GetHiddenValue("title", $id), "\n", &GetHiddenValue("oldtime", $pageTime), "\n", &GetHiddenValue("oldconflict", $isError), "\n"; if ($revision ne "") { print &GetHiddenValue("revision", $revision), "\n"; } print &GetTextArea('text', $oldText, $editRows, $editCols); $summary = &GetParam("summary", "*"); print "

", T('Summary:'), $q->textfield(-name=>'summary', -default=>$summary, -override=>1, -size=>60, -maxlength=>200),"",T(' Please include a summary for all non-minor edits.').""; $category = &OpenCategory; if (&UserIsAdmin()) { print "
", T('Category:'), $q->textfield(-name=>'category', -default=>$category->{data}, -override=>1, -size=>60);} if (&GetParam("recent_edit") eq "on") { print "
", $q->checkbox(-name=>'recent_edit', -checked=>1, -label=>T('This change is a minor edit.')); } else { print "
", $q->checkbox(-name=>'recent_edit', -label=>T('This change is a minor edit.')); } if ($EmailNotify) { print "   " . $q->checkbox(-name=> 'do_email_notify', -label=>Ts('Send email notification that %s has been changed.', $id)); } print "
"; if ($EditNote ne '') { print T($EditNote) . '
'; # Allow translation } print $q->submit(-name=>'Save', -value=>T('Save')), "\n"; $userName = &GetParam("username", ""); if ($userName ne "") { print ' (', T('Your user name is'), ' ', &GetAuthorLink($ENV{REMOTE_ADDR},$userName,$UserID) . ') '; } else { print ' (', Ts('Visit %s to set your user name.', &GetPrefsLink()), ') '; } print $q->submit(-name=>'Preview', -value=>T('Preview')), "\n"; if ($isError =~ /conflict/) { print "\n


", T('This is the text you submitted:'), "

", &GetTextArea('newtext', $newText, $editRows, $editCols), "

\n"; } print "


\n"; if ($preview) { print "

", T('Preview:'), "

\n"; if ($isError =~ /conflict/) { print "", T('NOTE: This preview shows the revision of the other author.'), "
\n"; } $MainPage = $id; $MainPage =~ s|/.*||; # Only the main page name (remove subpage) print "
\n" unless $id eq $HomePage; print &WikiToHTML($oldText) . "
\n"; print "\n
\n" unless $id eq $HomePage; print "

", T('Preview only, not yet saved'), "

\n"; } print &GetHistoryLink($id, T('View other revisions')) . "
\n"; print &GetGotoBar($id); print $q->endform; print &GetMinimumFooter(); } sub DoPost { my ($editDiff, $old, $newAuthor, $pgtime, $oldrev, $preview, $user); my $string = &GetParam("text", undef); my $id = &GetParam("title", ""); my $summary = &GetParam("summary", ""); my $oldtime = &GetParam("oldtime", ""); my $oldconflict = &GetParam("oldconflict", ""); my $category = &GetParam("category",""); my $isMinor = (&GetParam("recent_edit", "") eq 'on'); $preview = (&GetParam("Preview", "") ne ""); my $editTime = $Now; my $authorAddr = $ENV{REMOTE_ADDR}; if (!&UserCanEdit($id, 1)) { # This is an internal interface--we don't need to explain &ReportError(Ts('Editing not allowed for %s.', $id)); return; } if (($id eq 'SampleUndefinedPage') || ($id eq T('SampleUndefinedPage'))) { &ReportError(Ts('%s cannot be defined.', $id)); return; } if (($id eq 'Sample_Undefined_Page') || ($id eq T('Sample_Undefined_Page'))) { &ReportError(Ts('[[%s]] cannot be defined.', $id)); return; } $string =~ s/$Consts->{FS}//g; $summary =~ s/$Consts->{FS}//g; $summary =~ s/[\r\n]//g; $category =~ s/$Consts->{FS}//g; $category =~ s/[\r\n]//g; # Add a newline to the end of the string (if it doesn't have one) $string .= "\n" if (!($string =~ /\n$/)); # Lock before getting old page to prevent races &RequestLock() or die(T('Could not get editing lock')); # Consider extracting lock section into sub, and eval-wrap it? # (A few called routines can die, leaving locks.) my $page = &OpenPage($id); my $textpage = &OpenDefaultText(); my $cat = &OpenCategory(); $old = $textpage->{text}->{text}; $oldrev = $textpage->{section}->{revision}; $pgtime = $textpage->{section}->{'ts'}; # To force summary... if ($Consts->{ForceSummary} && !$isMinor && !$preview && $summary eq '*') { &ReleaseLock(); &DoEdit($id, 'summary', $pgtime, $string, $preview); return; } if (!$preview && ($old eq $string)) { # No changes (ok for preview) &ReleaseLock(); &ReBrowsePage($id, "", 1); return; } # Later extract comparison? if (($UserID > 399) || ($textpage->{section}->{id} > 399)) { $newAuthor = ($UserID ne $textpage->{section}->{id}); # known user(s) } else { $newAuthor = ($textpage->{section}->{ip} ne $authorAddr); # hostname fallback } $newAuthor = 1 if ($oldrev == 0); # New page $newAuthor = 0 if (!$newAuthor); # Standard flag form, not empty # Detect editing conflicts and resubmit edit if (($oldrev > 0) && ($newAuthor && ($oldtime != $pgtime))) { &ReleaseLock(); if ($oldconflict>0) { # Conflict again... &DoEdit($id, 'newconflict', $pgtime, $string, $preview); } else { &DoEdit($id, 'conflict', $pgtime, $string, $preview); } return; } if ($preview) { &ReleaseLock(); &DoEdit($id, 0, $pgtime, $string, 1); return; } $user = &GetParam("username", ""); # If the person doing editing chooses, send out email notification if ($EmailNotify) { EmailNotify($id, $user) if &GetParam("do_email_notify", "") eq 'on'; } if (!$isMinor) { &SetPageCache('oldmajor', $textpage->{section}->{revision}); } if ($newAuthor) { &SetPageCache('oldauthor', $textpage->{section}->{revision}); } &SaveKeepSection($textpage->{section}); &ExpireKeepFile(); if ($UseDiff) { &UpdateDiffs($id, $editTime, $old, $string, $isMinor, $newAuthor); } $textpage->{text}->{text} = $string; $textpage->{text}->{minor} = $isMinor; $textpage->{text}->{newauthor} = $newAuthor; $textpage->{text}->{summary} = $summary; $textpage->{section}->{host} = &GetRemoteHost(1); &SaveDefaultText($textpage); &SaveCategory($cat,$category); &SavePage(); &WriteRcLog($id, $summary, $isMinor, $editTime, $user, $Section{'host'}); if ($UseCache) { UnlinkHtmlCache($id); # Old cached copy is invalid if ($Page{'revision'} < 2) { # If this is a new page... &NewPageCacheClear($id); # ...uncache pages linked to this one. } } if ($UseIndex && ($Page{'revision'} == 1)) { unlink($IndexFile); # Regenerate index on next request } &ReleaseLock(); &ReBrowsePage($id, "", 1); }