broadband_nas export, #15284
authormark <mark>
Wed, 28 Dec 2011 23:56:20 +0000 (23:56 +0000)
committermark <mark>
Wed, 28 Dec 2011 23:56:20 +0000 (23:56 +0000)
FS/FS/Schema.pm
FS/FS/nas.pm
FS/FS/part_export/broadband_nas.pm [new file with mode: 0644]
FS/FS/svc_broadband.pm
httemplate/browse/nas.html
httemplate/edit/nas.html
httemplate/edit/part_export.cgi
httemplate/edit/process/svc_broadband.cgi
httemplate/edit/svc_broadband.cgi
httemplate/view/svc_broadband.cgi

index bd708a7..68a072f 100644 (file)
@@ -2282,6 +2282,7 @@ sub tables_hashref {
         'server',      'varchar', 'NULL',  64,              '', '',
         'community',   'varchar', 'NULL',  50,              '', '',
         'description', 'varchar',     '', 200, 'RADIUS Client', '',
         'server',      'varchar', 'NULL',  64,              '', '',
         'community',   'varchar', 'NULL',  50,              '', '',
         'description', 'varchar',     '', 200, 'RADIUS Client', '',
+        'svcnum',          'int', 'NULL',  '',              '', '',
       ],
       'primary_key' => 'nasnum',
       'unique'      => [ [ 'nasname' ], ],
       ],
       'primary_key' => 'nasnum',
       'unique'      => [ [ 'nasname' ], ],
index af5a23a..c7f2459 100644 (file)
@@ -50,6 +50,7 @@ FS::Record.  The following fields are currently supported:
 
 =item description - a longer descriptive name
 
 
 =item description - a longer descriptive name
 
+=item svcnum - the L<FS::svc_broadband> record that 'owns' this device
 
 =back
 
 
 =back
 
@@ -94,7 +95,7 @@ sub delete {
   ) || $self->SUPER::delete;
 
   if ( $error ) {
   ) || $self->SUPER::delete;
 
   if ( $error ) {
-    $dbh->rollback;
+    $dbh->rollback if $oldAutoCommit;
     return $error;
   }
   
     return $error;
   }
   
@@ -159,6 +160,7 @@ sub check {
     || $self->ut_textn('server')
     || $self->ut_textn('community')
     || $self->ut_text('description')
     || $self->ut_textn('server')
     || $self->ut_textn('community')
     || $self->ut_text('description')
+    || $self->ut_foreign_keyn('svcnum', 'svc_broadband', 'svcnum')
   ;
   return $error if $error;
 
   ;
   return $error if $error;
 
diff --git a/FS/FS/part_export/broadband_nas.pm b/FS/FS/part_export/broadband_nas.pm
new file mode 100644 (file)
index 0000000..a160c99
--- /dev/null
@@ -0,0 +1,145 @@
+package FS::part_export::broadband_nas;
+
+use strict;
+use vars qw(%info $DEBUG);
+use base 'FS::part_export';
+use FS::Record qw(qsearch qsearchs);
+use FS::nas;
+use FS::export_nas;
+use FS::svc_broadband;
+use FS::part_export::sqlradius;
+use Tie::IxHash;
+
+$DEBUG = 0;
+
+my $me = '['.__PACKAGE__.']';
+
+tie my %options, 'Tie::IxHash',
+  '1' => { type => 'title', label => 'Defaults' },
+  default_shortname => { label => 'Short name' },
+  default_secret    => { label => 'Shared secret' },
+  default_type      => { label => 'Type' },
+  default_ports     => { label => 'Ports' },
+  default_server    => { label => 'Virtual server' },
+  default_community => { label => 'Community' },
+  '2' => { type => 'title', label => 'Export to' },
+  # default export_nas entries will be inserted at runtime
+;
+
+FS::UID->install_callback(
+  sub {
+    #creating new options based on records in a table,
+    #has to be done after initialization
+    foreach ( FS::part_export::sqlradius->all_sqlradius ) {
+      my $name = 'exportnum' . $_->exportnum;
+      $options{$name} = 
+        { type => 'checkbox', label => $_->exportnum . ': ' . $_->label };
+
+    }
+  }
+);
+
+%info = (
+  'svc'     => 'svc_broadband',
+  'desc'    => 'Create a NAS entry in Freeside',
+  'options' => \%options,
+  'weight'  => 10,
+  'notes'   => <<'END'
+<p>Create an entry in the NAS (RADIUS client) table, inheriting the IP 
+address and description of the broadband service.  This can be used 
+with 'sqlradius' or 'broadband_sqlradius' exports to maintain entries
+in the client table on a RADIUS server.</p>
+<p>Most broadband configurations should not use this, even if they use 
+RADIUS for access control.</p>
+END
+);
+
+=item export_insert NEWSVC
+
+=item export_replace NEWSVC OLDSVC
+
+NEWSVC can contain pseudo-field entries for fields in nas.  Those changes 
+will be applied to the attached NAS record.
+
+=cut
+
+sub export_insert {
+  my $self = shift;
+  my $svc_broadband = shift;
+  my %hash = map { $_ => $svc_broadband->get($_) } FS::nas->fields;
+  my $nas = $self->default_nas(
+    %hash,
+    'nasname'     => $svc_broadband->ip_addr,
+    'description' => $svc_broadband->description,
+    'svcnum'      => $svc_broadband->svcnum,
+  );
+
+  my $error = 
+      $nas->insert()
+   || $nas->process_m2m('link_table' => 'export_nas',
+                        'target_table' => 'part_export',
+                        'params' => { $self->options });
+  die $error if $error;
+  return;
+}
+
+sub export_delete {
+  my $self = shift;
+  my $svc_broadband = shift;
+  my $svcnum = $svc_broadband->svcnum;
+  my $nas = qsearchs('nas', { 'svcnum' => $svcnum });
+  if ( !$nas ) {
+    # we were going to delete it anyway...
+    warn "linked NAS with svcnum $svcnum not found for deletion\n";
+    return;
+  }
+  my $error = $nas->delete; # will clean up export_nas records
+  die $error if $error;
+  return;
+}
+
+sub export_replace {
+  my $self = shift;
+  my ($new_svc, $old_svc) = (shift, shift);
+
+  my $svcnum = $new_svc->svcnum;
+  my $nas = qsearchs('nas', { 'svcnum' => $svcnum });
+  if ( !$nas ) {
+    warn "linked nas with svcnum $svcnum not found for update, creating new\n";
+    # then we should insert it
+    # (this happens if the nas table is wiped out, or if the broadband_nas 
+    # export is newly applied to an existing svcpart)
+    return $self->export_insert($new_svc);
+  }
+
+  my %hash = $new_svc->hash;
+  foreach (FS::nas->fields) {
+    $nas->set($_, $hash{$_}) if exists($hash{$_});
+  }
+  
+  $nas->nasname($new_svc->ip_addr); # this must always be true
+
+  my $error = $nas->replace;
+  die $error if $error;
+  return;
+}
+
+=item default_nas HASH
+
+Returns a new L<FS::nas> object containing the default values, plus anything
+in HASH.
+
+=cut
+
+sub default_nas {
+  my $self = shift;
+  FS::nas->new({
+    map( { $_ => $self->option("default_$_") }
+      qw(shortname type ports secret server community)
+    ),
+    @_
+  });
+}
+
+
+1;
index 1d1fa76..a85fc5c 100755 (executable)
@@ -2,6 +2,8 @@ package FS::svc_broadband;
 
 use strict;
 use vars qw(@ISA $conf);
 
 use strict;
 use vars qw(@ISA $conf);
+
+use base qw(FS::svc_Radius_Mixin FS::svc_Tower_Mixin FS::svc_Common);
 use NetAddr::IP;
 use FS::Record qw( qsearchs qsearch dbh );
 use FS::svc_Common;
 use NetAddr::IP;
 use FS::Record qw( qsearchs qsearch dbh );
 use FS::svc_Common;
@@ -10,8 +12,6 @@ use FS::addr_block;
 use FS::part_svc_router;
 use FS::tower_sector;
 
 use FS::part_svc_router;
 use FS::tower_sector;
 
-@ISA = qw( FS::svc_Radius_Mixin FS::svc_Tower_Mixin FS::svc_Common );
-
 $FS::UID::callback{'FS::svc_broadband'} = sub { 
   $conf = new FS::Conf;
 };
 $FS::UID::callback{'FS::svc_broadband'} = sub { 
   $conf = new FS::Conf;
 };
@@ -398,11 +398,11 @@ sub check {
   if ( $cust_pkg && ! $self->latitude && ! $self->longitude ) {
     my $l = $cust_pkg->cust_location_or_main;
     if ( $l->ship_latitude && $l->ship_longitude ) {
   if ( $cust_pkg && ! $self->latitude && ! $self->longitude ) {
     my $l = $cust_pkg->cust_location_or_main;
     if ( $l->ship_latitude && $l->ship_longitude ) {
-      $self->latitude  = $l->ship_latitude;
-      $self->longitude = $l->ship_longitude;
+      $self->latitude(  $l->ship_latitude  );
+      $self->longitude( $l->ship_longitude );
     } elsif ( $l->latitude && $l->longitude ) {
     } elsif ( $l->latitude && $l->longitude ) {
-      $self->latitude  = $l->latitude;
-      $self->longitude = $l->longitude;
+      $self->latitude(  $l->latitude  );
+      $self->longitude( $l->longitude );
     }
   }
 
     }
   }
 
index c9d57e8..5ce729b 100644 (file)
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
 
 die "access denied"
   unless $FS::CurrentUser::CurrentUser->access_right('Configuration');
 
-my $link = [ $p.'edit/nas.html?', 'nasnum' ];
+my $link = sub {
+  my $nas = shift;
+  if ( $nas->svcnum ) {
+    return [ $p.'view/svc_broadband.cgi?', 'svcnum' ];
+  }
+  else {
+    return [ $p.'edit/nas.html?', 'nasnum' ];
+  }
+};
 
 </%init>
 
 </%init>
index 9d9b8e9..2e66fc3 100644 (file)
@@ -48,7 +48,9 @@ sub html_bottom {
             'source_obj'    => $nas,
             'link_table'    => 'export_nas',
             'target_table'  => 'part_export',
             'source_obj'    => $nas,
             'link_table'    => 'export_nas',
             'target_table'  => 'part_export',
-            'hashref'       => { 'exporttype' => 'sqlradius' },
+            'hashref'       => { 'exporttype' => 
+                                  { op => 'LIKE', value => '%sqlradius' }
+                                },
             'name_callback' => sub { $_[0]->label },
             'default'       => 'yes',
             'target_link'   => $p.'edit/part_export.cgi?',
             'name_callback' => sub { $_[0]->label },
             'default'       => 'yes',
             'target_link'   => $p.'edit/part_export.cgi?',
index 9a0e0bd..1450ac3 100644 (file)
@@ -51,8 +51,12 @@ $action ||= $part_export->exportnum ? 'Edit' : 'Add';
 #my $exports = FS::part_export::export_info($svcdb);
 my $exports = FS::part_export::export_info();
 
 #my $exports = FS::part_export::export_info($svcdb);
 my $exports = FS::part_export::export_info();
 
-my %layers = map { $_ => "$_ - ". $exports->{$_}{desc} } keys %$exports;
-$layers{''}='';
+tie my %layers, 'Tie::IxHash',
+  '' => '',
+  map { $_ => "$_ - ". $exports->{$_}{desc} } 
+  sort { $a cmp $b }
+  keys %$exports;
+;
 
 my $widget = new HTML::Widgets::SelectLayers(
   'selected_layer' => $part_export->exporttype,
 
 my $widget = new HTML::Widgets::SelectLayers(
   'selected_layer' => $part_export->exporttype,
@@ -83,6 +87,13 @@ my $widget = new HTML::Widgets::SelectLayers(
                       ? $optinfo->{default}
                       : ''
                     );
                       ? $optinfo->{default}
                       : ''
                     );
+      if ( $type eq 'title' ) {
+        $html .= qq!<TR><TH COLSPAN=1 ALIGN="right"><FONT SIZE="+1">! .
+                 $label .
+                 '</FONT></TH></TR>';
+        next;
+      }
+
       # 'freeform': disables table formatting of options.  Instead, each 
       # option can define "before" and "after" strings which are inserted 
       # around the selector.
       # 'freeform': disables table formatting of options.  Instead, each 
       # option can define "before" and "after" strings which are inserted 
       # around the selector.
index 36c64d1..4184f5f 100644 (file)
@@ -1,6 +1,6 @@
 <& elements/svc_Common.html,
   table       => 'svc_broadband',
 <& elements/svc_Common.html,
   table       => 'svc_broadband',
-  fields      => [ fields('svc_broadband'), 'usergroup' ],
+  fields      => [ fields('svc_broadband'), fields('nas'), 'usergroup' ],
   precheck_callback => \&precheck,
 &>
 <%init>
   precheck_callback => \&precheck,
 &>
 <%init>
index ad4d604..b9e2fd2 100644 (file)
@@ -3,7 +3,9 @@
      'name'                 => 'broadband service',
      'table'                => 'svc_broadband',
      'fields'               => \@fields, 
      'name'                 => 'broadband service',
      'table'                => 'svc_broadband',
      'fields'               => \@fields, 
-     'field_callback'       => $callback,
+     'field_callback'       => $field_callback,
+     'svc_new_callback'     => $svc_edit_callback,
+     'svc_edit_callback'    => $svc_edit_callback,
      'dummy'                => $cgi->query_string,
      'onsubmit'             => 'validate_coords',
      'html_foot'            => $js,
      'dummy'                => $cgi->query_string,
      'onsubmit'             => 'validate_coords',
      'html_foot'            => $js,
@@ -113,17 +115,57 @@ if ( $conf->exists('svc_broadband-radius') ) {
   }
 }
 
   }
 }
 
-
 my $fixedblock = '';
 
 my $fixedblock = '';
 
-my $callback = sub {
-  my ($cgi, $object, $fieldref) = @_;
+my $part_svc;
+
+my $svc_edit_callback = sub {
+  my ($cgi, $svc_x, $part_svc_x, $cust_pkg, $fields, $opt) = @_;
+
+  $part_svc = $part_svc_x; #for field_callback to use
 
 
-  my $svcpart = $object->svcnum ? $object->cust_svc->svcpart
-                                : $cgi->param('svcpart');
+  $opt->{'labels'}{'block_label'} = 'Block';
 
 
-  my $part_svc = qsearchs( 'part_svc', { svcpart => $svcpart } );
-  die "No part_svc entry!" unless $part_svc;
+  my ($nas_export) = $part_svc->part_export('broadband_nas');
+  #can we assume there's only one of these per part_svc?
+  if ( $nas_export ) {
+    my $nas;
+    if ( $svc_x->svcnum ) {
+      $nas = qsearchs('nas', { 'svcnum' => $svc_x->svcnum });
+    }
+    $nas ||= $nas_export->default_nas;
+    $svc_x->set($_, $nas->$_) foreach fields('nas');
+
+    # duplicates the fields in httemplate/edit/nas.html (mostly)
+    push @$fields,
+      { type  => 'tablebreak-tr-title', 
+        #value => 'Attached NAS',
+        value => $nas_export->exportname,
+        colspan => 2,
+      },
+      { field=>'nasnum', type=>'hidden', },
+      { field=>'shortname', size=>16, maxlength=>32 },
+      { field=>'secret', size=>40, maxlength=>60, required=>1 },
+      { field=>'type', type=>'select',
+        options=>[qw( cisco computone livingston max40xx multitech netserver
+        pathras patton portslave tc usrhiper other )],
+      },
+      { field=>'ports', size=>5 },
+      { field=>'server', size=>40, maxlength=>64 },
+      { field=>'community', size=>40, maxlength=>50 },
+    ;
+
+    $opt->{'labels'}{'shortname'} = 'Short name';
+    $opt->{'labels'}{'secret'}    = 'Shared secret';
+    $opt->{'labels'}{'type'}      = 'Type';
+    $opt->{'labels'}{'ports'}     = 'Ports';
+    $opt->{'labels'}{'server'}    = 'Server';
+    $opt->{'labels'}{'community'} = 'Community';
+  }
+};
+
+my $field_callback = sub {
+  my ($cgi, $object, $fieldref) = @_;
 
   my $columndef = $part_svc->part_svc_column($fieldref->{'field'});
   if ($columndef->columnflag eq 'F') {
 
   my $columndef = $part_svc->part_svc_column($fieldref->{'field'});
   if ($columndef->columnflag eq 'F') {
index de39f6a..2e93d42 100644 (file)
@@ -2,6 +2,7 @@
   table   => 'svc_broadband',
   labels  => \%labels,
   fields  => \@fields,
   table   => 'svc_broadband',
   labels  => \%labels,
   fields  => \@fields,
+  svc_callback => \&svc_callback,
 &>
 <%init>
 
 &>
 <%init>
 
@@ -97,4 +98,25 @@ sub coordinates {
     include('/elements/coord-links.html', $s->latitude, $s->longitude, $d);
 }
 
     include('/elements/coord-links.html', $s->latitude, $s->longitude, $d);
 }
 
+sub svc_callback {
+  # trying to move to the callback style
+  my ($cgi, $svc_x, $part_svc, $cust_pkg, $fields, $opt) = @_;
+  # again, we assume at most one of these exports per part_svc
+  my ($nas_export) = $part_svc->part_export('broadband_nas');
+  if ( $nas_export ) {
+    my $nas = qsearchs('nas', { 'svcnum' => $svc_x->svcnum });
+    if ( $nas ) {
+      $svc_x->set($_, $nas->$_) foreach (fields('nas'));
+      push @$fields, qw(shortname secret type ports server community);
+      $opt->{'labels'}{'shortname'}  = 'Short name';
+      $opt->{'labels'}{'secret'}     = 'Shared secret';
+      $opt->{'labels'}{'type'}       = 'Type';
+      $opt->{'labels'}{'ports'}      = 'Ports';
+      $opt->{'labels'}{'server'}     = 'Server';
+      $opt->{'labels'}{'community'}  = 'Community';
+    } #if $nas
+  } #$nas_export
+};
+
+
 </%init>
 </%init>