Merge branch 'master' of vc.linet-services.de:public/lx-office-erp
[kivitendo-erp.git] / SL / Controller / Base.pm
index c63a8ee..ac09057 100644 (file)
@@ -5,7 +5,10 @@ use strict;
 use parent qw(Rose::Object);
 
 use Carp;
 use parent qw(Rose::Object);
 
 use Carp;
+use IO::File;
 use List::Util qw(first);
 use List::Util qw(first);
+use SL::Request qw(flatten);
+use SL::MoreCommon qw(uri_encode);
 
 #
 # public/helper functions
 
 #
 # public/helper functions
@@ -20,7 +23,7 @@ sub url_for {
   my $controller  = delete($params{controller}) || $self->_controller_name;
   my $action      = delete($params{action})     || 'dispatch';
   $params{action} = "${controller}/${action}";
   my $controller  = delete($params{controller}) || $self->_controller_name;
   my $action      = delete($params{action})     || 'dispatch';
   $params{action} = "${controller}/${action}";
-  my $query       = join('&', map { $::form->escape($_) . '=' . $::form->escape($params{$_}) } keys %params);
+  my $query       = join '&', map { uri_encode($_->[0]) . '=' . uri_encode($_->[1]) } @{ flatten(\%params) };
 
   return "controller.pl?${query}";
 }
 
   return "controller.pl?${query}";
 }
@@ -29,7 +32,12 @@ sub redirect_to {
   my $self = shift;
   my $url  = $self->url_for(@_);
 
   my $self = shift;
   my $url  = $self->url_for(@_);
 
-  print $::cgi->redirect($url);
+  if ($self->delay_flash_on_redirect) {
+    require SL::Helper::Flash;
+    SL::Helper::Flash::delay_flash();
+  }
+
+  print $::request->{cgi}->redirect($url);
 }
 
 sub render {
 }
 
 sub render {
@@ -44,6 +52,9 @@ sub render {
   if ($options->{inline}) {
     $source = \$template;
 
   if ($options->{inline}) {
     $source = \$template;
 
+  } elsif($options->{raw}) {
+    $source =  $template;
+
   } else {
     $source = "templates/webpages/${template}." . $options->{type};
     croak "Template file ${source} not found" unless -f $source;
   } else {
     $source = "templates/webpages/${template}." . $options->{type};
     croak "Template file ${source} not found" unless -f $source;
@@ -55,7 +66,7 @@ sub render {
       my $content_type  = $options->{type} eq 'js' ? 'text/javascript' : 'text/html';
 
       print $::form->create_http_response(content_type => $content_type,
       my $content_type  = $options->{type} eq 'js' ? 'text/javascript' : 'text/html';
 
       print $::form->create_http_response(content_type => $content_type,
-                                          charset      => $::dbcharset || Common::DEFAULT_CHARSET);
+                                          charset      => $::lx_office_conf{system}->{dbcharset} || Common::DEFAULT_CHARSET());
 
     } else {
       $::form->{title} = $locals{title} if $locals{title};
 
     } else {
       $::form->{title} = $locals{title} if $locals{title};
@@ -64,31 +75,46 @@ sub render {
   }
 
   my %params = ( %locals,
   }
 
   my %params = ( %locals,
-                 AUTH     => $::auth,
-                 FORM     => $::form,
-                 LOCALE   => $::locale,
-                 LXCONFIG => { dbcharset              => $::dbcharset,
-                               webdav                 => $::webdav,
-                               lizenzen               => $::lizenzen,
-                               latex_templates        => $::latex,
-                               opendocument_templates => $::opendocument_templates,
-                               vertreter              => $::vertreter,
-                               show_best_before       => $::show_best_before,
-                             },
-                 LXDEBUG  => $::lxdebug,
-                 MYCONFIG => \%::myconfig,
-                 SELF     => $self,
+                 AUTH          => $::auth,
+                 FLASH         => $::form->{FLASH},
+                 FORM          => $::form,
+                 INSTANCE_CONF => $::instance_conf,
+                 LOCALE        => $::locale,
+                 LXCONFIG      => \%::lx_office_conf,
+                 LXDEBUG       => $::lxdebug,
+                 MYCONFIG      => \%::myconfig,
+                 SELF          => $self,
                );
 
   my $output;
                );
 
   my $output;
-  my $parser = $self->_template_obj;
-  $parser->process($source, \%params, \$output) || croak $parser->error;
+  if (!$options->{raw}) {
+    my $parser = $self->_template_obj;
+    $parser->process($source, \%params, \$output) || croak $parser->error;
+  } else {
+    $output = $$source;
+  }
 
   print $output unless $options->{inline} || $options->{no_output};
 
   return $output;
 }
 
 
   print $output unless $options->{inline} || $options->{no_output};
 
   return $output;
 }
 
+sub send_file {
+  my ($self, $file_name, %params) = @_;
+
+  my $file            = IO::File->new($file_name, 'r') || croak("Cannot open file '${file_name}'");
+  my $content_type    =  $params{type} || 'application/octet_stream';
+  my $attachment_name =  $params{name} || $file_name;
+  $attachment_name    =~ s:.*//::g;
+
+  print $::form->create_http_response(content_type        => $content_type,
+                                      content_disposition => 'attachment; filename="' . $attachment_name . '"',
+                                      content_length      => -s $file);
+
+  $::locale->with_raw_io(\*STDOUT, sub { print while <$file> });
+  $file->close;
+}
+
 #
 # Before/after run hooks
 #
 #
 # Before/after run hooks
 #
@@ -133,6 +159,14 @@ sub _run_hooks {
   }
 }
 
   }
 }
 
+#
+#  behaviour. override these
+#
+
+sub delay_flash_on_redirect {
+  0;
+}
+
 #
 # private functions -- for use in Base only
 #
 #
 # private functions -- for use in Base only
 #
@@ -163,9 +197,13 @@ sub _dispatch {
   my $action  = first { $::form->{"action_${_}"} } @actions;
   my $sub     = "action_${action}";
 
   my $action  = first { $::form->{"action_${_}"} } @actions;
   my $sub     = "action_${action}";
 
-  $self->_run_hooks('before', $action);
-  $self->$sub(@_);
-  $self->_run_hooks('after', $action);
+  if ($self->can($sub)) {
+    $self->_run_hooks('before', $action);
+    $self->$sub(@_);
+    $self->_run_hooks('after', $action);
+  } else {
+    $::form->error($::locale->text('Oops. No valid action found to dispatch. Please report this case to the Lx-Office team.'));
+  }
 }
 
 sub _template_obj {
 }
 
 sub _template_obj {
@@ -179,7 +217,7 @@ sub _template_obj {
                     PLUGIN_BASE  => 'SL::Template::Plugin',
                     INCLUDE_PATH => '.:templates/webpages',
                     COMPILE_EXT  => '.tcc',
                     PLUGIN_BASE  => 'SL::Template::Plugin',
                     INCLUDE_PATH => '.:templates/webpages',
                     COMPILE_EXT  => '.tcc',
-                    COMPILE_DIR  => $::userspath . '/templates-cache',
+                    COMPILE_DIR  => $::lx_office_conf{paths}->{userspath} . '/templates-cache',
                   }) || croak;
 
   return $self->{__basepriv_template_obj};
                   }) || croak;
 
   return $self->{__basepriv_template_obj};
@@ -306,6 +344,10 @@ containing the template code to interprete. Additionally the output
 will not be sent to the browser. Instead it is only returned to the
 caller.
 
 will not be sent to the browser. Instead it is only returned to the
 caller.
 
+If C<< $options->{raw} >> is trueish, the function will treat the input as
+already parsed, and will not filter the input through Template. Unlike
+C<inline>, the input is taked as a reference.
+
 If C<< $options->{inline} >> is falsish then C<$template> is
 interpreted as the name of a template file. It is prefixed with
 "templates/webpages/" and postfixed with a file extension based on
 If C<< $options->{inline} >> is falsish then C<$template> is
 interpreted as the name of a template file. It is prefixed with
 "templates/webpages/" and postfixed with a file extension based on
@@ -336,9 +378,10 @@ The template itself has access to the following variables:
 
 =item * C<LOCALE> -- C<$::locale>
 
 
 =item * C<LOCALE> -- C<$::locale>
 
-=item * C<LXCONFIG> -- all parameters from C<config/lx-erp.conf> with
-the same name they appear in the file (e.g. C<dbcharset>, C<webdav>
-etc)
+=item * C<LXCONFIG> -- all parameters from C<config/lx_office.conf>
+with the same name they appear in the file (first level is the
+section, second the actual variable, e.g. C<system.dbcharset>,
+C<features.webdav> etc)
 
 =item * C<LXDEBUG> -- C<$::lxdebug>
 
 
 =item * C<LXDEBUG> -- C<$::lxdebug>
 
@@ -373,6 +416,21 @@ browser. Typical use for actions called via AJAX:
   $self->render('todo/single_item', { type => 'js' },
                 item => $employee->most_important_todo_item);
 
   $self->render('todo/single_item', { type => 'js' },
                 item => $employee->most_important_todo_item);
 
+=item C<send_file $file_name, [%params]>
+
+Sends the file C<$file_name> to the browser including appropriate HTTP
+headers for a download. C<%params> can include the following:
+
+=over 2
+
+=item * C<type> -- the file's content type; defaults to
+'application/octet_stream'
+
+=item * C<name> -- the name presented to the browser; defaults to
+C<$file_name>
+
+=back
+
 =item C<url_for $url>
 
 =item C<url_for $params>
 =item C<url_for $url>
 
 =item C<url_for $params>
@@ -439,6 +497,12 @@ action.
 
 The hook's return values are discarded.
 
 
 The hook's return values are discarded.
 
+=item delay_flash_on_redirect
+
+May be overridden by a controller. If this method returns true, redirect_to
+will delay all flash messages for the current request. Defaults to false for
+compatibility reasons.
+
 =back
 
 =head2 PRIVATE FUNCTIONS
 =back
 
 =head2 PRIVATE FUNCTIONS