UI improvements for agents
[freeside.git] / FS / FS / part_export.pm
index 59024f6..eabcede 100644 (file)
@@ -102,6 +102,7 @@ created (see L<FS::part_export_option>).
 #false laziness w/queue.pm
 sub insert {
   my $self = shift;
+  my $options = shift;
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
@@ -119,7 +120,6 @@ sub insert {
     return $error;
   }
 
-  my $options = shift;
   foreach my $optionname ( keys %{$options} ) {
     my $part_export_option = new FS::part_export_option ( {
       'exportnum'   => $self->exportnum,
@@ -191,6 +191,8 @@ created or modified (see L<FS::part_export_option>).
 
 sub replace {
   my $self = shift;
+  my $old = shift;
+  my $options = shift;
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
   local $SIG{QUIT} = 'IGNORE';
@@ -202,13 +204,12 @@ sub replace {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  my $error = $self->SUPER::replace;
+  my $error = $self->SUPER::replace($old);
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
   }
 
-  my $options = shift;
   foreach my $optionname ( keys %{$options} ) {
     my $old = qsearchs( 'part_export_option', {
         'exportnum'   => $self->exportnum,
@@ -219,6 +220,7 @@ sub replace {
         'optionname'  => $optionname,
         'optionvalue' => $options->{$optionname},
     } );
+    $new->optionnum($old->optionnum) if $old;
     my $error = $old ? $new->replace($old) : $new->insert;
     if ( $error ) {
       $dbh->rollback if $oldAutoCommit;
@@ -226,14 +228,16 @@ sub replace {
     }
   }
 
-  #remove extraneous old options?  not necessary now, but...
-  #foreach my $opt ( grep { !exist $options->{$_->optionname} } $old->part_export_option ) {
-  #  my $error = $opt->delete;
-  #  if ( $error ) {
-  #    $dbh->rollback if $oldAutoCommit;
-  #    return $error;
-  #  }
-  #}
+  #remove extraneous old options
+  foreach my $opt (
+    grep { !exists $options->{$_->optionname} } $old->part_export_option
+  ) {
+    my $error = $opt->delete;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
 
@@ -253,6 +257,7 @@ sub check {
   my $self = shift;
   my $error = 
     $self->ut_numbern('exportnum')
+    || $self->ut_domain('machine')
     || $self->ut_number('svcpart')
     || $self->ut_alpha('exporttype')
   ;
@@ -286,6 +291,9 @@ sub part_svc {
 
 =item part_export_option
 
+Returns all options as FS::part_export_option objects (see
+L<FS::part_export_option>).
+
 =cut
 
 sub part_export_option {
@@ -295,6 +303,8 @@ sub part_export_option {
 
 =item options 
 
+Returns a list of option names and values suitable for assigning to a hash.
+
 =cut
 
 sub options {
@@ -302,7 +312,9 @@ sub options {
   map { $_->optionname => $_->optionvalue } $self->part_export_option;
 }
 
-=item option
+=item option OPTIONNAME
+
+Returns the option value for the given name, or the empty string.
 
 =cut
 
@@ -318,6 +330,11 @@ sub option {
 
 =item rebless
 
+Reblesses the object into the FS::part_export::EXPORTTYPE class, where
+EXPORTTYPE is the object's I<exporttype> field.  There should be better docs
+on how to create new exports (and they should live in their own files and be
+autoloaded-on-demand), but until then, see L</NEW EXPORT CLASSES>.
+
 =cut
 
 sub rebless {
@@ -346,7 +363,7 @@ sub export_insert {
 #  $self->$method(@_);
 #}
 
-=item export_replace
+=item export_replace NEW OLD
 
 =cut
 
@@ -366,6 +383,22 @@ sub export_delete {
   $self->_export_delete(@_);
 }
 
+#fallbacks providing useful error messages intead of infinite loops
+sub _export_insert {
+  my $self = shift;
+  return "_export_insert: unknown export type ". $self->exporttype;
+}
+
+sub _export_replace {
+  my $self = shift;
+  return "_export_replace: unknown export type ". $self->exporttype;
+}
+
+sub _export_delete {
+  my $self = shift;
+  return "_export_delete: unknown export type ". $self->exporttype;
+}
+
 =back
 
 =cut
@@ -457,10 +490,22 @@ use vars qw(@ISA);
 
 sub _export_insert {
   my($self, $svc_acct) = (shift, shift);
-  $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
-    'reply', $svc_acct->username, $svc_acct->radius_reply );
-  $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
-    'check', $svc_acct->username, $svc_acct->radius_check );
+
+  foreach my $table (qw(reply check)) {
+    my $method = "radius_$table";
+    my %attrib = $svc_acct->$method;
+    next unless keys %attrib;
+    my $error = $self->sqlradius_queue( $svc_acct->svcnum, 'insert',
+      $table, $svc_acct->username, %attrib );
+    return $error if $error;
+  }
+  my @groups = $svc_acct->radius_groups;
+  if ( @groups ) {
+    my $error = $self->sqlradius_queue( $svc_acct->svcnum, 'usergroup_insert',
+      $svc_acct->username, @groups );
+    return $error if $error;
+  }
+  '';
 }
 
 sub _export_replace {
@@ -488,8 +533,34 @@ sub _export_replace {
     }
 
     my @del = grep { !exists $new{$_} } keys %old;
-    my $error = $self->sqlradius_queue( $new->svcnum, 'sqlradius_attrib_delete',
-      $table, $new->username, @del );
+    if ( @del ) {
+      my $error = $self->sqlradius_queue( $new->svcnum, 'attrib_delete',
+        $table, $new->username, @del );
+      return $error if $error;
+    }
+  }
+
+  # (sorta) false laziness with FS::svc_acct::replace
+  my @oldgroups = @{$old->usergroup}; #uuuh
+  my @newgroups = $new->radius_groups;
+  my @delgroups = ();
+  foreach my $oldgroup ( @oldgroups ) {
+    if ( grep { $oldgroup eq $_ } @newgroups ) {
+      @newgroups = grep { $oldgroup ne $_ } @newgroups;
+      next;
+    }
+    push @delgroups, $oldgroup;
+  }
+
+  if ( @delgroups ) {
+    my $error = $self->sqlradius_queue( $new->svcnum, 'usergroup_delete',
+      $new->username, @delgroups );
+    return $error if $error;
+  }
+
+  if ( @newgroups ) {
+    my $error = $self->sqlradius_queue( $new->svcnum, 'usergroup_insert',
+      $new->username, @newgroups );
     return $error if $error;
   }
 
@@ -525,8 +596,8 @@ sub sqlradius_insert { #subroutine, not method
       "UPDATE rad$replycheck SET Value = ? WHERE UserName = ? AND Attribute = ?"    ) or die $dbh->errstr;
     my $i_sth = $dbh->prepare(
       "INSERT INTO rad$replycheck ( id, UserName, Attribute, Value ) ".
-        "VALUES ( ?, ?, ?, ? )" )
-      or die $dbh->errstr;
+        "VALUES ( ?, ?, ?, ? )"
+    ) or die $dbh->errstr;
     $u_sth->execute($attributes{$attribute}, $username, $attribute) > 0
       or $i_sth->execute( '', $username, $attribute, $attributes{$attribute} )
         or die "can't insert into rad$replycheck table: ". $i_sth->errstr;
@@ -534,10 +605,38 @@ sub sqlradius_insert { #subroutine, not method
   $dbh->disconnect;
 }
 
+sub sqlradius_usergroup_insert { #subroutine, not method
+  my $dbh = sqlradius_connect(shift, shift, shift);
+  my( $username, @groups ) = @_;
+
+  my $sth = $dbh->prepare( 
+    "INSERT INTO usergroup ( id, UserName, GroupName ) VALUES ( ?, ?, ? )"
+  ) or die $dbh->errstr;
+  foreach my $group ( @groups ) {
+    $sth->execute( '', $username, $group )
+      or die "can't insert into groupname table: ". $sth->errstr;
+  }
+  $dbh->disconnect;
+}
+
+sub sqlradius_usergroup_delete { #subroutine, not method
+  my $dbh = sqlradius_connect(shift, shift, shift);
+  my( $username, @groups ) = @_;
+
+  my $sth = $dbh->prepare( 
+    "DELETE FROM usergroup ( id, UserName, GroupName ) VALUES ( ?, ?, ? )"
+  ) or die $dbh->errstr;
+  foreach my $group ( @groups ) {
+    $sth->execute( '', $username, $group )
+      or die "can't delete from groupname table: ". $sth->errstr;
+  }
+  $dbh->disconnect;
+}
+
 sub sqlradius_rename { #subroutine, not method
   my $dbh = sqlradius_connect(shift, shift, shift);
   my($new_username, $old_username) = @_;
-  foreach my $table (qw(radreply radcheck)) {
+  foreach my $table (qw(radreply radcheck usergroup )) {
     my $sth = $dbh->prepare("UPDATE $table SET Username = ? WHERE UserName = ?")
       or die $dbh->errstr;
     $sth->execute($new_username, $old_username)
@@ -564,7 +663,7 @@ sub sqlradius_delete { #subroutine, not method
   my $dbh = sqlradius_connect(shift, shift, shift);
   my $username = shift;
 
-  foreach my $table (qw( radcheck radreply )) {
+  foreach my $table (qw( radcheck radreply usergroup )) {
     my $sth = $dbh->prepare( "DELETE FROM $table WHERE UserName = ?" );
     $sth->execute($username)
       or die "can't delete from $table table: ". $sth->errstr;