]> wagnertech.de Git - mfinanz.git/commitdiff
Merge branch 'master' of git@lx-office.linet-services.de:lx-office-erp
authorSven Schöling <s.schoeling@linet-services.de>
Mon, 28 Feb 2011 13:16:47 +0000 (14:16 +0100)
committerSven Schöling <s.schoeling@linet-services.de>
Mon, 28 Feb 2011 13:16:47 +0000 (14:16 +0100)
32 files changed:
SL/Auth.pm
SL/Auth/Constants.pm
SL/Auth/DB.pm
SL/Controller/Base.pm
SL/DB.pm
SL/DB/Buchungsgruppe.pm
SL/DB/Manager/Buchungsgruppe.pm [new file with mode: 0644]
SL/Dispatcher.pm
SL/Form.pm
SL/Helper/Flash.pm
SL/Template/Plugin/L.pm
bin/mozilla/admin.pl
bin/mozilla/do.pl
bin/mozilla/drafts.pl
bin/mozilla/ic.pl
bin/mozilla/io.pl
bin/mozilla/licenses.pl
bin/mozilla/login.pl
bin/mozilla/ustva.pl
bin/mozilla/wh.pl
config/lx_office.conf.default
controller.pl [new symlink]
css/lx-office-erp.css
doc/INSTALL.fcgi
doc/changelog
doc/dokumentenvorlagen-und-variablen.html
locale/de/all
locale/de_DE/all
locale/en/all
templates/webpages/admin/list_users.html
templates/webpages/generic/error.html
templates/webpages/login/company_logo.html

index 3b7a6287f4101fdad1b5660d99a67e5d68ac9d74..cd16c8e0bc48c4541adb5290bcff3b732b48008e 100644 (file)
@@ -136,11 +136,11 @@ sub authenticate_root {
 sub authenticate {
   $main::lxdebug->enter_sub();
 
-  my $self = shift;
+  my ($self, $login, $password) = @_;
 
   $main::lxdebug->leave_sub();
 
-  my $result = $self->{authenticator}->authenticate(@_);
+  my $result = $login ? $self->{authenticator}->authenticate($login, $password) : ERR_USER;
   return OK if $result eq OK;
   sleep 5;
   return $result;
@@ -166,7 +166,7 @@ sub dbconnect {
 
   $main::lxdebug->message(LXDebug->DEBUG1, "Auth::dbconnect DSN: $dsn");
 
-  $self->{dbh} = DBI->connect($dsn, $cfg->{user}, $cfg->{password}, { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 0 });
+  $self->{dbh} = DBI->connect($dsn, $cfg->{user}, $cfg->{password}, { pg_enable_utf8 => $::locale->is_utf8, AutoCommit => 1 });
 
   if (!$may_fail && !$self->{dbh}) {
     $main::form->error($main::locale->text('The connection to the authentication database failed:') . "\n" . $DBI::errstr);
@@ -306,6 +306,8 @@ sub save_user {
 
   my ($sth, $query, $user_id);
 
+  $dbh->begin_work;
+
   $query     = qq|SELECT id FROM auth."user" WHERE login = ?|;
   ($user_id) = selectrow_query($form, $dbh, $query, $login);
 
@@ -426,11 +428,14 @@ sub delete_user {
   my $form  = $main::form;
 
   my $dbh   = $self->dbconnect();
+
+  $dbh->begin_work;
+
   my $query = qq|SELECT id FROM auth."user" WHERE login = ?|;
 
   my ($id)  = selectrow_query($form, $dbh, $query, $login);
 
-  return $main::lxdebug->leave_sub() if (!$id);
+  $dbh->rollback and return $main::lxdebug->leave_sub() if (!$id);
 
   do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE user_id = ?|, $id);
   do_query($form, $dbh, qq|DELETE FROM auth.user_config WHERE user_id = ?|, $id);
@@ -482,7 +487,10 @@ sub restore_session {
 
   while (my $ref = $sth->fetchrow_hashref()) {
     $self->{SESSION}->{$ref->{sess_key}} = $ref->{sess_value};
-    $form->{$ref->{sess_key}}            = $self->_load_value($ref->{sess_value}) if (!defined $form->{$ref->{sess_key}});
+    next if defined $form->{$ref->{sess_key}};
+
+    my $params                = $self->_load_value($ref->{sess_value});
+    $form->{$ref->{sess_key}} = $params->{data} if $params->{auto_restore} || $params->{simple};
   }
 
   $sth->finish();
@@ -493,15 +501,26 @@ sub restore_session {
 }
 
 sub _load_value {
-  return $_[1] if $_[1] !~ m/^---/;
+  my ($self, $value) = @_;
+
+  return { simple => 1, data => $value } if $value !~ m/^---/;
 
-  my $value;
+  my %params = ( simple => 1 );
   eval {
-    $value = YAML::Load($_[1]);
+    my $data = YAML::Load($value);
+
+    if (ref $data eq 'HASH') {
+      map { $params{$_} = $data->{$_} } keys %{ $data };
+      $params{simple} = 0;
+
+    } else {
+      $params{data}   = $data;
+    }
+
     1;
-  } or return $_[1];
+  } or $params{data} = $value;
 
-  return $value;
+  return \%params;
 }
 
 sub destroy_session {
@@ -512,6 +531,8 @@ sub destroy_session {
   if ($session_id) {
     my $dbh = $self->dbconnect();
 
+    $dbh->begin_work;
+
     do_query($main::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id);
     do_query($main::form, $dbh, qq|DELETE FROM auth.session WHERE id = ?|, $session_id);
 
@@ -530,6 +551,9 @@ sub expire_sessions {
   my $self  = shift;
 
   my $dbh   = $self->dbconnect();
+
+  $dbh->begin_work;
+
   my $query =
     qq|DELETE FROM auth.session_content
        WHERE session_id IN
@@ -575,6 +599,9 @@ sub create_or_refresh_session {
   $form  = $main::form;
   $dbh   = $self->dbconnect();
 
+  $dbh->begin_work;
+  do_query($::form, $dbh, qq|LOCK auth.session_content|);
+
   $query = qq|SELECT id FROM auth.session WHERE id = ?|;
 
   ($id)  = selectrow_query($form, $dbh, $query, $session_id);
@@ -598,8 +625,13 @@ sub save_session {
   my $self         = shift;
   my $provided_dbh = shift;
 
-  my $dbh          = $provided_dbh || $self->dbconnect();
+  my $dbh          = $provided_dbh || $self->dbconnect(1);
+
+  return unless $dbh;
+
+  $dbh->begin_work unless $provided_dbh;
 
+  do_query($::form, $dbh, qq|LOCK auth.session_content|);
   do_query($::form, $dbh, qq|DELETE FROM auth.session_content WHERE session_id = ?|, $session_id);
 
   if (%{ $self->{SESSION} }) {
@@ -625,7 +657,7 @@ sub set_session_value {
   $self->{SESSION} ||= { };
 
   while (my ($key, $value) = each %params) {
-    $self->{SESSION}->{ $key } = YAML::Dump($value);
+    $self->{SESSION}->{ $key } = YAML::Dump(ref($value) eq 'HASH' ? { data => $value } : $value);
   }
 
   $main::lxdebug->leave_sub();
@@ -649,12 +681,85 @@ sub delete_session_value {
 sub get_session_value {
   $main::lxdebug->enter_sub();
 
-  my $self  = shift;
-  my $value = $self->{SESSION} ? $self->_load_value($self->{SESSION}->{ $_[0] }) : undef;
+  my $self   = shift;
+  my $params = $self->{SESSION} ? $self->_load_value($self->{SESSION}->{ $_[0] }) : {};
 
   $main::lxdebug->leave_sub();
 
-  return $value;
+  return $params->{data};
+}
+
+sub create_unique_sesion_value {
+  my ($self, $value, %params) = @_;
+
+  $self->{SESSION} ||= { };
+
+  my @now                   = gettimeofday();
+  my $key                   = "$$-" . ($now[0] * 1000000 + $now[1]) . "-";
+  $self->{unique_counter} ||= 0;
+
+  $self->{unique_counter}++ while exists $self->{SESSION}->{$key . $self->{unique_counter}};
+  $self->{unique_counter}++;
+
+  $value  = { expiration => $params{expiration} ? ($now[0] + $params{expiration}) * 1000000 + $now[1] : undef,
+              no_auto    => !$params{auto_restore},
+              data       => $value,
+            };
+
+  $self->{SESSION}->{$key . $self->{unique_counter}} = YAML::Dump($value);
+
+  return $key . $self->{unique_counter};
+}
+
+sub save_form_in_session {
+  my ($self, %params) = @_;
+
+  my $form        = delete($params{form}) || $::form;
+  my $non_scalars = delete $params{non_scalars};
+  my $data        = {};
+
+  my %skip_keys   = map { ( $_ => 1 ) } (qw(login password stylesheet version titlebar), @{ $params{skip_keys} || [] });
+
+  foreach my $key (grep { !$skip_keys{$_} } keys %{ $form }) {
+    $data->{$key} = $form->{$key} if !ref($form->{$key}) || $non_scalars;
+  }
+
+  return $self->create_unique_sesion_value($data, %params);
+}
+
+sub restore_form_from_session {
+  my ($self, $key, %params) = @_;
+
+  my $data = $self->get_session_value($key);
+  return $self unless $data;
+
+  my $form    = delete($params{form}) || $::form;
+  my $clobber = exists $params{clobber} ? $params{clobber} : 1;
+
+  map { $form->{$_} = $data->{$_} if $clobber || !exists $form->{$_} } keys %{ $data };
+
+  return $self;
+}
+
+sub expire_session_keys {
+  my ($self) = @_;
+
+  $self->{SESSION} ||= { };
+
+  my @now = gettimeofday();
+  my $now = $now[0] * 1000000 + $now[1];
+
+  $self->delete_session_value(map  { $_->[0]                                                 }
+                              grep { $_->[1]->{expiration} && ($now > $_->[1]->{expiration}) }
+                              map  { [ $_, $self->_load_value($self->{SESSION}->{$_}) ]      }
+                              keys %{ $self->{SESSION} });
+
+  return $self;
+}
+
+sub _has_expiration {
+  my ($value) = @_;
+  return (ref $value eq 'HASH') && exists($value->{expiration}) && $value->{data};
 }
 
 sub set_cookie_environment_variable {
@@ -821,6 +926,8 @@ sub save_group {
   my $form  = $main::form;
   my $dbh   = $self->dbconnect();
 
+  $dbh->begin_work;
+
   my ($query, $sth, $row, $rights);
 
   if (!$group->{id}) {
@@ -866,6 +973,7 @@ sub delete_group {
   my $form = $main::from;
 
   my $dbh  = $self->dbconnect();
+  $dbh->begin_work;
 
   do_query($form, $dbh, qq|DELETE FROM auth.user_group WHERE group_id = ?|, $id);
   do_query($form, $dbh, qq|DELETE FROM auth.group_rights WHERE group_id = ?|, $id);
@@ -1046,3 +1154,93 @@ sub load_rights_for_user {
 }
 
 1;
+__END__
+
+=pod
+
+=encoding utf8
+
+=head1 NAME
+
+SL::Auth - Authentication and session handling
+
+=head1 FUNCTIONS
+
+=over 4
+
+=item C<set_session_value %values>
+
+Store all key/value pairs in C<%values> in the session. All of these
+values are copied back into C<$::form> in the next request
+automatically.
+
+The values can be any Perl structure. They are stored as YAML dumps.
+
+=item C<get_session_value $key>
+
+Retrieve a value from the session. Returns C<undef> if the value
+doesn't exist.
+
+=item C<create_unique_sesion_value $value, %params>
+
+Create a unique key in the session and store C<$value>
+there.
+
+If C<$params{expiration}> is set then it is interpreted as a number of
+seconds after which the value is removed from the session. It will
+never expire if that parameter is falsish.
+
+If C<$params{auto_restore}> is trueish then the value will be copied
+into C<$::form> upon the next request automatically. It defaults to
+C<false> and has therefore different behaviour than
+L</set_session_value>.
+
+Returns the key created in the session.
+
+=item C<expire_session_keys>
+
+Removes all keys from the session that have an expiration time set and
+whose expiration time is in the past.
+
+=item C<save_session>
+
+Stores the session values in the database. This is the only function
+that actually stores stuff in the database. Neither the various
+setters nor the deleter access the database.
+
+=item <save_form_in_session %params>
+
+Stores the content of C<$params{form}> (default: C<$::form>) in the
+session using L</create_unique_sesion_value>.
+
+If C<$params{non_scalars}> is trueish then non-scalar values will be
+stored as well. Default is to only store scalar values.
+
+The following keys will never be saved: C<login>, C<password>,
+C<stylesheet>, C<titlebar>, C<version>. Additional keys not to save
+can be given as an array ref in C<$params{skip_keys}>.
+
+Returns the unique key under which the form is stored.
+
+=item <restore_form_from_session $key, %params>
+
+Restores the form from the session into C<$params{form}> (default:
+C<$::form>).
+
+If C<$params{clobber}> is falsish then existing values with the same
+key in C<$params{form}> will not be overwritten. C<$params{clobber}>
+is on by default.
+
+Returns C<$self>.
+
+=back
+
+=head1 BUGS
+
+Nothing here yet.
+
+=head1 AUTHOR
+
+Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
+
+=cut
index 85227133844c46ee6c773f5dfd776e12bf6f20a2..5a44dc1e34d8b6c65b85e2ea3ecb9dd31e2f140c 100644 (file)
@@ -11,6 +11,7 @@ our %EXPORT_TAGS   = (
   ERR => [ qw(
     ERR_PASSWORD
     ERR_BACKEND
+    ERR_USER
   ) ],
   SESSION => [ qw(
     SESSION_OK
@@ -30,6 +31,7 @@ Exporter::export_ok_tags('all');
 
 use constant OK              =>   0;
 use constant ERR_PASSWORD    =>   1;
+use constant ERR_USER        =>   2;
 use constant ERR_BACKEND     => 100;
 
 use constant SESSION_OK      =>   0;
index 2ad131a8dc1b58d25a9ae31a5c346c985cab2412..0168896f9f4ef2bba9c34f4547613324740f6a66 100644 (file)
@@ -1,10 +1,12 @@
 package SL::Auth::DB;
 
+use strict;
+
+use Carp;
+
 use SL::Auth::Constants qw(:all);
 use SL::DBUtils;
 
-use strict;
-
 sub new {
   $main::lxdebug->enter_sub();
 
@@ -26,7 +28,6 @@ sub authenticate {
   my $self       = shift;
   my $login      = shift;
   my $password   = shift;
-  my $is_crypted = shift;
 
   my $dbh        = $self->{auth}->dbconnect();
 
@@ -38,8 +39,13 @@ sub authenticate {
   my $query             = qq|SELECT password FROM auth."user" WHERE login = ?|;
   my ($stored_password) = $dbh->selectrow_array($query, undef, $login);
 
-  $password        = crypt $password, substr($login, 0, 2)        if (!$password || !$is_crypted);
-  $stored_password = crypt $stored_password, substr($login, 0, 2) if (!$stored_password);
+  my ($algorithm, $algorithm2);
+
+  # Empty password hashes in the database mean just that -- empty
+  # passwords. Hash it for easier comparison.
+  $stored_password               = $self->hash_password(password => $stored_password) unless $stored_password;
+  ($algorithm, $stored_password) = $self->parse_password_entry($stored_password);
+  ($algorithm2, $password)       = $self->parse_password_entry($self->hash_password(password => $password, algorithm => $algorithm, login => $login));
 
   $main::lxdebug->leave_sub();
 
@@ -65,7 +71,7 @@ sub change_password {
     return ERR_BACKEND;
   }
 
-  $password = crypt $password, substr($login, 0, 2) if (!$is_crypted);
+  $password = $self->hash_password(password => $password) unless $is_crypted;
 
   do_query($main::form, $dbh, qq|UPDATE auth."user" SET password = ? WHERE login = ?|, $password, $login);
 
@@ -80,4 +86,42 @@ sub verify_config {
   return 1;
 }
 
+sub hash_password {
+  my ($self, %params) = @_;
+
+  if (!$params{algorithm}) {
+    $params{algorithm}          = 'SHA1';
+    $params{fallback_algorithm} = 'MD5';
+  }
+
+  if ($params{algorithm} eq 'SHA1') {
+    if (eval { require Digest::SHA1; 1 }) {
+      return '{SHA1}' . Digest::SHA1::sha1_hex($params{password});
+
+    } elsif ($params{fallback_algorithm}) {
+      return $self->hash_password(%params, algorithm => $params{fallback_algorithm});
+
+    } else {
+      die 'Digest::SHA1 not available';
+    }
+
+  } elsif ($params{algorithm} eq 'MD5') {
+    require Digest::MD5;
+    return '{MD5}' . Digest::MD5::md5_hex($params{password});
+
+  } elsif ($params{algorithm} eq 'CRYPT') {
+    return '{CRYPT}' . crypt($params{password}, substr($params{login}, 0, 2));
+
+  } else {
+    croak 'Unsupported hash algorithm ' . $params{algorithm};
+  }
+}
+
+sub parse_password_entry {
+  my ($self, $password) = @_;
+
+  return ($1, $2) if $password =~ m/^\{ ([^\}]+) \} (.+)/x;
+  return ('CRYPT', $password);
+}
+
 1;
index fff11ca3a99b494a516f1c2ad35ce1091dae64e2..d80fca16d71d99d729c27b26c58cea522545eb55 100644 (file)
@@ -65,6 +65,7 @@ sub render {
 
   my %params = ( %locals,
                  AUTH     => $::auth,
+                 FLASH    => $::form->{FLASH},
                  FORM     => $::form,
                  LOCALE   => $::locale,
                  LXCONFIG => \%::lx_office_conf,
index f90a9c6371a72710287499afbbe3c12384d2abd6..67888ef5942f34174b5a7a45dc7986e40f4ed6a7 100644 (file)
--- a/SL/DB.pm
+++ b/SL/DB.pm
@@ -65,7 +65,7 @@ sub _register_db {
   } elsif ($type eq 'LXOFFICE_AUTH') {
     %connect_settings = ( driver          => $::myconfig{dbdriver} || 'Pg',
                           database        => $::auth->{DB_config}->{db},
-                          host            => $::auth->{DB_config}->{host},
+                          host            => $::auth->{DB_config}->{host} || 'localhost',
                           port            => $::auth->{DB_config}->{port} || 5432,
                           username        => $::auth->{DB_config}->{user},
                           password        => $::auth->{DB_config}->{password},
@@ -79,7 +79,7 @@ sub _register_db {
 
     %connect_settings = ( driver          => $::myconfig{dbdriver} || 'Pg',
                           database        => $::myconfig{dbname},
-                          host            => $::myconfig{dbhost},
+                          host            => $::myconfig{dbhost} || 'localhost',
                           port            => $::myconfig{dbport} || 5432,
                           username        => $::myconfig{dbuser},
                           password        => $::myconfig{dbpasswd},
index 26f446b33ceef602a3c40f9959f5d60ad8795c2f..5a486796d08ba8bd1dcb531e7345c5fa3542e41b 100644 (file)
@@ -1,14 +1,9 @@
-# This file has been auto-generated only because it didn't exist.
-# Feel free to modify it at will; it will not be overwritten automatically.
-
 package SL::DB::Buchungsgruppe;
 
 use strict;
 
 use SL::DB::MetaSetup::Buchungsgruppe;
-
-# Creates get_all, get_all_count, get_all_iterator, delete_all and update_all.
-__PACKAGE__->meta->make_manager_class;
+use SL::DB::Manager::Buchungsgruppe;
 
 sub income_accno_id {
   my ($self, $taxzone) = @_;
diff --git a/SL/DB/Manager/Buchungsgruppe.pm b/SL/DB/Manager/Buchungsgruppe.pm
new file mode 100644 (file)
index 0000000..068ef6b
--- /dev/null
@@ -0,0 +1,21 @@
+package SL::DB::Manager::Buchungsgruppe;
+
+use strict;
+
+use SL::DB::Helper::Manager;
+use base qw(SL::DB::Helper::Manager);
+
+use SL::DB::Helper::Sorted;
+
+sub object_class { 'SL::DB::Buchungsgruppe' }
+
+__PACKAGE__->make_manager_methods;
+
+sub _sort_spec {
+  return ( default => [ 'sortkey', 1 ],
+           columns => { SIMPLE      => 'ALL',
+                        description => 'lower(description)',
+                      });
+}
+
+1;
index f22cf0e9f772241f0738d210da2bf6446764a4dd..6512f0312714fa9ff48c233a6c7bc05cb2f10aa3 100644 (file)
@@ -35,6 +35,11 @@ sub new {
   return $self;
 }
 
+sub interface_type {
+  my ($self) = @_;
+  return $self->{interface} eq 'cgi' ? 'CGI' : 'FastCGI';
+}
+
 sub pre_request_checks {
   if (!$::auth->session_tables_present) {
     if ($::form->{script} eq 'admin.pl') {
@@ -193,11 +198,11 @@ sub handle_request {
 
       $::locale = Locale->new($::myconfig{countrycode});
 
-      show_error('login/password_error', 'password') if SL::Auth::OK != $::auth->authenticate($::form->{login}, $::form->{password}, 0);
+      show_error('login/password_error', 'password') if SL::Auth::OK != $::auth->authenticate($::form->{login}, $::form->{password});
 
       $::auth->set_session_value('login', $::form->{login}, 'password', $::form->{password});
       $::auth->create_or_refresh_session;
-      $::auth->delete_session_value('FLASH')->save_session();
+      $::auth->delete_session_value('FLASH');
       delete $::form->{password};
 
       if ($action) {
@@ -227,7 +232,9 @@ sub handle_request {
   $::locale   = undef;
   $::form     = undef;
   $::myconfig = ();
-  Form::disconnect_standard_dbh unless $self->_interface_is_fcgi;
+  Form::disconnect_standard_dbh;
+  $::auth->expire_session_keys->save_session;
+  $::auth->dbdisconnect;
 
   $::lxdebug->end_request;
   $::lxdebug->leave_sub;
index 6e7145f20fb5d773897029abe9508fb422b3adbf..23dd5be50303f14be1440080ef08c3c35222a749 100644 (file)
@@ -133,6 +133,7 @@ sub _request_to_hash {
 
   my $self  = shift;
   my $input = shift;
+  my $uploads = {};
 
   if (!$ENV{'CONTENT_TYPE'}
       || ($ENV{'CONTENT_TYPE'} !~ /multipart\/form-data\s*;\s*boundary\s*=\s*(.+)$/)) {
@@ -140,7 +141,7 @@ sub _request_to_hash {
     $self->_input_to_hash($input);
 
     $main::lxdebug->leave_sub(2);
-    return;
+    return $uploads;
   }
 
   my ($name, $filename, $headers_done, $content_type, $boundary_found, $need_cr, $previous);
@@ -185,7 +186,7 @@ sub _request_to_hash {
           substr $line, $-[0], $+[0] - $-[0], "";
         }
 
-        $previous         = $self->_store_value($name, '') if ($name);
+        $previous         = _store_value($uploads, $name, '') if ($name);
         $self->{FILENAME} = $filename if ($filename);
 
         next;
@@ -206,6 +207,8 @@ sub _request_to_hash {
   ${ $previous } =~ s|\r?\n$|| if $previous;
 
   $main::lxdebug->leave_sub(2);
+
+  return $uploads;
 }
 
 sub _recode_recursively {
@@ -256,10 +259,11 @@ sub new {
   $self->_input_to_hash($ENV{QUERY_STRING}) if $ENV{QUERY_STRING};
   $self->_input_to_hash($ARGV[0])           if @ARGV && $ARGV[0];
 
+  my $uploads;
   if ($ENV{CONTENT_LENGTH}) {
     my $content;
     read STDIN, $content, $ENV{CONTENT_LENGTH};
-    $self->_request_to_hash($content);
+    $uploads = $self->_request_to_hash($content);
   }
 
   my $db_charset   = $::lx_office_conf{system}->{dbcharset};
@@ -270,6 +274,8 @@ sub new {
 
   _recode_recursively(SL::Iconv->new($encoding, $db_charset), $self);
 
+  map { $self->{$_} = $uploads->{$_} } keys %{ $uploads } if $uploads;
+
   #$self->{version} =  "2.6.1";                 # Old hardcoded but secure style
   open VERSION_FILE, "VERSION";                 # New but flexible code reads version from VERSION-file
   $self->{version} =  <VERSION_FILE>;
@@ -809,7 +815,7 @@ sub _prepare_html_template {
   $additional_params->{"conf_latex_templates"}        = $::lx_office_conf{print_templates}->{latex};
   $additional_params->{"conf_opendocument_templates"} = $::lx_office_conf{print_templates}->{opendocument};
   $additional_params->{"conf_vertreter"}              = $::lx_office_conf{system}->{vertreter};
-  $additional_params->{"conf_show_best_before"}       = $::lx_office_conf{system}->{show_best_before};
+  $additional_params->{"conf_show_best_before"}       = $::lx_office_conf{features}->{show_best_before};
   $additional_params->{"conf_parts_image_css"}        = $::lx_office_conf{features}->{parts_image_css};
   $additional_params->{"conf_parts_listing_images"}   = $::lx_office_conf{features}->{parts_listing_images};
   $additional_params->{"conf_parts_show_image"}       = $::lx_office_conf{features}->{parts_show_image};
index 8f68d00c78bbf5e673c193f653b627048ab95354..876de964436d86f759f16292114371c1cc1965da 100644 (file)
@@ -16,7 +16,7 @@ sub flash {
 }
 
 sub flash_later {
-  $::auth->set_session_value(FLASH => _store_flash($::auth->get_session_value('FLASH'), @_))->save_session();
+  $::auth->set_session_value(FLASH => _store_flash($::auth->get_session_value('FLASH'), @_));
 }
 
 sub render_flash {
index 9995722e10e0e1e8c9fe08322f7c2ab70465d21c..513f4a221c29f4d2d37fa96aa75b78b918e2b3a3 100644 (file)
@@ -207,7 +207,7 @@ sub options_for_select {
 
   my $value_title_sub = $options{value_title_sub};
 
-  my %selected        = map { ( $_ => 1 ) } @{ ref($options{default}) eq 'ARRAY' ? $options{default} : $options{default} ? [ $options{default} ] : [] };
+  my %selected        = map { ( $_ => 1 ) } @{ ref($options{default}) eq 'ARRAY' ? $options{default} : defined($options{default}) ? [ $options{default} ] : [] };
 
   my $access = sub {
     my ($element, $index, $key, $sub) = @_;
@@ -231,7 +231,7 @@ sub options_for_select {
   my $code = '';
   foreach my $result (@elements) {
     my %attributes = ( value => $result->[0] );
-    $attributes{selected} = 'selected' if $selected{ $result->[0] || '' };
+    $attributes{selected} = 'selected' if $selected{ defined($result->[0]) ? $result->[0] : '' };
 
     $code .= $self->html_tag('option', _H($result->[1]), %attributes);
   }
index b89487c7ef42d61af4a2fa10126ab624e664383d..ddb12b1d854481badd03a94b470f5f35d6b89f47 100755 (executable)
@@ -34,6 +34,7 @@
 
 use DBI;
 use CGI;
+use Encode;
 use English qw(-no_match_vars);
 use Fcntl;
 use File::Copy;
@@ -78,7 +79,7 @@ sub run {
   $form->{favicon}    = "favicon.ico";
 
   if ($form->{action}) {
-    if ($auth->authenticate_root($form->{rpw}, 0) != $auth->OK()) {
+    if ($auth->authenticate_root($form->{rpw}) != $auth->OK()) {
       $form->{error_message} = $locale->text('Incorrect Password!');
       adminlogin();
     } else {
@@ -342,7 +343,10 @@ sub list_users {
 
   delete $members{"root login"};
 
-  map { $_->{templates} =~ s|.*/||; } values %members;
+  for (values %members) {
+    $_->{templates} =~ s|.*/||;
+    $_->{login_url} =  $::locale->is_utf8 ? Encode::encode('utf-8-strict', $_->{login}) : $_->{login_url};
+  }
 
   $form->{title}   = "Lx-Office ERP " . $locale->text('Administration');
   $form->{LOCKED}  = -e _nologin_file_name();
index d6e594f5b08a331d5847b662214106894360f839..2bd7f6b42a09cc297f9bb5310325d10e40f39a69 100644 (file)
@@ -1361,7 +1361,7 @@ sub transfer_out {
         my $pinfo = $part_info_map{$request->{parts_id}};
         my $binfo = $bin_info_map{$request->{bin_id}};
 
-        if ($::lx_office_conf{system}->{show_best_before}) {
+        if ($::lx_office_conf{features}->{show_best_before}) {
             push @{ $form->{ERRORS} }, $locale->text("There is not enough available of '#1' at warehouse '#2', bin '#3', #4, #5, for the transfer of #6.",
                                                      $pinfo->{description},
                                                      $binfo->{warehouse_description},
index f6cc7b6d0dcc1801c46a5392ec2f20d623be96eb..c471d009bcca0a9f61210a8bfafe94f145fc4af2 100644 (file)
@@ -129,7 +129,10 @@ sub load_draft {
     $form->{draft_description}     = $description;
     $form->{remove_draft}          = 'checked';
   }
-
+  # Ich vergesse bei Rechnungsentwürfe das Rechnungsdatum zu ändern. Dadurch entstehen 
+  # ungültige Belege. Vielleicht geht es anderen ähnlich jan 19.2.2011
+  $form->{invdate} = $form->current_date(\%myconfig); # Aktuelles Rechnungsdatum  ...
+  $form->{duedate} = $form->current_date(\%myconfig); # Aktuelles Fälligkeitsdatum  ...
   update();
 
   $main::lxdebug->leave_sub();
index b5588be3b3952abde07dd264dac584f9780a112e..4eb1e41e108a32d790f6b8ba6d94624b2c81f2b0 100644 (file)
@@ -1759,7 +1759,7 @@ sub save {
 
   $auth->assert('part_service_assembly_edit');
 
-  my ($parts_id, %newform, $previousform, $amount, $callback);
+  my ($parts_id, %newform, $amount, $callback);
 
   # check if there is a part number - commented out, cause there is an automatic allocation of numbers
   # $form->isblank("partnumber", $locale->text(ucfirst $form->{item}." Part Number missing!"));
@@ -1800,20 +1800,14 @@ sub save {
     # save the new form variables before splitting previousform
     map { $newform{$_} = $form->{$_} } keys %$form;
 
-    $previousform = $form->unescape($form->{previousform});
-
     # don't trample on previous variables
     map { delete $form->{$_} } keys %newform;
 
     my $ic_cvar_configs = CVar->get_configs(module => 'IC');
     my @ic_cvar_fields  = map { "cvar_$_->{name}" } @{ $ic_cvar_configs };
 
-    # now take it apart and restore original values
-    foreach my $item (split /&/, $previousform) {
-      my ($key, $value) = split m/=/, $item, 2;
-      $value =~ s/%26/&/g;
-      $form->{$key} = $value;
-    }
+    # restore original values
+    $::auth->restore_form_from_session($newform{previousform}, form => $form);
     $form->{taxaccounts} = $newform{taxaccount2};
 
     if ($form->{item} eq 'assembly') {
index af69e4488106bc8f1c873bdd96972462c7634505..be7062ad2db787e731b2e1f3ba6c8e4832a6ac39 100644 (file)
@@ -703,11 +703,11 @@ sub new_item {
   $form->{old_callback} = $form->escape($form->{callback}, 1);
   $form->{callback}     = $form->escape("$form->{script}?action=display_form", 1);
 
-  # save all form variables except action in a previousform variable
-  my $previousform = join '&', map { my $value = $form->{$_}; $value =~ s/&/%26/; "$_=$value" } grep { !/action/ } keys %$form;
+  # save all form variables except action in the session and keep the key in the previousform variable
+  my $previousform = $::auth->save_form_in_session(skip_keys => [ qw(action) ]);
 
   my @HIDDENS;
-  push @HIDDENS,      { 'name' => 'previousform', 'value' => $form->escape($previousform, 1) };
+  push @HIDDENS,      { 'name' => 'previousform', 'value' => $previousform };
   push @HIDDENS, map +{ 'name' => $_,             'value' => $form->{$_} },                       qw(rowcount vc);
   push @HIDDENS, map +{ 'name' => $_,             'value' => $form->{"${_}_$form->{rowcount}"} }, qw(partnumber description unit);
   push @HIDDENS,      { 'name' => 'taxaccount2',  'value' => $form->{taxaccounts} };
index 5aee28b5d95e2fd3c05f6cf5124af90ad96696c2..fb065f2549b46678fc34c6e6b35729bf8fcbee47 100644 (file)
@@ -325,7 +325,7 @@ sub add {
 
   $form->{title} = $locale->text('Add License');
 
-  if (!$::lx_office_conf{system}->{lizenzen}) {
+  if (!$::lx_office_conf{features}->{lizenzen}) {
     $form->error(
                  $locale->text(
                    'The licensing module has been deactivated in the configuration.')
@@ -518,7 +518,7 @@ sub search {
 
   $form->{title} = $locale->text('Licenses');
 
-  if (!$::lx_office_conf{system}->{lizenzen}) {
+  if (!$::lx_office_conf{features}->{lizenzen}) {
     $form->error(
                  $locale->text(
                    'The licensing module has been deactivated in the configuration.')
index 49cb6c613e62bfafc0e48a6ee58457d13360ac96..03e6dd947f9fc6f47c494cf893002d52d28c543e 100644 (file)
@@ -65,7 +65,7 @@ sub run {
     %::myconfig = $auth->read_user($form->{login}) if ($form->{login});
     $::locale   = Locale->new($::myconfig{countrycode}) if $::myconfig{countrycode};
 
-    if (!$::myconfig{login} || (SL::Auth::OK != $auth->authenticate($form->{login}, $form->{password}, 0))) {
+    if (SL::Auth::OK != $auth->authenticate($::myconfig{login}, $form->{password})) {
       $form->{error_message} = $::locale->text('Incorrect username or password!');
       login_screen();
     } else {
@@ -163,6 +163,7 @@ sub company_logo {
 
   $form->{stylesheet} =  $myconfig{stylesheet};
   $form->{title}      =  $::locale->text('Lx-Office');
+  $form->{interface}  = $::dispatcher->interface_type;
 
   # create the logo screen
   $form->header() unless $form->{noheader};
index f7874cdad0fafea6c587d6e052060d03bfef2939..6466565b0e4e0c16ffba35c87a26c008cc278077 100644 (file)
@@ -116,8 +116,7 @@ sub report {
 
   my $company_given = ($form->{company} ne '')
     ? qq|<h3>$form->{company}</h3>\n|
-    : qq|<a href="am.pl?action=config|
-      . qq|&level=Programm--Preferences">|
+    : qq|<a href="am.pl?action=config">|
       . $locale->text('No Company Name given') . qq|!</a><br>|;
 
 
index f4971078554893cee622d2032ff57db942eabc38..2b49ba00cf6ab806727d121918577a399f0d9042 100644 (file)
@@ -438,7 +438,7 @@ sub create_assembly {
     $form->error($locale->text('The warehouse or the bin is missing.'));
   }
 
-  if (!$::lx_office_conf{system}->{show_best_before}) {
+  if (!$::lx_office_conf{features}->{show_best_before}) {
       $form->{bestbefore} = '';
   }
 
index b4d4471f72875198b057556ed5ebd51100742db5..1972e953070514f4e5de60ec7114e63a5fa7e478 100644 (file)
@@ -58,7 +58,7 @@ bind_password =
 
 [system]
 # EUR: Einnahmen-Überschussrechnung (net income method). Set this to 1
-# if your company uses the net income method and to 0 for balacing.
+# if your company uses the net income method and to 0 for balancing.
 eur = 1
 
 # Set language for login and admin forms. Currently "de" (German),
diff --git a/controller.pl b/controller.pl
new file mode 120000 (symlink)
index 0000000..385000d
--- /dev/null
@@ -0,0 +1 @@
+am.pl
\ No newline at end of file
index 8151719df06fa6b7f4a78d3eda464e3fad9c41a2..6f25ee507ea8b6dbf9f7986e442c79773c5936f5 100644 (file)
@@ -121,6 +121,15 @@ body.menu {
     border-style:solid;
     border-width:thin;
 }
+.message_error_label {
+    font-size: 0.8em;
+    padding:5px;
+    background-color: #FEE;
+    font-weight:normal;
+    text-align:left;
+    border-style:solid;
+    border-width:thin;
+}
 
 /*
     Überschriftsbalken
index 186ca33cb96f30f3a2840910cb8609f44c83b31f..454be03961b822f53a9536dd9e6fe738a6b802f6 100644 (file)
@@ -127,7 +127,7 @@ werden aber umgeleitet:
   # Zugriff über cgi
   Alias       /web/path/to/lx-office-erp                /path/to/lx-office-erp
 
-  # Zugriff mit mod_fastcgi:
+  # Zugriff mit mod_fcgid:
   AliasMatch ^/web/path/to/lx-office-erp-fcgid/[^/]+\.pl /path/to/lx-office-erp/dispatcher.fcgi
   Alias       /web/path/to/lx-office-erp-fcgid/          /path/to/lx-office-erp/
 
@@ -136,8 +136,8 @@ werden aber umgeleitet:
   Alias       /web/path/to/lx-office-erp-fastcgi/          /path/to/lx-office-erp/
 
 Dann ist unter C</web/path/to/lx-office-erp/> die normale Version erreichbar,
-und unter C</web/opath/to/lx-office-erp-fcgid/> bzw.
-C</web/opath/to/lx-office-erp-fastcgi/> die FastCGI Version.
+und unter C</web/path/to/lx-office-erp-fcgid/> bzw.
+C</web/path/to/lx-office-erp-fastcgi/> die FastCGI Version.
 
 Achtung:
 
@@ -148,7 +148,7 @@ vhost.
 =head2 Entwicklungsaspekte
 
 Wenn Änderungen in der Konfiguration von Lx-Office gemacht werden, muss der
-Server neu gestartet werden.
+Webserver neu gestartet werden.
 
 Bei der Entwicklung für FastCGI ist auf ein paar Fallstricke zu achten. Dadurch
 dass das Programm in einer Endlosschleife läuft, müssen folgende Aspekte
@@ -180,7 +180,7 @@ In C<SL::Dispatcher> gibt es einen sauber abgetrennten Block der alle
 kanonischen globalen Variablen listet und erklärt. Bitte keine anderen
 einführen ohne das sauber zu dokumentieren.
 
-Datenbankverbindungen wird noch ein Guide verfasst werden, wie man sichergeht,
+Datenbankverbindungen wird noch ein Guide verfasst werden, wie man sicher geht,
 dass man die richtige erwischt.
 
 =head2 Performance und Statistiken
index 0311afec77751abbf65493af801fad3790a0203d..520aa2774b153557714ad2fefa12e94dc7441a43 100644 (file)
@@ -2,6 +2,16 @@
 # Veränderungen von Lx-Office ERP #
 ###################################
 
+  ab Feb 2011 Release 2.7-unstable
+
+
+
+  Kleinere neue Features und Detailverbesserungen:
+
+  - Beim Laden von Rechnungsentwürfen, das Fälligkeits- und Rechnungsdatum duch
+    das Tagesdatum ersetzen
+
+
 2011-02-02 - Release 2.6.2
 
   Größere neue Features:
index d456541ff8a770add2ee8635833eca6cf1da9569..24df1142d15db68dfbb2d1a8ef688c9922618db3 100644 (file)
@@ -874,6 +874,10 @@ td {
     <td><code>serialnumber</code></td>
     <td>Seriennummer</td>
    </tr>
+   <tr>
+    <td><code>tax_rate</code></td>
+    <td>Steuersatz</td>
+   </tr>
    <tr>
     <td><code>transdate_oe</code></td>
     <td>Auftragsdatum des Originalauftrags, wenn die Rechnung aus einem Sammelauftrag erstellt wurde</td>
index 41038e16e6fc2fa6889010eeb8e908451c6f61e1..dd550435eb113a389bfa633162a6f3b374393e91 100644 (file)
@@ -1897,6 +1897,7 @@ $self->{texts} = {
   'Warning'                     => 'Warnung',
   'Warnings during template upgrade' => 'Warnungen bei Aktualisierung der Dokumentenvorlagen',
   'WebDAV link'                 => 'WebDAV-Link',
+  'Webserver interface'         => 'Webserverschnittstelle',
   'Weight'                      => 'Gewicht',
   'Weight unit'                 => 'Gewichtseinheit',
   'What <b>term</b> you are looking for?' => 'Nach welchem <b>Begriff</b> wollen Sie suchen?',
index 9d1902acd9df8a87c9a308f902c5c8ea715bc346..3220d04858a4abdb51aad05c659a92b2e0ea6fc1 100644 (file)
@@ -1897,6 +1897,7 @@ $self->{texts} = {
   'Warning'                     => 'Warnung',
   'Warnings during template upgrade' => 'Warnungen bei Aktualisierung der Dokumentenvorlagen',
   'WebDAV link'                 => 'WebDAV-Link',
+  'Webserver interface'         => 'Webserver nutzt',
   'Weight'                      => 'Gewicht',
   'Weight unit'                 => 'Gewichtseinheit',
   'What <b>term</b> you are looking for?' => 'Nach welchem <b>Begriff</b> wollen Sie suchen?',
index cddc3d0cdb9ea83b300746d4db9c687569283794..0253d49a0fd9d62d2b55b862ded52b9fdda29af8 100644 (file)
@@ -1896,6 +1896,7 @@ $self->{texts} = {
   'Warning'                     => '',
   'Warnings during template upgrade' => '',
   'WebDAV link'                 => '',
+  'Webserver interface'         => '',
   'Weight'                      => '',
   'Weight unit'                 => '',
   'What <b>term</b> you are looking for?' => '',
index 0828b00c30d8a3c52d5d3ccf1fa8c9296bb7f952..eb55dc51c30cebb41a60a50b0bf80eb980cf1012 100644 (file)
@@ -21,7 +21,7 @@
 
     [% FOREACH row = MEMBERS %]
      <tr class="listrow[% loop.count % 2 %]">
-      <td>&nbsp;<a href="admin.pl?action=edit&login=[% HTML.url(row.login) %]">[% HTML.escape(row.login) %]</a></td>
+      <td>&nbsp;<a href="admin.pl?action=edit&login=[% HTML.url(row.login_url) %]">[% HTML.escape(row.login) %]</a></td>
       <td>&nbsp;[% HTML.escape(row.name) %]</td>
       <td>&nbsp;[% HTML.escape(row.company) %]</td>
       <td>&nbsp;[% HTML.escape(row.templates) %]</td>
index cb3f2253153c60dbfd635056d908a201dd87bf72..7778152b693a233b51157395a08e10e6e726faf6 100644 (file)
@@ -2,7 +2,7 @@
 [% USE HTML %]<body>
 
  <div class="message_error">[% IF title_error %][% title_error %][% ELSE %][% 'Error!' | $T8 %][% END %]
- <p>[% label_error %]</p>
+ <p class="message_error_label">[% label_error %]</p>
  </div>
  
  <p style="text-align: left;"><input type="button" class="submit" onclick="history.back()" value="[% 'Back' | $T8 %]"></p>
@@ -10,7 +10,7 @@
  [%- IF SHOW_BACK_BUTTON %]
  <form>
   <p>
-   <!--- show back button always hack
+   <!--- TODO: show back button always hack
          In which situation is it necessary to hide it?
    <input type="button" onclick="history.back()" value="[% 'Back' | $T8 %]">
    -->
index 7946c527416dff94f17e9ca1270c2f891c8d14ec..10adcc0aa16d3e6e4a11b5da03cb903b3a2ff259 100644 (file)
 
    <table border="0">
     <tr>
-     <th align="left"><a href="am.pl?action=config&level=Program--Preferences" title="[% 'Preferences' | $T8 %]">[% 'User' | $T8 %]</a></th>
+     <th align="left"><a href="am.pl?action=config" title="[% 'Preferences' | $T8 %]">[% 'User' | $T8 %]</a></th>
      <td>[% HTML.escape(myconfig_name) %]</td>
     </tr>
     <tr>
-     <th align="left"><a href="am.pl?action=config&level=Program--Preferences" title="[% 'Preferences' | $T8 %]">[% 'Language' | $T8 %]</a></th>
+     <th align="left"><a href="am.pl?action=config" title="[% 'Preferences' | $T8 %]">[% 'Language' | $T8 %]</a></th>
      <td>[% HTML.escape(myconfig_countrycode) %]</td>
     </tr>
     <tr>
      <th align="left">[% 'Database Host' | $T8 %]</th>
      <td>[% HTML.escape(myconfig_dbhost) %]</td>
     </tr>
+    <tr>
+     <th align="left">[% 'Webserver interface' | $T8 %]</th>
+     <td>[% HTML.escape(interface) %]</td>
+    </tr>
     <tr class="nomobile">
      <th align="left">[% 'Lx-Office Homepage' | $T8 %]:</th>
      <td><a href="http://lx-office.org" target="_blank" title="[% 'Lx-Office Homepage' | $T8 %]">http://lx-office.org</a></td>