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:
322 =item null - The frament will also allow the selection of null agentnums.
324 =item null_right - The fragment will also allow the selection of null agentnums if the current user has the provided access right
326 =item table - Optional table name in which agentnum is being checked. Sometimes required to resolve 'column reference "agentnum" is ambiguous' errors.
334 my %opt = ref($_[0]) ? %{$_[0]} : @_;
336 my $agentnum = $opt{'table'} ? $opt{'table'}.'.agentnum' : 'agentnum';
338 my @agentnums = map { "$agentnum = $_" } $self->agentnums;
340 push @agentnums, "$agentnum IS NULL"
342 || ( $opt{'null_right'} && $self->access_right($opt{'null_right'}) );
344 return ' 1 = 0 ' unless scalar(@agentnums);
345 '( '. join( ' OR ', @agentnums ). ' )';
350 Returns true if the user can view the specified agent.
355 my( $self, $agentnum ) = @_;
356 my $sth = dbh->prepare(
357 "SELECT COUNT(*) FROM access_usergroup
358 JOIN access_groupagent USING ( groupnum )
359 WHERE usernum = ? AND agentnum = ?"
360 ) or die dbh->errstr;
361 $sth->execute($self->usernum, $agentnum) or die $sth->errstr;
362 $sth->fetchrow_arrayref->[0];
367 Returns the list of agents this user can view (via group membership), as
376 'hashref' => { disabled=>'' },
377 'extra_sql' => ' AND '. $self->agentnums_sql,
383 Given a right name, returns true if this user has this right (currently via
384 group membership, eventually also via user overrides).
389 my( $self, $rightname ) = @_;
390 my $sth = dbh->prepare("
391 SELECT groupnum FROM access_usergroup
392 LEFT JOIN access_group USING ( groupnum )
393 LEFT JOIN access_right
394 ON ( access_group.groupnum = access_right.rightobjnum )
396 AND righttype = 'FS::access_group'
398 ") or die dbh->errstr;
399 $sth->execute($self->usernum, $rightname) or die $sth->errstr;
400 my $row = $sth->fetchrow_arrayref;
401 $row ? $row->[0] : '';
410 L<FS::Record>, schema.html from the base documentation.