event refactor, landing on HEAD!
[freeside.git] / FS / FS / access_user.pm
index 5d1e183..8e4ad46 100644 (file)
@@ -2,14 +2,22 @@ package FS::access_user;
 
 use strict;
 use vars qw( @ISA $htpasswd_file );
+use FS::UID;
+use FS::Conf;
 use FS::Record qw( qsearch qsearchs dbh );
 use FS::m2m_Common;
+use FS::option_Common;
 use FS::access_usergroup;
+use FS::agent;
 
-@ISA = qw( FS::m2m_Common FS::Record );
+@ISA = qw( FS::m2m_Common FS::option_Common FS::Record );
+#@ISA = qw( FS::m2m_Common FS::option_Common );
 
-#kludge htpasswd for now
-$htpasswd_file = '/usr/local/etc/freeside/htpasswd';
+#kludge htpasswd for now (i hope this bootstraps okay)
+FS::UID->install_callback( sub {
+  my $conf = new FS::Conf;
+  $htpasswd_file = $conf->base_dir. '/htpasswd';
+} );
 
 =head1 NAME
 
@@ -68,6 +76,10 @@ points to.  You can ask the object for a copy with the I<hash> method.
 
 sub table { 'access_user'; }
 
+sub _option_table    { 'access_user_pref'; }
+sub _option_namecol  { 'prefname'; }
+sub _option_valuecol { 'prefvalue'; }
+
 =item insert
 
 Adds this record to the database.  If there is an error, returns the error,
@@ -89,10 +101,13 @@ sub insert {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  my $error =
-       $self->SUPER::insert(@_)
-    || $self->htpasswd_kludge()
-  ;
+  my $error = $self->htpasswd_kludge();
+  if ( $error ) {
+    $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+    return $error;
+  }
+
+  $error = $self->SUPER::insert(@_);
 
   if ( $error ) {
     $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
@@ -106,6 +121,10 @@ sub insert {
 
 sub htpasswd_kludge {
   my $self = shift;
+  
+  #awful kludge to skip setting htpasswd for fs_* users
+  return '' if $self->username =~ /^fs_/;
+
   unshift @_, '-c' unless -e $htpasswd_file;
   if ( 
        system('htpasswd', '-b', @_,
@@ -121,7 +140,6 @@ sub htpasswd_kludge {
   }
 }
 
-
 =item delete
 
 Delete this record from the database.
@@ -165,7 +183,11 @@ returns the error, otherwise returns false.
 =cut
 
 sub replace {
-  my($new, $old) = ( shift, shift );
+  my $new = shift;
+
+  my $old = ( ref($_[0]) eq ref($new) )
+              ? shift
+              : $new->replace_old;
 
   local $SIG{HUP} = 'IGNORE';
   local $SIG{INT} = 'IGNORE';
@@ -178,10 +200,15 @@ sub replace {
   local $FS::UID::AutoCommit = 0;
   my $dbh = dbh;
 
-  my $error =
-       $new->SUPER::replace($old, @_)
-    || $new->htpasswd_kludge()
-  ;
+  if ( $new->_password ne $old->_password ) {
+    my $error = $new->htpasswd_kludge();
+    if ( $error ) {
+      $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
+      return $error;
+    }
+  }
+
+  my $error = $new->SUPER::replace($old, @_);
 
   if ( $error ) {
     $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
@@ -209,7 +236,7 @@ sub check {
 
   my $error = 
     $self->ut_numbern('usernum')
-    || $self->ut_text('username')
+    || $self->ut_alpha('username')
     || $self->ut_text('_password')
     || $self->ut_text('last')
     || $self->ut_text('first')
@@ -281,20 +308,70 @@ Returns a hashref of agentnums this user can view.
 
 sub agentnums_href {
   my $self = shift;
-  { map { $_ => 1 } $self->agentnums };
+  scalar( { map { $_ => 1 } $self->agentnums } );
 }
 
-=item agentnums_sql
+=item agentnums_sql [ HASHREF | OPTION => VALUE ... ]
 
 Returns an sql fragement to select only agentnums this user can view.
 
+Options are passed as a hashref or a list.  Available options are:
+
+=over 4
+
+=item null - The frament will also allow the selection of null agentnums.
+
+=item null_right - The fragment will also allow the selection of null agentnums if the current user has the provided access right
+
+=back
+
 =cut
 
 sub agentnums_sql {
+  my( $self ) = shift;
+  my %opt = ref($_[0]) ? %{$_[0]} : @_;
+
+  my @agentnums = map { "agentnum = $_" } $self->agentnums;
+
+  push @agentnums, 'agentnum IS NULL'
+    if $opt{'null'}
+    || ( $opt{'null_right'} && $self->access_right($opt{'null_right'}) );
+
+  return ' 1 = 0 ' unless scalar(@agentnums);
+  '( '. join( ' OR ', @agentnums ). ' )';
+}
+
+=item agentnum
+
+Returns true if the user can view the specified agent.
+
+=cut
+
+sub agentnum {
+  my( $self, $agentnum ) = @_;
+  my $sth = dbh->prepare(
+    "SELECT COUNT(*) FROM access_usergroup
+                     JOIN access_groupagent USING ( groupnum )
+       WHERE usernum = ? AND agentnum = ?"
+  ) or die dbh->errstr;
+  $sth->execute($self->usernum, $agentnum) or die $sth->errstr;
+  $sth->fetchrow_arrayref->[0];
+}
+
+=item agents
+
+Returns the list of agents this user can view (via group membership), as
+FS::agent objects.
+
+=cut
+
+sub agents {
   my $self = shift;
-  '( '.
-    join( ' OR ', map "agentnum = $_", $self->agentnums ).
-  ' )';
+  qsearch({
+    'table'     => 'agent',
+    'hashref'   => { disabled=>'' },
+    'extra_sql' => ' AND '. $self->agentnums_sql,
+  });
 }
 
 =item access_right