App-WHMCSUtils
view release on metacpan or search on metacpan
information, much like how HTTP response headers provide additional
metadata.
Return value: (any)
restore_whmcs_client
Usage:
restore_whmcs_client(%args) -> [$status_code, $reason, $payload, \%result_meta]
Restore a missing client from SQL database backup.
This function is not exported.
This function supports dry-run operation.
Arguments ('*' denotes required arguments):
* client_email => *str*
* client_id => *posint*
* restore_domains => *bool* (default: 1)
* restore_hostings => *bool* (default: 1)
* restore_invoices => *bool* (default: 1)
* sql_backup_dir => *dirname*
Directory containing per-table SQL files.
* sql_backup_file => *filename*
Can accept either ".sql" or ".sql.gz".
Will be converted first to a directory where the SQL file will be
extracted to separate files on a per-table basis.
Special arguments:
* -dry_run => *bool*
lib/App/WHMCSUtils.pm view on Meta::CPAN
);
DBIx::Connect::MySQL->connect(
$dsn, $args{db_user}, $args{db_pass},
{RaiseError => 1},
);
}
$SPEC{restore_whmcs_client} = {
v => 1.1,
summary => "Restore a missing client from SQL database backup",
args => {
sql_backup_file => {
schema => 'filename*',
description => <<'_',
Can accept either `.sql` or `.sql.gz`.
Will be converted first to a directory where the SQL file will be extracted to
separate files on a per-table basis.
_
},
sql_backup_dir => {
summary => 'Directory containing per-table SQL files',
schema => 'dirname*',
description => <<'_',
_
},
client_email => {
schema => 'str*',
},
lib/App/WHMCSUtils.pm view on Meta::CPAN
schema => 'bool*',
default => 1,
},
restore_domains => {
schema => 'bool*',
default => 1,
},
},
args_rels => {
'req_one&' => [
['sql_backup_file', 'sql_backup_dir'],
['client_email', 'client_id'],
],
},
deps => {
prog => "mysql-sql-dump-extract-tables",
},
features => {
dry_run => 1,
},
};
sub restore_whmcs_client {
my %args = @_;
local $CWD;
my $sql_backup_dir;
my $decompress = 0;
if ($args{sql_backup_file}) {
return [404, "No such file: $args{sql_backup_file}"]
unless -f $args{sql_backup_file};
my $pt = path($args{sql_backup_file});
my $basename = $pt->basename;
if ($basename =~ /(.+)\.sql\z/i) {
$sql_backup_dir = $1;
} elsif ($basename =~ /(.+)\.sql\.gz\z/i) {
$sql_backup_dir = $1;
$decompress = 1;
} else {
return [412, "SQL backup file should be named *.sql or *.sql.gz: ".
"$args{sql_backup_file}"];
}
if (-d $sql_backup_dir) {
log_info "SQL backup dir '$sql_backup_dir' already exists, ".
"skipped extracting";
} else {
mkdir $sql_backup_dir, 0755
or return [500, "Can't mkdir '$sql_backup_dir': $!"];
$CWD = $sql_backup_dir;
my @cmd;
if ($decompress) {
push @cmd, "zcat", $pt->absolute->stringify, \"|";
} else {
push @cmd, "cat", $pt->absolute->stringify, \"|";
}
push @cmd, "mysql-sql-dump-extract-tables",
"--include-table-pattern", '^(tblclients|tblinvoices|tblinvoiceitems|tblorders)$';
system({shell=>1, die=>1, log=>1}, @cmd);
}
} elsif ($args{sql_backup_dir}) {
$sql_backup_dir = $args{sql_backup_dir};
return [404, "No such dir: $sql_backup_dir"]
unless -d $sql_backup_dir;
$CWD = $sql_backup_dir;
}
my @sql;
my $clientid = $args{client_id};
FIND_CLIENT:
{
open my $fh, "<", "tblclients"
or return [500, "Can't open $sql_backup_dir/tblclients: $!"];
my $clientemail;
$clientemail = lc $args{client_email} if defined $args{client_email};
while (<$fh>) {
next unless /^INSERT INTO `tblclients` \(`id`, `firstname`, `lastname`, `companyname`, `email`, [^)]+\) VALUES \((\d+),'(.*?)','(.*?)','(.*?)','(.*?)',/;
my ($rid, $rfirstname, $rlastname, $rcompanyname, $remail) = ($1, $2, $3, $4, $5);
if (defined $clientid) {
# find by ID
if ($rid == $clientid) {
$clientemail = $remail;
push @sql, $_;
log_info "Found client ID=%s in backup", $clientid;
last FIND_CLIENT;
}
} else {
# find by email
if (lc $remail eq $clientemail) {
$clientid = $rid;
push @sql, $_;
log_info "Found client email=%s in backup: ID=%s", $clientemail, $clientid;
last FIND_CLIENT;
}
}
}
return [404, "Couldn't find client email=$clientemail in database backup, please check the email or try another backup"];
}
my @invoiceids;
FIND_INVOICES:
{
last unless $args{restore_invoices};
open my $fh, "<", "tblinvoices"
or return [500, "Can't open $sql_backup_dir/tblinvoices: $!"];
while (<$fh>) {
next unless /^INSERT INTO `tblinvoices` \(`id`, `userid`, [^)]+\) VALUES \((\d+),(\d+),/;
my ($rid, $ruserid) = ($1, $2);
if ($ruserid == $clientid) {
push @invoiceids, $rid;
push @sql, $_;
log_info "Found client invoice in backup: ID=%s", $rid;
}
}
log_info "Number of invoices found for client in backup: %d", ~~@invoiceids if @invoiceids;
}
FIND_INVOICEITEMS:
{
last unless @invoiceids;
open my $fh, "<", "tblinvoiceitems"
or return [500, "Can't open $sql_backup_dir/tblinvoiceitems: $!"];
while (<$fh>) {
next unless /^INSERT INTO `tblinvoiceitems` \(`id`, `invoiceid`, `userid`, [^)]+\) VALUES \((\d+),(\d+),(\d+)/;
my ($rid, $rinvoiceid, $ruserid) = ($1, $2, $3);
if (grep {$rinvoiceid == $_} @invoiceids) {
log_trace "Adding invoice item %s for invoice #%s", $rid, $rinvoiceid;
push @sql, $_;
}
}
}
FIND_HOSTINGS:
{
last unless $args{restore_hostings};
open my $fh, "<", "tblhosting"
or return [500, "Can't open $sql_backup_dir/tblhosting: $!"];
while (<$fh>) {
next unless /^INSERT INTO `tblhosting` \(`id`, `userid`, [^)]+\) VALUES \((\d+),(\d+),(\d+)/;
my ($rid, $ruserid) = ($1, $2, $3);
if ($ruserid == $clientid) {
log_trace "Found hosting for client in backup: ID=%d", $rid;
push @sql, $_;
}
}
}
FIND_DOMAINS:
{
last unless $args{restore_domains};
open my $fh, "<", "tbldomains"
or return [500, "Can't open $sql_backup_dir/tbldomains: $!"];
while (<$fh>) {
next unless /^INSERT INTO `tbldomains` \(`id`, `userid`, [^)]+\) VALUES \((\d+),(\d+),(\d+)/;
my ($rid, $ruserid) = ($1, $2, $3);
if ($ruserid == $clientid) {
log_trace "Found domain for client in backup: ID=%d", $rid;
push @sql, $_;
}
}
}
# TODO: tickets?
# records in tblaccounts (transactions) are not deleted when client is
# deleted
lib/App/WHMCSUtils.pm view on Meta::CPAN
Return value: (any)
=head2 restore_whmcs_client
Usage:
restore_whmcs_client(%args) -> [$status_code, $reason, $payload, \%result_meta]
Restore a missing client from SQL database backup.
This function is not exported.
This function supports dry-run operation.
Arguments ('*' denotes required arguments):
=over 4
=item * B<client_email> => I<str>
=item * B<client_id> => I<posint>
=item * B<restore_domains> => I<bool> (default: 1)
=item * B<restore_hostings> => I<bool> (default: 1)
=item * B<restore_invoices> => I<bool> (default: 1)
=item * B<sql_backup_dir> => I<dirname>
Directory containing per-table SQL files.
=item * B<sql_backup_file> => I<filename>
Can accept either C<.sql> or C<.sql.gz>.
Will be converted first to a directory where the SQL file will be extracted to
separate files on a per-table basis.
=back
Special arguments:
script/restore-whmcs-client view on Meta::CPAN
our $VERSION = '0.012'; # VERSION
my $cmdline = Perinci::CmdLine::Any->new(
url => "/App/WHMCSUtils/restore_whmcs_client",
program_name => "restore-whmcs-client",
log => 1,
);
$cmdline->run;
# ABSTRACT: Restore a missing client from SQL database backup
# PODNAME: restore-whmcs-client
__END__
=pod
=encoding UTF-8
=head1 NAME
restore-whmcs-client - Restore a missing client from SQL database backup
=head1 VERSION
This document describes version 0.012 of restore-whmcs-client (from Perl distribution App-WHMCSUtils), released on 2021-11-30.
=head1 SYNOPSIS
Usage:
% B<restore-whmcs-client> [B<--client-email>=I<str>] [B<--client-id>=I<posint>] [B<--config-path>=I<path>|B<-c>|B<--no-config>|B<-C>] [B<--config-profile>=I<profile>|B<-P>] [B<--debug>|B<--log-level>=I<level>|B<--quiet>|B<--trace>|B<--verbose>] [B<--...
=head1 OPTIONS
C<*> marks required options.
=head2 Main options
=over
=item B<--client-email>=I<s>
=item B<--client-id>=I<s>
=item B<--no-restore-domains>
=item B<--no-restore-hostings>
=item B<--no-restore-invoices>
=item B<--sql-backup-dir>=I<s>
Directory containing per-table SQL files.
=item B<--sql-backup-file>=I<s>
Can accept either `.sql` or `.sql.gz`.
Will be converted first to a directory where the SQL file will be extracted to
separate files on a per-table basis.
=back
=head2 Configuration options
script/restore-whmcs-client view on Meta::CPAN
List of available configuration parameters:
client_email (see --client-email)
client_id (see --client-id)
format (see --format)
log_level (see --log-level)
naked_res (see --naked-res)
restore_domains (see --no-restore-domains)
restore_hostings (see --no-restore-hostings)
restore_invoices (see --no-restore-invoices)
sql_backup_dir (see --sql-backup-dir)
sql_backup_file (see --sql-backup-file)
=head1 ENVIRONMENT
=head2 RESTORE_WHMCS_CLIENT_OPT => str
Specify additional command-line options.
=head1 FILES
F<~/.config/restore-whmcs-client.conf>
( run in 0.693 second using v1.01-cache-2.11-cpan-49f99fa48dc )