per-agent disable_previous_balance, #15863
[freeside.git] / FS / FS / radius_attr.pm
1 package FS::radius_attr;
2
3 use strict;
4 use base qw( FS::Record );
5 use FS::Record qw( qsearch qsearchs );
6 use vars qw( $noexport_hack );
7
8 =head1 NAME
9
10 FS::radius_attr - Object methods for radius_attr records
11
12 =head1 SYNOPSIS
13
14   use FS::radius_attr;
15
16   $record = new FS::radius_attr \%hash;
17   $record = new FS::radius_attr { 'column' => 'value' };
18
19   $error = $record->insert;
20
21   $error = $new_record->replace($old_record);
22
23   $error = $record->delete;
24
25   $error = $record->check;
26
27 =head1 DESCRIPTION
28
29 An FS::radius_attr object represents a RADIUS group attribute.
30 FS::radius_attr inherits from FS::Record.  The following fields are 
31 currently supported:
32
33 =over 4
34
35 =item attrnum - primary key
36
37 =item groupnum - L<FS::radius_group> to assign this attribute
38
39 =item attrname - Attribute name, as defined in the RADIUS server's dictionary
40
41 =item value - Attribute value
42
43 =item attrtype - 'C' (check) or 'R' (reply)
44
45 =item op - Operator (see L<http://wiki.freeradius.org/Operators>)
46
47 =back
48
49 =head1 METHODS
50
51 =over 4
52
53 =item new HASHREF
54
55 Creates a new record.  To add the record to the database, see L<"insert">.
56
57 Note that this stores the hash reference, not a distinct copy of the hash it
58 points to.  You can ask the object for a copy with the I<hash> method.
59
60 =cut
61
62 # the new method can be inherited from FS::Record, if a table method is defined
63
64 sub table { 'radius_attr'; }
65
66 =item insert
67
68 Adds this record to the database.  If there is an error, returns the error,
69 otherwise returns false.  If any sqlradius-type exports exist and have the 
70 C<export_attrs> option enabled, the new attribute will be exported to them.
71
72 =cut
73
74 sub insert {
75   my $self = shift;
76   my $error = $self->SUPER::insert;
77   return $error if $error;
78   return if $noexport_hack;
79
80   foreach ( qsearch('part_export', {}) ) {
81     next if !$_->option('export_attrs',1);
82     $error = $_->export_attr_insert($self);
83     return $error if $error;
84   }
85
86   '';
87 }
88
89
90 =item delete
91
92 Delete this record from the database.  Like C<insert>, this will delete 
93 the attribute from any attached RADIUS databases.
94
95 =cut
96
97 sub delete {
98   my $self = shift;
99   my $error;
100   if ( !$noexport_hack ) {
101     foreach ( qsearch('part_export', {}) ) {
102       next if !$_->option('export_attrs',1);
103       $error = $_->export_attr_delete($self);
104       return $error if $error;
105     }
106   }
107   
108   $self->SUPER::delete;
109 }
110
111 =item replace OLD_RECORD
112
113 Replaces the OLD_RECORD with this one in the database.  If there is an error,
114 returns the error, otherwise returns false.
115
116 =cut
117
118 sub replace {
119   my ($self, $old) = @_;
120   $old ||= $self->replace_old;
121   return 'can\'t change radius_attr.groupnum'
122     if $self->groupnum != $old->groupnum;
123   return ''
124     unless grep { $self->$_ ne $old->$_ } qw(attrname value op attrtype);
125
126   # don't attempt export on an invalid record
127   my $error = $self->check;
128   return $error if $error;
129
130   # exportage
131   $old->set('groupname', $old->radius_group->groupname);
132   if ( !$noexport_hack ) {
133     foreach ( qsearch('part_export', {}) ) {
134       next if !$_->option('export_attrs',1);
135       $error = $_->export_attr_replace($self, $old);
136       return $error if $error;
137     }
138   }
139   
140   $self->SUPER::replace($old);
141 }
142
143
144 =item check
145
146 Checks all fields to make sure this is a valid record.  If there is
147 an error, returns the error, otherwise returns false.  Called by the insert
148 and replace methods.
149
150 =cut
151
152 sub check {
153   my $self = shift;
154
155   my $error = 
156     $self->ut_numbern('attrnum')
157     || $self->ut_foreign_key('groupnum', 'radius_group', 'groupnum')
158     || $self->ut_text('attrname')
159     || $self->ut_text('value')
160     || $self->ut_enum('attrtype', [ 'C', 'R' ])
161   ;
162   return $error if $error;
163
164   my @ops = $self->ops($self->get('attrtype'));
165   $self->set('op' => $ops[0]) if !$self->get('op');
166   $error ||= $self->ut_enum('op', \@ops);
167   
168   return $error if $error;
169
170   $self->SUPER::check;
171 }
172
173 =item radius_group
174
175 Returns the L<FS::radius_group> object to which this attribute applies.
176
177 =cut
178
179 sub radius_group {
180   my $self = shift;
181   qsearchs('radius_group', { 'groupnum' => $self->groupnum });
182 }
183
184 =back
185
186 =head1 CLASS METHODS
187
188 =over 4
189
190 =item ops ATTRTYPE
191
192 Returns a list of all legal values of the "op" field.  ATTRTYPE must be C for 
193 check or R for reply.
194
195 =cut
196
197 my %ops = (
198   C => [ '==', ':=', '+=', '!=', '>', '>=', '<', '<=', '=~', '!~', '=*', '!*' ],
199   R => [ '=', ':=', '+=' ],
200 );
201
202 sub ops {
203   my $self = shift;
204   my $attrtype = shift;
205   return @{ $ops{$attrtype} };
206 }
207
208 =back
209
210 =head1 BUGS
211
212 =head1 SEE ALSO
213
214 L<FS::Record>, schema.html from the base documentation.
215
216 =cut
217
218 1;