1 rizwank 1.1 # TWiki Collaboration Platform, http://TWiki.org/
2 #
3 # Copyright (C) 1999-2004 Peter Thoeny, peter@thoeny.com
4 #
5 # Based on parts of Ward Cunninghams original Wiki and JosWiki.
6 # Copyright (C) 1998 Markus Peter - SPiN GmbH (warpi@spin.de)
7 # Some changes by Dave Harris (drh@bhresearch.co.uk) incorporated
8 #
9 # For licensing info read license.txt file in the TWiki root.
10 # This program is free software; you can redistribute it and/or
11 # modify it under the terms of the GNU General Public License
12 # as published by the Free Software Foundation; either version 2
13 # of the License, or (at your option) any later version.
14 #
15 # This program is distributed in the hope that it will be useful,
16 # but WITHOUT ANY WARRANTY; without even the implied warranty of
17 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 # GNU General Public License for more details, published at
19 # http://www.gnu.org/copyleft/gpl.html
20 =begin twiki
21
22 rizwank 1.1 ---+ TWiki::UI::View
23
24 UI delegate for view function
25
26 =cut
27
28 package TWiki::UI::View;
29
30 use strict;
31 use TWiki;
32 use TWiki::UI;
33
34 =pod
35
36 ---++ view( $web, $topic, $scruptUrl, $query )
37 Generate a complete HTML page that represents the viewed topics.
38 The view is controlled by CGI parameters as follows:
39 | =rev= | topic revision to view |
40 | =raw= | don't format body text if set |
41 | =unlock= | remove any topic locks if set |
42 | =skin= | name of skin to use |
43 rizwank 1.1 | =contenttype= | |
44
45 =cut
46
47 sub view {
48 my ( $webName, $topic, $userName, $query ) = @_;
49
50 my $rev = $query->param( "rev" );
51 my $viewRaw = $query->param( "raw" ) || "";
52 my $unlock = $query->param( "unlock" ) || "";
53 my $skin = $query->param( "skin" );
54 my $contentType = $query->param( "contenttype" );
55
56 TWiki::UI::writeDebugTimes( "view - initialized" );
57
58 my $tmpl = "";
59 my $text = "";
60 my $meta = "";
61 my $maxrev = 1;
62 my $extra = "";
63 my $wikiUserName = &TWiki::userToWikiName( $userName );
64 rizwank 1.1 my $revdate = "";
65 my $revuser = "";
66
67 $skin = &TWiki::Prefs::getPreferencesValue( "SKIN" ) unless ( $skin );
68
69 # Set page generation mode to RSS if using an RSS skin
70 if( $skin =~ /^rss/ ) {
71 TWiki::setPageMode( 'rss' );
72 }
73
74 # get view template, standard view or a view with a different skin
75 $tmpl = &TWiki::Store::readTemplate( "view", $skin );
76 if( ! $tmpl ) {
77 TWiki::writeHeader( $query );
78 print "<html><body>\n"
79 . "<h1>TWiki Installation Error</h1>\n"
80 . "Template file view.tmpl not found or template directory \n"
81 . "$TWiki::templateDir not found.<p />\n"
82 . "Check the \$templateDir variable in TWiki.cfg.\n"
83 . "</body></html>\n";
84 return;
85 rizwank 1.1 }
86 TWiki::UI::writeDebugTimes( "view - readTemplate" );
87
88 return unless TWiki::UI::webExists( $webName, $topic );
89 TWiki::UI::writeDebugTimes( "view - webExists" );
90
91 if( $unlock eq "on" ) {
92 # unlock topic, user cancelled out of edit
93 &TWiki::Store::lockTopic( $topic, "on" );
94 }
95
96 # Most recent topic read in even if earlier topic requested - makes
97 # code simpler and performance impact should be minimal
98 my $topicExists = &TWiki::Store::topicExists( $webName, $topic );
99 if( $topicExists ) {
100 if( $viewRaw ) {
101 $text = &TWiki::Store::readTopicRaw( $webName, $topic );
102 } else {
103 ( $meta, $text ) = &TWiki::Store::readTopic( $webName, $topic );
104 }
105 ( $revdate, $revuser, $maxrev ) = &TWiki::Store::getRevisionInfoFromMeta( $webName, $topic, $meta);
106 rizwank 1.1 $revdate = TWiki::formatTime( $revdate );
107
108 if( $rev ) {
109 $rev =~ s/r?1\.//go; # cut 'r' and major
110 if( $rev < 1 ) { $rev = 1; }
111 if( $rev > $maxrev ) { $rev = $maxrev; }
112 } else {
113 $rev = $maxrev;
114 }
115
116 if( $rev < $maxrev ) {
117 if( $viewRaw ) {
118 $text = &TWiki::Store::readTopicRaw( $webName, $topic, "1.$rev" );
119 } else {
120 ( $meta, $text ) = &TWiki::Store::readTopicVersion( $webName, $topic, "1.$rev" );
121 }
122 ( $revdate, $revuser ) = &TWiki::Store::getRevisionInfo( $webName, $topic, "1.$rev");
123 $revdate = TWiki::formatTime( $revdate );
124 $extra .= "r1.$rev";
125 }
126 } else {
127 rizwank 1.1 $rev = 1;
128 if( &TWiki::isWikiName( $topic ) || &TWiki::isAbbrev( $topic ) ) {
129 ( $meta, $text ) = &TWiki::Store::readTemplateTopic( "WebTopicViewTemplate" );
130 } else {
131 ( $meta, $text ) = &TWiki::Store::readTemplateTopic( "WebTopicNonWikiTemplate" );
132 }
133 $extra .= " (not exist)";
134 }
135
136 if( $viewRaw ) {
137 $extra .= " raw=$viewRaw";
138 if( $viewRaw !~ /debug/i ) {
139 $text = join( "\n", grep{ !/^%META:([^{]+){(.*)}%$/ } split( /\r?\n/, $text ) );
140 }
141 if( $skin !~ /^text/ ) {
142 my $vtext = "<form><textarea readonly=\"readonly\" wrap=\"virtual\" rows=\"%EDITBOXHEIGHT%\" cols=\"%EDITBOXWIDTH%\">";
143 $vtext = &TWiki::handleCommonTags( $vtext, $topic );
144 $text =~ s/&/&\;/go;
145 $text =~ s/%/&\#037\;/go;
146 $text =~ s/</<\;/go;
147 $text =~ s/>/>\;/go;
148 rizwank 1.1 $text =~ s/\t/ /go;
149 $text = "$vtext$text</textarea></form>";
150 }
151 }
152
153 TWiki::UI::writeDebugTimes( "view - get rev info" );
154
155 if( ! $viewRaw ) {
156 $text = &TWiki::handleCommonTags( $text, $topic );
157 TWiki::UI::writeDebugTimes( "view - handleCommonTags done" );
158 $text = &TWiki::Render::getRenderedVersion( $text );
159 TWiki::UI::writeDebugTimes( "view - getRendereredVersion done" );
160 }
161
162 if( $TWiki::doLogTopicView ) {
163 # write log entry
164 &TWiki::Store::writeLog( "view", "$webName.$topic", $extra );
165 }
166
167 my( $mirrorSiteName, $mirrorViewURL, $mirrorLink, $mirrorNote ) = &TWiki::readOnlyMirrorWeb( $webName );
168 if( $mirrorSiteName ) {
169 rizwank 1.1 # disable edit and attach
170 # FIXME: won't work with non-default skins, see %EDITURL%
171 $tmpl =~ s/%EDITTOPIC%/$mirrorLink | <strike>Edit<\/strike>/go;
172 $tmpl =~ s/<a [^>]*?>Attach<\/a>/<strike>Attach<\/strike>/goi;
173 if( $topicExists ) {
174 # remove the NOINDEX meta tag
175 $tmpl =~ s/<meta name="robots"[^>]*>//goi;
176 } else {
177 $text = "";
178 }
179 $tmpl =~ s/%REVTITLE%//go;
180 } elsif( $rev < $maxrev ) {
181 # disable edit of previous revisions - FIXME consider change to use two templates
182 # FIXME: won't work with non-default skins, see %EDITURL%
183 $tmpl =~ s/%EDITTOPIC%/<strike>Edit<\/strike>/go;
184 $tmpl =~ s/<a [^>]*?>Attach<\/a>/<strike>Attach<\/strike>/goi;
185 $tmpl =~ s|<a [^>]*?>Rename/move<\/a>|<strike>Rename/move<\/strike>|goi;
186 $tmpl =~ s/%REVTITLE%/\(r1.$rev\)/go;
187 $tmpl =~ s/%REVARG%/&rev=1.$rev/go;
188 } else {
189 # Remove the NOINDEX meta tag (for robots) from both Edit and
190 rizwank 1.1 # Create pages
191 $tmpl =~ s/<meta name="robots"[^>]*>//goi;
192 my $editAction = $topicExists ? 'Edit' : 'Create';
193
194 # Special case for 'view' to handle %EDITTOPIC% and Edit vs. Create.
195 # New %EDITURL% variable is implemented by handleCommonTags, suffixes
196 # '?t=NNNN' to ensure that every Edit link is unique, fixing
197 # Codev.RefreshEditPage bug relating to caching of Edit page.
198 $tmpl =~ s!%EDITTOPIC%!<a href=\"%EDITURL%\"><b>$editAction</b></a>!go;
199
200 # FIXME: Implement ColasNahaboo's suggested %EDITLINK% along the
201 # same lines, within handleCommonTags
202 $tmpl =~ s/%REVTITLE%//go;
203 $tmpl =~ s/%REVARG%//go;
204 }
205
206 #SMELL: HUH? - TODO: why would you not show the revisions around the version that you are displaying? and this logic is yucky@!
207 my $i = $maxrev;
208 my $j = $maxrev;
209 my $revisions = "";
210 my $breakRev = 0;
211 rizwank 1.1 if( ( $TWiki::numberOfRevisions > 0 ) && ( $TWiki::numberOfRevisions < $maxrev ) ) {
212 $breakRev = $maxrev - $TWiki::numberOfRevisions + 1;
213 }
214 while( $i > 0 ) {
215 if( $i == $rev) {
216 $revisions = "$revisions | r1.$i";
217 } else {
218 $revisions = "$revisions | <a href=\"%SCRIPTURLPATH%/view%SCRIPTSUFFIX%/%WEB%/%TOPIC%?rev=1.$i\">r1.$i</a>";
219 }
220 if( $i != 1 ) {
221 if( $i == $breakRev ) {
222 $i = 1;
223 } else {
224 $j = $i - 1;
225 $revisions = "$revisions | <a href=\"%SCRIPTURLPATH%/rdiff%SCRIPTSUFFIX%/%WEB%/%TOPIC%?rev1=1.$i&rev2=1.$j\">></a>";
226 }
227 }
228 $i = $i - 1;
229 }
230 $tmpl =~ s/%REVISIONS%/$revisions/go;
231
232 rizwank 1.1 $tmpl =~ s/%REVINFO%/%REVINFO%$mirrorNote/go;
233
234 $tmpl = &TWiki::handleCommonTags( $tmpl, $topic );
235 if( $viewRaw ) {
236 $tmpl =~ s/%META{[^}]*}%//go;
237 } else {
238 $tmpl = &TWiki::handleMetaTags( $webName, $topic, $tmpl, $meta, ( $rev == $maxrev ) );
239 }
240 TWiki::UI::writeDebugTimes( "view - handleCommonTags for template done" );
241 $tmpl = &TWiki::Render::getRenderedVersion( $tmpl, "", $meta ); ## better to use meta rendering?
242 $tmpl =~ s/%TEXT%/$text/go;
243 $tmpl =~ s/%MAXREV%/1.$maxrev/go;
244 $tmpl =~ s/%CURRREV%/1.$rev/go;
245 $tmpl =~ s/( ?) *<\/?(nop|noautolink)\/?>\n?/$1/gois; # remove <nop> tags (PTh 06 Nov 2000)
246
247 # check access permission
248 my $viewAccessOK = &TWiki::Access::checkAccessPermission( "view", $wikiUserName, $text, $topic, $webName );
249
250 if( (!$topicExists) || $TWiki::readTopicPermissionFailed ) {
251 # Can't read requested topic and/or included (or other accessed topics
252 # user could not be authenticated, may be not logged in yet?
253 rizwank 1.1 my $viewauthFile = $ENV{'SCRIPT_FILENAME'};
254 $viewauthFile =~ s|/view|/viewauth|o;
255 if( ( ! $query->remote_user() ) && (-e $viewauthFile ) ) {
256 # try again with authenticated viewauth script
257 # instead of non authenticated view script
258 my $url = $ENV{"REQUEST_URI"};
259 if( $url && $url =~ m|/view| ) {
260 # $url i.e. is "twiki/bin/view.cgi/Web/Topic?cms1=val1&cmd2=val2"
261 $url =~ s|/view|/viewauth|o;
262 $url = "$TWiki::urlHost$url";
263 } else {
264 # If REQUEST_URI is rewritten and does not contain the name "view"
265 # try looking at the CGI environment variable SCRIPT_NAME.
266 #
267 # Assemble the new URL using the host, the changed script name,
268 # the path info, and the query string. All three query variables
269 # are in the list of the canonical request meta variables in CGI 1.1.
270 my $script = $ENV{'SCRIPT_NAME'};
271 my $pathInfo = $ENV{'PATH_INFO'};
272 my $queryString = $ENV{'QUERY_STRING'};
273 $pathInfo = '/' . $pathInfo if ($pathInfo);
274 rizwank 1.1 $queryString = '?' . $queryString if ($queryString);
275 if ($script && $script =~ m|/view| ) {
276 $script =~ s|/view|/viewauth|o;
277 $url = "$TWiki::urlHost$script$pathInfo$queryString";
278 } else {
279 # If SCRIPT_NAME does not contain the name "view"
280 # the last hope is to try the SCRIPT_FILENAME ...
281 $viewauthFile =~ s|^.*/viewauth|/viewauth|o; # strip off $Twiki::scriptUrlPath
282 $url = "$TWiki::urlHost$TWiki::scriptUrlPath/$viewauthFile$pathInfo$queryString";
283 }
284 }
285 TWiki::UI::redirect( $url );
286 }
287 }
288 if( ! $viewAccessOK ) {
289 TWiki::UI::oops( $webName, $topic, "accessview" );
290 }
291
292 TWiki::UI::writeDebugTimes( "view - checked access permissions" );
293
294 # Write header based on "contenttype" parameter, used to produce
295 rizwank 1.1 # MIME types like text/plain or text/xml, e.g. for RSS feeds.
296 if( $contentType ) {
297 TWiki::writeHeaderFull( $query, 'basic', $contentType, 0);
298 if( $skin =~ /^rss/ ) {
299 $tmpl =~ s/<img [^>]*>//g; # remove image tags
300 $tmpl =~ s/<a [^>]*>//g; # remove anchor tags
301 $tmpl =~ s/<\/a>//g; # remove anchor tags
302 }
303 } elsif( $skin =~ /^rss/ ) {
304 TWiki::writeHeaderFull( $query, 'basic', 'text/xml', 0);
305 $tmpl =~ s/<img [^>]*>//g; # remove image tags
306 $tmpl =~ s/<a [^>]*>//g; # remove anchor tags
307 $tmpl =~ s/<\/a>//g; # remove anchor tags
308 } else {
309 TWiki::writeHeader( $query );
310 }
311
312 # print page content
313 print $tmpl;
314
315 TWiki::UI::writeDebugTimes( "view - done" );
316 rizwank 1.1 }
317
318 1;
|