'server', 'varchar', 'NULL', 64, '', '',
'community', 'varchar', 'NULL', 50, '', '',
'description', 'varchar', '', 200, 'RADIUS Client', '',
+ 'svcnum', 'int', 'NULL', '', '', '',
],
'primary_key' => 'nasnum',
'unique' => [ [ 'nasname' ], ],
=item description - a longer descriptive name
+=item svcnum - the L<FS::svc_broadband> record that 'owns' this device
=back
) || $self->SUPER::delete;
if ( $error ) {
- $dbh->rollback;
+ $dbh->rollback if $oldAutoCommit;
return $error;
}
|| $self->ut_textn('server')
|| $self->ut_textn('community')
|| $self->ut_text('description')
+ || $self->ut_foreign_keyn('svcnum', 'svc_broadband', 'svcnum')
;
return $error if $error;
--- /dev/null
+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;
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 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;
};
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 ) {
- $self->latitude = $l->latitude;
- $self->longitude = $l->longitude;
+ $self->latitude( $l->latitude );
+ $self->longitude( $l->longitude );
}
}
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>
'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?',
#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,
? $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.
<& elements/svc_Common.html,
table => 'svc_broadband',
- fields => [ fields('svc_broadband'), 'usergroup' ],
+ fields => [ fields('svc_broadband'), fields('nas'), 'usergroup' ],
precheck_callback => \&precheck,
&>
<%init>
'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,
}
}
-
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') {
table => 'svc_broadband',
labels => \%labels,
fields => \@fields,
+ svc_callback => \&svc_callback,
&>
<%init>
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>