Aufräumskript für Steuerschlüssel 18,19 - Prüfung auf Kontenrahmen
[kivitendo-erp.git] / SL / DBUpgrade2 / Base.pm
index 2c1e111..cd698c5 100644 (file)
@@ -5,11 +5,15 @@ use strict;
 use parent qw(Rose::Object);
 
 use Carp;
 use parent qw(Rose::Object);
 
 use Carp;
+use Encode;
 use English qw(-no_match_vars);
 use File::Basename ();
 use File::Copy ();
 use File::Path ();
 use List::MoreUtils qw(uniq);
 use English qw(-no_match_vars);
 use File::Basename ();
 use File::Copy ();
 use File::Path ();
 use List::MoreUtils qw(uniq);
+use SL::DBUtils qw(selectfirst_hashref_query);
+use SL::Presenter::EscapedText qw(escape);
+use version;
 
 use Rose::Object::MakeMethods::Generic (
   scalar => [ qw(dbh myconfig) ],
 
 use Rose::Object::MakeMethods::Generic (
   scalar => [ qw(dbh myconfig) ],
@@ -27,9 +31,10 @@ sub execute_script {
     die $EVAL_ERROR;
   }
 
     die $EVAL_ERROR;
   }
 
+  my $auth    =  $file_name =~ m{/Pg-upgrade2-auth/} ? 'Auth::' : '';
   my $package =  delete $params{tag};
   $package    =~ s/[^a-zA-Z0-9_]+/_/g;
   my $package =  delete $params{tag};
   $package    =~ s/[^a-zA-Z0-9_]+/_/g;
-  $package    =  "SL::DBUpgrade2::${package}";
+  $package    =  "SL::DBUpgrade2::${auth}${package}";
 
   $package->new(%params)->run;
 }
 
   $package->new(%params)->run;
 }
@@ -37,18 +42,34 @@ sub execute_script {
 sub db_error {
   my ($self, $msg) = @_;
 
 sub db_error {
   my ($self, $msg) = @_;
 
-  die $::locale->text("Database update error:") . "<br>$msg<br>" . $DBI::errstr;
+  die $::locale->text("Database update error:") . "<br>$msg<br>" . $self->db_errstr('DBI');
 }
 
 sub db_query {
   my ($self, $query, %params) = @_;
 
 }
 
 sub db_query {
   my ($self, $query, %params) = @_;
 
-  return if $self->dbh->do($query, undef, @{ $params{bind} || [] });
+  my $dbh = $params{dbh} || $self->dbh;
+
+  return if $dbh->do($query, undef, @{ $params{bind} || [] });
 
   $self->db_error($query) unless $params{may_fail};
 
 
   $self->db_error($query) unless $params{may_fail};
 
-  $self->dbh->rollback;
-  $self->dbh->begin_work;
+  $dbh->rollback;
+  $dbh->begin_work;
+}
+
+sub db_errstr {
+  my ($self, $handle) = @_;
+
+  # DBD::Pg before 2.16.1 doesn't set the UTF-8 flag for error
+  # messages even if the connection has UTF-8 enabled. Therefore we
+  # have to convert it to Perl's internal encoding ourselves. See
+  # https://rt.cpan.org/Public/Bug/Display.html?id=53854
+
+  my $error = $handle ? $handle->errstr : $self->dbh->errstr;
+
+  return $error if version->new("$DBD::Pg::VERSION")->numify >= version->new("2.16.1")->numify;
+  return Encode::decode('utf-8', $error);
 }
 
 sub check_coa {
 }
 
 sub check_coa {
@@ -79,35 +100,71 @@ sub add_print_templates {
     croak "File '${src_dir}/$_' does not exist" unless -f "${src_dir}/$_";
   }
 
     croak "File '${src_dir}/$_' does not exist" unless -f "${src_dir}/$_";
   }
 
-  my %users         = $::auth->read_all_users;
-  my @template_dirs = uniq map { $_ = $_->{templates}; s:/+$::; $_ } values %users;
-
-  $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: template_dirs " . join('  ', @template_dirs));
+  # can't use Rose or InstanceConf here because defaults might not be fully upgraded yet.
+  my $defaults = selectfirst_hashref_query($::form, $::form->get_standard_dbh, "SELECT * FROM defaults");
+  return 1 unless my $template_dir = $defaults->{template};
+  $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: template_dir $template_dir");
 
   foreach my $src_file (@files) {
 
   foreach my $src_file (@files) {
-    foreach my $template_dir (@template_dirs) {
-      my $dest_file = $template_dir . '/' . $src_file;
+    my $dest_file = $template_dir . '/' . $src_file;
 
 
-      if (-f $dest_file) {
-        $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: dest_file exists, skipping: ${dest_file}");
-        next;
-      }
+    if (-f $dest_file) {
+      $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: dest_file exists, skipping: ${dest_file}");
+      next;
+    }
 
 
-      my $dest_dir = File::Basename::dirname($dest_file);
+    my $dest_dir = File::Basename::dirname($dest_file);
 
 
-      if ($dest_dir && !-d $dest_dir) {
-        File::Path::make_path($dest_dir) or die "Cannot create directory '${dest_dir}': $!";
-      }
+    if ($dest_dir && !-d $dest_dir) {
+      File::Path::make_path($dest_dir) or die "Cannot create directory '${dest_dir}': $!";
+    }
 
 
-      File::Copy::copy($src_dir . '/' . $src_file, $dest_file) or die "Cannot copy '${src_dir}/${src_file}' to '${dest_file}': $!";
+    File::Copy::copy($src_dir . '/' . $src_file, $dest_file) or die "Cannot copy '${src_dir}/${src_file}' to '${dest_file}': $!";
 
 
-      $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: copied '${src_dir}/${src_file}' to '${dest_file}'");
-    }
+    $::lxdebug->message(LXDebug::DEBUG1(), "add_print_templates: copied '${src_dir}/${src_file}' to '${dest_file}'");
   }
 
   return 1;
 }
 
   }
 
   return 1;
 }
 
+sub drop_constraints {
+  my ($self, %params) = @_;
+
+  croak "Missing parameter 'table'" unless $params{table};
+  $params{type}   ||= 'FOREIGN KEY';
+  $params{schema} ||= 'public';
+
+  my $constraints = $self->dbh->selectall_arrayref(<<SQL, undef, $params{type}, $params{schema}, $params{table});
+    SELECT constraint_name
+    FROM information_schema.table_constraints
+    WHERE (constraint_type = ?)
+      AND (table_schema    = ?)
+      AND (table_name      = ?)
+SQL
+
+  $self->db_query(qq|ALTER TABLE $params{schema}."$params{table}" DROP CONSTRAINT "${_}"|) for map { $_->[0] } @{ $constraints };
+}
+
+sub convert_column_to_html {
+  my ($self, $table, $column) = @_;
+
+  my $sth = $self->dbh->prepare(qq|UPDATE $table SET $column = ? WHERE id = ?|) || $self->dberror;
+
+  foreach my $row (selectall_hashref_query($::form, $self->dbh, qq|SELECT id, $column FROM $table WHERE $column IS NOT NULL|)) {
+    next if !$row->{$column} || (($row->{$column} =~ m{^<[a-z]+>}) && ($row->{$column} =~ m{</[a-z]+>$}));
+
+    my $new_content = "" . escape($row->{$column});
+    $new_content    =~ s{\r}{}g;
+    $new_content    =~ s{\n\n+}{</p><p>}g;
+    $new_content    =~ s{\n}{<br />}g;
+    $new_content    =  "<p>${new_content}</p>" if $new_content;
+
+    $sth->execute($new_content, $row->{id}) if $new_content ne $row->{$column};
+  }
+
+  $sth->finish;
+}
+
 1;
 __END__
 
 1;
 __END__
 
@@ -221,6 +278,48 @@ current transaction will be rolled back, a new one will be started.
 
 An optional array reference containing bind parameter for the query.
 
 
 An optional array reference containing bind parameter for the query.
 
+=item C<dbh>
+
+The database handle to use. If undefined then C<$self-E<gt>dbh> will
+be used.
+
+=back
+
+=item C<db_errstr [$handle]>
+
+Returns the last database from C<$handle> error message encoded in
+Perl's internal encoding. The PostgreSQL DBD before 2.16.1 leaves the
+UTF-8 flag off for error messages even if the C<pg_enable_utf8>
+attribute is set. For older versions the error string is already
+encoded correctly and is left unchanged.
+
+C<$handle> is optional and can be one of three things:
+
+=over 2
+
+=item 1. A database or statement handle. In that case
+C<$handle-E<gt>errstr> is used.
+
+=item 2. The string 'DBI'. In that case C<$DBI::errstr> is used.
+
+=item 3. If it is undefined then C<$self-E<gt>dbh-E<gt>errstr> is
+used.
+
+=back
+
+=item C<drop_constraints %params>
+
+Drops all constraints of a type (e.g. foreign keys) on a table. One
+parameter is mandatory: C<table>. Optional parameters include:
+
+=over 2
+
+=item * C<schema> -- if missing defaults to C<public>
+
+=item * C<type> -- if missing defaults to C<FOREIGN KEY>. Must be one of
+the values contained in the C<information_schema.table_constraints>
+view in the C<constraint_type> column.
+
 =back
 
 =item C<execute_script>
 =back
 
 =item C<execute_script>
@@ -240,6 +339,11 @@ C<acc_trans> yet.
 This method is the entry point for the actual upgrade. Each upgrade
 script must provide this method.
 
 This method is the entry point for the actual upgrade. Each upgrade
 script must provide this method.
 
+=item C<convert_column_to_html $table, $column>
+
+Converts the content of a single column from text to HTML suitable for
+use with the ckeditor.
+
 =back
 
 =head1 BUGS
 =back
 
 =head1 BUGS