File Coverage

blib/lib/WebEditor/OldController.pm
Criterion Covered Total %
statement 13 15 86.6
branch n/a
condition n/a
subroutine 5 5 100.0
pod n/a
total 18 20 90.0


"; "; \n"; ";
line stmt bran cond sub pod time code
1             # -*- perl -*-
2              
3             #
4             # $Id: OldController.pm,v 1.94 2006/02/16 12:32:34 cmuellermeta Exp $
5             #
6             # WebEditor::OldController used to be we_redisys.cgi in the old web.editor
7             # system.
8             #
9             # Original author:
10             # oleberlin@users.sourceforge.net
11             # Modified into a OO module and current maintainer:
12             # eserte@users.sourceforge.net
13             #
14             # See http://www.sourceforge.net/projects/we-framework
15             #
16             # Copyright (c) 1999-2002 Olaf Maetzner. All rights reserved.
17             # Copyright (c) 1999-2005 Slaven Rezic. All rights reserved.
18             # This is free software; you can redistribute it and/or modify it under the
19             # terms of the GNU General Public License, see the file COPYING.
20             #
21              
22             package WebEditor::OldController;
23              
24 1     1   650 use strict;
  1         2  
  1         28  
25 1     1   9 use vars qw($VERSION);
  1         2  
  1         66  
26             $VERSION = sprintf("%d.%02d", q$Revision: 1.94 $ =~ /(\d+)\.(\d+)/);
27              
28 1     1   6 use base qw(Class::Accessor);
  1         10  
  1         110  
29             __PACKAGE__->mk_accessors(qw(R C Class FE_Class HeaderPrinted
30             SessionName Session Goto Messages
31             EditorLang TemplateVars TemplateConf Root FE
32             ContentDumper ScriptDumper User Password
33             CustomUserDB
34             ));
35 1     1   7 use CGI qw(:standard);
  1         1  
  1         8  
36 1     1   3503 use Data::JavaScript {JS => 1.3}; # for unicode support
  0            
  0            
37             Data::JavaScript->VERSION('1.10');
38              
39             use WE::Util::LangString qw(langstring new_langstring set_langstring);
40              
41             BEGIN {
42             if ($] < 5.006) {
43             $INC{"warnings.pm"} = 1;
44             *warnings::import = sub { };
45             *warnings::unimport = sub { };
46             }
47             }
48             # {
49             # ## XXX This should go to the original Data::JavaScript!!!
50             # use Data::JavaScript;
51             # package Data::JavaScript;
52             # no warnings 'redefine';
53             # my $unicoderange = '\x{0100}-\x{fffd}';
54             # if ($] < 5.006) { $unicoderange = "" }
55             # sub quotemeta {
56             # my $text = shift;
57             # $text =~ s/([^\x20\x21\x23-\x26\x28-\x7E$unicoderange])/sprintf("\\%03o", ord($1))/geo;
58             # $text =~ s/([$unicoderange])/sprintf("\\u%04x", ord($1))/geo;
59             # $text;
60             # }
61             # }
62              
63             {
64             if (eval q{ use CGI::Util; 1 }) {
65             package CGI::Util;
66             no warnings 'redefine';
67             if (prototype(\&CGI::Util::utf8_chr) eq '$') {
68             *utf8_chr = sub ($) {
69             chr($_[0]);
70             };
71             } else {
72             *utf8_chr = sub {
73             chr($_[0]);
74             };
75             }
76             }
77             }
78              
79             sub subs {
80             # where do you want to go today ;-)
81              
82             my %admin_pages = map { ($_ => [$_, "WebEditor::OldController::Admin"]) }
83             (qw(admin publish linkchecker checkreleased releasepages useradmin));
84              
85             +{'login' => "login",
86             'pageeditorframe' => "pageeditorframe",
87             'mainframe' => "mainframe",
88             'mainpanel' => "mainpanel",
89             'siteeditorframe' => "siteeditorframe",
90             'main' => "siteeditorframe", # just an alias
91             'pageedit' => "pageedit",
92             'siteedit' => "siteedit",
93             'siteeditexplorer' => "siteeditexplorer",
94             'folderedit' => "folderedit",
95             'doctreeframe' => "doctreeframe",
96             'doctree' => "doctree",
97             'preview' => "preview",
98             'updatehtml' => "updatehtml",
99             'search' => "search",
100             'error' => "error",
101             'savepage' => "savepage",
102             'createpage' => "createpage",
103             'uploadpage' => "uploadpage",
104             'createfolder' => "createfolder",
105             'deletepage' => "deletepage",
106             'cancelpage' => "cancelpage",
107             'showeditor' => "showeditor",
108             'movecopyframeset' => "movecopyframeset",
109             'movecopyjs' => "movecopyjs",
110             'movecopyexplorer' => "movecopyexplorer",
111             'movecopyaction' => "movecopyaction",
112             'unlock' => "unlock",
113             'passthroughdb' => "passthrough", # like passthrough with DB access
114              
115             # mixin'ed:
116             'systemexplorer' => "systemexplorer",
117             'wwwauthedit' => "wwwauthedit",
118              
119             %admin_pages,
120             };
121             }
122              
123             sub showeditor_methods {
124             +{
125             "image" => "showeditor_any",
126             "download" => "showeditor_any",
127             "link" => "showeditor_link",
128             "teaserlink" => "showeditor_teaserlink",
129             };
130             }
131              
132             sub new {
133             my($class) = @_;
134             my $self = bless {}, $class;
135             $self;
136             }
137              
138             sub handle {
139             my($self, $c, $r) = @_;
140             my $ret = $self->init($c, $r);
141             return if !$ret;
142             $self->dispatch;
143             }
144              
145             # The output of templateconf is a hash ref. The method can be overridden to
146             # add other options to this hash, e.g. FILTERS => { filter => coderef }
147             sub templateconf {
148             my $self = shift;
149             my $c = $self->C;
150              
151             my $template_compile_dir = "/tmp/webeditor-cache-$<";
152             if (!-e $template_compile_dir) {
153             mkdir $template_compile_dir, 0700;
154             if (!-e $template_compile_dir) {
155             undef $template_compile_dir;
156             warn "Can't create $template_compile_dir, disabled caching...";
157             }
158             } else {
159             if (!-d $template_compile_dir) {
160             undef $template_compile_dir;
161             warn "$template_compile_dir is not a directory, disabled caching...";
162             }
163             }
164              
165             return {ABSOLUTE => 1,
166             POST_CHOMP => 1,
167             INCLUDE_PATH => [$c->paths->site_templatebase,
168             $c->paths->we_templatebase,
169             ],
170             EVAL_PERL => 1,
171             PLUGIN_BASE => ["WE_" . $c->project->name . "::Plugin",
172             "WE_Frontend::Plugin"],
173             #ERROR => "we_error.tpl.html",# worse diagnostics...
174             #DEBUG => "all",
175             (defined $template_compile_dir ?
176             (COMPILE_EXT => ".ttc",
177             COMPILE_DIR => $template_compile_dir,
178             ) : ()
179             ),
180             };
181             }
182              
183             sub init {
184             my($self, $c, $r, %args) = @_;
185              
186             my $batch = delete $args{-batch} || 0;
187             if ($batch) {
188             while(my($k,$v) = each %args) {
189             param(substr($k,1), $v);
190             }
191             }
192              
193             $self->R($r);
194             $self->C($c);
195              
196             $self->Class ($c->project->class);
197             $self->FE_Class($c->project->feclass);
198              
199             $self->Messages({});
200             $self->CustomUserDB({});
201             $self->HeaderPrinted(0);
202             $self->SessionName('we_session_' . $c->project->name);
203             my $session = $self->Session({ cookie($self->SessionName) });
204             my $editorlang = param('editorlang') ||
205             $session->{'editorlang'} ||
206             $c->project->defaulteditorlang;
207             my $scriptname = ($ENV{MOD_PERL} && $self->R ? $self->R->uri : script_name());
208             $editorlang =~ s/\W//g; # make safe characters
209             $self->EditorLang($editorlang);
210             $self->TemplateVars
211             ({c => $c,
212             config => $c, # backward compatibility
213             editorlang => $self->EditorLang,
214             # for convenience:
215             cgiurl => $c->paths->cgiurl,
216             rooturl => $c->paths->rooturl,
217             paths => $c->paths,
218             productname => $c->project->productname,
219             debug => $c->debug,
220             scriptname => $scriptname,
221             controller => $self,
222             });
223              
224             $self->TemplateConf($self->templateconf);
225              
226             local $| = 1;
227              
228             my $goto = param("goto");
229             $self->Goto($goto);
230             if (defined $goto && $goto =~ /^passthrough(site)?$/) {
231             if ($goto eq 'passthrough') {
232             $self->passthrough;
233             } else {
234             $self->passthroughsite;
235             }
236             return 0;
237             }
238              
239             if (($c->siteext && $c->siteext->external_auth)) {
240             my $user = remote_user();
241             if (defined $user && $user eq "logoutuser") {
242             if (defined $goto && $goto eq "logout") {
243             $self->logout;
244             return 0; # no dispatch
245             } else {
246             print redirect($c->paths->scheme . '://invalid@' . $c->paths->servername . ":" . $c->paths->serverport . $scriptname);
247             return 0;
248             }
249             }
250             }
251              
252             my $root = $self->Class->new(-rootdir => $c->paths->we_database,
253             -locking => 1,
254             -connect => exists $ENV{MOD_PERL} ? 0 : 1,
255             );
256             $self->Root($root);
257             my $fe = $self->FE_Class->new(-root => $root, -config => $c);
258             $self->FE($fe);
259              
260             $c->debug(1) if (param('debug'));
261              
262             # set some values from session or defaultvalues
263             my($user, $password, $got_user_password);
264             if ($c->project->features->{session} && $session->{'sid'}) {
265             my $sess = $self->get_session($session->{sid});
266             $user = $sess->{user};
267             $password = $sess->{password};
268             $got_user_password = 1;
269             } else {
270             $user = param('user') || $session->{'user'} || "";
271             $password = param('password') || $session->{'password'} || "";
272             $got_user_password = param('user') && (!$session->{'user'} || $session->{'user'} ne param('user'));
273             }
274             $self->User($user);
275             $self->Password($password);
276              
277             if ($got_user_password) {
278             $root->login($user, $password);
279             }
280              
281             if (!$batch && !($c->siteext && $c->siteext->external_auth)) {
282             if ($user =~ /^\s*$/ || $password =~ /^\s*$/) {
283             $self->login;
284             return 0;
285             }
286             }
287              
288             $self->TemplateVars->{is_allowed} = sub {
289             return 1 if $batch;
290             $self->identify;
291             my $root = $self->Root;
292             $root->is_allowed($_[0]);
293             };
294              
295             if (defined $goto && $goto eq "logout") {
296             $root->logout($user) if defined $user && $user ne "";
297             $self->login;
298             return 0; # no dispatch
299             }
300             if ($session->{sid} || $c->project->features->{session}) {
301             my $sess = $self->get_session($session->{sid});
302             $sess->{user} = $user;
303             $sess->{password} = $password;
304             $session->{editorlang} = $self->EditorLang; # XXX better store in %sess, but editorlang is used very early, see above...
305             $session->{sid} = $sess->{_session_id};
306             } else {
307             $session->{'user'} = $user;
308             $session->{'password'} = $password;
309             $session->{'editorlang'} = $self->EditorLang;
310             }
311             my $cookie = cookie(-name => $self->SessionName,
312             -value => $self->Session,
313             -expires => $c->project->cookieexpirationtime || '+1d');
314             $self->TemplateVars->{rootdb} = $root;
315             $self->TemplateVars->{objdb} = $root->ObjDB;
316             $self->TemplateVars->{username} = $user;
317             $self->TemplateVars->{'locking'} = $c->project->sessionlocking ? $user : "" ;
318              
319             $root->OnlineUserDB->ping($user) if $root->OnlineUserDB;
320              
321             my $content_dumper = $c->project->projectext && $c->project->projectext->{content_dumper};
322             if (!$content_dumper) { $content_dumper = "WE_Content::PerlDD" }
323             $self->ContentDumper($content_dumper);
324              
325             my $script_dumper = $c->project->projectext && $c->project->projectext->{script_dumper};
326             if (!$script_dumper) { $script_dumper = "WE_Content::PerlDD" }
327             $self->ScriptDumper($script_dumper);
328              
329             # print HTTP-header, set the cookies
330             if (!$batch && !param("nohttpheader") && (!defined param("goto") || param("goto") ne 'preview')) {
331             print $self->myheader(-cookie=> [$cookie]);
332             $self->{HeaderPrinted} = 1;
333             }
334              
335             1;
336             }
337              
338             sub dispatch {
339             my $self = shift;
340             my $goto = $self->Goto;
341             my $c = $self->C;
342             my $subs = $self->subs;
343             my $pageid = param("pageid");
344              
345             {
346             if (!defined $goto) {
347             if ($c->siteext && $c->siteext->external_auth) {
348             $goto = "mainframe"; # already authenticated...
349             } else {
350             $goto = "login";
351             }
352             }
353             my $method = $subs->{$goto};
354             if (!defined $method) {
355             if ($c && $c->siteext && $c->siteext->external_auth) {
356             if ($goto eq "logout") {
357             # XXX logout is not really possible with external_auth
358             # --- maybe remove the link from mainpanel?
359             return $self->logout;
360             } else {
361             $method = $subs->{'mainframe'};
362             }
363             } else {
364             warn "goto $goto is unknown";
365             $method = $subs->{'login'};
366             }
367             }
368             if (UNIVERSAL::isa($method, "ARRAY")) {
369             my $class;
370             ($method, $class) = @$method;
371             eval qq{ require $class }; die $@ if $@;
372             }
373             warn "goto: $goto (method $method $pageid)\n" if $c->debug;
374             $self->$method();
375             }
376              
377             die $@ if $@ and $c->debug;
378             }
379              
380             sub myheader {
381             my($self, %args) = @_;
382             $args{-charset} = $self->output_charset if !exists $args{-charset};
383             header(%args);
384             }
385              
386             sub output_charset {
387             "iso-8859-1"
388             }
389              
390             sub get_fh_charset_converter {
391             my $self = shift;
392             my $output_charset = $self->output_charset;
393             if ($output_charset eq "iso-8859-1") {
394             # do nothing
395             return sub { };
396             }
397             return sub {
398             my $fh = shift;
399             binmode($fh, ":encoding(" . $output_charset . ")");
400             };
401             }
402              
403             sub get_string_charset_converter {
404             my $self = shift;
405             my $output_charset = $self->output_charset;
406             if ($output_charset eq "iso-8859-1") {
407             # do nothing
408             return sub { $_[0] };
409             }
410             require Encode;
411             return sub {
412             Encode::encode($output_charset, $_[0]);
413             };
414             }
415              
416             sub get_string_charset_decode_converter {
417             my $self = shift;
418             my $output_charset = $self->output_charset;
419             if ($output_charset eq "iso-8859-1") {
420             # do nothing
421             return sub { $_[0] };
422             }
423             require Encode;
424             return sub {
425             Encode::decode($output_charset, $_[0]);
426             };
427             }
428              
429             sub reset_fh_charset_converter {
430             my $self = shift;
431             my $output_charset = $self->output_charset;
432             if ($output_charset eq "iso-8859-1") {
433             # do nothing
434             return sub { };
435             }
436             return sub {
437             my $fh = shift;
438             binmode($fh, ":raw");
439             };
440             }
441              
442             ######################################################################
443             #
444             # show login screen
445             #
446             sub login {
447             my $self = shift;
448             my $message = shift;
449             if (!$self->HeaderPrinted) {
450             # Create also a pseudo cookie for the cookie detection code in
451             # LoginDispatcher.pm.
452             print $self->myheader(-cookie => cookie(-name => $self->SessionName,
453             -value => {}));
454             }
455             my $templatevars = $self->TemplateVars;
456             my $c = $self->C;
457             $templatevars->{'editorlanguages'} = $c->project->editorlanguages;
458             if ($message) {
459             $templatevars->{'login_message'} = $message;
460             } elsif (param("message")) {
461             $templatevars->{'login_message'} = param("message");
462             }
463             $self->_tpl("bestwe", "we_login_screen.tpl.html");
464             } #### sub login END
465              
466             sub check_login {
467             my $self = shift;
468             $self->login unless $self->identify;
469             }
470              
471             sub logout {
472             my $self = shift;
473             if (!$self->HeaderPrinted) {
474             print $self->myheader(-cookie => undef);
475             }
476              
477             my $session = $self->Session;
478             my $c = $self->C;
479             if ($c->project->features->{session} && $session && $session->{'sid'}) {
480             $self->delete_session($session->{'sid'});
481             }
482              
483             my $templatevars = $self->TemplateVars;
484             $templatevars->{olduser} = param("olduser");
485             $self->_tpl("bestwe", "we_logout_screen.tpl.html");
486             }
487              
488             sub mainpanel {
489             my $self = shift;
490             if (!$self->HeaderPrinted) { print $self->myheader() }
491             $self->identify;
492             my $root = $self->Root;
493             my $templatevars = $self->TemplateVars;
494             $templatevars->{is_admin} = $root->is_allowed(["admin","useradmin","release","publish"]);
495             $self->_tpl("bestwe", "we_mainpanel.tpl.html");
496             }
497              
498             ######################################################################
499             #
500             # show a we template
501             #
502             sub passthrough {
503             my $self = shift;
504             my %args;
505             my $template = param('template');
506             my($content_type) = $self->get_we_template_contenttype($template);
507             if ($content_type ne "text/html") {
508             $args{"-Content-Type"} = $content_type;
509             }
510             if (!$self->HeaderPrinted) { print $self->myheader(%args) }
511             die "No '..' allowed in template specification!"
512             if $template =~ m"(/|^)\.\.(/|$)";
513             $self->_tpl("bestwe", $template);
514             } #### sub passthrough END
515              
516             ######################################################################
517             #
518             # show a project (site) template
519             #
520             sub passthroughsite {
521             my $self = shift;
522             my %args;
523             my $template = param('template');
524             my($content_type) = $self->get_we_template_contenttype($template);
525             if ($content_type ne "text/html") {
526             $args{"-Content-Type"} = $content_type;
527             }
528             if (!$self->HeaderPrinted) { print $self->myheader(%args) }
529             die "No '..' allowed in template specification!"
530             if $template =~ m"(/|^)\.\.(/|$)";
531             $self->_tpl("site_we", $template);
532             } #### sub passthrough END
533              
534             ######################################################################
535             #
536             # preview a page
537             #
538             sub preview {
539             my $self = shift;
540              
541             require Template;
542             my $t = Template->new($self->TemplateConf);
543             my $outdata;
544             my $pagetype;
545             if (!defined param("data") && defined param("pageid")) {
546             my $pageid = param("pageid");
547             my $root = $self->Root;
548             my $objdb = $root->ObjDB;
549             my $content = $objdb->content($pageid);
550             $outdata = $self->_get_outdata($content);
551             $pagetype = $outdata->{"data"}{"pagetype"};
552             } else {
553             $outdata = $self->_get_outdata();
554             $pagetype = param("pagetype");
555             }
556             if (!$pagetype) {
557             die "`pagetype' parameter is missing";
558             }
559             my $c = $self->C;
560             my $template = $c->project->templatefortype->{$pagetype}
561             or die "No template for page type `$pagetype'";
562              
563             my($content_type, $ext) = $self->get_template_contenttype($template);
564             if (!$self->HeaderPrinted) {
565             print $self->myheader(-type => $content_type);
566             } else {
567             warn "Header should not be already printed before preview()!";
568             }
569              
570             my $out = "";
571              
572             if ($content_type eq 'text/html') {
573             # fake a reasonable base, so internal links work to released pages
574             my $absrooturl = $c->paths->absoluteurl;
575             if ($absrooturl eq '') {
576             $absrooturl = $c->paths->rooturl;
577             if ($absrooturl !~ m|^https?://|) {
578             $absrooturl = "http://" . server_name() . ":" . server_port() . $absrooturl;
579             }
580             }
581             my $ext = $c->project->standardext;
582             # XXX This is not xhtml compliant!
583             print '' . "\n";
584             }
585              
586             if (open(DEBUG3, ">/tmp/debug_dd_$<.txt")) {
587             require Data::Dumper;
588             print DEBUG3 Data::Dumper->new([$outdata],[])->Indent(1)->Useqq(1)->Dump;
589             close DEBUG3;
590             }
591              
592             my $template_file = $c->paths->site_templatebase."/".$template;
593             $t->process($template_file,
594             { %{ $self->TemplateVars },
595             objid => $outdata->{'data'}->{'pageid'},
596             lang => $outdata->{'data'}->{'language'},
597             %$outdata },
598             \$out)
599             or die "Template process for file <$template_file> failed: "
600             . $t->error . ", \@INC is @INC, pid is $$, Template dump: "
601             . $t->context->_dump;
602              
603             if ($c->project->features->{validate} &&
604             $c->project->features->{validate} eq $content_type) {
605             $self->validate_page($out, contenttype => $content_type);
606              
607             }
608              
609             ## Use the converter if necessary
610             my $converter;
611             if (1) {
612             $converter = $self->get_string_charset_converter;
613             print STDOUT $converter->($out);
614              
615             ## Charset debugging
616             if (0) {
617             if (open(DEBUG, ">/tmp/debug_converted_$<.html")) {
618             print DEBUG $converter->($out);
619             close DEBUG;
620             }
621              
622             if (open(DEBUG2, ">/tmp/debug_raw_$<.html")) {
623             print DEBUG2 $out;
624             close DEBUG2;
625             }
626             }
627             }
628              
629             ## The version which does not care about conversion:
630             if (0) {
631             print $out;
632             }
633              
634             if ($content_type eq 'text/html') {
635             print <<'EOF',
636            
640             EOF
641             }
642              
643             } #### sub preview END
644              
645             ######################################################################
646             #
647             # save a page
648             #
649             sub savepage {
650             my $self = shift;
651             $self->check_login;
652             my $script_dumper = $self->ScriptDumper;
653             eval "require $script_dumper"; die "Can't load script dumper: $@" if $@;
654             my $outdata = $self->_get_outdata(undef, $script_dumper);
655             my $data = $outdata->{data};
656             my $pid = $data->{pageid};
657             my $title = new WE::Util::LangString;
658             my $keywords = new WE::Util::LangString;
659             my $pagetype = $data->{pagetype};
660             my $name = $data->{name};
661              
662             # check if Name is unique
663             my $uniquename = 1;
664             my $name_message;
665             my $root = $self->Root;
666             my $objdb = $root->ObjDB;
667             my $templatevars = $self->TemplateVars;
668             my $newobj = $objdb->get_object($pid);
669             if (!defined $newobj->Name || $newobj->Name ne $name) {
670             $name_message = $self->_ambiguous_name_message($name, $newobj);
671             if (defined $name_message) {
672             $uniquename = 0;
673             $data->{name} = undef;
674             }
675             }
676              
677             my $pagevisible = $data->{visible};
678             my $nodel = $data->{nodel} ? "nodel" : "";
679             my $inactive = !!$data->{inactive};
680             my $timeopen = $data->{timeopen};
681             my $timeexpire = $data->{timeexpire};
682             my $wwwauth = $data->{wwwauth} || "";
683             my $c = $self->C;
684             foreach my $l (@{ $c->project->sitelanguages }) {
685             next if (!$data->{$l}->{'title'});
686             set_langstring($title, "$l", $data->{$l}->{'title'});
687             set_langstring($keywords, "$l", $data->{$l}->{'keywords'});
688             }
689             $objdb->replace_content($pid, $self->_dump_outdata($outdata));
690              
691             my $set_attributes = sub {
692             my($obj, $release_state) = @_;
693             $obj->Release_State ($release_state);
694             $obj->Title ($title);
695             $obj->Keywords ($keywords);
696             $obj->{VisibleToMenu} = $pagevisible;
697             $obj->Rights ($nodel);
698             if (!defined $wwwauth || $wwwauth eq "") {
699             delete $obj->{WWWAuth};
700             } else {
701             $obj->{WWWAuth} = $wwwauth;
702             }
703             if ($self->has_timebasedpublishing) {
704             $obj->TimeOpen ($timeopen);
705             $obj->TimeExpire($timeexpire);
706             }
707             if ($uniquename) {
708             $obj->Name($name);
709             }
710             $objdb->replace_object($obj);
711             };
712              
713             my $notify_msg;
714             if (param('release') eq "yes" && !$inactive) {
715              
716             my $versionedobj;
717              
718             my $set_released_attributes = sub {
719             my $obj = shift;
720             $set_attributes->($obj, "released");
721             };
722              
723             # check in and release that version
724             if (!$c->project->useversioning) {
725             $objdb->trim_old_versions($pid, -all => 1);
726             }
727             $versionedobj = $objdb->ci($pid);
728             $set_released_attributes->($versionedobj);
729              
730             # set attributes for "main" object version
731             $set_released_attributes->($newobj);
732              
733             # create a html-page
734             #XXX only if TimeOpen/TimeExpire applies, otherwise fire at daemon and deletepage
735             $self->makehtmlpage($newobj->Id);
736             #XXX ditto
737             # recreate the menu
738             $self->makemenu if $self->can("makemenu");
739             $self->update_auth_files if $self->can("update_auth_files");
740              
741             #XXX use hooks? WebEditor::OldFeatures::TimeBased::Hooks::page_released($self, $newobj->Id) if
742              
743             if ($versionedobj && $c->project->sessionlocking) {
744             $objdb->unlock($versionedobj);
745             }
746             #XXX if TimeOpen/TimeExpire applies, send another action identifier
747             $notify_msg = $self->we_notify("release", { Id => $newobj->Id });
748             } else {
749             $set_attributes->($newobj,
750             $inactive ? "inactive" : "modified",
751             );
752             if ($inactive) {
753             $self->deletehtmlpage($newobj->Id);
754             }
755             }
756              
757             if (param('release') eq "yes") {
758             if ($inactive) {
759             $templatevars->{'message'} = $self->fmt_msg("msg_inactive_page_released", langstring($title));
760             } else {
761             $templatevars->{'message'} = $self->fmt_msg("msg_active_page_released", langstring($title));
762             }
763             } else {
764             $templatevars->{'message'} = $self->fmt_msg("msg_page_saved", langstring($title));
765             }
766             $templatevars->{'message'} = "\n$notify_msg" if $notify_msg;
767              
768             if (!$uniquename) {
769             if ($c->project->sessionlocking) {
770             $objdb->unlock($newobj);
771             }
772             return $self->pageeditorframe
773             (-currentaction => "savepage",
774             -message => $name_message,
775             -pageid => $newobj->Id);
776             }
777             #XXXdel:
778             # $newobj->Name($name);
779             # $objdb->replace_object($newobj);
780              
781             if ($c->project->sessionlocking) {
782             $objdb->unlock($newobj);
783             }
784             $templatevars->{'new'} = 1;
785             $templatevars->{'parid'} = ($objdb->parent_ids($newobj->Id))[0];
786             $self->_tpl("bestwe","we_ready_to_folder.tpl.html");
787             } #### sub savepage END
788              
789             sub unlock {
790             my $self = shift;
791             my($pageid, $redirect) = @_;
792             if (!defined $pageid) {
793             $pageid = param("pageid");
794             }
795             if (defined $pageid) {
796             my $c = $self->C;
797             my $root = $self->Root;
798             my $objdb = $root->ObjDB;
799             if ($c->project->sessionlocking) {
800             $self->check_login;
801             my $obj = $objdb->get_object($pageid);
802             if ($obj) {
803             $objdb->unlock($obj);
804             }
805             }
806             }
807             if (defined $redirect) {
808             $self->html_redirect($redirect);
809             }
810             }
811              
812             sub html_redirect {
813             my $self = shift;
814             my $url = shift;
815             print <
816            
817             EOF
818             exit;
819             }
820              
821             ######################################################################
822             #
823             # create a page
824             #
825             sub createpage {
826             my $self = shift;
827             local $^W = 0; # because of Rights =~ ...
828              
829             my $root = $self->Root;
830             $self->check_login;
831             my $parid = param('pageid');
832             my $objdb = $root->ObjDB;
833             my $parent = $objdb->get_object($parid);
834             my $fe = $self->FE;
835             my $c = $self->C;
836             my $rights = $parent->Rights;
837             $rights = "" if !defined $rights;
838             if (($rights !~ /nopage/ && $root->is_allowed("new-doc")) || $root->is_allowed("everything")) {
839             # choose a data-prototype according to the pagetype
840             my $pagetype = $self->_get_pagetype;
841             # XXX wird das hier jemals getriggert???
842             if ($fe->can("Uploadpagetypes") &&
843             $fe->Uploadpagetypes &&
844             $fe->Uploadpagetypes->{$pagetype}) {
845             $self->uploadpage($parid, $pagetype);
846             }
847              
848             # get empty data from file
849             use vars qw($emptydata);
850             undef $emptydata;
851             do $c->paths->prototypedir."/empty_".$pagetype.".bin"
852             or die "No prototype data for pagetype $pagetype";
853             my $outdata = {'data' => {
854             'pagetype' => $pagetype,
855             'pageid' => 'x',
856             }
857             };
858             # XXX add hook for additional outdata
859             # XXX move this also to hook???
860             #XXX $outdata->{data}->{section} = $root->get_section($parid);
861              
862             my $title = new WE::Util::LangString;
863             foreach my $l (@{ $c->project->sitelanguages }) {
864             # emptydata is from safe source (hopefully)
865             $ { $outdata->{data} }{$l} = eval $emptydata;
866             $title->{$l} = $outdata->{data}->{$l}->{'title'};
867             }
868             my $newobj = $objdb->insert_doc
869             (-content => $self->_dump_outdata($outdata),
870             -contentType => "application/x-perl",
871             -parent => $parid,
872             -Type => $pagetype,
873             -VisibleToMenu => 1,
874             -Title => $title,
875             ) or die "Could not create page";
876             warn "Created page id=" . $newobj->Id . "\n" if $c->debug;
877             param('pageid' => $newobj->Id);
878             $self->pageeditorframe(-currentaction => "createpage");
879             } else {
880             warn "Could not create page because of permissions";
881             $self->siteeditorframe("Could not create page");
882             }
883             } #### sub createpage END
884              
885             ######################################################################
886             #
887             # upload a HTML page
888             #
889             sub uploadpage {
890             my $self = shift;
891             my($parid, $pagetype) = @_;
892             my $c = $self->C;
893             my $objdb = $self->Root->ObjDB;
894             warn "parid=$parid, pagetype=$pagetype" if $c->debug;
895              
896             if (param('uploadfile'.$c->project->sitelanguages->[0])) {
897             $parid = param('parentid');
898             $pagetype = param("pagetype") || "static";
899             my $title = new WE::Util::LangString;
900             my $outdata = { data => {} };
901             $outdata->{data}->{pagetype} = $pagetype;
902             foreach my $lang (@{ $c->project->sitelanguages }) {
903             $outdata->{"data"}->{$lang}->{"ct"} = "";
904             my $infile = param('uploadfile'.$lang);
905             warn "Upload lang=" . param('uploadfile'.$lang) . ", file=$infile"
906             if $c->debug;
907             while (<$infile>) {
908             $_ =~ s/\n//g;
909             $_ =~ s/\r//g;
910             $outdata->{"data"}->{$lang}->{'ct'} .= $_;
911             }
912             $outdata->{"data"}->{$lang}->{'title'} = param('title'.$lang);
913             $title->{$lang} = param('title'.$lang);
914             }
915              
916             my $newobj = $objdb->insert_doc
917             (-content => $self->_dump_outdata($outdata),
918             -contentType => "application/x-perl",
919             -parent => $parid,
920             -Type => $pagetype,
921             -VisibleToMenu => 1,
922             -Title => $title) or die "Could not create page";
923             warn "Created page " . $newobj->Id if $c->debug;
924             param('pageid' => $newobj->Id);
925             $self->pageeditorframe(-currentaction => "uploadpage");
926             } else {
927             my $templatevars = $self->TemplateVars;
928             $templatevars->{'sitelanguages'} = $c->project->sitelanguages;
929             $templatevars->{'parid'} = $parid;
930             $templatevars->{'pagetype'} = $pagetype;
931             $self->_tpl("bestwe", "we_upload.tpl.html");
932             }
933             exit;
934             }
935              
936             ######################################################################
937             #
938             # create a folder
939             #
940             sub createfolder {
941             my $self = shift;
942             my $root = $self->Root;
943             $self->check_login;
944             my $c = $self->C;
945             my $objdb = $root->ObjDB;
946             my $parid = param('pageid');
947             my $parent = $objdb->get_object($parid);
948             warn "Folder $parid: allowed everything: " . $root->is_allowed("everything") .
949             ", new-folder: " . $root->is_allowed("new-folder") . "\n"
950             if $c->debug;
951             my $rights = $parent->Rights;
952             $rights = "" if !defined $rights;
953             if (($rights !~ /nofolder/ && $root->is_allowed("new-folder")) || $root->is_allowed("everything")) {
954             my $pagetype = "Folder";
955             my $title = new WE::Util::LangString();
956             foreach my $l (@{ $c->project->sitelanguages }) {
957             $title->{$l} = 'new folder';
958             }
959             $objdb->insert_folder(-parent => $parid,
960             -Release_State => "released",
961             -IndexDoc => undef,
962             -VisibleToMenu => 1,
963             -Title => $title);
964             $self->siteeditorframe("New folder created");
965             } else {
966             $self->siteeditorframe("No folder created (permission denied)");
967             }
968             } #### sub createfolder END
969              
970             ######################################################################
971             #
972             # Update all released html pages (i.e. after template changes). This
973             # is also used for creating a site for time based publishing.
974             # Arguments: -pubhtmldir, -time, -logfh
975             sub updatehtml {
976             my($self, %args) = @_;
977             $self->identify;
978             my $root = $self->Root;
979             if (!$root->is_allowed(["admin","release"])) {
980             die "This function is only allowed for users with admin or release rights\n";
981             }
982              
983             my $c = $self->C;
984             my $pubhtmldir = $args{-pubhtmldir} || $c->paths->pubhtmldir;
985             my $now = $args{-now}; # XXX use for modified ObjDB
986             my $logfh = $args{-logfh} || \*STDOUT;
987              
988             # This seems to safe some 60% of time:
989             my $objdb = $root->ObjDB;
990             $objdb = $objdb->cached_db;
991             # XXX require WE::DB::ObjUtils;$objdb->current_database_view;#XXX some day maybe...
992              
993             require Template;
994             my $templatevars = $self->TemplateVars;
995             $templatevars->{'objdb'} = $objdb; # override with cached version
996             $templatevars->{'localconfig'}{'now'} = $now;
997             my $t = Template->new($self->TemplateConf);
998             print $logfh <
999            
1000            
1001            
1002            
1003            
1004             EOF
1005             my $begin_time = time;
1006             print $logfh "

" . _html($self->msg("msg_update_html_pages")) . " (" . _html($self->msg("cap_prelive")) . ")" . "

\n";
1007             print $logfh "

" . _html($self->msg("msg_create_html_pages")) . "

\n";
1008             my $root_object = $objdb->root_object;
1009             my @seen_ids = $self->update_children($root_object->Id,
1010             $t,
1011             -objdb => $objdb,
1012             -indent => 0,
1013             -pubhtmldir => $pubhtmldir,
1014             -logfh => $logfh,
1015             -now => $now,
1016             );
1017              
1018             my $root_id;
1019             if (defined $root_object->IndexDoc) {
1020             $root_id = $root_object->IndexDoc;
1021             } else {
1022             $root_id = $root_object->Version_Parent || $root_object->Id;
1023             }
1024             push @seen_ids, $root_id;
1025              
1026             print $logfh "

" . _html($self->msg("msg_create_homepage_link")) . "

\n";
1027             foreach my $lang (@{ $c->project->sitelanguages }) {
1028             my $langdir = "$pubhtmldir/html/$lang";
1029             my $ext = $c->project->standardext;
1030             if (-e "$langdir/$root_id$ext") {
1031             print $logfh (_html("($lang: index$ext => $root_id$ext) "));
1032             unlink "$langdir/index$ext";
1033             symlink("$root_id$ext", "$langdir/index$ext")
1034             or warn "Can't symlink $root_id$ext -> $langdir/index$ext: $!";
1035             }
1036             }
1037              
1038             $self->makefolderpage($root_object->Id,
1039             $t,
1040             -objdb => $objdb,
1041             -pubhtmldir => $pubhtmldir,
1042             -logfh => $logfh,
1043             -now => $now,
1044             );
1045             print $logfh "

" . _html($self->msg("msg_remove_old_symlinks")) . "

\n";
1046             $self->cleanup_symlinks(-pubhtmldir => $pubhtmldir);
1047             print $logfh "

" . _html($self->msg("msg_remove_old_pages")) . "

\n";
1048             $self->cleanup_unreferenced_html(\@seen_ids, -pubhtmldir => $pubhtmldir);
1049             print $logfh "
\n";
1050              
1051             my $duration = time - $begin_time;
1052             printf $logfh "

" . _html($self->msg("msg_ready")) . " (%02d min %02d sec)

", $duration/60, $duration%60;
1053              
1054             print $logfh "
";
1055             $self->_tpl("bestwe", "we_admin_body.tpl.html", undef, $logfh);
1056             print $logfh "";
1057             }
1058              
1059             sub cleanup_symlinks {
1060             my($self, %args) = @_;
1061             require File::Find;
1062             # peacify -w
1063             local $File::Find::prune = $File::Find::prune;
1064             local $File::Find::dir = $File::Find::dir;
1065             my $c = $self->C;
1066             my $pubhtmldir = $args{-pubhtmldir} || $c->paths->pubhtmldir;
1067             File::Find::find(sub {
1068             if (/^(\.svn|CVS|RCS)$/) {
1069             $File::Find::prune = 1;
1070             return;
1071             }
1072             if (-l $_) {
1073             my $f = readlink($_);
1074             return if (-e $f);
1075             require File::Spec;
1076             $f = File::Spec->rel2abs($f, $File::Find::dir);
1077             return if (-e $f);
1078             unlink $_;
1079             }
1080             }, $pubhtmldir . "/html");
1081             }
1082              
1083             sub cleanup_unreferenced_html {
1084             my($self, $seen_ids_ref, %args) = @_;
1085             my %seen_ids = map { defined $_ ? ($_=>1) : () } @$seen_ids_ref;
1086             my $c = $self->C;
1087             my $pubhtmldir = $args{-pubhtmldir} || $c->paths->pubhtmldir;
1088             my $logfh = $args{-logfh} || \*STDOUT;
1089             my $basedir = $pubhtmldir;
1090             my $ext = quotemeta $c->project->standardext;
1091             my $rx = qr/^(\d+)$ext$/;
1092             foreach my $lang (@{ $c->project->sitelanguages }) {
1093             my $langdir = $basedir."/html/".$lang;
1094             if (opendir(D, $langdir)) {
1095             while(defined(my $f = readdir(D))) {
1096             my $lf = "$langdir/$f";
1097             next if !-f $lf || -l $lf;
1098             if ($f !~ $rx) {
1099             warn "Datei $lf wird ignoriert...\n";
1100             next;
1101             }
1102             my $id = $1;
1103             if (!$seen_ids{$1}) {
1104             print $logfh (_html($self->fmt_msg("msg_delete", $f)) . "
\n");
1105             unlink $lf;
1106             }
1107             }
1108             closedir D;
1109             }
1110             }
1111             }
1112              
1113             sub update_children {
1114             my($self, $objid, $t, %args) = @_;
1115             my $root = $self->Root;
1116             my $objdb = $args{-objdb} || $root->ObjDB;
1117             my $c = $self->C;
1118             my $indent = $args{-indent};
1119             my $pubhtmldir = $args{-pubhtmldir} || $c->paths->pubhtmldir;
1120             my $logfh = $args{-logfh} || \*STDOUT;
1121             my $now = $args{-now};
1122             my @seen_ids;
1123             my @children = $objdb->get_released_children($objid, -now => $now);
1124             foreach my $child (@children) {
1125             if ($child->is_folder) {
1126             if ($child->{VisibleToMenu}) {
1127             print $logfh " "x$indent if $indent;
1128             print $logfh (_html($self->msg("cap_folder"))) . " \"" . _html(langstring($child->Title, $self->EditorLang)) . "\" (Id=" . $child->Id . ")
\n";
1129             }
1130             if ($child->{VisibleToMenu}) {
1131             push @seen_ids, $self->makefolderpage
1132             ($child->Id,
1133             $t,
1134             -pubhtmldir => $pubhtmldir,
1135             -objdb => $objdb,
1136             -logfh => $logfh,
1137             -now => $now,
1138             );
1139             }
1140             push @seen_ids, $self->update_children
1141             ($child->Id,
1142             $t,
1143             -objdb => $objdb,
1144             (defined $indent ? (-indent => $indent+1) : ()),
1145             -now => $now,
1146             );
1147             } else {
1148             #next if !$child->{VisibleToMenu};
1149             print $logfh " "x$indent if $indent;
1150             print $logfh (_html($self->msg("cap_page"))) . " \"" . _html(langstring($child->Title, $self->EditorLang)) . "\" (Id=" . $child->Id . "): ";
1151             my($msg_html, $seen_ids_ref) = $self->makehtmlpage
1152             ($child->Id,
1153             -tmplobj => $t,
1154             -objdb => $objdb,
1155             -pubhtmldir => $pubhtmldir,
1156             );
1157             print $logfh $msg_html;
1158             push @seen_ids, @$seen_ids_ref;
1159             print $logfh "\n";
1160             }
1161             }
1162             @seen_ids;
1163             }
1164              
1165             # create an empty folder page if there is no IndexDoc
1166             sub makefolderpage {
1167             my($self, $id, $t, %args) = @_;
1168             my $root = $self->Root;
1169             my $basedir = $args{-pubhtmldir} || die "-pubhtmldir not specified";
1170             my $objdb = $args{-objdb} || $root->ObjDB;
1171             my $logfh = $args{-logfh} || \*STDOUT;
1172             my $now = $args{-now};
1173              
1174             my $obj = $objdb->get_object($id);
1175             return () if !$obj->{VisibleToMenu};
1176             my $mainid = $obj->Version_Parent;
1177             $mainid = $id if !defined $mainid;
1178             my $docid = $obj->IndexDoc;
1179              
1180             my @ret = ($docid);
1181             my $active = $objdb->is_active_page($obj);
1182             if (!$active) {
1183             @ret = ();
1184             print $logfh (_html(" - nicht erzeugen")); # XXX langres!
1185             }
1186              
1187             my $converter = $self->get_fh_charset_converter;
1188              
1189             my $c = $self->C;
1190             foreach my $lang (@{ $c->project->sitelanguages }) {
1191             my $langdir = $basedir."/html/".$lang;
1192             my $ext = $c->project->standardext;
1193             if (!-d $langdir) {
1194             mkdir $langdir, 0755 or die "Can't create $langdir: $!";
1195             }
1196             if (!defined $docid) {
1197             # XXX code doubled in WE_Frontend::Plugin::WE_Navigation::Object
1198             my $autoindexdoc = $c->project->features->{autoindexdoc};
1199             if (defined $autoindexdoc && $autoindexdoc eq 'first') {
1200             my(@children_ids) = $objdb->get_released_children($mainid, -now => $now);
1201             if (@children_ids) {
1202             $docid = $children_ids[0]->Id;
1203             }
1204             }
1205             }
1206             if (!defined $docid) {
1207             $docid = $mainid;
1208             # process Template
1209             my $outdata = {};
1210             $outdata->{'data'}->{'language'} = $lang;
1211             my $pagetype = "folderindex";
1212             my $template = $c->project->templatefortype->{$pagetype}
1213             or die "Can't get template for $pagetype";
1214             (undef, $ext) = $self->get_template_contenttype($template);
1215             my $htmlfile = $langdir."/".$mainid.$ext;
1216             if (!$active) {
1217             unlink $htmlfile;
1218             } else {
1219             my $tmpfile = "$htmlfile~";
1220             open HTML, ">$tmpfile" or die "Publish: can't write to $tmpfile: $!";
1221             $converter->(\*HTML);
1222              
1223             $outdata->{'data'}->{'pagetype'} = $pagetype;
1224             my $keywords = langstring($obj->{Keywords}, $lang) || undef;
1225             my $t = Template->new($self->TemplateConf);
1226             $t->process($c->paths->site_templatebase."/".$template,
1227             { %{$self->TemplateVars},
1228             objid => $mainid,
1229             lang => $lang,
1230             keywords => $keywords,
1231             %$outdata }, \*HTML)
1232             or die "Template process failed: " . $t->error . "\n";
1233             close HTML;
1234              
1235             require File::Compare;
1236             if (File::Compare::compare($htmlfile, $tmpfile) == 0) {
1237             # no change --- delete $tmpfile
1238             unlink $tmpfile;
1239             } else {
1240             unlink $htmlfile; # do not fail --- maybe file does not exist
1241             rename $tmpfile, $htmlfile or die "Can't rename $tmpfile to $htmlfile: $!";
1242             }
1243             }
1244             }
1245              
1246             if (eval { symlink("",""); 1 }) { # symlink exists
1247             if ($mainid != $docid) {
1248             my $oldfile = $docid.$ext;
1249             my $linkfile = $langdir."/".$mainid.$ext;
1250             local $^W = undef;
1251             if (readlink($linkfile) ne $oldfile) {
1252             unlink $linkfile;
1253             if ($active) {
1254             symlink $oldfile, $linkfile
1255             or warn "Can't symllink $oldfile -> $linkfile: $!";
1256             print $logfh (_html(" ($lang: " . $self->fmt_msg("msg_link_to", $oldfile) . ") "));
1257             }
1258             } else {
1259             print $logfh (_html(" ($lang: " . $self->msg("msg_no_change") . ") "));
1260             }
1261             push @ret, $mainid;
1262             }
1263             for my $name ($root->NameDB->get_names($docid),$root->NameDB->get_names($mainid)) {
1264             my $oldfile = $docid.$ext;
1265             my $linkfile = $langdir."/".$name.$ext;
1266             local $^W = undef;
1267             if (readlink($linkfile) ne $oldfile) {
1268             unlink $linkfile;
1269             if ($active) {
1270             symlink $oldfile, $linkfile
1271             or warn "Can't symllink $oldfile -> $linkfile: $!";
1272             print $logfh (_html(" ($lang: " . $self->fmt_msg("msg_link_to", $oldfile) . ") "));
1273             }
1274             } else {
1275             print $logfh (_html(" ($lang: " . $self->msg("msg_no_change") . ") "));
1276             }
1277             }
1278             }
1279             }
1280             print $logfh "
\n";
1281              
1282             return @ret;
1283             }
1284              
1285             sub makehtmlpage {
1286             my($self, $id, %args) = @_;
1287             my $c = $self->C;
1288             my $root = $self->Root;
1289             my $basedir = $args{-pubhtmldir} || $c->paths->pubhtmldir;
1290             my $t = $args{-tmplobj} || do {
1291             require Template;
1292             Template->new($self->TemplateConf);
1293             };
1294             my $objdb = $args{-objdb} || $root->ObjDB;
1295              
1296             my $msg = ""; # as HTML
1297             my $content = $objdb->content($id);
1298             my $outdata = $self->_get_outdata($content);
1299             my $obj = $objdb->get_object($id);
1300             my $mainid = $obj->Version_Parent || $id;
1301             my $template = $c->project->templatefortype->{ $outdata->{'data'}->{'pagetype'} };
1302             if (!defined $template) {
1303             die "No template for pagetype $outdata->{'data'}->{'pagetype'} defined";
1304             }
1305              
1306             require File::Compare;
1307             my($ext) = $template =~ /(\.[^\.]+)$/;
1308              
1309             my $converter = $self->get_fh_charset_converter;
1310              
1311             foreach my $lang (@{ $c->project->sitelanguages }) {
1312             my $langdir = $basedir."/html/".$lang;
1313             if (!-d $langdir) {
1314             mkdir $langdir, 0755 or die "Can't create $langdir: $!";
1315             }
1316             my $htmlfile = $langdir."/".$mainid.$ext;
1317             my $tmpfile = "$htmlfile~";
1318             open HTML, ">$tmpfile" or die "Publish: can't write to $tmpfile: $!";
1319             $converter->(\*HTML);
1320            
1321             # process Template
1322             $outdata->{'data'}->{'language'} = $lang;
1323             my $keywords = langstring($obj->{Keywords}, $lang) || undef;
1324             #warn "Using template ".$c->paths->site_templatebase."/".$template."\n";
1325             $t->process($c->paths->site_templatebase."/".$template,
1326             { %{ $self->TemplateVars },
1327             objid => $mainid,
1328             lang => $lang,
1329             keywords => $keywords,
1330             %$outdata }, \*HTML)
1331             or die "Template process failed: " . $t->error . "\n";
1332             close HTML;
1333              
1334             if (File::Compare::compare($htmlfile, $tmpfile) == 0) {
1335             # no change --- delete $tmpfile
1336             unlink $tmpfile;
1337             $msg .= _html(" ($lang: " . $self->msg("msg_no_change") . ") ");
1338             } else {
1339             unlink $htmlfile; # do not fail --- maybe file does not exist
1340             rename $tmpfile, $htmlfile or die "Can't rename $tmpfile to $htmlfile: $!";
1341             $msg .= _html(" ($lang: $htmlfile) ");
1342             }
1343              
1344             if (eval { symlink("",""); 1 }) { # symlink exists
1345             for my $name ($root->NameDB->get_names($mainid)) {
1346             unlink $langdir."/".$name.$ext;
1347             symlink $mainid.$ext, $langdir."/".$name.$ext;
1348             }
1349             }
1350              
1351             my @makehtmlhooks;
1352             my $makehtmlhook = $c->project->features->{makehtmlhook};
1353             if ($makehtmlhook) {
1354             if (UNIVERSAL::isa($makehtmlhook, "ARRAY")) {
1355             push @makehtmlhooks, @{ $makehtmlhook };
1356             } else {
1357             push @makehtmlhooks, $makehtmlhook;
1358             }
1359             }
1360             # legacy mixin'ed method:
1361             push @makehtmlhooks, "additional"
1362             if $self->can("makehtmlpage_additional");
1363              
1364             my @add_msg;
1365             for my $hook (@makehtmlhooks) {
1366             my $method = "makehtmlpage_" . $hook;
1367             my $ret = $self->$method
1368             (id => $id,
1369             mainid => $mainid,
1370             lang => $lang,
1371             basedir => $basedir,
1372             template => $template,
1373             addtemplatevars => { objid => $mainid,
1374             lang => $lang,
1375             %$outdata
1376             });
1377             if (UNIVERSAL::isa($ret, "HASH")) {
1378             # modern return type
1379             push @add_msg, $ret->{Message};
1380             } else {
1381             # legacy return type
1382             push @add_msg, $ret;
1383             }
1384             }
1385             my $add_msg = join "", @add_msg;
1386             $msg .= " - $add_msg" if defined $add_msg && $add_msg ne ""; # XXX htmlify?
1387             }
1388              
1389             ($msg . "
\n", [$mainid]);
1390             }
1391              
1392             sub deletehtmlpage {
1393             my $self = shift;
1394             my($id) = @_;
1395             my $c = $self->C;
1396             my $root = $self->Root;
1397             my $objdb = $root->ObjDB;
1398             my $basedir = $c->paths->pubhtmldir;
1399             my $obj = $objdb->get_object($id);
1400             my $mainid = $obj->Version_Parent || $id;
1401             my $ext = $c->project->standardext;
1402              
1403             foreach my $lang (@{ $c->project->sitelanguages }) {
1404             my $langdir = $basedir."/html/".$lang;
1405             next if (!-d $langdir);
1406             my $htmlfile = $langdir."/".$mainid.$ext;
1407             unlink $htmlfile;
1408              
1409             if (eval { symlink("",""); 1 }) { # symlink exists
1410             for my $name ($root->NameDB->get_names($mainid)) {
1411             unlink $langdir."/".$name.$ext;
1412             }
1413             }
1414             }
1415             }
1416              
1417             ######################################################################
1418             #
1419             # edit a folder
1420             #
1421             sub folderedit {
1422             my $self = shift;
1423              
1424             local $^W = 0; # because of Rights =~ ...
1425              
1426             $self->check_login;
1427              
1428             my $root = $self->Root;
1429             my $objdb = $root->ObjDB;
1430             my $c = $self->C;
1431              
1432             my $folderid = param('pageid');
1433             my $fldr = $objdb->get_object($folderid);
1434             if (!$fldr) {
1435             # Folder probably deleted => show blank page
1436             # XXX or probably a plain message/error page?
1437             exit(0);
1438             }
1439              
1440             if (!$root->is_allowed(["edit", "edit-only"], $folderid)) {
1441             $self->siteeditorframe("No permission to edit folder $folderid");
1442             return;
1443             }
1444              
1445             # Save folder
1446             TRY_SAVE_FOLDER: {
1447             if (param('action') eq "save") {
1448             my $converter = $self->get_string_charset_decode_converter;
1449             my $title = new WE::Util::LangString;
1450             foreach my $l (@{ $c->project->sitelanguages }) {
1451             $title->{$l} = $converter->(param("newtitle$l"));
1452             }
1453             $fldr->Title($title);
1454             my $idxp = param('indexpage') || undef;
1455             $fldr->IndexDoc($idxp);
1456             my $foldername = param('foldername') || 0;
1457             if ($foldername) {
1458             # check if Name is unique
1459             if ($fldr->Name ne $foldername) {
1460             my $name_message = $self->_ambiguous_name_message($foldername, $fldr);
1461             if (defined $name_message) {
1462             param('message' => $name_message);
1463             param('action' => 'show');
1464             last TRY_SAVE_FOLDER;
1465             }
1466             }
1467             }
1468             $fldr->Name($foldername);
1469             my $foldergroup = param('group') || "none";
1470             if ($foldergroup) { $fldr->{Group} = $foldergroup }
1471             my $rights = join(",", param('nodel'), param('nopage'), param('nofolder'));
1472             $fldr->Rights($rights);
1473             if (param('inactive')) {
1474             $fldr->Release_State('inactive');
1475             } elsif ($fldr->{Release_State} eq 'inactive') {
1476             $fldr->Release_State('released');
1477             }
1478             $fldr->{VisibleToMenu} = !param('hidden');
1479              
1480             my $timeopen = param('timeopen') || "";
1481             if ($timeopen) {
1482             $timeopen .= " " . param('timeopen_time');
1483             }
1484             my $timeexpire = param('timeexpire') || "";
1485             if ($timeexpire) {
1486             $timeexpire .= " " . param('timeexpire_time');
1487             }
1488             $fldr->TimeOpen($timeopen);
1489             $fldr->TimeExpire($timeexpire);
1490              
1491             $objdb->replace_object($fldr);
1492             param('fromid' => $folderid);
1493             return $self->siteeditorframe();
1494             }
1495             }
1496              
1497             # Delete folder
1498             if (param('action') eq "delete") {
1499             if ($folderid == $objdb->root_object->Id) {
1500             param('message' => $self->msg("msg_cant_del_root"));
1501             param("action" => "show");
1502             } else {
1503             if (($fldr->Rights !~ /nodel/ && $root->is_allowed("change-folder"))
1504             || $root->is_allowed("everything")) {
1505             my $parid = ($objdb->parent_ids($folderid))[0];
1506             $objdb->remove($folderid);
1507             my $notify_msg = $self->we_notify("deletefolder", { Id => $folderid });
1508             param("pageid" => $parid);
1509             my $msg = $self->fmt_msg("msg_folder_del_id", $folderid);
1510             $msg .= "\n$notify_msg" if $notify_msg;
1511             param("message" => $msg);
1512             }
1513             }
1514             return $self->siteeditorframe();
1515             }
1516              
1517             # Release folder
1518             if (param('action') eq 'release') {
1519             if (!$root->is_allowed("everything") &&
1520             !$root->is_allowed("release", $folderid)) {
1521             $self->siteeditorframe("No permission to release folder $folderid");
1522             return;
1523             }
1524              
1525             my @objids;
1526              
1527             my $useversioning = $c->project->useversioning;
1528              
1529             my $release_sub = sub {
1530             my $objid = shift;
1531             my $obj = $objdb->get_object($objid);
1532             if ($root->is_releasable_page($obj)) {
1533             $root->release_page($obj, -useversioning => $useversioning);
1534             push @objids, $objid;
1535             }
1536             };
1537             # First release all ...
1538             $objdb->walk_preorder($folderid, $release_sub);
1539              
1540             # ... then update html
1541             require Template;
1542             my $t = Template->new($self->TemplateConf);
1543             $self->update_children($folderid, $t);# XXX supply -now => $now?
1544             param("message" => $self->msg("msg_release_complete"));
1545              
1546             my $notify_msg;
1547             if (@objids) {
1548             $notify_msg = $self->we_notify("release", { Id => \@objids });
1549             }
1550              
1551             return $self->siteeditorframe($notify_msg);
1552              
1553             # Publish folder
1554             } elsif (param('action') eq 'publish') {
1555             if (!$root->is_allowed("everything") &&
1556             !$root->is_allowed("publish", $folderid)) {
1557             $self->siteeditorframe($self->fmt_msg("msg_no_perm_folder_publish", $folderid));
1558             return;
1559             }
1560             $self->folderpublish($folderid);
1561              
1562             # Show folder listing
1563             } elsif (param('action') eq "show") {
1564             # Show folder editor
1565              
1566             my $templatevars = $self->TemplateVars;
1567             # resolve Languagestring
1568             my $titlestr = $fldr->Title;
1569             my $title;
1570             my %mytitles;
1571             if (UNIVERSAL::isa($titlestr,'WE::Util::LangString')) {
1572             foreach my $l (@{ $c->project->sitelanguages }) {
1573             $mytitles{$l} = $titlestr->get($l);
1574             }
1575             } else {
1576             $title = $titlestr;
1577             }
1578             my $name = $fldr->Name || "";
1579             my $movechildid = param('movechildid');
1580             if (defined $movechildid && $movechildid ne "") {
1581             my $beforechildid = param('beforechildid');
1582             if (defined $beforechildid && $beforechildid ne "") {
1583             $objdb->move($movechildid, $folderid,
1584             -before => $beforechildid);
1585             warn "move $movechildid before $beforechildid\n"
1586             if $c->debug;
1587             }
1588             my $belowchildid = param('belowchildid');
1589             if (defined $belowchildid && $belowchildid ne "") {
1590             $objdb->move($movechildid, $folderid,
1591             -after => $belowchildid);
1592             warn "move $movechildid below $belowchildid\n"
1593             if $c->debug;
1594             }
1595             $templatevars->{'updatebutton'} = 1;
1596             }
1597             my $can_move_doc = $root->is_allowed("move-doc");
1598             my $can_move_folder = $root->is_allowed("move-folder");
1599             my $can_copy_doc = $root->is_allowed("copy-doc");
1600             my $can_copy_folder = $root->is_allowed("copy-folder");
1601             my @list;
1602             my @children = $objdb->children($folderid);
1603             my $last = -1;
1604             my $noindex = 1;
1605             foreach my $child (@children) {
1606             my $ttl = langstring($child->Title, $self->EditorLang);
1607             my $str = "
";
1608             if ($child->is_folder) {
1609             $str .= " 
1610             } else {
1611             my $c = defined $fldr->IndexDoc && $fldr->IndexDoc eq $child->Id ? " checked":"";
1612             $str .= "
1613             if ($c eq " checked") { $noindex = 0 }
1614             };
1615             $str .= "" . _html($ttl) . " ";
1616             my $i1 = $child->Id;
1617             if ($last >= 0) {
1618             my $i2 = $children[$last]->Id;
1619             $str .= "" . _html($self->msg("cap_up")) . "";
1620             } else {
1621             my $i2 = $children[-1]->Id;
1622             $str .= "" . _html($self->msg("cap_bottom")) . "";
1623             }
1624             $str .= "";
1625             $last++;
1626             if ($last < $#children) {
1627             my $i2 = $children[$last+1]->Id;
1628             $str .= "" . _html($self->msg("cap_down")) . "";
1629             } else {
1630             my $i2 = $children[0]->Id;
1631             $str .= "" . _html($self->msg("cap_top")) . "";
1632             }
1633             $str .= "";
1634              
1635             if ( ($child->is_folder && $can_move_folder)
1636             || ($child->is_doc && $can_move_doc)) {
1637             $str .= "fmt_msg("cap_move_with_title", $ttl))) . ">" . _html($self->msg("cap_move")) . "";
1638             }
1639             $str .= "";
1640             if ( ($child->is_folder && $can_copy_folder)
1641             || ($child->is_doc && $can_copy_doc)) {
1642             $str .= "fmt_msg("cap_copy_with_title", $ttl))) . ">" . _html($self->msg("cap_copy")) . "";
1643             }
1644             $str .= "
1645             push @list, $str;
1646             }
1647             $templatevars->{'foldername'} = $name;
1648             $templatevars->{'noindex'} = $noindex;
1649             $templatevars->{'list'} = \@list;
1650             $templatevars->{'mytitles'} = \%mytitles;
1651             $templatevars->{'sitelanguages'} = $c->project->sitelanguages;
1652             $templatevars->{'f_id'} = $folderid;
1653             $templatevars->{'message'} = param('message');
1654             require Data::JavaScript;
1655             $templatevars->{'datadump'} = Data::JavaScript::jsdump('data', $fldr);
1656             # whether this folder may be deleted
1657             $templatevars->{'delbutton'} = 0;
1658             if ( $fldr->Rights !~ /nodel/ && $root->is_allowed("change-folder")) { $templatevars->{'delbutton'} = 1 }
1659             if ( $root->is_allowed("change-folder", $folderid)) { $templatevars->{'changeorder'} = 1 }
1660             if ( $can_move_folder || $can_move_doc ) { $templatevars->{'move'} = 1 }
1661             if ( $can_copy_folder || $can_move_folder ) { $templatevars->{'copy'} = 1 }
1662             if ( $fldr->Rights =~ /\bnodel\b/) { $templatevars->{'nodel'}="checked" }
1663             if ( $fldr->Rights =~ /\bnopage\b/) { $templatevars->{'nopage'}="checked" }
1664             if ( $fldr->Rights =~ /\bnofolder\b/) { $templatevars->{'nofolder'}="checked" }
1665             if ( $fldr->Release_State eq 'inactive') { $templatevars->{'inactive'}="checked";}
1666             if ( !$fldr->{VisibleToMenu}) { $templatevars->{'hidden'}="checked" }
1667             # whether user may release the folder
1668             $templatevars->{'releasebutton'} = 0; # deprec? XXX
1669             if ( $root->is_allowed("everything")) { $templatevars->{'delbutton'} = 1 }
1670             # whether user is admin
1671             if ( $root->is_allowed("everything")) { $templatevars->{'isadmin'} = 1 }
1672             #XXX delete (?)
1673             if ( UNIVERSAL::isa($fldr, "WE::Obj::Site") ) {
1674             $templatevars->{'issite'} = 1;
1675             }
1676             if ($root->is_allowed("everything") ||
1677             $root->is_allowed("release", $folderid)) {
1678             $templatevars->{'releasebutton'} = 1;
1679             }
1680             if ($c->staging &&
1681             ($root->is_allowed("everything") ||
1682             $root->is_allowed("publish", $folderid))
1683             ) {
1684             $templatevars->{'publishbutton'} = 1;
1685             }
1686              
1687             # group
1688             $templatevars->{'group'} = $objdb->get_object($folderid)->{Group} || "none";
1689              
1690             # process Template
1691             $self->_tpl("bestwe", "we_folderedit.tpl.html");
1692             } else {
1693             $self->siteeditorframe();
1694             }
1695             } #### sub folderedit END
1696              
1697             sub folderpublish {
1698             my($self, $folderid) = @_;
1699             # Access checks should be already done.
1700              
1701             # XXX only supported for rsync method
1702             require WE_Frontend::Publish::Rsync;
1703              
1704             my $root = $self->Root;
1705             my $objdb = $root->ObjDB;
1706             my $c = $self->C;
1707             my $ext = $c->project->standardext;
1708              
1709             my @unlang_base_file_names;
1710             my $publish_sub = sub {
1711             my $objid = shift;
1712             if ($root->is_releasable_page($objid)) {
1713             push @unlang_base_file_names, $objid;
1714             push @unlang_base_file_names, $self->get_alias_pages($objid);
1715             }
1716             };
1717             $objdb->walk_preorder($folderid, $publish_sub);
1718              
1719             my @base_file_names;
1720             for my $base (@unlang_base_file_names) {
1721             for my $lang (@{ $c->project->sitelanguages }) {
1722             push @base_file_names, "html/$lang/$base$ext";
1723             }
1724             }
1725              
1726             #also publish _p files if available
1727             for my $base (@unlang_base_file_names) {
1728             for my $lang (@{ $c->project->sitelanguages }) {
1729             push @base_file_names, "html/$lang/$base"."_p"."$ext"
1730             if -r $c->paths->pubhtmldir . "/html/$lang/$base"."_p"."$ext";
1731             }
1732             }
1733              
1734             # also stage download and photo dirs
1735             require File::Find;
1736             local $File::Find::find = $File::Find::find;
1737             local $File::Find::name = $File::Find::name;
1738              
1739             push my @search_base, $c->paths->photodir;
1740             push @search_base, $c->paths->downloaddir;
1741              
1742             File::Find::find({follow_fast => 1,
1743             follow_skip => 2,
1744             wanted => sub {
1745             push @base_file_names, substr($File::Find::name,length($c->paths->rootdir)+1);
1746             }},@search_base);
1747              
1748             my $ret = WE_Frontend::Publish::Rsync::publish_files
1749             ($self->FE, \@base_file_names, -n => 0, -verbose => 1);
1750              
1751             if ($ret) {
1752             if (@base_file_names) {
1753             my $last = pop @base_file_names;
1754             my $quote = sub { '»'.$_[0].'«' };
1755             my $file_list = $quote->($last);
1756             if (@base_file_names) {
1757             $file_list = join(", ", map { $quote->($_) } @base_file_names)
1758             . " " . $self->msg("cap_and") . " " . $file_list;
1759             }
1760             param("message" => $self->fmt_msg("msg_html_published", $file_list));
1761             } else {
1762             param("message" => $self->msg("msg_no_html_published"));
1763             }
1764             } else {
1765             param("message" => $self->msg("msg_html_publish_error"));
1766             }
1767              
1768             my $notify_msg = $self->we_notify("folderpublish", { Id => $folderid });
1769              
1770             return $self->siteeditorframe($notify_msg);
1771             }
1772              
1773             ######################################################################
1774             #
1775             # delete a page
1776             #
1777             sub deletepage {
1778             my $self = shift;
1779             my $objid = param('pageid');
1780             my $root = $self->Root;
1781             my $objdb = $root->ObjDB;
1782             if (!$objdb->exists($objid)) {
1783             die "The object with the id $objid does not exist and cannot be deleted.";
1784             }
1785              
1786             $self->identify;
1787             if (!$root->is_allowed(["edit", "delete-doc"], $objid)) { # but not edit-only
1788             die "Deletion of $objid not allowed for " . $self->User;
1789             }
1790              
1791             my $templatevars = $self->TemplateVars;
1792             $templatevars->{'parid'} = ($objdb->parent_ids($objid))[0];
1793             $objdb->remove($objid);
1794              
1795             my $notify_msg = $self->we_notify("deletepage", { Id => $objid });
1796              
1797             $templatevars->{'message'} = $self->fmt_msg("msg_page_deleted", $objid);
1798             $templatevars->{'message'} .= "\n$notify_msg" if $notify_msg;
1799             $templatevars->{'new'} = 1;
1800             $self->_tpl("bestwe", "we_ready_to_folder.tpl.html");
1801             } #### sub deletepage END
1802              
1803             sub cancelpage {
1804             my $self = shift;
1805             my $objid = param('pageid');
1806             my $root = $self->Root;
1807             my $objdb = $root->ObjDB;
1808             my $c = $self->C;
1809             my $obj = $objdb->get_object($objid);
1810             if (!$obj) {
1811             die "Object with id $objid does not exist in database";
1812             }
1813             if ($c->project->sessionlocking) {
1814             $objdb->unlock($obj);
1815             }
1816             my $parentid = ($objdb->parent_ids($objid))[0];
1817             # XXX maybe make a template
1818             print <
1819            
1822             EOF
1823             }
1824              
1825             ######################################################################
1826             #
1827             # main frame
1828             #
1829             sub mainframe {
1830             my $self = shift;
1831             $self->login($self->msg("msg_login_incorrect"))
1832             unless $self->identify;
1833             $self->_tpl("bestwe", "we_mainframe.tpl.html");
1834             }
1835              
1836             ######################################################################
1837             #
1838             # content editor frame
1839             #
1840             sub pageeditorframe {
1841             my($self, %args) = @_;
1842             $self->_tpl("bestwe", "we_pageframeset.tpl.html",
1843             {
1844             'pageid' => defined $args{-pageid} ? $args{-pageid} : param('pageid'),
1845             'currentaction' => $args{'-currentaction'},
1846             'message' => $args{'-message'},
1847             }
1848             );
1849             }
1850              
1851             ######################################################################
1852             #
1853             # content editor page
1854             #
1855             sub pageedit {
1856             my $self = shift;
1857             local $^W = 0; # because of Rights =~ ...
1858              
1859             my $root = $self->Root;
1860             my $objdb = $root->ObjDB;
1861             my $c = $self->C;
1862             $self->check_login;
1863              
1864             my $pageid = param('pageid') || $_[0];
1865             unless ($root->is_allowed(["edit", "edit-only"], $pageid)) {
1866             my $obj = $objdb->get_object($pageid);
1867             $self->siteeditorframe($self->fmt_msg("msg_no_perm_page_edit", langstring($obj->Title) . " (Id $pageid)"));
1868             return;
1869             }
1870              
1871             my $pageobj = $objdb->get_object($pageid);
1872             my $datfile;
1873              
1874             if ($c->project->sessionlocking) {
1875             if ($objdb->is_locked($pageobj)) {
1876             my $lock_msg = _uri_escape
1877             ($self->fmt_msg("msg_page_locked",
1878             langstring($pageobj->Title, $self->EditorLang),
1879             $pageobj->LockedBy));
1880             my $folderid = ($objdb->parent_ids($pageobj))[0];
1881             print <
1882            
1886             EOF
1887             exit;
1888             }
1889             $objdb->lock($pageobj, -type => 'SessionLock');
1890             }
1891              
1892             my $outdata = eval { $self->_get_outdata($objdb->content($pageid)) };
1893             my $message = $@;
1894             $outdata->{'data'}->{'pageid'} = $pageid;
1895             $outdata->{'data'}->{'visible'} = $pageobj->{'VisibleToMenu'};
1896             $outdata->{'data'}->{'nodel'} = $pageobj->{'Rights'}=~"nodel" ? "1" : "0";
1897             $outdata->{'data'}->{'timeopen'} = $pageobj->TimeOpen || "";
1898             $outdata->{'data'}->{'timeexpire'} = $pageobj->TimeExpire || "";
1899              
1900             require Data::JavaScript;
1901             my @jscode = Data::JavaScript::jsdump('data', $outdata->{data});
1902              
1903             my $delbutton = $pageobj->Rights !~ /nodel/ || $root->is_allowed("everything") ? 1:0;
1904             my $releasebutton = $root->is_allowed("release", $pageid) ? 1:0;
1905             $self->_tpl("bestwe", "we_pagedata.tpl.html",
1906             {
1907             'delbutton' => $delbutton,
1908             'releasebutton' => $releasebutton,
1909             'jsarray' => \@jscode,
1910             'sitelanguages' => $c->project->sitelanguages,
1911             'new' => 1,
1912             'message' => $message,
1913             }
1914             );
1915             }
1916              
1917             ######################################################################
1918             #
1919             # show content-element editor
1920             #
1921             sub showeditor {
1922             my $self = shift;
1923              
1924             if (param("usetemplate")) {
1925             return $self->showeditor_template;
1926             }
1927              
1928             my $et = param('elementtype');
1929             my $c = $self->C;
1930             warn "showeditor elementtype=$et\n" if $c->debug;
1931              
1932             my $showeditor_methods = $self->showeditor_methods;
1933             while(my($key, $method) = each %$showeditor_methods) {
1934             if ($et =~ /^$key/) {
1935             return $self->$method();
1936             }
1937             }
1938             print <
1939            
1940             unhandled type $et
1941            
1942             EOF
1943             }
1944              
1945             sub showeditor_any {
1946             my $self = shift;
1947             $self->identify;
1948             my $type = param("elementtype");
1949             my $root = $self->Root;
1950             my $c = $self->C;
1951             my $basedir = ($type =~ /^image/ ? $c->paths->photodir :
1952             $type =~ /^download/ ? $c->paths->rootdir ."/download" :
1953             die "Unhandled type $type");
1954             my @accept = ($type =~ /^image/ ? ("image/gif", "image/jpeg", "image/png") : ());
1955              
1956             my $action = param("action");
1957             my $message = param("message");
1958             my $selectedfolder = param("selectedfolder");
1959              
1960             my $can_edit = $root->is_allowed(["edit", "edit-only"]);
1961             my $can_upload = $can_edit || $root->is_allowed('new-image');
1962             my $can_newdir = $can_edit || $root->is_allowed('new-imagefolder');
1963             my $can_delete = $can_edit || $root->is_allowed('delete-image');
1964             my $can_rename = $can_edit || $root->is_allowed('rename-image');
1965              
1966             if (defined $action && $action ne "") {
1967             if (!$can_edit && !$can_upload && !$can_newdir && !$can_delete && !$can_rename) {
1968             die "Edit not allowed for " . $self->User;
1969             }
1970             if ($action eq 'upload' && ($can_edit || $can_upload)) {
1971             $message = $self->showeditor_any_upload
1972             ($basedir,
1973             -checkext => $type,
1974             );
1975             } elsif ($action eq 'newfolder' && ($can_edit || $can_newdir)) {
1976             $message = $self->showeditor_any_newfolder
1977             ($basedir
1978             );
1979             } elsif ($action eq 'delete' && ($can_edit || $can_delete)) {
1980             $message = $self->showeditor_any_delete
1981             ($basedir
1982             );
1983             } elsif ($action eq 'rename' && ($can_edit || $can_rename)) {
1984             $message = $self->showeditor_any_rename
1985             ($basedir,
1986             -checkext => $type,
1987             );
1988             }
1989             # fall through...
1990             }
1991              
1992             my $handle_directory;
1993             $handle_directory = sub {
1994             my($dir) = @_;
1995              
1996             my %files;
1997             # for the correct sort order
1998             if (eval 'local $SIG{__DIE__}; require Tie::IxHash; 1') {
1999             tie %files, 'Tie::IxHash';
2000             }
2001              
2002             local *DIR;
2003             opendir(DIR, $dir)
2004             or $self->error("Can't open $dir: $!");
2005             while (defined(my $direntry = readdir(DIR))) {
2006             next if $direntry=~/^\.|CVS|RCS|\.svn/i; # dont show hidden or special files
2007             my $f = "$dir/$direntry";
2008             if (-d $f) {
2009             my $subfiles = $handle_directory->($f);
2010             $files{$direntry} = $subfiles;
2011             } else {
2012             $files{$direntry} = undef;
2013             }
2014             }
2015             closedir DIR;
2016              
2017             if (tied %files && (tied %files)->can('SortByKey')) {
2018             (tied %files)->SortByKey;
2019             }
2020              
2021             \%files;
2022             };
2023              
2024             my $files = $handle_directory->($basedir);
2025              
2026             require Data::JavaScript;
2027             my @filedata = Data::JavaScript::jsdump('filedata', $files);
2028              
2029             $self->_tpl("bestwe", "we_imagechooser.tpl.html",
2030             {
2031             'elementtype' => param('elementtype')||"",
2032             'filedata' => \@filedata,
2033             'message' => $message,
2034             'selectedfolder' => $selectedfolder,
2035             'accept' => \@accept,
2036             'no_edit' => !$can_edit,
2037             'can_upload' => $can_upload,
2038             'can_newdir' => $can_newdir,
2039             'can_delete' => $can_delete,
2040             'can_rename' => $can_rename,
2041             }
2042             );
2043             }
2044              
2045             sub showeditor_template {
2046             my $self = shift;
2047             my $elementtype = param("elementtype");
2048             if ($elementtype !~ /^[a-zA-Z0-9_.-]+$/) {
2049             die "Invalid characters in elementtype $elementtype (only characters, numbers, dot, dash and underline allowed";
2050             }
2051             require Safe;
2052             my $cpt = Safe->new;
2053             my $obj = $cpt->reval(CGI::unescape(param("obj")));
2054             my %addvars = (elementtype => $elementtype,
2055             lang => param("language")||"",
2056             path => param("path")||"",
2057             obj => $obj,
2058             );
2059             $self->_tpl("bestwe", "editor_template_header.tpl.html",
2060             { %{ $self->TemplateVars }, %addvars }
2061             );
2062             $self->_tpl("bestwe", "editor_template_$elementtype.tpl.html",
2063             { %{ $self->TemplateVars }, %addvars }
2064             );
2065             $self->_tpl("bestwe", "editor_template_footer.tpl.html",
2066             { %{ $self->TemplateVars }, %addvars }
2067             );
2068             }
2069              
2070             ######################################################################
2071              
2072             sub showeditor_any_upload {
2073             my $self = shift;
2074             my($basedir, %args) = @_;
2075             my $filename = param("uploadname");
2076             my $folder = param("selectedfolder");
2077             my $e = $self->msg("msg_showeditor_upload_error") . ": ";
2078             if (!defined $filename || $filename eq '') {
2079             return $e . $self->msg("msg_showeditor_no_upload_file");
2080             }
2081             if ($folder =~ /^\s*$/) {
2082             return $e . $self->msg("msg_showeditor_missing_upload_dir");
2083             }
2084             if (_invalid_file_name($folder) || $folder =~ /^\./) {
2085             return $e . $self->fmt_msg("msg_showeditor_invalid_dirname", $folder);
2086             }
2087             my $abs_folder = $basedir . "/" . $folder;
2088             if (!-e $abs_folder) {
2089             return $e . $self->fmt_msg("msg_showeditor_no_upload_dir", $abs_folder);
2090             }
2091             my $sane_filename = _sane_file_name(_universal_basename($filename));
2092             if ($args{'-checkext'} eq 'image') {
2093             if (!$self->_check_allowed_image_extensions($sane_filename)) {
2094             return $e . $self->fmt_msg("msg_showeditor_invalid_ext",
2095             join(", ", $self->_allowed_image_extensions()),
2096             $sane_filename
2097             );
2098             }
2099             }
2100             my $dest_filename = "$abs_folder/$sane_filename";
2101             if (-e $dest_filename) {
2102             return $e . $self->fmt_msg("msg_showeditor_filename_exists",
2103             $dest_filename);
2104             }
2105             if (!open(OUT, "> $dest_filename")) {
2106             return $e . $self->fmt_msg("msg_showeditor_create_error",
2107             $dest_filename, $!);
2108             }
2109             binmode(OUT);
2110              
2111             my $fh = $filename;
2112             if (!$fh) {
2113             close(OUT);
2114             unlink $dest_filename;
2115             return $e . $self->msg("msg_showeditor_upload_cancelled");
2116             }
2117             while(<$fh>) {
2118             print OUT $_;
2119             }
2120             if (!close(OUT)) {
2121             return $e . $self->fmt_msg("msg_showeditor_close_error", $!);
2122             }
2123             return $self->fmt_msg("msg_showeditor_upload_success", $sane_filename);
2124             }
2125              
2126             sub showeditor_any_newfolder {
2127             my $self = shift;
2128             my($basedir) = @_;
2129             my $newfolder = param("newfoldername");
2130             my $e = $self->msg("msg_showeditor_mkdir_error") . ": ";
2131             if ($newfolder =~ /^\s*$/) {
2132             return $e . $self->msg("msg_showeditor_missing_dirname");
2133             }
2134             if (_invalid_file_name($newfolder) || $newfolder =~ /^\./) {
2135             return $e . $self->fmt_msg("msg_showeditor_invalid_dirname",
2136             $newfolder);
2137             }
2138             $newfolder = _sane_file_name($newfolder);
2139             my $abs_folder = $basedir . "/" . $newfolder;
2140             if (-e $abs_folder) {
2141             return $e . $self->fmt_msg("msg_showeditor_dir_exists", $newfolder);
2142             }
2143             if (!mkdir($abs_folder, 0775)) {
2144             return $e . $!;
2145             }
2146             return $self->fmt_msg("msg_showeditor_mkdir_success", $newfolder);
2147             }
2148              
2149             sub showeditor_any_delete {
2150             my $self = shift;
2151             my($basedir) = @_;
2152             my $file = param("deletename");
2153             my $e = $self->msg("msg_showeditor_del_error") . ": ";
2154             if ($file =~ /^\s*$/) {
2155             return $e . $self->msg("msg_showeditor_missing_filename");
2156             }
2157             if (_invalid_file_name($file) || $file eq '.') {
2158             return $e . $self->fmt_msg("msg_showeditor_invalid_filename", $file);
2159             }
2160             my $abs_file = $basedir . "/" . $file;
2161             if (!-e $abs_file) {
2162             return $e . $self->fmt_msg("msg_showeditor_no_file", $file);
2163             }
2164             if (-d $abs_file) {
2165             my(@f) = glob("$abs_file/*");
2166             if (@f) {
2167             return $e . $self->fmt_msg("msg_showeditor_nonempty_dir", $file);
2168             }
2169             }
2170             if (-d $abs_file) {
2171             if (!rmdir($abs_file)) {
2172             return $e . $!;
2173             }
2174             return $self->fmt_msg("msg_showeditor_rmdir_success", $file);
2175             } else {
2176             if (!unlink($abs_file)) {
2177             return $e . $!;
2178             }
2179             return $self->fmt_msg("msg_showeditor_del_success", $file);
2180             }
2181             }
2182              
2183             sub showeditor_any_rename {
2184             my $self = shift;
2185             my($basedir, %args) = @_;
2186             my $from = param("renamefrom");
2187             my $to = param("renameto");
2188             my $e = $self->msg("msg_showeditor_rename_error") . ": ";
2189             if ($from =~ /^\s*$/ || $to =~ /^\s*$/) {
2190             return $e . $self->msg("msg_showeditor_missing_filenames");
2191             }
2192             if (_invalid_file_name($from)) {
2193             return $e . $self->fmt_msg("msg_showeditor_invalid_filename", $from);
2194             }
2195             if (_invalid_file_name($to)) {
2196             return $e . $self->fmt_msg("msg_showeditor_invalid_filename", $to);
2197             }
2198             require File::Basename;
2199             if ($to !~ m|/| && !-d "$basedir/$to") {
2200             $to = File::Basename::dirname($from) . "/" . $to;
2201             }
2202             my $abs_from = $basedir . "/" . $from;
2203             my $sane_to = _sane_file_name($to);
2204             my $abs_to = $basedir . "/" . $sane_to;
2205             if (!-e $abs_from) {
2206             return $e . $self->fmt_msg("msg_showeditor_no_file", $from);
2207             }
2208             if (-d $abs_to) {
2209             $abs_to .= "/" . File::Basename::basename($from);
2210             $sane_to .= "/" . File::Basename::basename($from);
2211             }
2212             if (-e $abs_to) {
2213             return $e . $self->fmt_msg("msg_showeditor_filename_exists", $sane_to)
2214             }
2215             if (!-d $abs_from) {
2216             if ($args{'-checkext'} eq 'image') {
2217             if (!$self->_check_allowed_image_extensions($abs_to)) {
2218             return $e . $self->fmt_msg("msg_showeditor_invalid_ext",
2219             join(", ", $self->_allowed_image_extensions()),
2220             $abs_to
2221             );
2222             }
2223             }
2224             }
2225             if (File::Basename::basename($abs_to) =~ /^\./) {
2226             return $e . $self->msg("msg_showeditor_nodot_filename");
2227             }
2228             require File::Copy;
2229             if (!File::Copy::move($abs_from, $abs_to)) {
2230             return $e . $!;
2231             }
2232             $self->fmt_msg("msg_showeditor_rename_success", $from, $sane_to);
2233             }
2234              
2235             # object method
2236             sub _allowed_image_extensions {
2237             qw(gif png jpg jpeg jpe tiff tif swf);
2238             }
2239              
2240             sub _check_allowed_image_extensions {
2241             my $self = shift;
2242             my $filename = shift;
2243             my $allowed_extensions = '\.(' . join("|", $self->_allowed_image_extensions()) . ")\$";
2244             if ($filename !~ /$allowed_extensions/) {
2245             return 0;
2246             } else {
2247             return 1;
2248             }
2249             }
2250              
2251             sub _invalid_file_name {
2252             my $file = shift;
2253             return 1 if $file =~ /(^|\/)\.\.($|\/)/;
2254             }
2255             sub _universal_basename {
2256             my $file = shift;
2257             if ($file =~ m|[/\\]([^/\\]+)$|) {
2258             $1;
2259             } else {
2260             $file;
2261             }
2262             }
2263             sub _sane_file_name {
2264             my $file = shift;
2265             # Umlaute korrigieren:
2266             my $convert = {'ä' => 'ae',
2267             'ö' => 'oe',
2268             'ü' => 'ue',
2269             'Ä' => 'Ae',
2270             'Ö' => 'Oe',
2271             'Ü' => 'Ue',
2272             'ß' => 'ss',
2273             };
2274             my $convert_rx = "(".join("|",map {quotemeta} keys %$convert).")";
2275             $file =~ s/$convert_rx/$convert->{$1}/g;
2276             # "gefährliche" Zeichen umwandeln
2277             $file =~ s/[^A-Za-z0-9_.\/-]/_/g;
2278             $file;
2279             }
2280              
2281             sub showeditor_link {
2282             my $self = shift;
2283             if (param('elementtype') =~ /download/ && $self->can("showeditor_download")) {
2284             $self->showeditor_download($self->C);
2285             } else {
2286             $self->_tpl("bestwe", "we_linkeditor.tpl.html",
2287             {
2288             'elementtype' => param('elementtype')||'',
2289             }
2290             );
2291             }
2292             }
2293              
2294             ######################################################################
2295             #
2296             # tree editor page
2297             sub siteeditorframe {
2298             my $self = shift;
2299             my $message = shift;
2300             if (defined $message) {
2301             param("message" => $message);
2302             }
2303             my $c = $self->C;
2304             my $objdb = $self->Root->ObjDB;
2305             if (defined param("fromid") && param("fromid") ne "" &&
2306             $c->project->sessionlocking) {
2307             my $pageobj = $objdb->get_object(param("fromid"));
2308             if ($pageobj && $pageobj->LockedBy eq $self->User) {
2309             $objdb->unlock($pageobj);
2310             }
2311             }
2312             $self->_tpl("bestwe", "we_folderreload.tpl.html",
2313             {
2314             'folderid' => param("pageid") ||'',
2315             'message' => param("message")||'',
2316             }
2317             );
2318             }
2319              
2320             ######################################################################
2321             #
2322             # tree editor page
2323             sub siteeditexplorer {
2324             my $self = shift;
2325             $self->_tpl("bestwe", "we_siteedit_explorer.tpl.html");
2326             }
2327              
2328             ######################################################################
2329             #
2330             # tree editor page
2331             # Return a javascript source line to create this object in a html tree.
2332             sub show_children_line {
2333             my $self = shift;
2334             my($k,$level,$recursive) = @_;
2335             my $line = "";
2336              
2337             my $root = $self->Root;
2338             my $c = $self->C;
2339              
2340             if (!defined $k) {
2341             warn "*** SHOULD not happen (database corrupt?): \$k is undefined ***";
2342             return;
2343             }
2344             my $id = $k->Id;
2345             my $titlestr = $k->Title;
2346             my $title = "";
2347             # resolve Languagestring
2348             if (UNIVERSAL::isa($titlestr, 'WE::Util::LangString')) {
2349             $title = $titlestr->get($c->project->sitelanguages->[0]);
2350             } else {
2351             $title = $titlestr;
2352             }
2353             my $escapedTitle = _uri_escape($title);
2354             my $timeCreated = $k->TimeCreated;
2355             my $timeModified = $k->TimeModified;
2356             my $temp = $k->Release_State;
2357             my $releaseState;
2358             if (defined($temp) && $temp ne "") {
2359             $releaseState = $temp;
2360             }
2361             else {
2362             $releaseState = "modified";
2363             }
2364              
2365             my $inactive = defined $k->Release_State && $k->Release_State eq 'inactive' ? "1":"0";
2366             ## XXX It's not yet clear what "inactive" really means...
2367             # if (!$root->is_allowed("everything") && $inactive) {
2368             # # inactive folders and documents are not visible to non-admins
2369             # next;
2370             # }
2371              
2372             if ($k->is_folder) {
2373             local $^W = 0; # because of Rights =~ ...
2374             #my $nop = $k->Rights =~ /nopage/ ? "1":"0";
2375             #my $nof = $k->Rights =~ /nofolder/ ? "1":"0";
2376             my($nop, $nof);
2377             if ($root->is_allowed("everything")) {
2378             $nop="0";$nof="0";
2379             } else {
2380             $nop = $k->Rights =~ /nopage/ || !$root->is_allowed("new-doc",$k->Id) ? "1" : "0";
2381             $nof = $k->Rights =~ /nofolder/ || !$root->is_allowed("new-folder", $k->Id) ? "1" : "0";
2382             }
2383             $line .= qq ;
2384             $line .= $self->show_children($k,$level) if $recursive;
2385             }
2386             else {
2387             my $type = $k->{Type} || "";
2388             my $icon = $c->project->iconfortype && $c->project->iconfortype->{$type} ? $c->project->iconfortype->{$type} : "text";
2389             $line .= qq ;
2390             }
2391              
2392             $line;
2393             }
2394              
2395             sub show_children {
2396             my $self = shift;
2397             my($obj,$level) = @_;
2398             my $pagelist = "";
2399             $level++;
2400             my $objdb = $self->Root->ObjDB;
2401             foreach my $k ($objdb->children($obj)) {
2402             $pagelist .= $self->show_children_line($k, $level, 1);
2403             }
2404             $pagelist;
2405             }
2406              
2407             sub siteedit {
2408             my $self = shift;
2409             $self->check_login;
2410             #XXX check here if user has the right rights...
2411             my $fromid = param("fromid");
2412             my $root = $self->Root;
2413             my $c = $self->C;
2414             my $root_obj = $root->root_object;
2415             my $pagelist = $self->show_children_line($root_obj,0,0) .
2416             $self->show_children($root_obj,0);
2417              
2418             $self->_tpl("bestwe", "we_site.tpl.html",
2419             {
2420             siteinfobutton => $root->is_allowed("everything") || $root->is_allowed("site-info") ? 1:0,
2421             publishbutton => $root->is_allowed("publish") || $root->is_allowed("everything") ? 1:0,
2422             pagelist => $pagelist,
2423             fromid => $fromid,
2424             pagetypes => $c->project->pagetypes,
2425             pagelabels => $c->project->labelfortype,
2426             hometitle => $root_obj ? langstring($root_obj->Title, $self->EditorLang) : "",
2427             nofolderview => param("nofolderview")||0,
2428             message => param("message")||"",
2429             new => 1,
2430             }
2431             );
2432             }
2433              
2434             ######################################################################
2435             #
2436             # doc tree frameset
2437             #
2438             sub doctreeframe {
2439             my $self = shift;
2440             $self->_tpl("bestwe", "we_documenttreeframeset.tpl.html");
2441             }
2442              
2443             sub doctree {
2444             my $self = shift;
2445             #XXX check here if user has the right rights...
2446             my $message = shift || "";
2447              
2448             my $c = $self->C;
2449             my $root = $self->Root;
2450             my $root_obj = $root->root_object;
2451              
2452             my $pagelist = $self->show_children($root_obj,0);
2453              
2454             $self->_tpl("bestwe", "we_doctree_main.tpl.html",
2455             {
2456             'pagelist' => $pagelist,
2457             'message' => $message,
2458             'pagetypes' => $c->project->pagetypes,
2459             'pagelabels' => $c->project->labelfortype,
2460             }
2461             );
2462             }
2463              
2464             ######################################################################
2465             #
2466             # search
2467             sub search {
2468             my $self = shift;
2469             if (param("search") ne "") {
2470             # XXX actually implement it
2471             $self->_tpl("bestwe","we_searchresult.tpl.html");
2472             } else {
2473             $self->_tpl("bestwe","we_search.tpl.html");
2474             }
2475             }
2476              
2477             ######################################################################
2478             #
2479             # move/copy frameset
2480             sub movecopyframeset {
2481             my $self = shift;
2482             $self->_tpl("bestwe", "we_movecopy_frameset.tpl.html",
2483             { cgidir => $self->C->paths->cgiurl,
2484             lang => $self->EditorLang,
2485             action => param('action')||'',
2486             sourceid => param('sourceid')||'',
2487             title => param('title')||'',
2488             });
2489             }
2490              
2491             ######################################################################
2492             #
2493             # move/copy js frame
2494             sub movecopyjs {
2495             my $self = shift;
2496             my $root = $self->Root;
2497             my $root_obj = $root->root_object;
2498             my $pagelist = $self->show_children($root_obj, 0);
2499              
2500             $self->_tpl("bestwe", "we_movecopy_js.tpl.html",
2501             { pagelist => $pagelist,
2502             action => param('action')||"",
2503             sourceid => param('sourceid')||"",
2504             title => CGI::unescape(param('title')),
2505             }
2506             );
2507             }
2508              
2509             ######################################################################
2510             #
2511             # move/copy explorer frame
2512             sub movecopyexplorer {
2513             my $self = shift;
2514             $self->_tpl("bestwe", "we_movecopy_explorer.tpl.html");
2515             }
2516              
2517             ######################################################################
2518             #
2519             # move/copy action
2520             sub movecopyaction {
2521             my $self = shift;
2522              
2523             $self->check_login;
2524              
2525             my $sourceid = param('sourceid');
2526             die "No sourceid given" if !defined $sourceid;
2527             my $targetid = param('targetid');
2528             die "No targetid given" if !defined $targetid;
2529             my $action = param('action');
2530             die "Invalid action $action" if $action !~ /^(copy|move)$/;
2531              
2532             # The web.editor does not support objects under multiple parents,
2533             # but the WE_Framework does. If the support will ever be built in, then
2534             # here the parent id has also to be supplied for the move action.
2535             # See (*) below.
2536              
2537             my $root = $self->Root;
2538             my $objdb = $root->ObjDB;
2539             my $source_obj = $objdb->get_object($sourceid);
2540             my $folderid = ($objdb->parent_ids($source_obj))[0]; # (*) should be supplied
2541             my $error;
2542             if ($action eq 'move') {
2543             unless ((($source_obj->is_folder && $root->is_allowed("move-folder")) ||
2544             ($source_obj->is_doc && $root->is_allowed("move-doc")))
2545             && $root->is_allowed("edit", $folderid)
2546             && $root->is_allowed("edit", $sourceid)
2547             ) {
2548             die "No permission to move $sourceid to $targetid"
2549             }
2550              
2551             eval {
2552             local $SIG{__DIE__};
2553             $objdb->move($sourceid, undef, -destination => $targetid);
2554             };
2555             if ($@) {
2556             warn $@;
2557             $error = $@;
2558             }
2559             } else {
2560             unless ((($source_obj->is_folder && $root->is_allowed("copy-folder")) ||
2561             ($source_obj->is_doc && $root->is_allowed("copy-doc")))
2562             && $root->is_allowed("edit", $folderid)
2563             && $root->is_allowed("edit", $sourceid)
2564             ) {
2565             die "No permission to copy $sourceid to $targetid"
2566             }
2567              
2568             eval {
2569             local $SIG{__DIE__};
2570             my @copy_obj = $objdb->copy($sourceid, $targetid);
2571             for my $copy_obj (@copy_obj) {
2572             my $need_replace;
2573             if ($source_obj->Release_State eq 'released') {
2574             $copy_obj->Release_State("modified");
2575             $need_replace++;
2576             }
2577             if (grep { $_ eq $targetid } $objdb->parent_ids($sourceid)) {
2578             # XXX Maybe use numbering if there is something named
2579             # "This Title (Copy)"
2580             WE::Util::LangString::concat
2581             ($copy_obj->Title,
2582             new_langstring(de => " (Kopie)", en => " (Copy)")
2583             );
2584             $need_replace++;
2585             }
2586             if ($need_replace) {
2587             $objdb->replace_object($copy_obj);
2588             }
2589             }
2590             };
2591             if ($@) {
2592             warn $@;
2593             $error = $@;
2594             }
2595             }
2596              
2597             $self->_tpl("bestwe", "we_movecopy_action.tpl.html",
2598             { folderid => $folderid,
2599             error => $error,
2600             }
2601             );
2602             }
2603              
2604             ######################################################################
2605              
2606             sub _tpl {
2607             my($self, $type, $templatefile, $add_vars, $outfh) = @_;
2608             require Template;
2609             my $t = Template->new($self->TemplateConf);
2610             my $dir;
2611             my $c = $self->C;
2612             if ($type eq 'bestwe') {
2613             my @try_dirs = ($c->paths->site_we_templatebase,
2614             $c->paths->we_templatebase,
2615             );
2616             for my $try_dir (@try_dirs) {
2617             if (-r "$try_dir/$templatefile") {
2618             $dir = $try_dir;
2619             last;
2620             }
2621             }
2622             if (!defined $dir) {
2623             die "Can't find template $templatefile in directories: @try_dirs";
2624             }
2625             } elsif ($type eq 'we') {
2626             $dir = $c->paths->we_templatebase;
2627             } elsif ($type eq 'site') {
2628             $dir = $c->paths->site_templatebase;
2629             } elsif ($type eq 'site_we') {
2630             $dir = $c->paths->we_htmldir . "/" . $c->project->name . "_we_templates";
2631             } else {
2632             die "Invalid type $type for _tpl";
2633             }
2634              
2635             # Only for heavy debugging:
2636             local $Template::Plugins::DEBUG = 1 if defined $c->debug && $c->debug >= 10;
2637              
2638             $outfh = \*STDOUT if !defined $outfh;
2639              
2640             # local $SIG{__DIE__} = undef;
2641             $t->process("$dir/$templatefile",
2642             { %{ $self->TemplateVars },
2643             ($add_vars ? %$add_vars : ()),
2644             },
2645             $outfh
2646             )
2647             or do {
2648             die "Template process for $dir/$templatefile failed: "
2649             . $t->error . ", \@INC is @INC, pid is $$, Template dump: "
2650             . $t->context->_dump;
2651             };
2652             }
2653              
2654             sub error {
2655             my $self = shift;
2656             my $message = shift;
2657             eval { $message = _html($message) };
2658             my $c = $self->C;
2659             my $developermail = 'eserte@users.sourceforge.net';
2660             if ($c) {
2661             eval { $developermail = _html($c->project->developermail) };
2662             }
2663             unless ($self->HeaderPrinted) {
2664             if (defined &header) { # CGI already loaded?
2665             print header(); # no myheader needed here...
2666             } else { # fallback
2667             print "Content-type: text/html\r\n\r\n";
2668             }
2669             }
2670              
2671             my @caller_info;
2672             for my $i (1 .. 20) {
2673             local $^W = 0;
2674             my(@info) = caller($i);
2675             if (!defined $info[0]) {
2676             last;
2677             }
2678             push @caller_info, "$info[0] in $info[1]:$info[2]";
2679             }
2680             my $caller_info = "Can't get caller information";
2681             eval { $caller_info = _html(join("\n", @caller_info)) };
2682              
2683             my $context;
2684             eval {
2685             my @context;
2686             my $row = sub {
2687             push @context, "
" . _html($_[0]) ." =>"
2688             . _html($_[1]) . "
2689             };
2690             for my $k (sort keys %$self) {
2691             my $v = $self->{$k};
2692             if ($k eq 'Password') {
2693             $row->($k, "********");
2694             } else {
2695             $row->($k, $v);
2696             }
2697             }
2698             my @param = param();
2699             for my $param (sort @param) {
2700             if ($param eq 'password') {
2701             $row->("(CGI) $param", "********");
2702             } else {
2703             $row->("(CGI) $param", param($param));
2704             }
2705             }
2706             $context = "Context:
" . join("\n", @context) . "
";
2707             };
2708              
2709             my $version = '$Id: OldController.pm,v 1.94 2006/02/16 12:32:34 cmuellermeta Exp $';
2710              
2711             my $stylesheet;
2712             eval {
2713             $stylesheet=' 2714             $c->paths->we_htmlurl . "/styles/cms.css"
2715             .'" />';
2716             };
2717              
2718             print <
2719            
2720            
2721             ERROR
2722             $stylesheet
2723            
2724            
2725            
2726            

Ooops!

2727            
2728             Three things are certain:
2729             Death, taxes, and lost data.
2730             Guess which has occurred.
2731            
2732             -- David Dixon

2733             Please send the content of this page to:
2734             $developermail

2735             $message
2736             \$!: $! (<= may be irrelevant)
2737             in
2738            
 
2739             $caller_info
2740            
2741             $context
2742             Version: $version
2743            


2744            
2745             EOF
2746             exit();
2747             }
2748              
2749             sub _dump_outdata {
2750             my($self, $obj) = @_;
2751             my $content_dumper = $self->ContentDumper;
2752             eval "require $content_dumper"; die $@ if $@;
2753             my $c_o = $content_dumper->new(-object => $obj);
2754             $c_o->serialize;
2755             }
2756              
2757             sub _get_outdata {
2758             my($self, $data, $dumper) = @_;
2759             if (!defined $data) {
2760             $data = param("data");
2761             }
2762             if (!defined $data || $data eq '') {
2763             die "`data' parameter is missing";
2764             }
2765             if (!defined $dumper) {
2766             require WE_Content::Base;
2767             $dumper = "WE_Content::Base";
2768             }
2769             my $c_o = $dumper->new(-string => $data);
2770             $c_o->{Object};
2771             }
2772              
2773             sub _get_pagetype {
2774             my $self = shift;
2775             my $pagetype = shift;
2776             if (!defined $pagetype) {
2777             $pagetype = param('pagetype') || 'new'; # XXX new?
2778             }
2779             # make it safe:
2780             if ($pagetype !~ /^[a-zA-Z0-9_.-]+$/) {
2781             die "Invalid characters in pagetype (only characters, numbers, dot, dash and underline allowed";
2782             }
2783             $pagetype;
2784             }
2785              
2786             # Return error message or undef
2787             sub _ambiguous_name_message {
2788             my($self, $new_name, $old_object) = @_;
2789             return if (!$new_name);
2790             return if ($old_object->Name eq $new_name);
2791             # XXX langres
2792             if ($new_name =~ /^\d/) {
2793             return $self->msg("msg_name_no_leading_digit");
2794             }
2795             if ($new_name =~ /[^a-zA-Z0-9_-]/) {
2796             return $self->msg("msg_name_word_chars");
2797             }
2798             if ($new_name eq 'index') {
2799             return $self->msg("msg_name_index_reserved");
2800             }
2801             my $root = $self->Root;
2802             my $namedb = $root->NameDB;
2803             if ($namedb->exists($new_name)) {
2804             my $name_objid = $namedb->get_id($new_name);
2805             return $self->fmt_msg("msg_name_exists", $new_name, $name_objid);
2806             }
2807             undef;
2808             }
2809              
2810             sub _js_status_str {
2811             my($message) = @_;
2812             "onmouseover='self.status=unescape(\"$message\"); return true;' onmouseout='self.status=\"\"; return true;'";
2813             }
2814              
2815             sub _html_method { shift; _html($_[0]) }
2816              
2817             sub _html {
2818             require HTML::Entities;
2819             if (defined &HTML::Entities::encode_entities_numeric) { # since 1.27
2820             HTML::Entities::encode_entities_numeric($_[0]);
2821             } else {
2822             HTML::Entities::encode_entities($_[0]);
2823             }
2824             }
2825              
2826             sub _uri_escape {
2827             require WE::Util::Escape;
2828             WE::Util::Escape::uri_escape($_[0]);
2829             }
2830              
2831             sub msg {
2832             my($self, $key) = @_;
2833             my $stash = $self->Messages->{$self->EditorLang};
2834             if (!$stash) {
2835             my $c = $self->C;
2836             my @try_langs = ($self->EditorLang);
2837             push @try_langs, "en" if $self->EditorLang ne "en";
2838             for my $lang (@try_langs) {
2839             my $langres_file = $c->paths->we_templatebase . "/langres_$lang";
2840             if (-r $langres_file) {
2841             require Template::Context;
2842             my $ctx = Template::Context->new({ ABSOLUTE => 1});
2843             $ctx->process($langres_file);
2844             $stash = $ctx->stash;
2845             last if $stash;
2846             }
2847             }
2848             if (!$stash) {
2849             return "[[$key]]";
2850             }
2851             $self->Messages->{$self->EditorLang} = $stash;
2852             }
2853             my $val = $stash->get($key);
2854             if (!defined $val) {
2855             "[[$key]]";
2856             } else {
2857             $val;
2858             }
2859             }
2860              
2861             sub fmt_msg {
2862             my($self, $key, @arg) = @_;
2863             sprintf $self->msg($key), @arg;
2864             }
2865              
2866             sub identify {
2867             my $self = shift;
2868             my $c = $self->C;
2869             my $root = $self->Root;
2870             if ($c && $c->siteext && $c->siteext->external_auth) {
2871             $root->CurrentUser(remote_user());
2872             return 1;
2873             } else {
2874             my($user, $password) = @_ ? @_[0, 1] : ($self->User, $self->Password);
2875             $root->identify($user, $password);
2876             }
2877             }
2878              
2879             sub current_user {
2880             my $self = shift;
2881             if (!$self->Root->CurrentUser) {
2882             $self->identify;
2883             }
2884             $self->Root->CurrentUser;
2885             }
2886              
2887             sub get_session {
2888             my($self, $sid) = @_;
2889             my $c = $self->C;
2890             my $sessdef = $c->siteext->{session};
2891             eval q{local $SIG{__DIE__}; require } . $sessdef->{module}; die $@ if $@;
2892             tie my %sess, $sessdef->{module}, $sid,
2893             {
2894             FileName => $sessdef->{FileName},
2895             LockDirectory => $sessdef->{LockDirectory},
2896             }
2897             or die "Can't get session: $!";
2898             \%sess;
2899             }
2900              
2901             sub delete_session {
2902             my($self, $sid) = @_;
2903             my $sessref = $self->get_session($sid);
2904             tied(%$sessref)->delete;
2905             }
2906              
2907             sub get_die_handler {
2908             my $oc = shift;
2909             return sub {
2910             die @_ if $^S; # we're in an eval
2911              
2912             my $stack_i = 1;
2913             while($stack_i < 200) {
2914             my @c = caller($stack_i);
2915             last if !@c;
2916             # Another exception is any THROW call from the Template-Toolkit
2917             if ($c[3] =~ m{^Template::.*::throw$}) {
2918             die @_;
2919             }
2920             $stack_i++;
2921             }
2922             $oc->error($_[0]);
2923             };
2924             }
2925              
2926             sub has_timebasedpublishing {
2927             my $self = shift;
2928             my $c = $self->C;
2929             $c->project->features->{timebasedpublishing};
2930             }
2931              
2932             sub get_we_template_contenttype {
2933             shift->get_template_contenttype(@_);
2934             }
2935              
2936             sub get_template_contenttype {
2937             my($self, $templatefile) = @_;
2938             my $content_type = "text/html";
2939             my $ext = ".html";
2940             if ($templatefile =~ /\.wml$/) {
2941             $content_type = "text/vnd.wap.wml";
2942             $ext = ".wml";
2943             } elsif ($templatefile =~ /\.js$/) {
2944             $content_type = "application/x-javascript";
2945             $ext = ".js";
2946             }
2947             ($content_type, $ext);
2948             }
2949              
2950             sub get_custom_userdb {
2951             my($self, $useradmindb) = @_;
2952             die if !$useradmindb;
2953             if ($self->CustomUserDB &&
2954             $self->CustomUserDB->{$useradmindb}) {
2955             return $self->CustomUserDB->{$useradmindb};
2956             }
2957              
2958             my $root = $self->Root;
2959             my $c = $self->C;
2960             my($userdb_basename, $userdb_newparam);
2961             if ($c->project->features->{userdb} &&
2962             $c->project->features->{userdb}{$useradmindb}) {
2963             my $userdb_prop = $c->project->features->{userdb}{$useradmindb};
2964             $userdb_basename = $userdb_prop->{basename};
2965             $userdb_newparam = $userdb_prop->{newparam};
2966             } else {
2967             my $userdb_prop = $root->get_userdb_prop($useradmindb);
2968             $userdb_basename = $userdb_prop->_basename;
2969             $userdb_newparam = $userdb_prop->_newparam;
2970             }
2971             require WE::DB::ComplexUser;
2972             my $u = WE::DB::ComplexUser->new
2973             (undef,
2974             $c->paths->we_database . "/" . $userdb_basename,
2975             @{ $userdb_newparam },
2976             -locking => 1,
2977             -connect => exists $ENV{MOD_PERL} ? 0 : 1,
2978             );
2979             $self->CustomUserDB->{$useradmindb} = $u;
2980             eval {
2981             require Scalar::Util;
2982             Scalar::Util::weaken($u);
2983             };
2984             if ($@) {
2985             warn "Weakening failed --- what about older perls? $@";
2986             }
2987             $u;
2988             }
2989              
2990             sub get_alias_pages {
2991             my($self, $id, %args) = @_;
2992             my $now = $args{-now};
2993             my $root = $self->Root;
2994             my $objdb = $root->ObjDB;
2995             my $c = $self->C;
2996              
2997             my @alias_pages;
2998             push @alias_pages, $root->NameDB->get_names($id);
2999              
3000             # XXX Handle other cases, too (autoindexdoc ne "first" ...)
3001             my $autoindexdoc = $c->project->features->{autoindexdoc};
3002             if (defined $autoindexdoc && $autoindexdoc eq 'first') {
3003             my $o = $objdb->get_object($id);
3004             if ($o->is_folder) {
3005             my(@children_ids) = $objdb->get_released_children($id, -now => $now);
3006             if (@children_ids) {
3007             push @alias_pages, $children_ids[0]->Id;
3008             }
3009             } else {
3010             my($parent_id) = $objdb->parent_ids($id);
3011             if (defined $parent_id) {
3012             my(@children_ids) = $objdb->get_released_children($parent_id, -now => $now);
3013             if ($children_ids[0]->Id eq $id) {
3014             push @alias_pages, $parent_id, $self->get_alias_pages($parent_id, %args);
3015             }
3016             }
3017             }
3018             }
3019              
3020             # make unique
3021             my %alias_pages = map {($_=>1)} grep { $_ ne $id } @alias_pages;
3022             keys %alias_pages;
3023             }
3024              
3025             sub we_notify {
3026             my($self, $action, $info) = @_;
3027             my $msg;
3028             if ($self->can('notify')) {
3029             my $retinfo = {};
3030             $self->notify($action, $info, $retinfo);
3031             if ($retinfo->{message}) {
3032             $msg = $retinfo->{message};
3033             } elsif ($retinfo->{receivers} && @{$retinfo->{receivers}}) {
3034             $msg = $self->fmt_msg("msg_notify_sent", "@{$retinfo->{receivers}}");
3035             }
3036             }
3037             $msg;
3038             }
3039              
3040             ### XXX Ueberdenken. Insbesondere sollte mehr Information zurueckgegeben
3041             ### werden (symlink advised, folderindex page advised etc.)
3042             ### Am Ende wird diese Funktion viele "code doubled"-Stuecke hier
3043             ### und anderswo ersetzen.
3044             # sub get_content_objectid {
3045             # my($self, $obj) = @_;
3046             # my $root = $self->Root;
3047             # my $objdb = $root->ObjDB;
3048             # my $c = $self->C;
3049             # $objdb->objectify_params($obj);
3050             # if ($obj->is_folder) {
3051             # my $docid = $obj->IndexDoc;
3052             # if (!defined $docid || $docid eq "") {
3053             # my $mainid = $obj->Version_Parent;
3054             # $mainid = $obj->Id if !defined $mainid;
3055             # my $autoindexdoc = $c->project->features->{autoindexdoc};
3056             # if (defined $autoindexdoc && $autoindexdoc eq 'first') {
3057             # my(@children_ids) = $objdb->get_released_children($mainid, -now => $now);
3058             # if (@children_ids) {
3059             # return $children_ids[0]->Id;
3060             # }
3061             # }
3062             # # else: folderindex template will be used
3063             # return undef;
3064             # } else {
3065             # return $docid;
3066             # }
3067             # } else { return $obj->Id }
3068             # }
3069              
3070             1;
3071              
3072             __END__