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 my $error = $self->check;
94 return $error if $error;
96 local $SIG{HUP} = 'IGNORE';
97 local $SIG{INT} = 'IGNORE';
98 local $SIG{QUIT} = 'IGNORE';
99 local $SIG{TERM} = 'IGNORE';
100 local $SIG{TSTP} = 'IGNORE';
101 local $SIG{PIPE} = 'IGNORE';
103 my $oldAutoCommit = $FS::UID::AutoCommit;
104 local $FS::UID::AutoCommit = 0;
107 $error = $self->htpasswd_kludge();
109 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
113 $error = $self->SUPER::insert(@_);
116 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
118 #make sure it isn't a dup username? or you could nuke people's passwords
119 #blah. really just should do our own login w/cookies
120 #and auth out of the db in the first place
121 #my $hterror = $self->htpasswd_kludge('-D');
122 #$error .= " - additionally received error cleaning up htpasswd file: $hterror"
126 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
132 sub htpasswd_kludge {
135 #awful kludge to skip setting htpasswd for fs_* users
136 return '' if $self->username =~ /^fs_/;
138 unshift @_, '-c' unless -e $htpasswd_file;
140 system('htpasswd', '-b', @_,
149 return 'htpasswd exited unsucessfully';
155 Delete this record from the database.
162 local $SIG{HUP} = 'IGNORE';
163 local $SIG{INT} = 'IGNORE';
164 local $SIG{QUIT} = 'IGNORE';
165 local $SIG{TERM} = 'IGNORE';
166 local $SIG{TSTP} = 'IGNORE';
167 local $SIG{PIPE} = 'IGNORE';
169 my $oldAutoCommit = $FS::UID::AutoCommit;
170 local $FS::UID::AutoCommit = 0;
174 $self->SUPER::delete(@_)
175 || $self->htpasswd_kludge('-D')
179 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
182 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
188 =item replace OLD_RECORD
190 Replaces the OLD_RECORD with this one in the database. If there is an error,
191 returns the error, otherwise returns false.
198 my $old = ( ref($_[0]) eq ref($new) )
202 local $SIG{HUP} = 'IGNORE';
203 local $SIG{INT} = 'IGNORE';
204 local $SIG{QUIT} = 'IGNORE';
205 local $SIG{TERM} = 'IGNORE';
206 local $SIG{TSTP} = 'IGNORE';
207 local $SIG{PIPE} = 'IGNORE';
209 my $oldAutoCommit = $FS::UID::AutoCommit;
210 local $FS::UID::AutoCommit = 0;
213 if ( $new->_password ne $old->_password ) {
214 my $error = $new->htpasswd_kludge();
216 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
221 my $error = $new->SUPER::replace($old, @_);
224 $dbh->rollback or die $dbh->errstr if $oldAutoCommit;
227 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
235 Checks all fields to make sure this is a valid internal access user. If there is
236 an error, returns the error, otherwise returns false. Called by the insert
241 # the check method should currently be supplied - FS::Record contains some
242 # data checking routines
248 $self->ut_numbern('usernum')
249 || $self->ut_alpha_lower('username')
250 || $self->ut_text('_password')
251 || $self->ut_text('last')
252 || $self->ut_text('first')
253 || $self->ut_enum('disabled', [ '', 'Y' ] )
255 return $error if $error;
262 Returns a name string for this user: "Last, First".
268 $self->get('last'). ', '. $self->first;
271 =item access_usergroup
275 sub access_usergroup {
277 qsearch( 'access_usergroup', { 'usernum' => $self->usernum } );
288 #=item access_groupnames
292 #sub access_groupnames {
298 Returns a list of agentnums this user can view (via group membership).
304 my $sth = dbh->prepare(
305 "SELECT DISTINCT agentnum FROM access_usergroup
306 JOIN access_groupagent USING ( groupnum )
308 ) or die dbh->errstr;
309 $sth->execute($self->usernum) or die $sth->errstr;
310 map { $_->[0] } @{ $sth->fetchall_arrayref };
315 Returns a hashref of agentnums this user can view.
321 { map { $_ => 1 } $self->agentnums };
326 Returns an sql fragement to select only agentnums this user can view.
333 my @agentnums = map { "agentnum = $_" } $self->agentnums;
335 push @agentnums, 'agentnum IS NULL'
336 if $self->access_right('View/link unlinked services');
338 return ' 1 = 0 ' unless scalar(@agentnums);
339 '( '. join( ' OR ', @agentnums ). ' )';
344 Returns true if the user can view the specified agent.
349 my( $self, $agentnum ) = @_;
350 my $sth = dbh->prepare(
351 "SELECT COUNT(*) FROM access_usergroup
352 JOIN access_groupagent USING ( groupnum )
353 WHERE usernum = ? AND agentnum = ?"
354 ) or die dbh->errstr;
355 $sth->execute($self->usernum, $agentnum) or die $sth->errstr;
356 $sth->fetchrow_arrayref->[0];
361 Returns the list of agents this user can view (via group membership), as
370 'hashref' => { disabled=>'' },
371 'extra_sql' => ' AND '. $self->agentnums_sql,
377 Given a right name, returns true if this user has this right (currently via
378 group membership, eventually also via user overrides).
383 my( $self, $rightname ) = @_;
384 my $sth = dbh->prepare("
385 SELECT groupnum FROM access_usergroup
386 LEFT JOIN access_group USING ( groupnum )
387 LEFT JOIN access_right
388 ON ( access_group.groupnum = access_right.rightobjnum )
390 AND righttype = 'FS::access_group'
392 ") or die dbh->errstr;
393 $sth->execute($self->usernum, $rightname) or die $sth->errstr;
394 my $row = $sth->fetchrow_arrayref;
395 $row ? $row->[0] : '';
404 L<FS::Record>, schema.html from the base documentation.