RT# 81961 Repair broken links in POD documentation
[freeside.git] / FS / FS / svc_acct.pm
index 40f65d6..efe6c73 100644 (file)
@@ -7,7 +7,11 @@ use base qw( FS::svc_Domain_Mixin
              FS::svc_Radius_Mixin
              FS::svc_Tower_Mixin
              FS::svc_IP_Mixin
-             FS::svc_Common );
+             FS::Password_Mixin
+             FS::svc_Common
+           );
+
+use strict;
 use vars qw( $DEBUG $me $conf $skip_fuzzyfiles
              $dir_prefix @shells $usernamemin
              $usernamemax $passwordmin $passwordmax
@@ -58,7 +62,6 @@ use FS::svc_www;
 use FS::cdr;
 use FS::acct_snarf;
 use FS::tower_sector;
-use FS::Misc;
 
 $DEBUG = 0;
 $me = '[FS::svc_acct]';
@@ -111,12 +114,11 @@ FS::UID->install_callback( sub {
   $smtpmachine = $conf->config('smtpmachine');
   $radius_password = $conf->config('radius-password') || 'Password';
   $radius_ip = $conf->config('radius-ip') || 'Framed-IP-Address';
-  @pw_set = ( 'A'..'Z' ) if $conf->exists('password-generated-allcaps');
+  @pw_set = FS::svc_acct->pw_set;
 }
 );
 
 @saltset = ( 'a'..'z' , 'A'..'Z' , '0'..'9' , '.' , '/' );
-@pw_set = ( 'a'..'z', 'A'..'Z', '0'..'9', '(', ')', '#', '.', ',' );
 
 sub _cache {
   my $self = shift;
@@ -315,7 +317,7 @@ sub table_info {
                          disable_inventory => 1,
                        },
         '_password' => { label => 'Password',
-                         required => 1
+          #required => 1
                        },
         'gid'       => {
                          label    => 'GID',
@@ -335,6 +337,7 @@ sub table_info {
         'domsvc'    => {
                          label     => 'Domain',
                          type      => 'select',
+                         select_svc => 1,
                          select_table => 'svc_domain',
                          select_key   => 'svcnum',
                          select_label => 'domain',
@@ -347,6 +350,15 @@ sub table_info {
                          disable_select => 1, #UI wonky, pry works otherwise
                        },
         'sectornum' => 'Tower sector',
+        'routernum' => 'Router/block',
+        'blocknum'  => {
+                         'label' => 'Address block',
+                         'type'  => 'select',
+                         'select_table' => 'addr_block',
+                          'select_key'   => 'blocknum',
+                         'select_label' => 'cidr',
+                         'disable_inventory' => 1,
+                       },
         'usergroup' => {
                          label => 'RADIUS groups',
                          type  => 'select-radius_group.html',
@@ -702,6 +714,9 @@ sub insert {
     'child_objects' => $self->child_objects,
     %options,
   );
+
+  $error ||= $self->insert_password_history;
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -730,11 +745,9 @@ sub insert {
       $cust_main->invoicing_list(\@invoicing_list);
     }
 
-    #welcome email/letter
+    #welcome email
     my @welcome_exclude_svcparts = $conf->config('svc_acct_welcome_exclude');
-    unless ( grep { $_ eq $self->svcpart } @welcome_exclude_svcparts ) {
-      #indent skips a level for some reason
-        #welcome email
+    unless ($FS::svc_Common::noexport_hack or ( grep { $_ eq $self->svcpart } @welcome_exclude_svcparts )) {
         my $error = '';
         my $msgnum = $conf->config('welcome_msgnum', $agentnum);
         if ( $msgnum ) {
@@ -818,21 +831,7 @@ sub insert {
 
           } # if $welcome_template
         } # if !$msgnum
-        # print welcome letter
-        if ($conf->exists('svc_acct_welcome_letter')) {
-          my $queue = new FS::queue {
-            'job'     => 'FS::svc_acct::process_print_welcome_letter',
-          };
-          $error = $queue->insert(
-            'svcnum'  => $self->svcnum,
-            'template' => 'svc_acct_welcome_letter',
-          );
-          if ($error) {
-            warn "can't send welcome letter: $error";
-          }
-        }
-      #indent skipped a level for some reason
-    } # unless in @welcome_exclude_svcparts
+    }
   } # if $cust_pkg
 
   $dbh->commit or die $dbh->errstr if $oldAutoCommit;
@@ -935,7 +934,19 @@ sub delete {
     }
   }
 
-  my $error = $self->SUPER::delete; # usergroup here
+  foreach my $svc_phone (
+    qsearch( 'svc_phone', { 'forward_svcnum' => $self->svcnum })
+  ) {
+    $svc_phone->set('forward_svcnum', '');
+    my $error = $svc_phone->replace;
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  my $error = $self->delete_password_history
+           || $self->SUPER::delete; # usergroup here
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error;
@@ -1002,6 +1013,12 @@ sub replace {
   my $dbh = dbh;
 
   $error = $new->SUPER::replace($old, @_); # usergroup here
+
+  # don't need to record this unless the password was changed
+  if ( $old->_password ne $new->_password ) {
+    $error ||= $new->insert_password_history;
+  }
+
   if ( $error ) {
     $dbh->rollback if $oldAutoCommit;
     return $error if $error;
@@ -1405,8 +1422,7 @@ sub check {
       $recref->{_password} = $1;
     } else {
       return gettext('illegal_password'). " $passwordmin-$passwordmax ".
-             FS::Msgcat::_gettext('illegal_password_characters').
-             ": ". $recref->{_password};
+             FS::Msgcat::_gettext('illegal_password_characters');
     }
 
     if ( $password_noampersand ) {
@@ -2087,14 +2103,16 @@ sub _op_usage {
   die "Can't update $column for svcnum". $self->svcnum
     if $rv == 0;
 
-  #$self->snapshot; #not necessary, we retain the old values
-  #create an object with the updated usage values
-  my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
-  #call exports
-  my $error = $new->replace($self);
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return "Error replacing: $error";
+  if ( $conf->exists('radius-chillispot-max') ) {
+    #$self->snapshot; #not necessary, we retain the old values
+    #create an object with the updated usage values
+    my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
+    #call exports
+    my $error = $new->replace($self);
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error replacing: $error";
+    }
   }
 
   #overlimit_action eq 'cancel' handling
@@ -2290,15 +2308,17 @@ sub set_usage {
     die "Can't update usage for svcnum ". $self->svcnum
       if $rv == 0;
   }
-
-  #$self->snapshot; #not necessary, we retain the old values
-  #create an object with the updated usage values
-  my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
-  local($FS::Record::nowarn_identical) = 1;
-  my $error = $new->replace($self); #call exports
-  if ( $error ) {
-    $dbh->rollback if $oldAutoCommit;
-    return "Error replacing: $error";
+  
+  if ( $conf->exists('radius-chillispot-max') ) {
+    #$self->snapshot; #not necessary, we retain the old values
+    #create an object with the updated usage values
+    my $new = qsearchs('svc_acct', { 'svcnum' => $self->svcnum });
+    local($FS::Record::nowarn_identical) = 1;
+    my $error = $new->replace($self); #call exports
+    if ( $error ) {
+      $dbh->rollback if $oldAutoCommit;
+      return "Error replacing: $error";
+    }
   }
 
   if ( $reset ) {
@@ -2375,7 +2395,7 @@ sub is_rechargable {
 =item seconds_since TIMESTAMP
 
 Returns the number of seconds this account has been online since TIMESTAMP,
-according to the session monitor (see L<FS::Session>).
+according to the session monitor (see L<FS::session>).
 
 TIMESTAMP is specified as a UNIX timestamp; see L<perlfunc/"time">.  Also see
 L<Time::Local> and L<Date::Parse> for conversion functions.
@@ -2403,8 +2423,8 @@ sub last_login_text {
 
 Returns a paged search (L<FS::PagedSearch>) for Call Detail Records
 associated with this service. For svc_acct, "associated with" means that
-either the "src" or the "charged_party" field of the CDR matches the
-"username" field of the service.
+either the "src" or the "charged_party" field of the CDR matches either
+the "username" field of the service or the username@domain label.
 
 =cut
 
@@ -2415,6 +2435,7 @@ sub psearch_cdrs {
   my @where;
 
   my $did = dbh->quote($self->username);
+  my $diddomain = dbh->quote($self->label);
 
   my $prefix = $options{'default_prefix'} || ''; #convergent.au '+61'
   my $prefixdid = dbh->quote($prefix . $self->username);
@@ -2430,12 +2451,16 @@ sub psearch_cdrs {
   if (!$options{'disable_charged_party'}) {
     push @orwhere,
       "charged_party = $did",
-      "charged_party = $prefixdid";
+      "charged_party = $prefixdid",
+      "charged_party = $diddomain"
+      ;
   }
   if (!$options{'disable_src'}) {
     push @orwhere,
       "src = $did AND charged_party IS NULL",
-      "src = $prefixdid AND charged_party IS NULL";
+      "src = $prefixdid AND charged_party IS NULL",
+      "src = $diddomain AND charged_party IS NULL"
+      ;
   }
   push @where, '(' . join(' OR ', @orwhere) . ')';
 
@@ -2779,6 +2804,25 @@ sub virtual_maildir {
   $self->domain. '/maildirs/'. $self->username. '/';
 }
 
+=item password_svc_check
+
+Override, for L<FS::Password_Mixin>.  Not really intended for other use.
+
+=cut
+
+sub password_svc_check {
+  my ($self, $password) = @_;
+  foreach my $field ( qw(username finger) ) {
+    foreach my $word (split(/\W+/,$self->get($field))) {
+      next unless length($word) > 2;
+      if ($password =~ /$word/i) {
+        return qq(Password contains account information '$word');
+      }
+    }
+  }
+  return '';
+}
+
 =back
 
 =head1 CLASS METHODS
@@ -3045,26 +3089,6 @@ sub reached_threshold {
   }
 }
 
-sub process_print_welcome_letter {
-  my %opt = @_;
-
-  my $self = qsearchs('svc_acct', { 'svcnum' => $opt{'svcnum'} } )
-    or die "invalid svc_acct: " . $opt{'svcnum'};
-  my $cust_main = $self->cust_svc->cust_pkg->cust_main;
-
-  my $ps = $cust_main->print_ps('svc_acct_welcome_letter',
-    'extra_fields' => {
-      map { $_ => $self->$_ } $self->fields, # or maybe just username & password?
-    },
-  );
-  my $error = FS::Misc::do_print(
-    [ $ps ],
-    'agentnum' => $cust_main->agentnum,
-  );
-  die $error if $error;
-
-}
-
 =back
 
 =head1 BUGS