X-Git-Url: http://wagnertech.de/git?a=blobdiff_plain;f=SL%2FUser.pm;h=68fd2c520ed8971dd88e437d47670e89d22683b1;hb=bfa674c9d4edc551afa6e27aac6f684a7b8cb656;hp=a267fcd6f55afc73e020f047002672af858d7317;hpb=83fb0fe04ed0f7855c4d54f91a5fc508c47e058e;p=kivitendo-erp.git diff --git a/SL/User.pm b/SL/User.pm index a267fcd6f..68fd2c520 100644 --- a/SL/User.pm +++ b/SL/User.pm @@ -25,7 +25,8 @@ # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software -# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1335, USA. #===================================================================== # # user related functions @@ -35,16 +36,19 @@ package User; use IO::File; -use Fcntl qw(:seek); +use List::MoreUtils qw(any); +use SL::DB; #use SL::Auth; use SL::DB::AuthClient; +use SL::DB::Employee; use SL::DBConnect; use SL::DBUpgrade2; use SL::DBUtils; use SL::Iconv; use SL::Inifile; use SL::System::InstallationLock; +use SL::DefaultManager; use strict; @@ -99,6 +103,42 @@ sub country_codes { return %cc; } +sub _handle_superuser_privileges { + my ($self, $form) = @_; + + if ($form->{database_superuser_username}) { + $::auth->set_session_value("database_superuser_username" => $form->{database_superuser_username}, "database_superuser_password" => $form->{database_superuser_password}); + } + + my %dbconnect_form = %{ $form }; + my ($su_user, $su_password) = map { $::auth->get_session_value("database_superuser_$_") } qw(username password); + + if ($su_user) { + $dbconnect_form{dbuser} = $su_user; + $dbconnect_form{dbpasswd} = $su_password; + } + + dbconnect_vars(\%dbconnect_form, $form->{dbname}); + + my %result = ( + username => $dbconnect_form{dbuser}, + password => $dbconnect_form{dbpasswd}, + ); + + $::auth->set_session_value("database_superuser_username" => $dbconnect_form{dbuser}, "database_superuser_password" => $dbconnect_form{dbpasswd}); + + my $dbh = SL::DBConnect->connect($dbconnect_form{dbconnect}, $dbconnect_form{dbuser}, $dbconnect_form{dbpasswd}, SL::DBConnect->get_options); + return (%result, error => $::locale->text('The credentials (username & password) for connecting database are wrong.')) if !$dbh; + + my $is_superuser = SL::DBUtils::role_is_superuser($dbh, $dbconnect_form{dbuser}); + + $dbh->disconnect; + + return (%result, have_privileges => 1) if $is_superuser; + return (%result) if !$su_user; # no error message if credentials weren't set by the user + return (%result, error => $::locale->text('The database user \'#1\' does not have superuser privileges.', $dbconnect_form{dbuser})); +} + sub login { my ($self, $form) = @_; @@ -111,7 +151,7 @@ sub login { return LOGIN_AUTH_DBUPDATE_AVAILABLE() if $dbupdater_auth->unapplied_upgrade_scripts($::auth->dbconnect); # check if database is down - my $dbh = $form->dbconnect_noauto; + my $dbh = SL::DB->client->dbh; # we got a connection, check the version my ($dbversion) = $dbh->selectrow_array(qq|SELECT version FROM defaults|); @@ -123,10 +163,18 @@ sub login { $self->create_schema_info_table($form, $dbh); my $dbupdater = SL::DBUpgrade2->new(form => $form)->parse_dbupdate_controls; - my $update_available = $dbupdater->update2_available($dbh); - $dbh->disconnect; + my @unapplied_scripts = $dbupdater->unapplied_upgrade_scripts($dbh); +# $dbh->disconnect; - return LOGIN_OK() if !$update_available; + if (!@unapplied_scripts) { + SL::DB::Manager::Employee->update_entries_for_authorized_users; + return LOGIN_OK(); + } + + # Store the fact that we're applying database upgrades at the + # moment. That way functions called from the layout modules that may + # require updated tables can chose only to use basic features. + $::request->applying_database_upgrades(1); $form->{$_} = $::auth->client->{$_} for qw(dbname dbhost dbport dbuser dbpasswd); $form->{$_} = $myconfig{$_} for qw(datestyle); @@ -137,9 +185,23 @@ sub login { $form->{dbupdate} = "db" . $::auth->client->{dbname}; - if ($form->{"show_dbupdate_warning"}) { - print $form->parse_html_template("dbupgrade/warning"); - ::end_of_request(); + my $show_update_warning = $form->{"show_dbupdate_warning"}; + my %superuser = (need_privileges => (any { $_->{superuser_privileges} } @unapplied_scripts)); + + if ($superuser{need_privileges}) { + %superuser = ( + %superuser, + $self->_handle_superuser_privileges($form), + ); + $show_update_warning = 1 if !$superuser{have_privileges}; + } + + if ($show_update_warning) { + print $form->parse_html_template("dbupgrade/warning", { + unapplied_scripts => \@unapplied_scripts, + superuser => \%superuser, + }); + $::dispatcher->end_request; } # update the tables @@ -151,6 +213,16 @@ sub login { $self->dbupdate2(form => $form, updater => $dbupdater, database => $::auth->client->{dbname}); + # If $self->dbupdate2 returns than this means all upgrade scripts + # have been applied successfully, none required user + # interaction. Otherwise the deeper layers would have called + # $::dispatcher->end_request already, and return would not have returned to + # us. Therefore we can now use RDBO instances because their supposed + # table structures do match the actual structures. So let's ensure + # that the "employee" table contains the appropriate entries for all + # users authorized for the current client. + SL::DB::Manager::Employee->update_entries_for_authorized_users; + SL::System::InstallationLock->unlock; print $form->parse_html_template("dbupgrade/footer"); @@ -262,18 +334,60 @@ sub dbcreate { &dbconnect_vars($form, $form->{db}); + # make a shim myconfig so that rose db connections work + $::myconfig{$_} = $form->{$_} for qw(dbhost dbport dbuser dbpasswd); + $::myconfig{dbname} = $form->{db}; + $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options) or $form->dberror; - my $dbupdater = SL::DBUpgrade2->new(form => $form); + my $dbupdater = SL::DBUpgrade2->new(form => $form, return_on_error => 1, silent => 1)->parse_dbupdate_controls; # create the tables $dbupdater->process_query($dbh, "sql/lx-office.sql"); - - # load chart of accounts $dbupdater->process_query($dbh, "sql/$form->{chart}-chart.sql"); - $query = qq|UPDATE defaults SET coa = ?, accounting_method = ?, profit_determination = ?, inventory_system = ?, curr = ?|; - do_query($form, $dbh, $query, map { $form->{$_} } qw(chart accounting_method profit_determination inventory_system defaultcurrency)); + $query = qq|UPDATE defaults SET coa = ?|; + do_query($form, $dbh, $query, map { $form->{$_} } qw(chart)); + + $dbh->disconnect; + + # update new database + $self->dbupdate2(form => $form, updater => $dbupdater, database => $form->{db}, silent => 1); + + $dbh = SL::DBConnect->connect($form->{dbconnect}, $form->{dbuser}, $form->{dbpasswd}, SL::DBConnect->get_options) + or $form->dberror; + + $query = "SELECT * FROM currencies WHERE name = ?"; + my $curr = selectfirst_hashref_query($form, $dbh, $query, $form->{defaultcurrency}); + if (!$curr->{id}) { + do_query($form, $dbh, "INSERT INTO currencies (name) VALUES (?)", $form->{defaultcurrency}); + $curr = selectfirst_hashref_query($form, $dbh, $query, $form->{defaultcurrency}); + } + + $query = qq|UPDATE defaults SET + accounting_method = ?, + profit_determination = ?, + inventory_system = ?, + precision = ?, + currency_id = ?, + feature_balance = ?, + feature_datev = ?, + feature_erfolgsrechnung = ?, + feature_eurechnung = ?, + feature_ustva = ? + |; + do_query($form, $dbh, $query, + $form->{accounting_method}, + $form->{profit_determination}, + $form->{inventory_system}, + $form->parse_amount(\%::myconfig, $form->{precision_as_number}), + $curr->{id}, + $form->{feature_balance}, + $form->{feature_datev}, + $form->{feature_erfolgsrechnung}, + $form->{feature_eurechnung}, + $form->{feature_ustva} + ); $dbh->disconnect; @@ -360,14 +474,12 @@ sub create_schema_info_table { } sub dbupdate2 { - $main::lxdebug->enter_sub(); - my ($self, %params) = @_; my $form = $params{form}; my $dbupdater = $params{updater}; my $db = $params{database}; - my $rc = -2; + my $silent = $params{silent}; map { $_->{description} = SL::Iconv::convert($_->{charset}, 'UTF-8', $_->{description}) } values %{ $dbupdater->{all_controls} }; @@ -380,27 +492,59 @@ sub dbupdate2 { $self->create_schema_info_table($form, $dbh); my @upgradescripts = $dbupdater->unapplied_upgrade_scripts($dbh); + my $need_superuser = (any { $_->{superuser_privileges} } @upgradescripts); + my $superuser_dbh; + + if ($need_superuser) { + my %dbconnect_form = ( + %{ $form }, + dbuser => $::auth->get_session_value("database_superuser_username"), + dbpasswd => $::auth->get_session_value("database_superuser_password"), + ); + + if ($dbconnect_form{dbuser} ne $form->{dbuser}) { + dbconnect_vars(\%dbconnect_form, $db); + $superuser_dbh = SL::DBConnect->connect($dbconnect_form{dbconnect}, $dbconnect_form{dbuser}, $dbconnect_form{dbpasswd}, SL::DBConnect->get_options) or $form->dberror; + } + } - $dbh->disconnect and next if !@upgradescripts; + $::lxdebug->log_time("DB upgrades commencing"); foreach my $control (@upgradescripts) { - # apply upgrade - $main::lxdebug->message(LXDebug->DEBUG2(), "Applying Update $control->{file}"); - print $form->parse_html_template("dbupgrade/upgrade_message2", $control); + # Apply upgrade. Control will only return to us if the upgrade has + # been applied correctly and if the update has not requested user + # interaction. + my $script_dbh = $control->{superuser_privileges} ? ($superuser_dbh // $dbh) : $dbh; - $dbupdater->process_file($dbh, "sql/Pg-upgrade2/$control->{file}", $control); - } + $::lxdebug->message(LXDebug->DEBUG2(), "Applying Update $control->{file}" . ($control->{superuser_privileges} ? " with superuser privileges" : "")); + print $form->parse_html_template("dbupgrade/upgrade_message2", $control) unless $silent; - $rc = 0; - $dbh->disconnect; + $dbupdater->process_file($script_dbh, "sql/Pg-upgrade2/$control->{file}", $control); + } - $main::lxdebug->leave_sub(); + $::lxdebug->log_time("DB upgrades finished"); - return $rc; + $dbh->disconnect; + $superuser_dbh->disconnect if $superuser_dbh; } sub data { +{ %{ $_[0] } } } +sub get_default_myconfig { + my ($self_or_class, %user_config) = @_; + my $defaults = SL::DefaultManager->new($::lx_office_conf{system}->{default_manager}); + + return ( + countrycode => $defaults->language('de'), + css_path => 'css', # Needed for menunew, see SL::Layout::Base::get_stylesheet_for_user + dateformat => $defaults->dateformat('dd.mm.yy'), + numberformat => $defaults->numberformat('1.000,00'), + stylesheet => $defaults->stylesheet('kivitendo.css'), + timeformat => $defaults->timeformat('hh:mm'), + %user_config, + ); +} + 1;