+sub backup_dataset {
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} =
+ "Lx-Office ERP "
+ . $locale->text('Database Administration') . " / "
+ . $locale->text('Backup Dataset');
+
+ if ("$main::pg_dump_exe" eq "DISABLED") {
+ $form->error($locale->text('Database backups and restorations are disabled in lx-erp.conf.'));
+ }
+
+ my @dbsources = sort User->dbsources($form);
+ $form->{DATABASES} = [ map { { "dbname" => $_ } } @dbsources ];
+ $form->{NO_DATABASES} = !scalar @dbsources;
+
+ my $username = getpwuid $UID || "unknown-user";
+ my $hostname = hostname() || "unknown-host";
+ $form->{from} = "Lx-Office Admin <${username}\@${hostname}>";
+
+ $form->header();
+ print $form->parse_html_template("admin/backup_dataset");
+}
+
+sub backup_dataset_start {
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} =
+ "Lx-Office ERP "
+ . $locale->text('Database Administration') . " / "
+ . $locale->text('Backup Dataset');
+
+ $main::pg_dump_exe ||= "pg_dump";
+
+ if ("$main::pg_dump_exe" eq "DISABLED") {
+ $form->error($locale->text('Database backups and restorations are disabled in lx-erp.conf.'));
+ }
+
+ $form->isblank("dbname", $locale->text('The dataset name is missing.'));
+ $form->isblank("to", $locale->text('The email address is missing.')) if $form->{destination} eq "email";
+
+ my $tmpdir = "/tmp/lx_office_backup_" . Common->unique_id();
+ mkdir $tmpdir, 0700 || $form->error($locale->text('A temporary directory could not be created:') . " $ERRNO");
+
+ my $pgpass = IO::File->new("${tmpdir}/.pgpass", O_WRONLY | O_CREAT, 0600);
+
+ if (!$pgpass) {
+ unlink $tmpdir;
+ $form->error($locale->text('A temporary file could not be created:') . " $ERRNO");
+ }
+
+ print $pgpass "$form->{dbhost}:$form->{dbport}:$form->{dbname}:$form->{dbuser}:$form->{dbpasswd}\n";
+ $pgpass->close();
+
+ $ENV{HOME} = $tmpdir;
+
+ my @args = ("-Ft", "-c", "-o", "-h", $form->{dbhost}, "-U", $form->{dbuser});
+ push @args, ("-p", $form->{dbport}) if ($form->{dbport});
+ push @args, $form->{dbname};
+
+ my $cmd = "$main::pg_dump_exe " . join(" ", map { s/\\/\\\\/g; s/\"/\\\"/g; $_ } @args);
+ my $name = "dataset_backup_$form->{dbname}_" . strftime("%Y%m%d", localtime()) . ".tar";
+
+ if ($form->{destination} ne "email") {
+ my $in = IO::File->new("$cmd |");
+
+ if (!$in) {
+ unlink "${tmpdir}/.pgpass";
+ rmdir $tmpdir;
+
+ $form->error($locale->text('The pg_dump process could not be started.'));
+ }
+
+ print "content-type: application/x-tar\n";
+ print "content-disposition: attachment; filename=\"${name}\"\n\n";
+
+ while (my $line = <$in>) {
+ print $line;
+ }
+
+ $in->close();
+
+ unlink "${tmpdir}/.pgpass";
+ rmdir $tmpdir;
+
+ } else {
+ my $tmp = $tmpdir . "/dump_" . Common::unique_id();
+
+ if (system("$cmd > $tmp") != 0) {
+ unlink "${tmpdir}/.pgpass", $tmp;
+ rmdir $tmpdir;
+
+ $form->error($locale->text('The pg_dump process could not be started.'));
+ }
+
+ my $mail = new Mailer;
+
+ map { $mail->{$_} = $form->{$_} } qw(from to cc subject message);
+
+ $mail->{charset} = $main::dbcharset ? $main::dbcharset : Common::DEFAULT_CHARSET;
+ $mail->{attachments} = [ { "filename" => $tmp, "name" => $name } ];
+ $mail->send();
+
+ unlink "${tmpdir}/.pgpass", $tmp;
+ rmdir $tmpdir;
+
+ $form->{title} =
+ "Lx-Office ERP "
+ . $locale->text('Database Administration') . " / "
+ . $locale->text('Backup Dataset');
+
+ $form->header();
+ print $form->parse_html_template("admin/backup_dataset_email_done");
+ }
+}
+
+sub restore_dataset {
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} =
+ "Lx-Office ERP "
+ . $locale->text('Database Administration') . " / "
+ . $locale->text('Restore Dataset');
+
+ if ("$main::pg_restore_exe" eq "DISABLED") {
+ $form->error($locale->text('Database backups and restorations are disabled in lx-erp.conf.'));
+ }
+
+ my $default_charset = $main::dbcharset;
+ $default_charset ||= Common::DEFAULT_CHARSET;
+
+ $form->{DBENCODINGS} = [];
+
+ foreach my $encoding (@Common::db_encodings) {
+ push @{ $form->{DBENCODINGS} }, { "dbencoding" => $encoding->{dbencoding},
+ "label" => $encoding->{label},
+ "selected" => $encoding->{charset} eq $default_charset };
+ }
+
+ $form->header();
+ print $form->parse_html_template("admin/restore_dataset");
+}
+
+sub restore_dataset_start {
+ my $form = $main::form;
+ my $locale = $main::locale;
+
+ $form->{title} =
+ "Lx-Office ERP "
+ . $locale->text('Database Administration') . " / "
+ . $locale->text('Restore Dataset');
+
+ $main::pg_restore_exe ||= "pg_restore";
+
+ if ("$main::pg_restore_exe" eq "DISABLED") {
+ $form->error($locale->text('Database backups and restorations are disabled in lx-erp.conf.'));
+ }
+
+ $form->isblank("new_dbname", $locale->text('The dataset name is missing.'));
+ $form->isblank("content", $locale->text('No backup file has been uploaded.'));
+
+ # Create temporary directories. Write the backup file contents to a temporary
+ # file. Create a .pgpass file with the username and password for the pg_restore
+ # utility.
+
+ my $tmpdir = "/tmp/lx_office_backup_" . Common->unique_id();
+ mkdir $tmpdir, 0700 || $form->error($locale->text('A temporary directory could not be created:') . " $ERRNO");
+
+ my $pgpass = IO::File->new("${tmpdir}/.pgpass", O_WRONLY | O_CREAT, 0600);
+
+ if (!$pgpass) {
+ unlink $tmpdir;
+ $form->error($locale->text('A temporary file could not be created:') . " $ERRNO");
+ }
+
+ print $pgpass "$form->{dbhost}:$form->{dbport}:$form->{new_dbname}:$form->{dbuser}:$form->{dbpasswd}\n";
+ $pgpass->close();
+
+ $ENV{HOME} = $tmpdir;
+
+ my $tmp = $tmpdir . "/dump_" . Common::unique_id();
+ my $tmpfile;
+
+ if (substr($form->{content}, 0, 2) eq "\037\213") {
+ $tmpfile = IO::File->new("| gzip -d > $tmp");
+ $tmpfile->binary();
+
+ } else {
+ $tmpfile = IO::File->new($tmp, O_WRONLY | O_CREAT | O_BINARY, 0600);
+ }
+
+ if (!$tmpfile) {
+ unlink "${tmpdir}/.pgpass";
+ rmdir $tmpdir;
+
+ $form->error($locale->text('A temporary file could not be created:') . " $ERRNO");
+ }
+
+ print $tmpfile $form->{content};
+ $tmpfile->close();
+
+ delete $form->{content};
+
+ # Try to connect to the database. Find out if a database with the same name exists.
+ # If yes, then drop the existing database. Create a new one with the name and encoding
+ # given by the user.
+
+ User::dbconnect_vars($form, "template1");
+
+ my %myconfig = map { $_ => $form->{$_} } grep /^db/, keys %{ $form };
+ my $dbh = $form->dbconnect(\%myconfig) || $form->dberror();
+
+ my ($query, $sth);
+
+ $form->{new_dbname} =~ s|[^a-zA-Z0-9_\-]||g;
+
+ $query = qq|SELECT COUNT(*) FROM pg_database WHERE datname = ?|;
+ my ($count) = selectrow_query($form, $dbh, $query, $form->{new_dbname});
+ if ($count) {
+ do_query($form, $dbh, qq|DROP DATABASE $form->{new_dbname}|);
+ }
+
+ my $found = 0;
+ foreach my $item (@Common::db_encodings) {
+ if ($item->{dbencoding} eq $form->{dbencoding}) {
+ $found = 1;
+ last;
+ }
+ }
+ $form->{dbencoding} = "LATIN9" unless $form->{dbencoding};
+
+ do_query($form, $dbh, qq|CREATE DATABASE $form->{new_dbname} ENCODING ? TEMPLATE template0|, $form->{dbencoding});
+
+ $dbh->disconnect();
+
+ # Spawn pg_restore on the temporary file.
+
+ my @args = ("-h", $form->{dbhost}, "-U", $form->{dbuser}, "-d", $form->{new_dbname});
+ push @args, ("-p", $form->{dbport}) if ($form->{dbport});
+ push @args, $tmp;
+
+ my $cmd = "$main::pg_restore_exe " . join(" ", map { s/\\/\\\\/g; s/\"/\\\"/g; $_ } @args);
+
+ my $in = IO::File->new("$cmd 2>&1 |");
+
+ if (!$in) {
+ unlink "${tmpdir}/.pgpass", $tmp;
+ rmdir $tmpdir;
+
+ $form->error($locale->text('The pg_restore process could not be started.'));
+ }
+
+ $English::AUTOFLUSH = 1;
+
+ $form->header();
+ print $form->parse_html_template("admin/restore_dataset_start_header");
+
+ while (my $line = <$in>) {
+ print $line;
+ }
+ $in->close();
+
+ $form->{retval} = $CHILD_ERROR >> 8;
+ print $form->parse_html_template("admin/restore_dataset_start_footer");
+
+ unlink "${tmpdir}/.pgpass", $tmp;
+ rmdir $tmpdir;
+}
+