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