[freeside-commits] branch FREESIDE_4_BRANCH updated. 2f4438896ca993e27b14d949e4195b2a173a3179

Mitch Jackson mitch at freeside.biz
Tue Oct 23 14:08:40 PDT 2018


The branch, FREESIDE_4_BRANCH has been updated
       via  2f4438896ca993e27b14d949e4195b2a173a3179 (commit)
       via  0ce4dcd4dad9777fe4c6436a3308a81496ae9ac3 (commit)
       via  ead0cc76f66c0806321443657b49f829034e23ae (commit)
       via  34106a87f830297c8ad676599ef170f5e4ec53ba (commit)
       via  3c26afebaaada34db1028184571f0fb38e5b74bf (commit)
       via  714d702814b985d90eb8224ee914b0c898b66a58 (commit)
      from  c18ec0f6b17d602909aaa2cbbe06fff4dcba98ec (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 2f4438896ca993e27b14d949e4195b2a173a3179
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Sun Jul 8 20:02:25 2018 -0500

    RT# 30783 js fix for ip selection

diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html
index eac41cfad..72640d3d5 100644
--- a/httemplate/elements/tr-select-router_block_ip.html
+++ b/httemplate/elements/tr-select-router_block_ip.html
@@ -4,8 +4,8 @@ var ip_addr_curr_value = <% $opt{'ip_addr'} |js_string %>;
 var blocknum_curr_value = <% $opt{'blocknum'} |js_string %>;
 
 function update_ip_addr() {
-  var routernum = $('#router_select_0').val();
-  var blocknum  = $('#router_select_1').val();
+  var routernum = $('#router_select_0').val() || "";
+  var blocknum  = $('#router_select_1').val() || "";
   var e_input_ip_addr = $('#input_ip_addr');
   var e_router_select_1 = $('#router_select_1');
 

commit 0ce4dcd4dad9777fe4c6436a3308a81496ae9ac3
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Fri Jun 29 13:04:33 2018 -0500

    RT# 30783 Clean up json code for free_addrs

diff --git a/FS/FS/svc_IP_Mixin.pm b/FS/FS/svc_IP_Mixin.pm
index 499abb8ac..e0b04c6ab 100644
--- a/FS/FS/svc_IP_Mixin.pm
+++ b/FS/FS/svc_IP_Mixin.pm
@@ -132,7 +132,7 @@ sub _used_addresses {
   #       parameter to bypass FS::Record objects creation and just
   #       return hashrefs from DBI.  200,000 hashrefs are many seconds faster
   #       than 200,000 FS::Record objects
-  my %qsearch = (
+  my %qsearch_param = (
       table     => $class->table,
       select    => $ip_field,
       hashref   => \%qsearch,
@@ -140,7 +140,8 @@ sub _used_addresses {
   );
   if ( $octets ) {
     my $block_str = join('.', (split(/\D/, $block_na->first))[0..$octets-1]);
-    $qsearch{extra_sql} .= " AND $ip_field LIKE ".dbh->quote("${block_str}.%");
+    $qsearch_param{extra_sql}
+      .= " AND $ip_field LIKE ".dbh->quote("${block_str}.%");
   }
 
   if ( $block->ip_netmask % 8 ) {
@@ -154,7 +155,7 @@ sub _used_addresses {
 
   return
     map { $_->$ip_field }
-    qsearch( \%qsearch );
+    qsearch( \%qsearch_param );
 }
 
 sub _is_used {
diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html
index 535e953c4..eac41cfad 100644
--- a/httemplate/elements/tr-select-router_block_ip.html
+++ b/httemplate/elements/tr-select-router_block_ip.html
@@ -71,7 +71,7 @@ function populate_ip_select() {
 % }
   if ( blocknum && $.isNumeric(blocknum) && ! e.is(':hidden')) {
     $.getJSON(
-      '<% $p %>json/free_addresses_in_block.json.html',
+      '<% $p %>misc/xmlhttp-free_addresses_in_block.json.html',
       {blocknum: blocknum},
       function(ip_json) {
         $.each( ip_json, function(idx, val) {
diff --git a/httemplate/json/free_addresses_in_block.json.html b/httemplate/misc/xmlhttp-free_addresses_in_block.json.html
similarity index 94%
rename from httemplate/json/free_addresses_in_block.json.html
rename to httemplate/misc/xmlhttp-free_addresses_in_block.json.html
index 6785aac6b..801718d35 100644
--- a/httemplate/json/free_addresses_in_block.json.html
+++ b/httemplate/misc/xmlhttp-free_addresses_in_block.json.html
@@ -3,7 +3,7 @@
   Unless block is larger than /24 - Does somebody really want to populate
   65k addresses into a HTML selectbox?
 </%doc>
-<% encode_rest($json) %>\
+<% encode_json($json) %>\
 <%init>
 
 my $json = [];

commit ead0cc76f66c0806321443657b49f829034e23ae
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Tue Jun 26 18:18:51 2018 -0500

    RT# 30783 Clean up IP utility code

diff --git a/FS/FS/IP_Mixin.pm b/FS/FS/IP_Mixin.pm
index 07fa9e776..1967ccd57 100644
--- a/FS/FS/IP_Mixin.pm
+++ b/FS/FS/IP_Mixin.pm
@@ -268,45 +268,27 @@ sub router {
   FS::router->by_key($self->routernum);
 }
 
-=item used_addresses [ BLOCK ]
+=item used_addresses [ FS::addr_block ]
 
-Returns a list of all addresses that are in use by a service.  If called as an
-instance method, excludes that instance from the search.
+Returns a list of all addresses in use within the given L<FS::addr_block>.
 
-Does not filter by block, will return ALL used addresses. ref:f197bdbaa1
+If called as an instance method, excludes that instance from the search.
 
 =cut
 
 sub used_addresses {
-  my $self = shift;
-  my $block = shift;
-  return ( map { $_->_used_addresses($block, $self) } @subclasses );
-}
-
-sub _used_addresses {
-  my $class = shift;
-  die "$class->_used_addresses not implemented";
-}
-
-=item used_addresses_in_block [ FS::addr_block ]
-
-Returns a list of all addresses in use within the given L<FS::addr_block>
-
-=cut
-
-sub used_addresses_in_block {
   my ($self, $block) = @_;
 
   (
     $block->ip_gateway ? $block->ip_gateway : (),
     $block->NetAddr->broadcast->addr,
-    map { $_->_used_addresses_in_block($block, $self ) } @subclasses
+    map { $_->_used_addresses($block, $self ) } @subclasses
   );
 }
 
-sub _used_addresses_in_block {
+sub _used_addresses {
   my $class = shift;
-  die "$class->_used_addresses_in_block not implemented";
+  die "$class->_used_addresses not implemented";
 }
 
 =item is_used ADDRESS
diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index 74c372e29..5fd64bf7a 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -218,7 +218,7 @@ sub free_addrs {
 
   my %used_addr_map =
     map {$_ => 1}
-    FS::IP_Mixin->used_addresses_in_block($self),
+    FS::IP_Mixin->used_addresses($self),
     FS::Conf->new()->config('exclude_ip_addr');
 
   [
@@ -254,7 +254,7 @@ sub next_free_addr {
     $selfaddr->addr,
     $selfaddr->network->addr,
     $selfaddr->broadcast->addr,
-    FS::IP_Mixin->used_addresses_in_block($self)
+    FS::IP_Mixin->used_addresses($self)
   );
 
   # just do a linear search of the block
diff --git a/FS/FS/svc_IP_Mixin.pm b/FS/FS/svc_IP_Mixin.pm
index 502745a52..499abb8ac 100644
--- a/FS/FS/svc_IP_Mixin.pm
+++ b/FS/FS/svc_IP_Mixin.pm
@@ -91,38 +91,21 @@ sub svc_ip_check {
 }
 
 sub _used_addresses {
+  my ($class, $block, $exclude_svc) = @_;
 
-  # Returns all addresses in use.  Does not filter with $block. ref:f197bdbaa1
-
-  my ($class, $block, $exclude) = @_;
-  my $ip_field = $class->table_info->{'ip_field'}
-    or return ();
-  # if the service doesn't have an ip_field, then it has no IP addresses 
-  # in use, yes? 
-
-  my %hash = ( $ip_field => { op => '!=', value => '' } );
-  #$hash{'blocknum'} = $block->blocknum if $block;
-  $hash{'svcnum'} = { op => '!=', value => $exclude->svcnum } if ref $exclude;
-  map { my $na = $_->NetAddr; $na ? $na->addr : () }
-    qsearch({
-        table     => $class->table,
-        hashref   => \%hash,
-        extra_sql => " AND $ip_field != '0e0'",
-    });
-}
-
-sub _used_addresses_in_block {
-  my ($class, $block) = @_;
-
-  croak "_used_addresses_in_block() requires an FS::addr_block parameter"
+  croak "_used_addresses() requires an FS::addr_block parameter"
     unless ref $block && $block->isa('FS::addr_block');
 
   my $ip_field = $class->table_info->{'ip_field'};
   if ( !$ip_field ) {
-    carp "_used_addresses_in_block() skipped, no ip_field";
+    carp "_used_addresses() skipped, no ip_field";
     return;
   }
 
+  my %qsearch = ( $ip_field => { op => '!=', value => '' });
+  $qsearch{svcnum} = { op => '!=', value => $exclude_svc->svcnum }
+    if ref $exclude_svc && $exclude_svc->svcnum;
+
   my $block_na = $block->NetAddr;
 
   my $octets;
@@ -152,7 +135,7 @@ sub _used_addresses_in_block {
   my %qsearch = (
       table     => $class->table,
       select    => $ip_field,
-      hashref   => { $ip_field => { op => '!=', value => '' }},
+      hashref   => \%qsearch,
       extra_sql => " AND $ip_field != '0e0' ",
   );
   if ( $octets ) {

commit 34106a87f830297c8ad676599ef170f5e4ec53ba
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Tue Jun 26 17:34:50 2018 -0500

    RT# 30783 Selectbox of available IPs when provisioning

diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index eb84dafc3..74c372e29 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -209,7 +209,7 @@ sub cidr {
 
 =item free_addrs
 
-Returns a sorted list of free addresses in the block.
+Returns an aref sorted list of free addresses in the block.
 
 =cut
 
@@ -221,7 +221,11 @@ sub free_addrs {
     FS::IP_Mixin->used_addresses_in_block($self),
     FS::Conf->new()->config('exclude_ip_addr');
 
-  grep { !exists $used_addr_map{$_} } map { $_->addr } $self->NetAddr->hostenum;
+  [
+    grep { !exists $used_addr_map{$_} }
+    map { $_->addr }
+    $self->NetAddr->hostenum
+  ];
 }
 
 =item next_free_addr
diff --git a/httemplate/elements/tr-select-router_block_ip.html b/httemplate/elements/tr-select-router_block_ip.html
index 2aa715e29..535e953c4 100644
--- a/httemplate/elements/tr-select-router_block_ip.html
+++ b/httemplate/elements/tr-select-router_block_ip.html
@@ -2,34 +2,110 @@
 var manual_addr_routernum = <% encode_json(\%manual_addr_routernum) %>;
 var ip_addr_curr_value = <% $opt{'ip_addr'} |js_string %>;
 var blocknum_curr_value = <% $opt{'blocknum'} |js_string %>;
-function update_ip_addr(obj, i) {
-  var routernum = document.getElementById('router_select_0').value;
-  var select_blocknum = document.getElementById('router_select_1');
-  var blocknum = select_blocknum.value;
-  var input_ip_addr = document.getElementById('input_ip_addr');
+
+function update_ip_addr() {
+  var routernum = $('#router_select_0').val();
+  var blocknum  = $('#router_select_1').val();
+  var e_input_ip_addr = $('#input_ip_addr');
+  var e_router_select_1 = $('#router_select_1');
+
+  <% # Is block is automatically selected for this router? %>
   if ( manual_addr_routernum[routernum] == 'Y' ) {
-%# hide block selection and default ip address to its previous value
-    select_blocknum.style.display = 'none';
-    input_ip_addr.value = ip_addr_curr_value;
-  }
-  else {
-%# the reverse
-    select_blocknum.style.display = '';
-%# default ip address to null, unless the router/block are set to the 
-%# previous value, in which case default it to current value
+    show_ip_input();
+    hide_ip_select();
+    e_router_select_1.hide();
+    e_input_ip_addr.val( ip_addr_curr_value );
+  } else {
+    e_router_select_1.show();
+    e_input_ip_addr.attr('placeholder', <% mt('(automatic)') | js_string %> );
     if ( routernum == router_curr_values[0] &&
-         blocknum  == router_curr_values[1] ) {
-      input_ip_addr.value = ip_addr_curr_value;
+         blocknum == router_curr_values[1] ) {
+      e_input_ip_addr.val( ip_addr_curr_value );
     } else {
-      input_ip_addr.value = <% mt('(automatic)') |js_string %>;
+      e_input_ip_addr.val('');
     }
   }
+  show_or_hide_toggle_ip();
+  populate_ip_select();
+}
+
+function toggle_ip_input() {
+  if ( $('#input_ip_addr').is(':hidden') ) {
+    show_ip_input();
+  } else {
+    show_ip_select();
+  }
+}
+
+function show_ip_input() {
+  $('#input_ip_addr').show();
+  $('#select_ip_addr').hide();
+  depopulate_ip_select();
+}
+
+function show_ip_select() {
+  var e_input_ip_addr = $('#input_ip_addr');
+  var e_select_ip_addr = $('#select_ip_addr');
+
+  e_select_ip_addr.width( e_input_ip_addr.width() );
+  e_input_ip_addr.hide();
+  e_select_ip_addr.show();
+  populate_ip_select();
+}
+
+function populate_ip_select() {
+  depopulate_ip_select();
+  var e = $('#select_ip_addr');
+  var blocknum = $('#router_select_1').val();
+
+  var opts = [ '<option value="">loading...</option>' ];
+  e.html(opts.join(''));
+
+% if ( $opt{ip_addr} ) {
+  opts = [
+    '<option value="<% $opt{ip_addr} |h %>"><% $opt{ip_addr} |h %></option>',
+    '<option value="">-----------</option>'
+  ];
+% } else {
+  opts = [ '<option value=""><% mt('(automatic)') |h %></option>' ];
+% }
+  if ( blocknum && $.isNumeric(blocknum) && ! e.is(':hidden')) {
+    $.getJSON(
+      '<% $p %>json/free_addresses_in_block.json.html',
+      {blocknum: blocknum},
+      function(ip_json) {
+        $.each( ip_json, function(idx, val) {
+          opts.push(
+            '<option' + (val == ip_addr_curr_value ? 'selected' : '') + '>'
+            + val
+            + '</option>'
+          );
+        });
+        e.html(opts.join(''));
+      }
+    );
+  }
 }
-function clearhint_ip_addr (what) {
-  if ( what.value == <% mt('(automatic)') |js_string %> )
-    what.value = '';
+
+function depopulate_ip_select() {
+  $('#select_ip_addr').children().remove();
 }
+
+function propogate_ip_select() {
+  $('#input_ip_addr').val( $('#select_ip_addr').val() );
+}
+
+function show_or_hide_toggle_ip() {
+  if ( $('#router_select_1').val() ) {
+    $('#toggle_ip').show();
+  } else {
+    show_ip_input();
+    $('#toggle_ip').hide();
+  }
+}
+
 </script>
+
 <& /elements/tr-td-label.html, label => ($opt{'label'} || 'Router'), required => $opt{'required'} &>
 <td>
   <& /elements/select-tiered.html, prefix => 'router_', tiers => [
@@ -58,14 +134,20 @@ function clearhint_ip_addr (what) {
 </td></tr>
 <& /elements/tr-td-label.html, label => ($opt{'ip_addr_label'} || 'IP address'), required => $opt{'ip_addr_required'} &>
 <td>
-% #warn Dumper \%fixed;
 % if ( exists $fixed{$ip_field} ) {
   <input type="hidden" id="input_ip_addr" name="<% $ip_field %>" 
     value="<% $opt{'ip_addr'} |h%>"><% $opt{'ip_addr'} || '' %>
 % }
 % else {
-  <input type="text" id="input_ip_addr" name="<% $ip_field %>" 
-  value="<% $opt{'ip_addr'} |h%>" onfocus="clearhint_ip_addr(this)">
+    <input type="text"
+           id="input_ip_addr"
+           name="<% $ip_field %>"
+           value="<% $opt{'ip_addr'} | h %>"
+           onfocus="clearhint_ip_addr(this)">
+    <select id="select_ip_addr" style="display: none;" onChange='javascript:propogate_ip_select();'>
+      <option><% mt('loading') |h %>...</option>
+    </select>
+    <button type="button" onClick='javascript:toggle_ip_input();' id="toggle_ip" style="display: none;">▼</button>
 % }
 </td> </tr>
 <script type="text/javascript">
diff --git a/httemplate/json/free_addresses_in_block.json.html b/httemplate/json/free_addresses_in_block.json.html
new file mode 100644
index 000000000..6785aac6b
--- /dev/null
+++ b/httemplate/json/free_addresses_in_block.json.html
@@ -0,0 +1,18 @@
+<%doc>
+  Return a json array containing all free ip addresses within a given block
+  Unless block is larger than /24 - Does somebody really want to populate
+  65k addresses into a HTML selectbox?
+</%doc>
+<% encode_rest($json) %>\
+<%init>
+
+my $json = [];
+
+my $blocknum = $cgi->param('blocknum');
+
+my $addr_block = qsearchs( addr_block => { blocknum => $blocknum });
+
+$json = $addr_block->free_addrs
+  if ref $addr_block && $addr_block->ip_netmask >= 24;
+
+</%init>

commit 3c26afebaaada34db1028184571f0fb38e5b74bf
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Mon Jun 25 14:09:42 2018 -0500

    RT# 30783 Improve speed of ip address auto-assignment

diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index fa0e42f62..eb84dafc3 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -250,7 +250,7 @@ sub next_free_addr {
     $selfaddr->addr,
     $selfaddr->network->addr,
     $selfaddr->broadcast->addr,
-    FS::IP_Mixin->used_addresses($self)
+    FS::IP_Mixin->used_addresses_in_block($self)
   );
 
   # just do a linear search of the block

commit 714d702814b985d90eb8224ee914b0c898b66a58
Author: Mitch Jackson <mitch at freeside.biz>
Date:   Mon Jun 25 14:07:52 2018 -0500

    RT# 30783 Add network block enumerating utils

diff --git a/FS/FS/IP_Mixin.pm b/FS/FS/IP_Mixin.pm
index 8920cebc5..07fa9e776 100644
--- a/FS/FS/IP_Mixin.pm
+++ b/FS/FS/IP_Mixin.pm
@@ -270,9 +270,10 @@ sub router {
 
 =item used_addresses [ BLOCK ]
 
-Returns a list of all addresses (in BLOCK, or in all blocks)
-that are in use.  If called as an instance method, excludes 
-that instance from the search.
+Returns a list of all addresses that are in use by a service.  If called as an
+instance method, excludes that instance from the search.
+
+Does not filter by block, will return ALL used addresses. ref:f197bdbaa1
 
 =cut
 
@@ -287,6 +288,27 @@ sub _used_addresses {
   die "$class->_used_addresses not implemented";
 }
 
+=item used_addresses_in_block [ FS::addr_block ]
+
+Returns a list of all addresses in use within the given L<FS::addr_block>
+
+=cut
+
+sub used_addresses_in_block {
+  my ($self, $block) = @_;
+
+  (
+    $block->ip_gateway ? $block->ip_gateway : (),
+    $block->NetAddr->broadcast->addr,
+    map { $_->_used_addresses_in_block($block, $self ) } @subclasses
+  );
+}
+
+sub _used_addresses_in_block {
+  my $class = shift;
+  die "$class->_used_addresses_in_block not implemented";
+}
+
 =item is_used ADDRESS
 
 Returns a string describing what object is using ADDRESS, or 
diff --git a/FS/FS/addr_block.pm b/FS/FS/addr_block.pm
index ba0f61db1..fa0e42f62 100755
--- a/FS/FS/addr_block.pm
+++ b/FS/FS/addr_block.pm
@@ -207,6 +207,23 @@ sub cidr {
   $self->NetAddr->cidr;
 }
 
+=item free_addrs
+
+Returns a sorted list of free addresses in the block.
+
+=cut
+
+sub free_addrs {
+  my $self = shift;
+
+  my %used_addr_map =
+    map {$_ => 1}
+    FS::IP_Mixin->used_addresses_in_block($self),
+    FS::Conf->new()->config('exclude_ip_addr');
+
+  grep { !exists $used_addr_map{$_} } map { $_->addr } $self->NetAddr->hostenum;
+}
+
 =item next_free_addr
 
 Returns a NetAddr::IP object corresponding to the first unassigned address 
@@ -416,4 +433,3 @@ now because that's the smallest block that makes any sense at all.
 =cut
 
 1;
-
diff --git a/FS/FS/svc_IP_Mixin.pm b/FS/FS/svc_IP_Mixin.pm
index 4b402fa8d..502745a52 100644
--- a/FS/FS/svc_IP_Mixin.pm
+++ b/FS/FS/svc_IP_Mixin.pm
@@ -3,7 +3,8 @@ use base 'FS::IP_Mixin';
 
 use strict;
 use NEXT;
-use FS::Record qw(qsearchs qsearch);
+use Carp qw(croak carp);
+use FS::Record qw(qsearchs qsearch dbh);
 use FS::Conf;
 use FS::router;
 use FS::part_svc_router;
@@ -90,6 +91,9 @@ sub svc_ip_check {
 }
 
 sub _used_addresses {
+
+  # Returns all addresses in use.  Does not filter with $block. ref:f197bdbaa1
+
   my ($class, $block, $exclude) = @_;
   my $ip_field = $class->table_info->{'ip_field'}
     or return ();
@@ -107,6 +111,69 @@ sub _used_addresses {
     });
 }
 
+sub _used_addresses_in_block {
+  my ($class, $block) = @_;
+
+  croak "_used_addresses_in_block() requires an FS::addr_block parameter"
+    unless ref $block && $block->isa('FS::addr_block');
+
+  my $ip_field = $class->table_info->{'ip_field'};
+  if ( !$ip_field ) {
+    carp "_used_addresses_in_block() skipped, no ip_field";
+    return;
+  }
+
+  my $block_na = $block->NetAddr;
+
+  my $octets;
+  if ($block->ip_netmask >= 24) {
+    $octets = 3;
+  } elsif ($block->ip_netmask >= 16) {
+    $octets = 2;
+  } elsif ($block->ip_netmask >= 8) {
+    $octets = 1;
+  }
+
+  #  e.g.
+  # SELECT ip_addr
+  # FROM svc_broadband
+  # WHERE ip_addr != ''
+  #   AND ip_addr != '0e0'
+  #   AND ip_addr LIKE '10.0.2.%';
+  #
+  # For /24, /16 and /8 this approach is fast, even when svc_broadband table
+  # contains 650,000+ ip records.  For other allocations, this approach is
+  # not speedy, but usable.
+  #
+  # Note: A use case like this would could greatly benefit from a qsearch()
+  #       parameter to bypass FS::Record objects creation and just
+  #       return hashrefs from DBI.  200,000 hashrefs are many seconds faster
+  #       than 200,000 FS::Record objects
+  my %qsearch = (
+      table     => $class->table,
+      select    => $ip_field,
+      hashref   => { $ip_field => { op => '!=', value => '' }},
+      extra_sql => " AND $ip_field != '0e0' ",
+  );
+  if ( $octets ) {
+    my $block_str = join('.', (split(/\D/, $block_na->first))[0..$octets-1]);
+    $qsearch{extra_sql} .= " AND $ip_field LIKE ".dbh->quote("${block_str}.%");
+  }
+
+  if ( $block->ip_netmask % 8 ) {
+    # Some addresses returned by qsearch may be outside the network block,
+    # so each ip address is tested to be in the block before it's returned.
+    return
+      grep { $block_na->contains( NetAddr::IP->new( $_ ) ) }
+      map { $_->$ip_field }
+      qsearch( \%qsearch );
+  }
+
+  return
+    map { $_->$ip_field }
+    qsearch( \%qsearch );
+}
+
 sub _is_used {
   my ($class, $addr, $exclude) = @_;
   my $ip_field = $class->table_info->{'ip_field'}

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

Summary of changes:
 FS/FS/IP_Mixin.pm                                  |  18 +--
 FS/FS/addr_block.pm                                |  22 +++-
 FS/FS/svc_IP_Mixin.pm                              |  83 ++++++++++---
 httemplate/elements/tr-select-router_block_ip.html | 128 +++++++++++++++++----
 .../misc/xmlhttp-free_addresses_in_block.json.html |  18 +++
 5 files changed, 222 insertions(+), 47 deletions(-)
 create mode 100644 httemplate/misc/xmlhttp-free_addresses_in_block.json.html




More information about the freeside-commits mailing list