From 5f6313579f01166e0c6b23a9882e15e1184b58f1 Mon Sep 17 00:00:00 2001 From: JT Smith Date: Sun, 2 Mar 2003 21:15:56 +0000 Subject: [PATCH] Only process macros once per page. --- docs/gotcha.txt | 5 +++ docs/upgrades/upgrade_5.1.2-5.2.0.sql | 5 +++ lib/WebGUI/Discussion.pm | 15 +++---- lib/WebGUI/ErrorHandler.pm | 4 +- lib/WebGUI/Form.pm | 46 +++++++++++++++++++ lib/WebGUI/HTML.pm | 14 +++--- lib/WebGUI/HTMLForm.pm | 64 +++++++++++++++++++++++++++ lib/WebGUI/Macro.pm | 30 ++++++++++++- lib/WebGUI/Operation/International.pm | 5 ++- lib/WebGUI/Operation/Settings.pm | 2 - lib/WebGUI/Wobject.pm | 53 +++++++++++++++++++--- lib/WebGUI/Wobject/USS.pm | 2 +- 12 files changed, 219 insertions(+), 26 deletions(-) diff --git a/docs/gotcha.txt b/docs/gotcha.txt index a09f66689..253711294 100644 --- a/docs/gotcha.txt +++ b/docs/gotcha.txt @@ -49,6 +49,11 @@ save you many hours of grief. significantly. Macros written for versions prior to 5.2.0 are not compatible with this version or after. + * All discussions and user submission systems now have a property + for filtering content. This filter has been set to remove + javascript and macros, but you may wish to set these to one + of the other options. + 5.1.0 -------------------------------------------------------------------- diff --git a/docs/upgrades/upgrade_5.1.2-5.2.0.sql b/docs/upgrades/upgrade_5.1.2-5.2.0.sql index 4438a8974..e5635c280 100644 --- a/docs/upgrades/upgrade_5.1.2-5.2.0.sql +++ b/docs/upgrades/upgrade_5.1.2-5.2.0.sql @@ -58,6 +58,11 @@ INSERT INTO international VALUES (4,'HttpProxy',2,'Timeout (Sekunden)',104039557 INSERT INTO international VALUES (3,'HttpProxy',2,'HTTP Proxy',1040395372); INSERT INTO international VALUES (2,'HttpProxy',2,'HTTP Proxy ändern',1040395360); INSERT INTO international VALUES (1,'HttpProxy',2,'URL',1040395344); +alter table wobject add column filterPost varchar(30) not null default 'javascript'; +delete from settings where name='filterContributedHTML'; +update international set namespace='Discussion' where internationalId=524 and namespace='WebGUI'; +alter table wobject add column addEditStampToPosts int not null default 1; + diff --git a/lib/WebGUI/Discussion.pm b/lib/WebGUI/Discussion.pm index 3537431c3..986dc818f 100644 --- a/lib/WebGUI/Discussion.pm +++ b/lib/WebGUI/Discussion.pm @@ -210,8 +210,7 @@ sub formatHeader { #------------------------------------------------------------------- sub formatMessage { my $output; - $output = $_[0]; - $output = WebGUI::HTML::filter($output); + $output = WebGUI::HTML::filter($_[0],$_[1]); unless ($output =~ /\/ig || $output =~ /\/ig || $output =~ /\/ig) { $output =~ s/\n/\/g; } @@ -244,7 +243,7 @@ sub post { %message = getMessage($session{form}{replyTo}); $footer = formatHeader($message{subject},$message{userId},$message{username},$message{dateOfPost},$message{views}, '',$message{status}) - .'

'.formatMessage($message{message}); + .'

'.formatMessage($message{message},$_[0]->get("filterPost")); $message{message} = $signature; $message{subject} = "Re: ".$message{subject} unless ($message{subject} =~ /^Re:/); $session{form}{mid} = "new"; @@ -278,7 +277,7 @@ sub post { %message = getMessage($session{form}{mid}); $footer = formatHeader($message{subject},$message{userId},$message{username},$message{dateOfPost},$message{views}, '',$message{status}) - .'

'.formatMessage($message{message}); + .'

'.formatMessage($message{message},$_[0]->get("filterPost")); } $f->hidden("func","postSave"); $f->hidden("wid",$session{form}{wid}); @@ -347,7 +346,7 @@ sub postSave { if ($session{form}{subscribe}) { subscribeToThread($session{user}{userId},$rid); } - } elsif ($session{setting}{addEditStampToPosts}) { + } elsif ($_[0]->get("addEditStampToPosts")) { $session{form}{message} = "\n --- (Edited at ".epochToHuman(time())." by $session{user}{username}) --- \n\n" .$session{form}{message}; } @@ -490,7 +489,7 @@ sub showMessage { .WebGUI::International::get(364).'
'; $html .= $_[0]; $html .= ''; - $html .= formatMessage($message{message}).'

'; + $html .= formatMessage($message{message},$_[1]->get("filterPost")).'

'; $html .= ''; } else { $html = WebGUI::International::get(402); @@ -544,7 +543,7 @@ sub showReplyTree { if ($data{messageId} == $message{messageId}) { $html .= 'class="highlight"'; } - $html .= '>'.formatMessage($data{message}).'

'; + $html .= '>'.formatMessage($data{message},$_[0]->get("filterPost")).'

'; } } $sth->finish; @@ -598,7 +597,7 @@ sub showThreads { if ($data{messageId} eq $session{form}{mid}) { $html .= 'class="highlight"'; } - $html .= '>'.formatMessage($data{message}).'

'; + $html .= '>'.formatMessage($data{message},$_[0]->get("filterPost")).'

'; } } $html .= ''; diff --git a/lib/WebGUI/ErrorHandler.pm b/lib/WebGUI/ErrorHandler.pm index 10d482d5c..2f1d87e9f 100644 --- a/lib/WebGUI/ErrorHandler.pm +++ b/lib/WebGUI/ErrorHandler.pm @@ -134,7 +134,9 @@ sub fatalError { print '
'.$WebGUI::Session::session{setting}{companyURL}; } else { print "

WebGUI Fatal Error

Something unexpected happened that caused this system to fault.

"; - print "

".$data."
"; + my $formattedData = $data; + $formattedData =~ s/\n/\/g; + print $formattedData; } my $log = _log(); print $log $data; diff --git a/lib/WebGUI/Form.pm b/lib/WebGUI/Form.pm index 904aaa1fa..4811c039f 100644 --- a/lib/WebGUI/Form.pm +++ b/lib/WebGUI/Form.pm @@ -443,6 +443,52 @@ sub file { return '{extras}.'>'; } + +#------------------------------------------------------------------- + +=head2 filterContent ( hashRef ) + +Returns a select list containing the content filter options. This is for use with WebGUI::HTML::filter(). + +=over + +=item name + +The name field for this form element. This defaults to "filterContent". + +=item value + +The default value for this form element. + +=item extras + +If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here as follows: + + 'onChange="this.form.submit()"' + +=back + +=cut + +sub filterContent { + my %filter; + tie %filter, 'Tie::IxHash'; + %filter = ( + 'none'=>WebGUI::International::get(420), + 'macros'=>WebGUI::International::get(891), + 'javascript'=>WebGUI::International::get(526), + 'most'=>WebGUI::International::get(421), + 'all'=>WebGUI::International::get(419) + ); + my $name = $_[0]->{name} || "filterContent"; + return selectList({ + name=>$name, + options=>\%filter, + value=>[$_[0]->{value}], + extras=>$_[0]->{extras} + }); +} + #------------------------------------------------------------------- =head2 formHeader ( hashRef ) diff --git a/lib/WebGUI/HTML.pm b/lib/WebGUI/HTML.pm index b7ff07082..4c033d863 100644 --- a/lib/WebGUI/HTML.pm +++ b/lib/WebGUI/HTML.pm @@ -16,6 +16,7 @@ package WebGUI::HTML; use HTML::TagFilter; use strict; +use WebGUI::Macro; use WebGUI::Session; =head1 NAME @@ -84,7 +85,7 @@ The HTML content you want filtered. =item filter -Choose from all, none, javascript, or most. Defaults to most. All removes all HTML tags; none removes no HTML tags; javascript removes all references to javacript; and most removes all but simple formatting tags like bold and italics. +Choose from "all", "none", "macros", "javascript", or "most". Defaults to "most". "all" removes all HTML tags and macros; "none" removes no HTML tags; "javascript" removes all references to javacript and macros; "macros" removes all macros, but nothing else; and "most" removes all but simple formatting tags like bold and italics. =back @@ -92,10 +93,11 @@ Choose from all, none, javascript, or most. Defaults to most. All removes all H sub filter { my ($filter, $html, $type); - $type = $_[1] || $session{setting}{filterContributedHTML}; + $type = $_[1]; if ($type eq "all") { $filter = HTML::TagFilter->new(allow=>{'none'},strip_comments=>1); $html = $filter->filter($_[0]); + return WebGUI::Macro::filter($html); } elsif ($type eq "javascript") { $html = $_[0]; $html =~ s/\//ixsg; @@ -113,17 +115,19 @@ sub filter { $html =~ s/onKeyDown/removed/ixsg; $html =~ s/onSubmit/removed/ixsg; $html =~ s/onReset/removed/ixsg; + $html = WebGUI::Macro::filter($html); + } elsif ($type eq "macros") { + return WebGUI::Macro::filter($_[0]); } elsif ($type eq "none") { - $html = $_[0]; + return $_[0]; } else { $filter = HTML::TagFilter->new; # defaultly strips almost everything $html = $filter->filter($_[0]); + return WebGUI::Macro::filter($html); } - return $html; } - 1; diff --git a/lib/WebGUI/HTMLForm.pm b/lib/WebGUI/HTMLForm.pm index ffb78a01d..a93c53ec6 100644 --- a/lib/WebGUI/HTMLForm.pm +++ b/lib/WebGUI/HTMLForm.pm @@ -43,6 +43,7 @@ Package that makes HTML forms typed data and significantly reduces the code need $f->email("emailAddress","Email Address"); $f->fieldType("dataType",\%supportedTypes,"Type of Field"); $f->file("image","Image to Upload"); + $f->filterContent("filterThisContent","Filter This Content"); $f->group("groupToPost","Who can post?"); $f->hidden("wid","55"); $f->HTMLArea("description","Description"); @@ -597,6 +598,69 @@ sub file { $self->{_data} .= $output; } +#------------------------------------------------------------------- + +=head2 filterContent ( [ name, label, value, extras, subtext, uiLevel ] ) + +Adds a content filter select list to the form for use with the WebGUI::HTML::filter() function. + +=over + +=item name + +The name field for this form element. Defaults to "filterContent". + +=item label + +The left column label for this form row. Defaults to "Filter Content" (internationalized). + +=item value + +The default value for this form element. + +=item extras + +If you want to add anything special to this form element like javascript actions, or stylesheet information, you'd add it in here +as follows: + + 'onChange="this.form.submit()"' + +=item subtext + +Extra text to describe this form element or to provide special instructions. + +=item uiLevel + +The UI level for this field. See the WebGUI developer's site for details. Defaults to "0". + +=back + +=cut + +sub filterContent { + my ($output); + my ($self, @p) = @_; + my ($name, $label, $value, $extras, $subtext, $uiLevel) = + rearrange([qw(name label value extras subtext uiLevel)], @p); + if (_uiLevelChecksOut($uiLevel)) { + $label = WebGUI::International::get(418) if ($label eq ""); + $output = WebGUI::Form::filterContent({ + "name"=>$name, + "value"=>$value, + "extras"=>$extras + }); + $output .= _subtext($subtext); + $output = $self->_tableFormRow($label,$output); + } else { + $output = WebGUI::Form::hidden({ + "name"=>$name, + "value"=>$value + }); + } + $self->{_data} .= $output; +} + + #------------------------------------------------------------------- =head2 group ( name [ label, value, size, multiple, extras, subtext, uiLevel, excludeGroups ] ) diff --git a/lib/WebGUI/Macro.pm b/lib/WebGUI/Macro.pm index dee0b0aca..41c9aed8c 100644 --- a/lib/WebGUI/Macro.pm +++ b/lib/WebGUI/Macro.pm @@ -45,8 +45,8 @@ These functions are available from this package: #------------------------------------------------------------------- +# Returns a complex regular expression for matching macro patterns. sub _nestedMacro { - # This sub returns the regular expression for matching nested macro's. # Regular expression for matching balanced parenthesis my $parenthesis = qr /\( # Start with '(', (?: # Followed by @@ -69,6 +69,32 @@ sub _nestedMacro { +#------------------------------------------------------------------- + +=head2 filter ( html ) + +Removes all the macros from the HTML segment. + +=over + +=item html + +The segment to be filtered. + +=back + +=cut + +sub filter { + my $content = shift; + my $nestedMacro = _nestedMacro(); + while ($content =~ /($nestedMacro)/gs) { + $content =~ s/\Q$1//gs; + } + return $content; +} + + #------------------------------------------------------------------- =head2 getParams ( parameterString ) @@ -115,7 +141,7 @@ A string of HTML to be processed. sub process { my $content = shift; - my $nestedMacro = &_nestedMacro; + my $nestedMacro = _nestedMacro(); while ($content =~ /($nestedMacro)/gs) { my ($macro, $searchString, $params) = ($1, $2, $3); next if ($searchString =~ /^\d+$/); # don't process ^0; ^1; ^2; etc. diff --git a/lib/WebGUI/Operation/International.pm b/lib/WebGUI/Operation/International.pm index 63aa1c9ad..a85b10afd 100644 --- a/lib/WebGUI/Operation/International.pm +++ b/lib/WebGUI/Operation/International.pm @@ -86,7 +86,7 @@ sub www_addInternationalMessage { $f->hidden("lid",1); $f->hidden("op","addInternationalMessageSave"); $f->combo("namespace", - WebGUI::SQL->buildHashRef("select namespace,namespace from international where language=1 order by namespace") + WebGUI::SQL->buildHashRef("select namespace,namespace from international where languageId=1 order by namespace") ,"Namespace",['WebGUI']); $f->textarea("message","Message"); $f->submit; @@ -100,8 +100,9 @@ sub www_addInternationalMessageSave { ($nextId) = WebGUI::SQL->quickArray("select max(internationalId) from international where languageId=1 and namespace=".quote($session{form}{namespace})); $nextId++; + my $namespace = $session{form}{namespace_new} || $session{form}{namespace}; WebGUI::SQL->write("insert into international (languageId, internationalId, namespace, message, lastUpdated) values - (1,$nextId,".quote($session{form}{namespace}).",".quote($session{form}{message}).",".time().")"); + (1,$nextId,".quote($namespace).",".quote($session{form}{message}).",".time().")"); return "Message was added with id $nextId.".www_listInternationalMessages(); } diff --git a/lib/WebGUI/Operation/Settings.pm b/lib/WebGUI/Operation/Settings.pm index 98f8fca13..9cefb0a72 100644 --- a/lib/WebGUI/Operation/Settings.pm +++ b/lib/WebGUI/Operation/Settings.pm @@ -92,8 +92,6 @@ sub www_editContentSettings { $f->select("defaultPage",$pages,WebGUI::International::get(527),[$session{setting}{defaultPage}]); $f->select("notFoundPage",$pages,WebGUI::International::get(141),[$session{setting}{notFoundPage}]); $f->text("docTypeDec",WebGUI::International::get(398),$session{setting}{docTypeDec}); - $f->yesNo("addEditStampToPosts",WebGUI::International::get(524),$session{setting}{addEditStampToPosts}); - $f->select("filterContributedHTML",\%htmlFilter,WebGUI::International::get(418),[$session{setting}{filterContributedHTML}]); $f->integer("maxAttachmentSize",WebGUI::International::get(130),$session{setting}{maxAttachmentSize}); $f->integer("maxImageSize",WebGUI::International::get(583),$session{setting}{maxImageSize}); $f->integer("thumbnailSize",WebGUI::International::get(406),$session{setting}{thumbnailSize}); diff --git a/lib/WebGUI/Wobject.pm b/lib/WebGUI/Wobject.pm index 05c03d41e..27561a45f 100644 --- a/lib/WebGUI/Wobject.pm +++ b/lib/WebGUI/Wobject.pm @@ -177,6 +177,13 @@ sub discussionProperties { $editTimeout = $_[0]->get("editTimeout"); $moderationType = $_[0]->get("moderationType"); } + my $filterPost = $_[0]->get("filterPost") || "most"; + $f->filterContent( + -name=>"filterPost", + -value=>$filterPost, + -label=>WebGUI::International::get(1,"Discussion"), + -uiLevel=>7 + ); $groupToModerate = $_[0]->get("groupToModerate") || 4; $f->group( -name=>"groupToPost", @@ -210,6 +217,12 @@ sub discussionProperties { -value=>[$moderationType], -uiLevel=>7 ); + $f->yesNo( + -name=>"addEditStampToPosts", + -label=>WebGUI::International::get(524,"Discussion"), + -value=>$_[0]->get("addEditStampToPosts"), + -uiLevel=>9 + ); return $f->printRowsOnly; } @@ -487,7 +500,7 @@ sub moveCollateralUp { #------------------------------------------------------------------- -=head2 new ( properties ) +=head2 new ( properties [, extendedProperties, allowDiscussion] ) Constructor. @@ -497,16 +510,46 @@ NOTE: This method should never need to be overridden or extended. =item properties -A hash reference containing at minimum "wobjectId" and "namespace" and wobjectId may be set to "new" if you're creating a new instance. This hash reference should be the one created by WebGUI.pm and passed to the wobject subclass. +A hash reference containing at minimum "wobjectId" and "namespace". wobjectId may be set to "new" if you're creating a new instance. This hash reference should be the one created by WebGUI.pm and passed to the wobject subclass. NOTE: It may seem a little weird that the initial data for the wobject instance is coming from WebGUI.pm, but this was done to lessen database traffic thus increasing the speed of all wobjects. +=item extendedProperties + +An array reference containing a list of properties that extend the wobject class. This list should match the properties that are added to this wobject's namespace table in the database. So if this wobject has a namespace of "MyWobject" and a table definition that looks like this: + + create MyWobject ( + wobjectId int not null primary key, + something varchar(25), + foo int not null default 1, + bar int + ); + +Then the extended property list would be "[something, foo, bar]". + +NOTE: This is used to define the wobject and should only be passed in by a wobject subclass. + +=item allowDiscussion + + Defaults to "0". If set to "1" this will add a discussion properties tab to this wobject to enable content managers to set the properties of a discussion attached to this wobject. + +NOTE: This is used to define the wobject and should only be passed in by a wobject subclass. + =back =cut sub new { - bless {_property => $_[1]}, $_[0]; + my $self = shift; + my $properties = shift; + my $extendedProperties = shift; + my $allowDiscussion = shift || 0; + bless({ + _property=>$properties, + _extendedProperties=>$extendedProperties, + _allowDiscussion=>$allowDiscussion + }, + $self); } #------------------------------------------------------------------- @@ -1224,7 +1267,7 @@ Displays a discussion message post form. sub www_post { if (WebGUI::Privilege::isInGroup($_[0]->get("groupToPost"))) { - return WebGUI::Discussion::post(); + return WebGUI::Discussion::post($_[0]); } else { return WebGUI::Privilege::insufficient(); } @@ -1280,7 +1323,7 @@ sub www_showMessage { ($defaultMid) = WebGUI::SQL->quickArray("select min(messageId) from discussion where wobjectId=".$_[0]->get("wobjectId")); $session{form}{mid} = $session{form}{mid} || $defaultMid || 0; $output = WebGUI::Discussion::showMessage($_[1],$_[0]); - $output .= WebGUI::Discussion::showReplyTree(); + $output .= WebGUI::Discussion::showReplyTree($_[0]); return $output; } diff --git a/lib/WebGUI/Wobject/USS.pm b/lib/WebGUI/Wobject/USS.pm index 93d521617..170b2a487 100644 --- a/lib/WebGUI/Wobject/USS.pm +++ b/lib/WebGUI/Wobject/USS.pm @@ -456,7 +456,7 @@ sub www_viewSubmission { $var{"attachment.icon"} = $file->getIcon; $var{"attachment.name"} = $file->getFilename; } - $var{"replies"} = WebGUI::Discussion::showThreads(); + $var{"replies"} = WebGUI::Discussion::showThreads($_[0]); return WebGUI::Template::process(WebGUI::Template::get($_[0]->get("submissionTemplateId"),"USS/Submission"), \%var); }