1 package FS::access_user;
4 use vars qw( @ISA $htpasswd_file );
7 use FS::Record qw( qsearch qsearchs dbh );
10 use FS::access_usergroup;
13 @ISA = qw( FS::m2m_Common FS::option_Common FS::Record );
14 #@ISA = qw( FS::m2m_Common FS::option_Common );
16 #kludge htpasswd for now (i hope this bootstraps okay)
17 FS::UID->install_callback( sub {
18 my $conf = new FS::Conf;
19 $htpasswd_file = $conf->base_dir. '/htpasswd';
24 FS::access_user - Object methods for access_user records
30 $record = new FS::access_user \%hash;
31 $record = new FS::access_user { 'column' => 'value' };
33 $error = $record->insert;
35 $error = $new_record->replace($old_record);
37 $error = $record->delete;
39 $error = $record->check;
43 An FS::access_user object represents an internal access user. FS::access_user inherits from
44 FS::Record. The following fields are currently supported:
48 =item usernum - primary key
58 =item disabled - empty or 'Y'
68 Creates a new internal access user. To add the user to the database, see L<"insert">.
70 Note that this stores the hash reference, not a distinct copy of the hash it
71 points to. You can ask the object for a copy with the I<hash> method.
75 # the new method can be inherited from FS::Record, if a table method is defined
77 sub table { 'access_user'; }
79 sub _option_table { 'access_user_pref'; }
80 sub _option_namecol { 'prefname'; }
81 sub _option_valuecol { 'prefvalue'; }
85 Adds this record to the database. If there is an error, returns the error,
86 otherwise returns false.
93 local $SIG{HUP} = 'IGNORE';
94 local $SIG{INT} = 'IGNORE';
95 local $SIG{QUIT} = 'IGNORE';
96 local $SIG{TERM} = 'IGNORE';
97 local $SIG{TSTP} = 'IGNORE';
98 local $SIG{PIPE} = 'IGNORE';
100 my $oldAutoCommit = $FS::UID::AutoCommit;
101 local $FS::UID::AutoCommit = 0;
104 my $error = $self->htpasswd_kludge();
106 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
110 $error = $self->SUPER::insert(@_);
113 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
116 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
122 sub htpasswd_kludge {
125 #awful kludge to skip setting htpasswd for fs_* users
126 return '' if $self->username =~ /^fs_/;
128 unshift @_, '-c' unless -e $htpasswd_file;
130 system('htpasswd', '-b', @_,
139 return 'htpasswd exited unsucessfully';
145 Delete this record from the database.
152 local $SIG{HUP} = 'IGNORE';
153 local $SIG{INT} = 'IGNORE';
154 local $SIG{QUIT} = 'IGNORE';
155 local $SIG{TERM} = 'IGNORE';
156 local $SIG{TSTP} = 'IGNORE';
157 local $SIG{PIPE} = 'IGNORE';
159 my $oldAutoCommit = $FS::UID::AutoCommit;
160 local $FS::UID::AutoCommit = 0;
164 $self->SUPER::delete(@_)
165 || $self->htpasswd_kludge('-D')
169 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
172 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
178 =item replace OLD_RECORD
180 Replaces the OLD_RECORD with this one in the database. If there is an error,
181 returns the error, otherwise returns false.
188 my $old = ( ref($_[0]) eq ref($new) )
192 local $SIG{HUP} = 'IGNORE';
193 local $SIG{INT} = 'IGNORE';
194 local $SIG{QUIT} = 'IGNORE';
195 local $SIG{TERM} = 'IGNORE';
196 local $SIG{TSTP} = 'IGNORE';
197 local $SIG{PIPE} = 'IGNORE';
199 my $oldAutoCommit = $FS::UID::AutoCommit;
200 local $FS::UID::AutoCommit = 0;
203 if ( $new->_password ne $old->_password ) {
204 my $error = $new->htpasswd_kludge();
206 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
211 my $error = $new->SUPER::replace($old, @_);
214 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
217 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
225 Checks all fields to make sure this is a valid internal access user. If there is
226 an error, returns the error, otherwise returns false. Called by the insert
231 # the check method should currently be supplied - FS::Record contains some
232 # data checking routines
238 $self->ut_numbern('usernum')
239 || $self->ut_alpha('username')
240 || $self->ut_text('_password')
241 || $self->ut_text('last')
242 || $self->ut_text('first')
243 || $self->ut_enum('disabled', [ '', 'Y' ] )
245 return $error if $error;
252 Returns a name string for this user: "Last, First".
258 $self->get('last'). ', '. $self->first;
261 =item access_usergroup
265 sub access_usergroup {
267 qsearch( 'access_usergroup', { 'usernum' => $self->usernum } );
278 #=item access_groupnames
282 #sub access_groupnames {
288 Returns a list of agentnums this user can view (via group membership).
294 my $sth = dbh->prepare(
295 "SELECT DISTINCT agentnum FROM access_usergroup
296 JOIN access_groupagent USING ( groupnum )
298 ) or die dbh->errstr;
299 $sth->execute($self->usernum) or die $sth->errstr;
300 map { $_->[0] } @{ $sth->fetchall_arrayref };
305 Returns a hashref of agentnums this user can view.
311 scalar( { map { $_ => 1 } $self->agentnums } );
314 =item agentnums_sql [ HASHREF | OPTION => VALUE ... ]
316 Returns an sql fragement to select only agentnums this user can view.
318 Options are passed as a hashref or a list. Available options are:
324 The frament will also allow the selection of null agentnums.
328 The fragment will also allow the selection of null agentnums if the current
329 user has the provided access right
333 Optional table name in which agentnum is being checked. Sometimes required to
334 resolve 'column reference "agentnum" is ambiguous' errors.
342 my %opt = ref($_[0]) ? %{$_[0]} : @_;
344 my $agentnum = $opt{'table'} ? $opt{'table'}.'.agentnum' : 'agentnum';
346 my @agentnums = map { "$agentnum = $_" } $self->agentnums;
348 push @agentnums, "$agentnum IS NULL"
350 || ( $opt{'null_right'} && $self->access_right($opt{'null_right'}) );
352 return ' 1 = 0 ' unless scalar(@agentnums);
353 '( '. join( ' OR ', @agentnums ). ' )';
358 Returns true if the user can view the specified agent.
363 my( $self, $agentnum ) = @_;
364 my $sth = dbh->prepare(
365 "SELECT COUNT(*) FROM access_usergroup
366 JOIN access_groupagent USING ( groupnum )
367 WHERE usernum = ? AND agentnum = ?"
368 ) or die dbh->errstr;
369 $sth->execute($self->usernum, $agentnum) or die $sth->errstr;
370 $sth->fetchrow_arrayref->[0];
375 Returns the list of agents this user can view (via group membership), as
384 'hashref' => { disabled=>'' },
385 'extra_sql' => ' AND '. $self->agentnums_sql,
391 Given a right name, returns true if this user has this right (currently via
392 group membership, eventually also via user overrides).
397 my( $self, $rightname ) = @_;
398 my $sth = dbh->prepare("
399 SELECT groupnum FROM access_usergroup
400 LEFT JOIN access_group USING ( groupnum )
401 LEFT JOIN access_right
402 ON ( access_group.groupnum = access_right.rightobjnum )
404 AND righttype = 'FS::access_group'
406 ") or die dbh->errstr;
407 $sth->execute($self->usernum, $rightname) or die $sth->errstr;
408 my $row = $sth->fetchrow_arrayref;
409 $row ? $row->[0] : '';
418 L<FS::Record>, schema.html from the base documentation.