[freeside-commits] branch FREESIDE_3_BRANCH updated. 4573e0bbb9eae530da0d711b97fcb161ba4662d8

Jonathan Prykop jonathan at 420.am
Thu Mar 31 20:43:28 PDT 2016


The branch, FREESIDE_3_BRANCH has been updated
       via  4573e0bbb9eae530da0d711b97fcb161ba4662d8 (commit)
       via  548cbd2f1d59abd32fbef1a08cead8475b658cfe (commit)
      from  1d09c1581a1291c6bf77d601b960d841238d0894 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 4573e0bbb9eae530da0d711b97fcb161ba4662d8
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Fri Mar 25 00:10:00 2016 -0500

    RT#37912: Service Provisioning Export for ISPConfig 3 [bug fixes]

diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
index b68528c..1f46cf1 100644
--- a/FS/FS/cust_svc.pm
+++ b/FS/FS/cust_svc.pm
@@ -15,6 +15,7 @@ use FS::domain_record;
 use FS::part_export;
 use FS::cdr;
 use FS::UI::Web;
+use FS::export_cust_svc;
 
 #most FS::svc_ classes are autoloaded in svc_x emthod
 use FS::svc_acct;  #this one is used in the cache stuff
diff --git a/FS/FS/part_export/ispconfig3.pm b/FS/FS/part_export/ispconfig3.pm
index 2878c51..3345b3f 100644
--- a/FS/FS/part_export/ispconfig3.pm
+++ b/FS/FS/part_export/ispconfig3.pm
@@ -141,21 +141,22 @@ sub _mail_user_params {
 
 sub _export_insert {
   my ($self, $svc_acct) = @_;
+  return $self->api_error || 'Error logging in'
+    unless $self->api_login;
   my $params = $self->_mail_user_params($svc_acct);
-  $self->api_login;
   my $remoteid = $self->api_call('mail_user_add',$self->option('client_id'),$params);
   return $self->api_error_logout if $self->api_error;
   my $error = $self->set_remoteid($svc_acct,$remoteid);
   $error = "Remote system updated, but error setting remoteid ($remoteid): $error"
     if $error;
   $self->api_logout;
-  $error ||= "Systems updated, but error logging out: ".$self->api_error
-    if $self->api_error;
   return $error;
 }
 
 sub _export_replace {
   my ($self, $svc_acct, $svc_acct_old) = @_;
+  return $self->api_error || 'Error logging in'
+    unless $self->api_login;
   my $remoteid = $self->get_remoteid($svc_acct_old);
   return "Could not load remoteid for old service" unless $remoteid;
   my $params = $self->_mail_user_params($svc_acct);
@@ -170,23 +171,32 @@ sub _export_replace {
       if $error;
   }
   $self->api_logout;
-  $error ||= "Systems updated, but error logging out: ".$self->api_error
-    if $self->api_error;
   return $error;
 }
 
 sub _export_delete {
   my ($self, $svc_acct) = @_;
+  return $self->api_error || 'Error logging in'
+    unless $self->api_login;
   my $remoteid = $self->get_remoteid($svc_acct);
-  return "Could not load remoteid for old service" unless $remoteid;
+  #don't abort deletion--
+  #  might have been provisioned before export was implemented,
+  #  still need to be able to delete from freeside
+  unless ($remoteid) {
+    warn "Could not load remoteid for svcnum ".$svc_acct->svcnum.", unprovisioning anyway";
+    return '';
+  }
   #API docs claim "Returns the number of deleted records"
   my $success = $self->api_call('mail_user_delete',$remoteid);
   return $self->api_error_logout if $self->api_error;
-  my $error = $success ? '' : "Server returned no records deleted";
+  #don't abort deletion--
+  #  if it's already been deleted remotely,
+  #  still need to be able to delete from freeside
+  warn "Server returned no records deleted for svcnum ".$svc_acct->svcnum.
+       " remoteid $remoteid, unprovisioning anyway"
+    unless $success;
   $self->api_logout;
-  $error ||= "Systems updated, but error logging out: ".$self->api_error
-    if $self->api_error;
-  return $error;
+  return '';
 }
 
 sub _export_suspend {
@@ -219,7 +229,6 @@ automatically.  Must run L</api_login> first.
 
 sub api_call {
   my ($self,$method, at params) = @_;
-  $self->{'__ispconfig_response'} = undef;
   # This does get used by api_login,
   # to retrieve the session id after it sets the client,
   # so we only check for existence of client,
@@ -244,7 +253,6 @@ sub api_call {
   $self->{'__ispconfig_error'} = $response->fault
                                ? "Error from server: " . $response->faultstring
                                : '';
-  $self->{'__ispconfig_response'} = $response;
   return $response->result;
 }
 

commit 548cbd2f1d59abd32fbef1a08cead8475b658cfe
Author: Jonathan Prykop <jonathan at freeside.biz>
Date:   Thu Mar 24 21:41:04 2016 -0500

    RT#37912: Service Provisioning Export for ISPConfig 3 [v3 hand merge transactions in cust_svc delete]

diff --git a/FS/FS/Schema.pm b/FS/FS/Schema.pm
index 422ecd9..a7dcc40 100644
--- a/FS/FS/Schema.pm
+++ b/FS/FS/Schema.pm
@@ -3044,6 +3044,26 @@ sub tables_hashref {
       'index'       => [ [ 'exportnum' ], [ 'svcpart' ] ],
     },
 
+    'export_cust_svc' => {
+      'columns' => [
+        'exportcustsvcnum', 'serial', '', '', '', '', 
+        'exportnum', 'int', '', '', '', '', 
+        'svcnum', 'int', '', '', '', '', 
+        'remoteid', 'varchar', '', 512, '', '', 
+      ],
+      'primary_key'  => 'exportcustsvcnum',
+      'unique'       => [ [ 'exportnum', 'svcnum' ] ],
+      'index'        => [ [ 'exportnum', 'svcnum' ] ],
+      'foreign_keys' => [
+                          { columns    => [ 'exportnum' ],
+                            table      => 'part_export',
+                          },
+                          { columns    => [ 'svcnum' ],
+                            table      => 'cust_svc',
+                          },
+                        ],
+    },
+
     'export_device' => {
       'columns' => [
         'exportdevicenum' => 'serial', '', '', '', '', 
diff --git a/FS/FS/cust_svc.pm b/FS/FS/cust_svc.pm
index 7d29749..b68528c 100644
--- a/FS/FS/cust_svc.pm
+++ b/FS/FS/cust_svc.pm
@@ -158,8 +158,35 @@ sub delete {
   my $cust_pkg = $self->cust_pkg;
   my $custnum = $cust_pkg->custnum if $cust_pkg;
 
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  # delete associated export_cust_svc
+  foreach my $export_cust_svc (
+    qsearch('export_cust_svc',{ 'svcnum' => $self->svcnum })
+  ) {
+    my $error = $export_cust_svc->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   my $error = $self->SUPER::delete;
-  return $error if $error;
+  if ( $error ) {
+    $dbh->rollback if $oldAutoCommit;
+    return $error;
+  }
+
+  $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
   if ( $ticket_system eq 'RT_Internal' ) {
     unless ( $rt_session ) {
diff --git a/FS/FS/export_cust_svc.pm b/FS/FS/export_cust_svc.pm
new file mode 100644
index 0000000..7cfdcc6
--- /dev/null
+++ b/FS/FS/export_cust_svc.pm
@@ -0,0 +1,134 @@
+package FS::export_cust_svc;
+use base qw(FS::Record);
+
+use strict;
+use FS::Record qw( qsearchs );
+
+=head1 NAME
+
+FS::export_cust_svc - Object methods for export_cust_svc records
+
+=head1 SYNOPSIS
+
+  use FS::export_cust_svc;
+
+  $record = new FS::export_cust_svc \%hash;
+  $record = new FS::export_cust_svc { 'column' => 'value' };
+
+  $error = $record->insert;
+
+  $error = $new_record->replace($old_record);
+
+  $error = $record->delete;
+
+  $error = $record->check;
+
+=head1 DESCRIPTION
+
+An FS::export_cust_svc object represents information unique
+to a given part_export and cust_svc pair.
+FS::export_cust_svc inherits from FS::Record.  
+The following fields are currently supported:
+
+=over 4
+
+=item exportcustsvcnum - primary key
+
+=item exportnum - export (see L<FS::part_export>)
+
+=item svcnum - service (see L<FS::cust_svc>)
+
+=item remoteid - id for accessing service on export remote system
+
+=back
+
+=head1 METHODS
+
+=over 4
+
+=item new HASHREF
+
+Creates a new export_cust_svc object.  To add the object to the database, see
+L<"insert">.
+
+Note that this stores the hash reference, not a distinct copy of the hash it
+points to.  You can ask the object for a copy with the I<hash> method.
+
+=cut
+
+# the new method can be inherited from FS::Record, if a table method is defined
+
+sub table { 'export_cust_svc'; }
+
+=item insert
+
+Adds this record to the database.  If there is an error, returns the error,
+otherwise returns false.
+
+=cut
+
+sub insert {
+  my $self = shift;
+  return "export_cust_svc for exportnum ".$self->exportnum.
+         " svcnum ".$self->svcnum." already exists"
+    if qsearchs('export_cust_svc',{ 'exportnum' => $self->exportnum,
+                                    'svcnum'    => $self->svcnum });
+  $self->SUPER::insert;
+}
+
+=item delete
+
+Delete this record from the database.
+
+=cut
+
+# the delete method can be inherited from FS::Record
+
+=item replace OLD_RECORD
+
+Replaces the OLD_RECORD with this one in the database.  If there is an error,
+returns the error, otherwise returns false.
+
+=cut
+
+# the replace method can be inherited from FS::Record
+
+=item check
+
+Checks all fields to make sure this is a valid export option.  If there is
+an error, returns the error, otherwise returns false.  Called by the insert
+and replace methods.
+
+=cut
+
+# the check method should currently be supplied - FS::Record contains some
+# data checking routines
+
+sub check {
+  my $self = shift;
+
+  my $error = 
+    $self->ut_numbern('exportcustsvcnum')
+    || $self->ut_foreign_key('exportnum', 'part_export', 'exportnum')
+    || $self->ut_foreign_key('svcnum', 'cust_svc', 'svcnum')
+    || $self->ut_text('remoteid')
+  ;
+  return $error if $error;
+
+  $self->SUPER::check;
+}
+
+=back
+
+=head1 BUGS
+
+Possibly.
+
+=head1 SEE ALSO
+
+L<FS::part_export>, L<FS::cust_svc>, L<FS::Record>
+
+=cut
+
+1;
+
diff --git a/FS/FS/part_export.pm b/FS/FS/part_export.pm
index 0bffa0c..e43524d 100644
--- a/FS/FS/part_export.pm
+++ b/FS/FS/part_export.pm
@@ -11,6 +11,7 @@ use FS::part_export_option;
 use FS::part_export_machine;
 use FS::svc_export_machine;
 use FS::export_svc;
+use FS::export_cust_svc;
 
 #for export modules, though they should probably just use it themselves
 use FS::queue;
@@ -163,6 +164,17 @@ sub delete {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
+  # delete associated export_cust_svc
+  foreach my $export_cust_svc ( 
+    qsearch('export_cust_svc',{ 'exportnum' => $self->exportnum })
+  ) {
+    my $error = $export_cust_svc->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
   # clean up export_nas records
   my $error = $self->process_m2m(
     'link_table'    => 'export_nas',
@@ -648,6 +660,81 @@ sub _export_unsuspend {
   $self->_export_replace( $svc_x, $old );
 }
 
+=item get_remoteid SVC
+
+Returns the remote id for this export for the given service.
+
+=cut
+
+sub get_remoteid {
+  my ($self, $svc_x) = @_;
+
+  my $export_cust_svc = qsearchs('export_cust_svc',{
+    'exportnum' => $self->exportnum,
+    'svcnum' => $svc_x->svcnum
+  });
+
+  return $export_cust_svc ? $export_cust_svc->remoteid : '';
+}
+
+=item set_remoteid SVC VALUE
+
+Sets the remote id for this export for the given service.
+See L<FS::export_cust_svc>.
+
+If value is true, inserts or updates export_cust_svc record.
+If value is false, deletes any existing record.
+
+Returns error message, blank on success.
+
+=cut
+
+sub set_remoteid {
+  my ($self, $svc_x, $value) = @_;
+
+  my $export_cust_svc = qsearchs('export_cust_svc',{
+    'exportnum' => $self->exportnum,
+    'svcnum' => $svc_x->svcnum
+  });
+
+  local $SIG{HUP} = 'IGNORE';
+  local $SIG{INT} = 'IGNORE';
+  local $SIG{QUIT} = 'IGNORE';
+  local $SIG{TERM} = 'IGNORE';
+  local $SIG{TSTP} = 'IGNORE';
+  local $SIG{PIPE} = 'IGNORE';
+
+  my $oldAutoCommit = $FS::UID::AutoCommit;
+  local $FS::UID::AutoCommit = 0;
+  my $dbh = dbh;
+
+  my $error = '';
+  if ($value) {
+    if ($export_cust_svc) {
+      $export_cust_svc->set('remoteid',$value);
+      $error = $export_cust_svc->replace;
+    } else {
+      $export_cust_svc = new FS::export_cust_svc {
+        'exportnum' => $self->exportnum,
+        'svcnum' => $svc_x->svcnum,
+        'remoteid' => $value
+      };
+      $error = $export_cust_svc->insert;
+    }
+  } else {
+    if ($export_cust_svc) {
+      $error = $export_cust_svc->delete;
+    } #otherwise, it already doesn't exist
+  }
+
+  if ($oldAutoCommit) {
+    $dbh->rollback if $error;
+    $dbh->commit unless $error;
+  }
+
+  return $error;  
+}
+
 =item export_links SVC_OBJECT ARRAYREF
 
 Adds a list of web elements to ARRAYREF specific to this export and SVC_OBJECT.
diff --git a/FS/FS/part_export/ispconfig3.pm b/FS/FS/part_export/ispconfig3.pm
new file mode 100644
index 0000000..2878c51
--- /dev/null
+++ b/FS/FS/part_export/ispconfig3.pm
@@ -0,0 +1,361 @@
+package FS::part_export::ispconfig3;
+
+use strict;
+
+use base qw( FS::part_export );
+
+use Data::Dumper;
+use SOAP::Lite;
+
+=pod
+
+=head1 NAME
+
+FS::part_export::ispconfig3
+
+=head1 SYNOPSIS
+
+ISPConfig 3 integration for Freeside
+
+=head1 DESCRIPTION
+
+This export offers basic svc_acct provisioning for ISPConfig 3.
+All email accounts will be assigned to a single specified client.
+
+This module also provides generic methods for working through the L</ISPConfig3 API>.
+
+=cut
+
+use vars qw( %info );
+
+my @yesno = (
+  options => ['y','n'],
+  option_labels => { 'y' => 'yes', 'n' => 'no' },
+);
+
+tie my %options, 'Tie::IxHash',
+  'soap_location'      => { label   => 'SOAP Location' },
+  'username'           => { label   => 'User Name',
+                            default => '' },
+  'password'           => { label   => 'Password',
+                            default => '' },
+  'debug'              => { type    => 'checkbox',
+                            label   => 'Enable debug warnings' },
+  'subheading'         => { type    => 'title',
+                            label   => 'Account defaults' },
+  'client_id'          => { label   => 'Client ID' },
+  'server_id'          => { label   => 'Server ID' },
+  'maildir'            => { label   => 'Maildir (substitutions from svc_acct, e.g. /mail/$domain/$username)', },
+  'cc'                 => { label   => 'Cc' },
+  'autoresponder_text' => { label   => 'Autoresponder text', 
+                            default => 'Out of Office Reply' },
+  'move_junk'          => { type    => 'select',
+                            options => ['y','n'],
+                            option_labels => { 'y' => 'yes', 'n' => 'no' },
+                            label   => 'Move junk' },
+  'postfix'            => { type    => 'select',
+                            @yesno,
+                            label   => 'Postfix' },
+  'access'             => { type    => 'select',
+                            @yesno,
+                            label   => 'Access' },
+  'disableimap'        => { type    => 'select',
+                            @yesno,
+                            label   => 'Disable IMAP' },
+  'disablepop3'        => { type    => 'select',
+                            @yesno,
+                            label   => 'Disable POP3' },
+  'disabledeliver'     => { type    => 'select',
+                            @yesno,
+                            label   => 'Disable deliver' },
+  'disablesmtp'        => { type    => 'select',
+                            @yesno,
+                            label   => 'Disable SMTP' },
+;
+
+%info = (
+  'svc'             => 'svc_acct',
+  'desc'            => 'Export email account to ISPConfig 3',
+  'options'         => \%options,
+  'no_machine'      => 1,
+  'notes'           => <<'END',
+All email accounts will be assigned to a single specified client and server.
+END
+);
+
+sub _mail_user_params {
+  my ($self, $svc_acct) = @_;
+  # all available api fields are in comments below, even if we don't use them
+  return {
+    #server_id  (int(11))
+    'server_id' => $self->option('server_id'),
+    #email  (varchar(255))
+    'email' => $svc_acct->username.'@'.$svc_acct->domain,
+    #login  (varchar(255))
+    'login' => $svc_acct->username.'@'.$svc_acct->domain,
+    #password  (varchar(255))
+    'password' => $svc_acct->_password,
+    #name  (varchar(255))
+    'name' => $svc_acct->finger,
+    #uid  (int(11))
+    'uid' => $svc_acct->uid,
+    #gid  (int(11))
+    'gid' => $svc_acct->gid,
+    #maildir  (varchar(255))
+    'maildir' => $self->_substitute($self->option('maildir'),$svc_acct),
+    #quota  (bigint(20))
+    'quota' => $svc_acct->quota,
+    #cc  (varchar(255))
+    'cc' => $self->option('cc'),
+    #homedir  (varchar(255))
+    'homedir' => $svc_acct->dir,
+
+    ## initializing with autoresponder off, but this could become an export option...
+    #autoresponder  (enum('n','y'))
+    'autoresponder' => 'n',
+    #autoresponder_start_date  (datetime)
+    #autoresponder_end_date  (datetime)
+    #autoresponder_text  (mediumtext)
+    'autoresponder_text' => $self->option('autoresponder_text'),
+
+    #move_junk  (enum('n','y'))
+    'move_junk' => $self->option('move_junk'),
+    #postfix  (enum('n','y'))
+    'postfix' => $self->option('postfix'),
+    #access  (enum('n','y'))
+    'access' => $self->option('access'),
+
+    ## not needed right now, not sure what it is
+	#custom_mailfilter  (mediumtext)
+
+    #disableimap  (enum('n','y'))
+    'disableimap' => $self->option('disableimap'),
+    #disablepop3  (enum('n','y'))
+    'disablepop3' => $self->option('disablepop3'),
+    #disabledeliver  (enum('n','y'))
+    'disabledeliver' => $self->option('disabledeliver'),
+    #disablesmtp  (enum('n','y'))
+    'disablesmtp' => $self->option('disablesmtp'),
+  };
+}
+
+sub _export_insert {
+  my ($self, $svc_acct) = @_;
+  my $params = $self->_mail_user_params($svc_acct);
+  $self->api_login;
+  my $remoteid = $self->api_call('mail_user_add',$self->option('client_id'),$params);
+  return $self->api_error_logout if $self->api_error;
+  my $error = $self->set_remoteid($svc_acct,$remoteid);
+  $error = "Remote system updated, but error setting remoteid ($remoteid): $error"
+    if $error;
+  $self->api_logout;
+  $error ||= "Systems updated, but error logging out: ".$self->api_error
+    if $self->api_error;
+  return $error;
+}
+
+sub _export_replace {
+  my ($self, $svc_acct, $svc_acct_old) = @_;
+  my $remoteid = $self->get_remoteid($svc_acct_old);
+  return "Could not load remoteid for old service" unless $remoteid;
+  my $params = $self->_mail_user_params($svc_acct);
+  #API docs claim "Returns the number of affected rows"
+  my $success = $self->api_call('mail_user_update',$self->option('client_id'),$remoteid,$params);
+  return $self->api_error_logout if $self->api_error;
+  return "Server returned no rows updated, but no other error message" unless $success;
+  my $error = '';
+  unless ($svc_acct->svcnum eq $svc_acct_old->svcnum) { # are these ever not equal?
+    $error = $self->set_remoteid($svc_acct,$remoteid);
+    $error = "Remote system updated, but error setting remoteid ($remoteid): $error"
+      if $error;
+  }
+  $self->api_logout;
+  $error ||= "Systems updated, but error logging out: ".$self->api_error
+    if $self->api_error;
+  return $error;
+}
+
+sub _export_delete {
+  my ($self, $svc_acct) = @_;
+  my $remoteid = $self->get_remoteid($svc_acct);
+  return "Could not load remoteid for old service" unless $remoteid;
+  #API docs claim "Returns the number of deleted records"
+  my $success = $self->api_call('mail_user_delete',$remoteid);
+  return $self->api_error_logout if $self->api_error;
+  my $error = $success ? '' : "Server returned no records deleted";
+  $self->api_logout;
+  $error ||= "Systems updated, but error logging out: ".$self->api_error
+    if $self->api_error;
+  return $error;
+}
+
+sub _export_suspend {
+  my ($self, $svc_acct) = @_;
+  return '';
+}
+
+sub _export_unsuspend {
+  my ($self, $svc_acct) = @_;
+  return '';
+}
+
+=head1 ISPConfig3 API
+
+These methods allow access to the ISPConfig3 API using the credentials
+set in the export options.
+
+=cut
+
+=head2 api_call
+
+Accepts I<$method> and I<@params>.  Places an api call to the specified
+method with the specified params.  Returns the result of that call
+(empty on failure.)  Retrieve error messages using L</api_error>.
+
+Do not include session id in list of params;  it will be included
+automatically.  Must run L</api_login> first.
+
+=cut
+
+sub api_call {
+  my ($self,$method, at params) = @_;
+  $self->{'__ispconfig_response'} = undef;
+  # This does get used by api_login,
+  # to retrieve the session id after it sets the client,
+  # so we only check for existence of client,
+  # and we only include session id if we have one
+  my $client = $self->{'__ispconfig_client'};
+  unless ($client) {
+    $self->{'__ispconfig_error'} = 'Not logged in';
+    return;
+  }
+  if ($self->{'__ispconfig_session'}) {
+    unshift(@params,$self->{'__ispconfig_session'});
+  }
+  # Contact server in eval, to trap connection errors
+  warn "Calling SOAP method $method with params:\n".Dumper(\@params)."\n"
+    if $self->option('debug');
+  my $response = eval { $client->$method(@params) };
+  unless ($response) {
+    $self->{'__ispconfig_error'} = "Error contacting server: $@";
+    return;
+  }
+  # Set results and return
+  $self->{'__ispconfig_error'} = $response->fault
+                               ? "Error from server: " . $response->faultstring
+                               : '';
+  $self->{'__ispconfig_response'} = $response;
+  return $response->result;
+}
+
+=head2 api_error
+
+Returns the error string set by L</ISPConfig3 API> methods,
+or a blank string if most recent call produced no errors.
+
+=cut
+
+sub api_error {
+  my $self = shift;
+  return $self->{'__ispconfig_error'} || '';
+}
+
+=head2 api_error_logout
+
+Attempts L</api_logout>, but returns L</api_error> message from
+before logout was attempted.  Useful for logging out
+properly after an error.
+
+=cut
+
+sub api_error_logout {
+  my $self = shift;
+  my $error = $self->api_error;
+  $self->api_logout;
+  return $error;
+}
+
+=head2 api_login
+
+Initializes an api session using the credentials for this export.
+Returns true on success, false on failure.
+Retrieve error messages using L</api_error>.
+
+=cut
+
+sub api_login {
+  my $self = shift;
+  if ($self->{'__ispconfig_session'} || $self->{'__ispconfig_client'}) {
+    $self->{'__ispconfig_error'} = 'Already logged in';
+    return;
+  }
+  $self->{'__ispconfig_session'} = undef;
+  $self->{'__ispconfig_client'} =
+    SOAP::Lite->proxy($self->option('soap_location'), ssl_opts => [ verify_hostname => 0 ] )
+    || undef;
+  unless ($self->{'__ispconfig_client'}) {
+    $self->{'__ispconfig_error'} = 'Error creating SOAP client';
+    return;
+  }
+  $self->{'__ispconfig_session'} = 
+    $self->api_call('login',$self->option('username'),$self->option('password'))
+    || undef;
+  return unless $self->{'__ispconfig_session'};
+  return 1;
+}
+
+=head2 api_logout
+
+Ends the current api session established by L</api_login>.
+Returns true on success, false on failure.
+
+=cut
+
+sub api_logout {
+  my $self = shift;
+  unless ($self->{'__ispconfig_session'}) {
+    $self->{'__ispconfig_error'} = 'Not logged in';
+    return;
+  }
+  my $result = $self->api_call('logout');
+  # clear these even if there was a failure to logout
+  $self->{'__ispconfig_client'} = undef;
+  $self->{'__ispconfig_session'} = undef;
+  return if $self->api_error;
+  return 1;
+}
+
+# false laziness with portaone export
+sub _substitute {
+  my ($self, $string, @objects) = @_;
+  return '' unless $string;
+  foreach my $object (@objects) {
+    next unless $object;
+    my @fields = $object->fields;
+    push(@fields,'domain') if $object->table eq 'svc_acct';
+    foreach my $field (@fields) {
+      next unless $field;
+      my $value = $object->$field;
+      $string =~ s/\$$field/$value/g;
+    }
+  }
+  # strip leading/trailing whitespace
+  $string =~ s/^\s//g;
+  $string =~ s/\s$//g;
+  return $string;
+}
+
+=head1 SEE ALSO
+
+L<FS::part_export>
+
+=head1 AUTHOR
+
+Jonathan Prykop 
+jonathan at freeside.biz
+
+=cut
+
+1;
+
+

-----------------------------------------------------------------------

Summary of changes:
 FS/FS/Schema.pm                                    |   20 ++
 FS/FS/cust_svc.pm                                  |   30 +-
 .../{part_export_option.pm => export_cust_svc.pm}  |   56 +--
 FS/FS/part_export.pm                               |   87 +++++
 FS/FS/part_export/ispconfig3.pm                    |  369 ++++++++++++++++++++
 5 files changed, 533 insertions(+), 29 deletions(-)
 copy FS/FS/{part_export_option.pm => export_cust_svc.pm} (55%)
 create mode 100644 FS/FS/part_export/ispconfig3.pm




More information about the freeside-commits mailing list