Auftrags-Controller: Preisquellenermittlung in eigene Funktion ausgelagert
[kivitendo-erp.git] / SL / DBUpgrade2 / Base.pm
index 9978b20..cd698c5 100644 (file)
@@ -11,6 +11,9 @@ use File::Basename ();
 use File::Copy ();
 use File::Path ();
 use List::MoreUtils qw(uniq);
 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) ],
@@ -28,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;
 }
@@ -57,9 +61,15 @@ sub db_query {
 sub db_errstr {
   my ($self, $handle) = @_;
 
 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;
 
   my $error = $handle ? $handle->errstr : $self->dbh->errstr;
 
-  return $::locale->is_utf8 ? Encode::decode('utf-8', $error) : $error;
+  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 {
@@ -90,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__
 
@@ -242,8 +288,10 @@ be used.
 =item C<db_errstr [$handle]>
 
 Returns the last database from C<$handle> error message encoded in
 =item C<db_errstr [$handle]>
 
 Returns the last database from C<$handle> error message encoded in
-Perl's internal encoding. The PostgreSQL DBD leaves the UTF-8 flag off
-for error messages even if the C<pg_enable_utf8> attribute is set.
+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:
 
 
 C<$handle> is optional and can be one of three things:
 
@@ -259,6 +307,21 @@ used.
 
 =back
 
 
 =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>
 
 Executes a named database upgrade script. This function is not
 =item C<execute_script>
 
 Executes a named database upgrade script. This function is not
@@ -276,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