diff options
Diffstat (limited to 'FS')
| -rw-r--r-- | FS/FS/Record.pm | 54 | ||||
| -rw-r--r-- | FS/FS/Report/Table.pm | 2 | ||||
| -rw-r--r-- | FS/FS/contact.pm | 12 | ||||
| -rw-r--r-- | FS/FS/cust_main.pm | 82 | ||||
| -rw-r--r-- | FS/FS/deploy_zone.pm | 2 | ||||
| -rw-r--r-- | FS/FS/part_export/saisei.pm | 60 | ||||
| -rwxr-xr-x | FS/FS/svc_broadband.pm | 6 |
7 files changed, 209 insertions, 9 deletions
diff --git a/FS/FS/Record.pm b/FS/FS/Record.pm index 9f9b1e2fc..5048e4407 100644 --- a/FS/FS/Record.pm +++ b/FS/FS/Record.pm @@ -2999,6 +2999,60 @@ sub ut_enumn { : ''; } +=item ut_date COLUMN + +Check/untaint a column containing a date string. + +Date will be normalized to YYYY-MM-DD format + +=cut + +sub ut_date { + my ( $self, $field ) = @_; + my $value = $self->getfield( $field ); + + my @date = split /[\-\/]/, $value; + if ( scalar(@date) == 3 ) { + @date = @date[2,0,1] if $date[2] >= 1900; + + local $@; + my $ymd; + eval { + # DateTime will die given invalid date + $ymd = DateTime->new( + year => $date[0], + month => $date[1], + day => $date[2], + )->ymd('-'); + }; + + unless( $@ ) { + $self->setfield( $field, $ymd ) unless $value eq $ymd; + return ''; + } + + } + return "Illegal (date) field $field: $value"; +} + +=item ut_daten COLUMN + +Check/untaint a column containing a date string. + +Column may be null. + +Date will be normalized to YYYY-MM-DD format + +=cut + +sub ut_daten { + my ( $self, $field ) = @_; + + $self->getfield( $field ) =~ /^()$/ + ? $self->setfield( $field, '' ) + : $self->ut_date( $field ); +} + =item ut_flag COLUMN Check/untaint a column if it contains either an empty string or 'Y'. This diff --git a/FS/FS/Report/Table.pm b/FS/FS/Report/Table.pm index cef7813af..7c4f97309 100644 --- a/FS/FS/Report/Table.pm +++ b/FS/FS/Report/Table.pm @@ -1115,7 +1115,7 @@ sub calculate_churn_cust { as suspended, SUM((s_active = 0 and s_suspended > 0 and e_active > 0)::int) as resumed, - SUM((s_active > 0 and e_active = 0 and e_suspended = 0)::int) + SUM((e_active = 0 and e_cancelled > s_cancelled)::int) as cancelled FROM ($cust_sql) AS x "; diff --git a/FS/FS/contact.pm b/FS/FS/contact.pm index 4db3cdfd1..8f6b6a3b5 100644 --- a/FS/FS/contact.pm +++ b/FS/FS/contact.pm @@ -131,7 +131,6 @@ sub insert { my $dbh = dbh; my $error = $self->SUPER::insert; - $error ||= $self->insert_password_history; if ( $error ) { $dbh->rollback if $oldAutoCommit; @@ -191,6 +190,15 @@ sub insert { } } + if ( $self->get('password') ) { + my $error = $self->is_password_allowed($self->get('password')) + || $self->change_password($self->get('password')); + if ( $error ) { + $dbh->rollback if $oldAutoCommit; + return $error; + } + } + $dbh->commit or die $dbh->errstr if $oldAutoCommit; ''; @@ -614,7 +622,7 @@ sub authenticate_password { $hash eq $check_hash; - } else { + } else { return 0 if $self->_password eq ''; diff --git a/FS/FS/cust_main.pm b/FS/FS/cust_main.pm index 621f3d144..b103996a4 100644 --- a/FS/FS/cust_main.pm +++ b/FS/FS/cust_main.pm @@ -2145,6 +2145,10 @@ sub check { if !$import && !$ignore_expired_card && ( $y<$nowy || ( $y==$nowy && $1<$nowm ) ); + + if ( my $error = $self->ut_daten('paydate') ) { + return $error; + } } if ( $self->payname eq '' && $self->payby !~ /^(CHEK|DCHK)$/ && @@ -5643,8 +5647,86 @@ sub _upgrade_data { #class method FS::Setup::enable_encryption(); } + $class->_upgrade_data_paydate_edgebug; } +=item _upgrade_data_paydate_edgebug + +Correct bad data injected into payment expire date column by Edge browser bug + +The month and year values may have an extra character injected into form POST +data by Edge browser. It was possible for some bad month values to slip +past data validation. + +If the stored value was out of range, it was causing payments screen to crash. +We can detect and fix this by dropping the second digit. + +If the stored value is is 11 or 12, it's possible the user inputted a 1. In +this case, the payment method will fail to authorize, but the record will +not cause crashdumps for being out of range. + +In short, check for any expiration month > 12, and drop the extra digit + +=cut + +sub _upgrade_data_paydate_edgebug { + my $journal_label = 'cust_main_paydate_edgebug'; + return if FS::upgrade_journal->is_done( $journal_label ); + + my $oldAutoCommit = $FS::UID::AutoCommit; + local $FS::UID::AutoCommit = 0; + + for my $row ( + FS::Record::qsearch( + cust_main => { paydate => { op => '!=', value => '' }} + ) + ) { + next unless $row->ut_daten('paydate'); + + # paydate column stored in database has failed date validation + my $bad_paydate = $row->paydate; + + my @date = split /[\-\/]/, $bad_paydate; + @date = @date[2,0,1] if $date[2] > 1900; + + # Only autocorrecting when month > 12 - notify operator + unless ( $date[1] > 12 ) { + die sprintf( + 'Unable to correct bad paydate stored in cust_main row '. + 'custnum(%s) paydate(%s)', + $row->custnum, + $bad_paydate, + ); + } + + $date[1] = substr( $date[1], 0, 1 ); + $row->paydate( join('-', @date )); + + if ( my $error = $row->replace ) { + die sprintf( + 'Failed to autocorrect bad paydate stored in cust_main row '. + 'custnum(%s) paydate(%s) - error: %s', + $row->custnum, + $bad_paydate, + $error + ); + } + + warn sprintf( + 'Autocorrected bad paydate stored in cust_main row '. + "custnum(%s) old-paydate(%s) new-paydate(%s)\n", + $row->custnum, + $bad_paydate, + $row->paydate, + ); + + } + + FS::upgrade_journal->set_done( $journal_label ); + dbh->commit unless $oldAutoCommit; +} + + sub queueable_upgrade { my $class = shift; diff --git a/FS/FS/deploy_zone.pm b/FS/FS/deploy_zone.pm index 6ad355f72..7c3a76ca5 100644 --- a/FS/FS/deploy_zone.pm +++ b/FS/FS/deploy_zone.pm @@ -6,7 +6,7 @@ use FS::Record qw( qsearch qsearchs dbh ); use Storable qw(thaw); use MIME::Base64; -use JSON qw(encode_json decode_json) ; +use Cpanel::JSON::XS qw(encode_json decode_json); use LWP::UserAgent; use HTTP::Request::Common; diff --git a/FS/FS/part_export/saisei.pm b/FS/FS/part_export/saisei.pm index af77dfa78..6a42b94ba 100644 --- a/FS/FS/part_export/saisei.pm +++ b/FS/FS/part_export/saisei.pm @@ -201,12 +201,28 @@ sub _export_insert { my $accesspoint = process_sector($self, $sector_opt); return $self->api_error if $self->{'__saisei_error'}; +## get custnum and pkgpart from cust_pkg for virtual access point + my $cust_pkg = FS::Record::qsearchs({ + 'table' => 'cust_pkg', + 'hashref' => { 'pkgnum' => $svc_broadband->{Hash}->{pkgnum}, }, + }); + my $virtual_ap_name = $cust_pkg->{Hash}->{custnum}.'_'.$cust_pkg->{Hash}->{pkgpart}.'_'.$svc_broadband->{Hash}->{speed_down}.'_'.$svc_broadband->{Hash}->{speed_up}; + + my $virtual_ap_opt = { + 'virtual_name' => $virtual_ap_name, + 'sector_name' => $sector_name, + 'virtual_uprate_limit' => $svc_broadband->{Hash}->{speed_up}, + 'virtual_downrate_limit' => $svc_broadband->{Hash}->{speed_down}, + }; + my $virtual_ap = process_virtual_ap($self, $virtual_ap_opt); + return $self->api_error if $self->{'__saisei_error'}; + ## tie host to user add sector name as access point. $self->api_add_host_to_user( $user->{collection}->[0]->{name}, $rateplan->{collection}->[0]->{name}, $svc_broadband->{Hash}->{ip_addr}, - $accesspoint->{collection}->[0]->{name}, + $virtual_ap->{collection}->[0]->{name}, ) unless $self->{'__saisei_error'}; } @@ -216,8 +232,8 @@ sub _export_insert { sub _export_replace { my ($self, $svc_broadband) = @_; - $self->_export_insert($svc_broadband); - return ''; + my $error = $self->_export_insert($svc_broadband); + return $error; } sub _export_delete { @@ -805,6 +821,44 @@ sub process_sector { return $accesspoint; } +sub process_virtual_ap { + my ($self, $opt) = @_; + + my $existing_virtual_ap; + my $virtual_name = $opt->{virtual_name}; + + #check if sector has been set up as an access point. + $existing_virtual_ap = $self->api_get_accesspoint($virtual_name); + + # modify the existing virtual accesspoint if changing it. this should never happen + $self->api_modify_existing_accesspoint ( + $virtual_name, + $opt->{sector_name}, + $opt->{virtual_uprate_limit}, + $opt->{virtual_downrate_limit}, + ) if $existing_virtual_ap && $opt->{modify_existing}; + + #if virtual ap does not exist as an access point create it. + $self->api_create_accesspoint( + $virtual_name, + $opt->{virtual_uprate_limit}, + $opt->{virtual_downrate_limit}, + ) unless $existing_virtual_ap; + +my $update_sector; +if ($existing_virtual_ap && ($existing_virtual_ap->{collection}->[0]->{uplink}->{link}->{name} ne $opt->{sector_name})) { + $update_sector = 1; +} + + # Attach newly created virtual ap to tower sector ap or if sector has changed. + $self->api_modify_accesspoint($virtual_name, $opt->{sector_name}) unless ($self->{'__saisei_error'} || ($existing_virtual_ap && !$update_sector)); + + # set access point to existing one or newly created one. + my $accesspoint = $existing_virtual_ap ? $existing_virtual_ap : $self->api_get_accesspoint($virtual_name); + + return $accesspoint; +} + sub export_provisioned_services { my $job = shift; my $param = thaw(decode_base64(shift)); diff --git a/FS/FS/svc_broadband.pm b/FS/FS/svc_broadband.pm index 11e3331a0..9cd085942 100755 --- a/FS/FS/svc_broadband.pm +++ b/FS/FS/svc_broadband.pm @@ -156,8 +156,8 @@ sub table_info { disable_inventory => 1, }, 'serviceid' => 'Torrus serviceid', #but is should be hidden - 'speed_test_up' => 'Speed test download (Kbps)', - 'speed_test_down' => 'Speed test upload (Kbps)', + 'speed_test_up' => { 'label' => 'Speed test upload (Kbps)' }, + 'speed_test_down' => { 'label' => 'Speed test download (Kbps)' }, 'speed_test_latency' => 'Speed test latency (ms)', }, }; @@ -364,6 +364,8 @@ sub check { || $self->ut_textn('description') || $self->ut_numbern('speed_up') || $self->ut_numbern('speed_down') + || $self->ut_numbern('speed_test_up') + || $self->ut_numbern('speed_test_down') || $self->ut_ipn('ip_addr') || $self->ut_hexn('mac_addr') || $self->ut_hexn('auth_key') |
