diff options
| author | ivan <ivan> | 2011-10-06 07:02:49 +0000 | 
|---|---|---|
| committer | ivan <ivan> | 2011-10-06 07:02:49 +0000 | 
| commit | 14c5096e04f0d1ac2a19a3c6c41e537a9aa0f78c (patch) | |
| tree | 4b87a5eb5ec1acac9ac60c50fc79f1138de4338d | |
| parent | ce18f284969a1eaed7985a91123a275a57090e12 (diff) | |
add dsl_device to track mac addresses, RT#13656
| -rw-r--r-- | FS/FS/ClientAPI/MyAccount.pm | 78 | ||||
| -rw-r--r-- | FS/FS/ClientAPI_XMLRPC.pm | 3 | ||||
| -rw-r--r-- | FS/FS/Record.pm | 36 | ||||
| -rw-r--r-- | FS/FS/dsl_device.pm | 2 | ||||
| -rw-r--r-- | FS/FS/svc_dsl.pm | 13 | ||||
| -rw-r--r-- | FS/MANIFEST | 2 | ||||
| -rw-r--r-- | FS/t/dsl_device.t | 5 | ||||
| -rw-r--r-- | fs_selfservice/FS-SelfService/SelfService.pm | 3 | ||||
| -rw-r--r-- | httemplate/edit/dsl_device.html | 31 | ||||
| -rw-r--r-- | httemplate/edit/process/dsl_device.html | 22 | ||||
| -rwxr-xr-x | httemplate/misc/delete-dsl_device.html | 23 | ||||
| -rw-r--r-- | httemplate/view/elements/svc_devices.html | 102 | ||||
| -rw-r--r-- | httemplate/view/svc_dsl.cgi | 65 | 
13 files changed, 357 insertions, 28 deletions
| diff --git a/FS/FS/ClientAPI/MyAccount.pm b/FS/FS/ClientAPI/MyAccount.pm index 3976ab239..e3afac14a 100644 --- a/FS/FS/ClientAPI/MyAccount.pm +++ b/FS/FS/ClientAPI/MyAccount.pm @@ -25,6 +25,8 @@ use FS::svc_acct;  use FS::svc_domain;  use FS::svc_phone;  use FS::svc_external; +use FS::svc_dsl; +use FS::dsl_device;  use FS::part_svc;  use FS::cust_main;  use FS::cust_bill; @@ -1403,6 +1405,82 @@ sub list_svcs {  } +sub _customer_svc_x { +  my($custnum, $svcnum, $table) = @_; + +  $custnum =~ /^(\d+)$/ or die "illegal custnum"; +  my $search = " AND custnum = $1"; +  #$search .= " AND agentnum = ". $session->{'agentnum'} if $context eq 'agent'; + +  qsearchs( { +    'table'     => ($table || 'svc_acct'), +    'addl_from' => 'LEFT JOIN cust_svc  USING ( svcnum  ) '. +                   'LEFT JOIN cust_pkg  USING ( pkgnum  ) ',#. +                   #'LEFT JOIN cust_main USING ( custnum ) ', +    'hashref'   => { 'svcnum' => $svcnum, }, +    'extra_sql' => $search, #important +  } ); + +} + +sub list_dsl_devices { +  my $p = shift; + +  my($context, $session, $custnum) = _custoragent_session_custnum($p); +  return { 'error' => $session } if $context eq 'error'; + +  my $svc_dsl = _customer_svc_x( $custnum, $p->{'svcnum'}, 'svc_dsl' ) +    or return { 'error' => "Service not found" }; + +  return { +    'devices' => [ map { +                         +{ 'mac_addr' => $_->mac_addr }; +                       } $svc_dsl->dsl_device +                 ], +  }; + +} + +sub add_dsl_device { +  my $p = shift; + +  my($context, $session, $custnum) = _custoragent_session_custnum($p); +  return { 'error' => $session } if $context eq 'error'; + +  my $svc_dsl = _customer_svc_x( $custnum, $p->{'svcnum'}, 'svc_dsl' ) +    or return { 'error' => "Service not found" }; + +  return { 'error' => 'No MAC address supplied' } +    unless length($p->{'mac_addr'}); + +  my $dsl_device = new FS::dsl_device { 'svcnum'   => $svc_dsl->svcnum, +                                        'mac_addr' => scalar($p->{'mac_addr'}), +                                      }; +  my $error = $dsl_device->insert; +  return { 'error' => $error }; + +} + +sub delete_dsl_device { +  my $p = shift; + +  my($context, $session, $custnum) = _custoragent_session_custnum($p); +  return { 'error' => $session } if $context eq 'error'; + +  my $svc_dsl = _customer_svc_x( $custnum, $p->{'svcnum'}, 'svc_dsl' ) +    or return { 'error' => "Service not found" }; + +  my $dsl_device = qsearchs('dsl_device', { 'svcnum'   => $svc_dsl->svcnum, +                                            'mac_addr' => scalar($p->{'mac_addr'}), +                                          } +                           ) +    or return { 'error' => 'Unknown MAC address: '. $p->{'mac_addr'} }; + +  my $error = $dsl_device->delete; +  return { 'error' => $error }; + +} +  sub port_graph {    my $p = shift;    _usage_details( \&_port_graph, $p, diff --git a/FS/FS/ClientAPI_XMLRPC.pm b/FS/FS/ClientAPI_XMLRPC.pm index b077bf27a..2913ffd47 100644 --- a/FS/FS/ClientAPI_XMLRPC.pm +++ b/FS/FS/ClientAPI_XMLRPC.pm @@ -87,6 +87,9 @@ sub ss2clientapi {    'list_pkgs'                 => 'MyAccount/list_pkgs',     #add to ss (added?)    'list_svcs'                 => 'MyAccount/list_svcs',     #add to ss (added?)    'list_svc_usage'            => 'MyAccount/list_svc_usage',    +  'list_dsl_devices'          => 'MyAccount/list_dsl_devices',    +  'add_dsl_device'            => 'MyAccount/add_dsl_device',    +  'delete_dsl_device'         => 'MyAccount/delete_dsl_device',       'port_graph'                => 'MyAccount/port_graph',       'list_cdr_usage'            => 'MyAccount/list_cdr_usage',       'list_support_usage'        => 'MyAccount/list_support_usage',    diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index bccc8e6d4..2fec8e00f 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -2385,6 +2385,42 @@ sub ut_hexn {    $self->setfield($field, uc($1));    '';  } + +=item ut_mac_addr COLUMN + +Check/untaint mac addresses.  May be null. + +=cut + +sub ut_mac_addr { +  my($self, $field) = @_; + +  my $mac = $self->get($field); +  $mac =~ s/\s+//g; +  $mac =~ s/://g; +  $self->set($field, $mac); + +  my $e = $self->ut_hex($field); +  return $e if $e; + +  return "Illegal (mac address) $field: ". $self->getfield($field) +    unless length($self->getfield($field)) == 12; + +  ''; + +} + +=item ut_mac_addrn COLUMN + +Check/untaint mac addresses.  May be null. + +=cut + +sub ut_mac_addrn { +  my($self, $field) = @_; +  ($self->getfield($field) eq '') ? '' : $self->ut_mac_addr($field); +} +  =item ut_ip COLUMN  Check/untaint ip addresses.  IPv4 only for now, though ::1 is auto-translated diff --git a/FS/FS/dsl_device.pm b/FS/FS/dsl_device.pm index 276eedd64..2efe1f56e 100644 --- a/FS/FS/dsl_device.pm +++ b/FS/FS/dsl_device.pm @@ -106,7 +106,7 @@ sub check {    my $error =       $self->ut_numbern('devicenum')      || $self->ut_foreign_key('svcnum', 'svc_dsl', 'svcnum' ) -    || $self->ut_mac_addrn('mac_addr') +    || $self->ut_mac_addr('mac_addr')    ;    return $error if $error; diff --git a/FS/FS/svc_dsl.pm b/FS/FS/svc_dsl.pm index ce4342e27..89f1159bd 100644 --- a/FS/FS/svc_dsl.pm +++ b/FS/FS/svc_dsl.pm @@ -4,6 +4,7 @@ use strict;  use vars qw( @ISA $conf $DEBUG $me );  use FS::Record qw( qsearch qsearchs );  use FS::svc_Common; +use FS::dsl_device;  use FS::dsl_note;  use FS::qual; @@ -273,6 +274,18 @@ sub check {    $self->SUPER::check;  } +=item dsl_device + +Returns the MAC addresses associated with this DSL service, as FS::dsl_device +objects. + +=cut + +sub dsl_device { +  my $self = shift; +  qsearch('dsl_device', { 'svcnum' => $self->svcnum }); +} +  sub predelete_hook_first {      my $self = shift;      my @exports = $self->part_svc->part_export_dsl_pull; diff --git a/FS/MANIFEST b/FS/MANIFEST index 43a1ed87e..557e61279 100644 --- a/FS/MANIFEST +++ b/FS/MANIFEST @@ -610,3 +610,5 @@ FS/radius_group.pm  t/radius_group.t  FS/template_content.pm  t/template_content.t +FS/dsl_device.pm +t/dsl_device.t diff --git a/FS/t/dsl_device.t b/FS/t/dsl_device.t new file mode 100644 index 000000000..2e97424b8 --- /dev/null +++ b/FS/t/dsl_device.t @@ -0,0 +1,5 @@ +BEGIN { $| = 1; print "1..1\n" } +END {print "not ok 1\n" unless $loaded;} +use FS::dsl_device; +$loaded=1; +print "ok 1\n"; diff --git a/fs_selfservice/FS-SelfService/SelfService.pm b/fs_selfservice/FS-SelfService/SelfService.pm index e778f79c2..356784642 100644 --- a/fs_selfservice/FS-SelfService/SelfService.pm +++ b/fs_selfservice/FS-SelfService/SelfService.pm @@ -49,6 +49,9 @@ $socket .= '.'.$tag if defined $tag && length($tag);    'list_pkgs'                 => 'MyAccount/list_pkgs',     #add to ss (added?)    'list_svcs'                 => 'MyAccount/list_svcs',     #add to ss (added?)    'list_svc_usage'            => 'MyAccount/list_svc_usage',    +  'list_dsl_devices'          => 'MyAccount/list_dsl_devices',    +  'add_dsl_device'            => 'MyAccount/add_dsl_device',    +  'delete_dsl_device'         => 'MyAccount/delete_dsl_device',       'port_graph'                => 'MyAccount/port_graph',       'list_cdr_usage'            => 'MyAccount/list_cdr_usage',       'list_support_usage'        => 'MyAccount/list_support_usage',    diff --git a/httemplate/edit/dsl_device.html b/httemplate/edit/dsl_device.html new file mode 100644 index 000000000..0d20fe522 --- /dev/null +++ b/httemplate/edit/dsl_device.html @@ -0,0 +1,31 @@ +<% include( 'elements/edit.html', +                 'name'   => 'DSL device', +                 'table'  => 'dsl_device', +                 'labels' => {  +                               'devicenum'  => 'Device', +                               'mac_addr'   => 'MAC address', +                             }, +                 'fields' => [ { field => 'mac_addr', +			         type => 'select-mac', +			       }, +                               { 'field' => 'svcnum', +                                 'type'  => 'hidden', +                               }, +                             ], +                 'menubar' => [], #disable viewall +                 #'viewall_dir' => 'browse', +                 'new_callback' => sub { +                                     my( $cgi, $object ) = @_; +                                     $object->svcnum( $cgi->param('svcnum') ); +                                   }, +           ) +%> +<%init> + +# :/  needs agent-virt so you can't futz with arbitrary devices + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + + +</%init> diff --git a/httemplate/edit/process/dsl_device.html b/httemplate/edit/process/dsl_device.html new file mode 100644 index 000000000..4dd53d444 --- /dev/null +++ b/httemplate/edit/process/dsl_device.html @@ -0,0 +1,22 @@ +<% include( 'elements/process.html', +               'table'    => 'dsl_device', +               'redirect' => sub { +                 my( $cgi, $dsl_device ) = @_; +                 popurl(3).'view/svc_dsl.cgi?'. +                   'svcnum='. $dsl_device->svcnum. +                   ';devicenum='; +               }, +           ) +%> +<%init> + +if($cgi->param('sel_mac_addr') && !$cgi->param('mac_addr')) { +    $cgi->param('mac_addr',$cgi->param('sel_mac_addr')); +} + +# :/  needs agent-virt so you can't futz with arbitrary devices + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +</%init> diff --git a/httemplate/misc/delete-dsl_device.html b/httemplate/misc/delete-dsl_device.html new file mode 100755 index 000000000..0b985faa7 --- /dev/null +++ b/httemplate/misc/delete-dsl_device.html @@ -0,0 +1,23 @@ +% if ( $error ) { +%   errorpage($error); +% } else { +<% $cgi->redirect($p. "view/svc_dsl.cgi?". $svcnum) %> +% } +<%init> + +# :/  needs agent-virt so you can't futz with arbitrary devices + +die "access denied" +  unless $FS::CurrentUser::CurrentUser->access_right('Provision customer service'); #something else more specific? + +#untaint devicenum +my($query) = $cgi->keywords; +$query =~ /^(\d+)$/ || die "Illegal devicenum"; +my $devicenum = $1; + +my $dsl_device = qsearchs('dsl_device', { 'devicenum' => $devicenum } ); +my $svcnum = $dsl_device->svcnum; + +my $error = $dsl_device->delete; + +</%init> diff --git a/httemplate/view/elements/svc_devices.html b/httemplate/view/elements/svc_devices.html new file mode 100644 index 000000000..d71c82f07 --- /dev/null +++ b/httemplate/view/elements/svc_devices.html @@ -0,0 +1,102 @@ +<%doc> + +#Example: + +  include( 'elements/svc_devices.html', +             #required +             'svc_x' => $svc_phone,     #or $svc_dsl +             'table' => 'phone_device', #or dsl_device + +             #optional +             'no_edit' => 0, #set true to turn off edit link +         ) + +</%doc> +<% $devices %> +<%init> + +  my %opt = @_; +  my $table = $opt{'table'}; #part_device, dsl_device +  my $svc_x = $opt{'svc_x'}; + +  my $devices = ''; + +  my $num_part_device = 0; +  if ( $table eq 'phone_device' )  { +    my $sth = dbh->prepare("SELECT COUNT(*) FROM part_device") +                              #WHERE disabled = '' OR disabled IS NULL;"); +      or die dbh->errstr; +    $sth->execute or die $sth->errstr; +    $num_part_device = $sth->fetchrow_arrayref->[0]; +} + +  my @devices = $svc_x->$table(); + +  #should move the below to proper mason code above instead of making $devices +  if ( @devices || $num_part_device || $table eq 'dsl_device' ) { +    my $svcnum = $svc_x->svcnum; +    $devices .= +      qq[Devices (<A HREF="${p}edit/$table.html?svcnum=$svcnum">Add device</A>)<BR>]; +    if ( @devices ) { + +      $devices .= qq! +        <SCRIPT> +          function areyousure(href) { +           if (confirm("Are you sure you want to delete this device?") == true) +             window.location.href = href; +          } +        </SCRIPT> +      !; + + +      $devices .=  +        include('/elements/table-grid.html'). +          '<TR>'; + +      $devices .= +            '<TH CLASS="grid" BGCOLOR="#cccccc">Type</TH>' +        if $table eq 'phone_device'; + +      $devices .= +            '<TH CLASS="grid" BGCOLOR="#cccccc">MAC Addr</TH>'. +            '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'. +            '<TH CLASS="grid" BGCOLOR="#cccccc"></TH>'. +          '</TR>'; +      my $bgcolor1 = '#eeeeee'; +      my $bgcolor2 = '#ffffff'; +      my $bgcolor = ''; + +      foreach my $device ( @devices ) { + +        if ( $bgcolor eq $bgcolor1 ) { +          $bgcolor = $bgcolor2; +        } else { +          $bgcolor = $bgcolor1; +        } +        my $td = qq(<TD CLASS="grid" BGCOLOR="$bgcolor">); + +        my $devicenum = $device->devicenum; +        my $export_links = join( '<BR>', @{ $device->export_links } ) +          if $device->can('export_links'); + +        $devices .= '<TR>'; +        $devices .= $td. $device->part_device->devicename. '</TD>' +          if $table eq 'phone_device'; #$devices->can('part_device'); + +        $devices .=   $td. $device->mac_addr. '</TD>'. +                      $td. $export_links. '</TD>'. +                      "$td( "; + +        $devices .= qq(<A HREF="${p}edit/$table.html?$devicenum">edit</A> | ) +          unless $opt{'no_edit'}; + +        $devices .= qq(<A HREF="javascript:areyousure('${p}misc/delete-$table.html?$devicenum')">delete</A>). +                      ' )</TD>'. +                    '</TR>'; +      } +      $devices .= '</TABLE><BR>'; +    } +    $devices .= '<BR>'; +  } + +</%init> diff --git a/httemplate/view/svc_dsl.cgi b/httemplate/view/svc_dsl.cgi index 9d9134a4d..477da268b 100644 --- a/httemplate/view/svc_dsl.cgi +++ b/httemplate/view/svc_dsl.cgi @@ -33,33 +33,44 @@ my $svc_cb = sub {      # if no DSL-pulling exports, then just display everything, which is the      # default behaviour implemented above -    return if ( scalar(@exports) == 0 ); - -    my $export = @exports[0]; - -    @fields = ( 'phonenum', -            { field => 'loop_type',  -              value => 'FS::part_export::'.$export->exporttype.'::loop_type_long' -            }, -            { field => 'desired_due_date', type => 'date', }, -            { field => 'due_date', type => 'date', }, -            { field => 'pushed', type => 'datetime', }, -            { field => 'monitored', type => 'checkbox', }, -            { field => 'last_pull', type => 'datetime', }, -            'first', -            'last', -            'company'  ); - -    my $status = ''; -    if($export->exporttype eq 'ikano') { -        push @fields, qw ( username password isp_chg isp_prev staticips ); -        $status = "Ikano " . $svc_dsl->vendor_order_type . " order #" -                . $svc_dsl->vendor_order_id . "   Status: "  -                . $svc_dsl->vendor_order_status; -    } -    # else add any other export-specific stuff here +    if ( scalar(@exports) ) { + +      my $export = @exports[0]; + +      @fields = ( +        'phonenum', +        { field => 'loop_type',  +          value => 'FS::part_export::'.$export->exporttype.'::loop_type_long' +        }, +        { field => 'desired_due_date', type => 'date', }, +        { field => 'due_date', type => 'date', }, +        { field => 'pushed', type => 'datetime', }, +        { field => 'monitored', type => 'checkbox', }, +        { field => 'last_pull', type => 'datetime', }, +        'first', +        'last', +        'company', +      ); + +      my $status = ''; +      if($export->exporttype eq 'ikano') { +          push @fields, qw ( username password isp_chg isp_prev staticips ); +          $status = "Ikano " . $svc_dsl->vendor_order_type . " order #" +                  . $svc_dsl->vendor_order_id . "   Status: "  +                  . $svc_dsl->vendor_order_status; +      } +      # else add any other export-specific stuff here -    $footer = "<B>$status</B>"; +      $footer = "<B>$status</B>"; + +    } + +    $footer .= '<BR><BR>'. +               include( '/view/elements/svc_devices.html', +                          'svc_x'   => $svc_dsl, +                          'table'   => 'dsl_device', +                          'no_edit' => 1, +                      );      my @notes = $svc_dsl->notes;      if ( @notes ) { @@ -68,7 +79,7 @@ my $svc_cb = sub {        my $date_format = $conf->config('date_format') || '%m/%d/%Y';        $footer .= -        "<BR><BR>Order Notes<BR>". ntable('#cccccc', 2). #id="dsl_notes" +        "Order Notes<BR>". ntable('#cccccc', 2). #id="dsl_notes"          '<TR><TH>Date</TH><TH>By</TH><TH>Priority</TH><TH>Note</TH></TR>';        foreach my $note ( @notes ) { | 
