1 package FS::part_export;
4 use vars qw( @ISA @EXPORT_OK $DEBUG %exports );
7 use base qw( FS::option_Common FS::m2m_Common );
8 use FS::Record qw( qsearch qsearchs dbh );
10 use FS::part_export_option;
11 use FS::part_export_machine;
14 #for export modules, though they should probably just use it themselves
17 @EXPORT_OK = qw(export_info);
23 FS::part_export - Object methods for part_export records
29 $record = new FS::part_export \%hash;
30 $record = new FS::part_export { 'column' => 'value' };
32 #($new_record, $options) = $template_recored->clone( $svcpart );
34 $error = $record->insert( { 'option' => 'value' } );
35 $error = $record->insert( \%options );
37 $error = $new_record->replace($old_record);
39 $error = $record->delete;
41 $error = $record->check;
45 An FS::part_export object represents an export of Freeside data to an external
46 provisioning system. FS::part_export inherits from FS::Record. The following
47 fields are currently supported:
51 =item exportnum - primary key
53 =item exportname - Descriptive name
55 =item machine - Machine name
57 =item exporttype - Export type
59 =item nodomain - blank or "Y" : usernames are exported to this service with no domain
69 Creates a new export. To add the export to the database, see L<"insert">.
71 Note that this stores the hash reference, not a distinct copy of the hash it
72 points to. You can ask the object for a copy with the I<hash> method.
76 # the new method can be inherited from FS::Record, if a table method is defined
78 sub table { 'part_export'; }
84 #An alternate constructor. Creates a new export by duplicating an existing
85 #export. The given svcpart is assigned to the new export.
87 #Returns a list consisting of the new export object and a hashref of options.
93 # my $class = ref($self);
94 # my %hash = $self->hash;
95 # $hash{'exportnum'} = '';
96 # $hash{'svcpart'} = shift;
97 # ( $class->new( \%hash ),
98 # { map { $_->optionname => $_->optionvalue }
99 # qsearch('part_export_option', { 'exportnum' => $self->exportnum } )
106 Adds this record to the database. If there is an error, returns the error,
107 otherwise returns false.
109 If a hash reference of options is supplied, part_export_option records are
110 created (see L<FS::part_export_option>).
117 local $SIG{HUP} = 'IGNORE';
118 local $SIG{INT} = 'IGNORE';
119 local $SIG{QUIT} = 'IGNORE';
120 local $SIG{TERM} = 'IGNORE';
121 local $SIG{TSTP} = 'IGNORE';
122 local $SIG{PIPE} = 'IGNORE';
123 my $oldAutoCommit = $FS::UID::AutoCommit;
124 local $FS::UID::AutoCommit = 0;
127 my $error = $self->SUPER::insert(@_);
129 $dbh->rollback if $oldAutoCommit;
133 #kinda false laziness with process_m2name
134 my @machines = map { $_ =~ s/^\s+//; $_ =~ s/\s+$//; $_ }
137 $self->part_export_machine_textarea;
139 foreach my $machine ( @machines ) {
141 my $part_export_machine = new FS::part_export_machine {
142 'exportnum' => $self->exportnum,
143 'machine' => $machine,
145 $error = $part_export_machine->insert;
147 $dbh->rollback if $oldAutoCommit;
152 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
158 Delete this record from the database.
162 #foreign keys would make this much less tedious... grr dumb mysql
166 local $SIG{HUP} = 'IGNORE';
167 local $SIG{INT} = 'IGNORE';
168 local $SIG{QUIT} = 'IGNORE';
169 local $SIG{TERM} = 'IGNORE';
170 local $SIG{TSTP} = 'IGNORE';
171 local $SIG{PIPE} = 'IGNORE';
172 my $oldAutoCommit = $FS::UID::AutoCommit;
173 local $FS::UID::AutoCommit = 0;
176 # clean up export_nas records
177 my $error = $self->process_m2m(
178 'link_table' => 'export_nas',
179 'target_table' => 'nas',
181 ) || $self->SUPER::delete;
183 $dbh->rollback if $oldAutoCommit;
187 foreach my $export_svc ( $self->export_svc ) {
188 my $error = $export_svc->delete;
190 $dbh->rollback if $oldAutoCommit;
195 foreach my $part_export_machine ( $self->part_export_machine ) {
196 my $error = $part_export_machine->delete;
198 $dbh->rollback if $oldAutoCommit;
203 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
207 =item replace [ OLD_RECORD ] [ HASHREF | OPTION => VALUE ... ]
209 Replaces the OLD_RECORD with this one in the database. If there is an error,
210 returns the error, otherwise returns false.
212 If a list or hash reference of options is supplied, option records are created
220 local $SIG{HUP} = 'IGNORE';
221 local $SIG{INT} = 'IGNORE';
222 local $SIG{QUIT} = 'IGNORE';
223 local $SIG{TERM} = 'IGNORE';
224 local $SIG{TSTP} = 'IGNORE';
225 local $SIG{PIPE} = 'IGNORE';
227 my $oldAutoCommit = $FS::UID::AutoCommit;
228 local $FS::UID::AutoCommit = 0;
231 my $error = $self->SUPER::replace(@_);
233 $dbh->rollback if $oldAutoCommit;
237 if ( $self->part_export_machine_textarea ) {
239 my %part_export_machine = map { $_->machine => $_ }
240 $self->part_export_machine;
242 my @machines = map { $_ =~ s/^\s+//; $_ =~ s/\s+$//; $_ }
245 $self->part_export_machine_textarea;
247 foreach my $machine ( @machines ) {
249 if ( $part_export_machine{$machine} ) {
251 if ( $part_export_machine{$machine}->disabled eq 'Y' ) {
252 $part_export_machine{$machine}->disabled('');
253 $error = $part_export_machine{$machine}->replace;
255 $dbh->rollback if $oldAutoCommit;
260 delete $part_export_machine{$machine}; #so we don't disable it below
264 my $part_export_machine = new FS::part_export_machine {
265 'exportnum' => $self->exportnum,
266 'machine' => $machine
268 $error = $part_export_machine->insert;
270 $dbh->rollback if $oldAutoCommit;
279 foreach my $part_export_machine ( values %part_export_machine ) {
280 $part_export_machine->disabled('Y');
281 $error = $part_export_machine->replace;
283 $dbh->rollback if $oldAutoCommit;
290 $dbh->commit or die $dbh->errstr if $oldAutoCommit;
296 Checks all fields to make sure this is a valid export. If there is
297 an error, returns the error, otherwise returns false. Called by the insert
305 $self->ut_numbern('exportnum')
306 || $self->ut_textn('exportname')
307 || $self->ut_domainn('machine')
308 || $self->ut_alpha('exporttype')
310 return $error if $error;
312 $self->nodomain =~ /^(Y?)$/ or return "Illegal nodomain: ". $self->nodomain;
315 $self->deprecated(1); #BLAH
324 Returns a label for this export, "exportname||exportype (machine)".
330 ($self->exportname || $self->exporttype ). ' ('. $self->machine. ')';
335 #Returns the service definition (see L<FS::part_svc>) for this export.
341 # qsearchs('part_svc', { svcpart => $self->svcpart } );
346 croak "FS::part_export::part_svc deprecated";
347 #confess "FS::part_export::part_svc deprecated";
352 Returns a list of associated FS::svc_* records.
358 map { $_->svc_x } $self->cust_svc;
363 Returns a list of associated FS::cust_svc records.
369 map { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
370 grep { qsearch('cust_svc', { 'svcpart' => $_->svcpart } ) }
374 =item part_export_machine
376 Returns all machines as FS::part_export_machine objects (see
377 L<FS::part_export_machine>).
381 sub part_export_machine {
383 map { $_ } #behavior of sort undefined in scalar context
384 sort { $a->machine cmp $b->machine }
385 qsearch('part_export_machine', { 'exportnum' => $self->exportnum } );
390 Returns a list of associated FS::export_svc records.
396 qsearch('export_svc', { 'exportnum' => $self->exportnum } );
401 Returns a list of associated FS::export_device records.
407 qsearch('export_device', { 'exportnum' => $self->exportnum } );
410 =item part_export_option
412 Returns all options as FS::part_export_option objects (see
413 L<FS::part_export_option>).
417 sub part_export_option {
419 $self->option_objects;
424 Returns a list of option names and values suitable for assigning to a hash.
426 =item option OPTIONNAME
428 Returns the option value for the given name, or the empty string.
432 Reblesses the object into the FS::part_export::EXPORTTYPE class, where
433 EXPORTTYPE is the object's I<exporttype> field. There should be better docs
434 on how to create new exports, but until then, see L</NEW EXPORT CLASSES>.
440 my $exporttype = $self->exporttype;
441 my $class = ref($self). "::$exporttype";
444 bless($self, $class) unless $@;
448 #these should probably all go away, just let the subclasses define em
450 =item export_insert SVC_OBJECT
457 $self->_export_insert(@_);
463 # my $method = $AUTOLOAD;
464 # #$method =~ s/::(\w+)$/::_$1/; #infinite loop prevention
465 # $method =~ s/::(\w+)$/_$1/; #infinite loop prevention
466 # $self->$method(@_);
469 =item export_replace NEW OLD
476 $self->_export_replace(@_);
486 $self->_export_delete(@_);
496 $self->_export_suspend(@_);
499 =item export_unsuspend
503 sub export_unsuspend {
506 $self->_export_unsuspend(@_);
509 #fallbacks providing useful error messages intead of infinite loops
512 return "_export_insert: unknown export type ". $self->exporttype;
515 sub _export_replace {
517 return "_export_replace: unknown export type ". $self->exporttype;
522 return "_export_delete: unknown export type ". $self->exporttype;
525 #call svcdb-specific fallbacks
527 sub _export_suspend {
529 #warn "warning: _export_suspened unimplemented for". ref($self);
531 my $new = $svc_x->clone_suspended;
532 $self->_export_replace( $new, $svc_x );
535 sub _export_unsuspend {
537 #warn "warning: _export_unsuspend unimplemented for ". ref($self);
539 my $old = $svc_x->clone_kludge_unsuspend;
540 $self->_export_replace( $svc_x, $old );
543 =item export_links SVC_OBJECT ARRAYREF
545 Adds a list of web elements to ARRAYREF specific to this export and SVC_OBJECT.
546 The elements are displayed in the UI to lead the the operator to external
547 configuration, monitoring, and similar tools.
549 =item export_getsettings SVC_OBJECT SETTINGS_HASHREF DEFAUTS_HASHREF
551 Adds a hashref of settings to SETTINGSREF specific to this export and
552 SVC_OBJECT. The elements can be displayed in the UI on the service view.
554 DEFAULTSREF is a hashref with the same keys where true values indicate the
555 setting is a default (and thus can be displayed in the UI with less emphasis,
556 or hidden by default).
562 Returns the 'weight' element from the export's %info hash, or 0 if there is
569 export_info()->{$self->exporttype}->{'weight'} || 0;
578 =item export_info [ SVCDB ]
580 Returns a hash reference of the exports for the given I<svcdb>, or if no
581 I<svcdb> is specified, for all exports. The keys of the hash are
582 I<exporttype>s and the values are again hash references containing information
585 'desc' => 'Description',
587 'option' => { label=>'Option Label' },
588 'option2' => { label=>'Another label' },
590 'nodomain' => 'Y', #or ''
591 'notes' => 'Additional notes',
597 return $exports{$_[0]} || {} if @_;
598 #{ map { %{$exports{$_}} } keys %exports };
599 my $r = { map { %{$exports{$_}} } keys %exports };
603 sub _upgrade_data { #class method
604 my ($class, %opts) = @_;
606 my @part_export_option = qsearch('part_export_option', { 'optionname' => 'overlimit_groups' });
607 foreach my $opt ( @part_export_option ) {
608 next if $opt->optionvalue =~ /^[\d\s]+$/ || !$opt->optionvalue;
609 my @groupnames = split(' ',$opt->optionvalue);
612 foreach my $groupname ( @groupnames ) {
613 my $g = qsearchs('radius_group', { 'groupname' => $groupname } );
615 $g = new FS::radius_group {
616 'groupname' => $groupname,
617 'description' => $groupname,
620 die $error if $error;
622 push @groupnums, $g->groupnum;
624 $opt->optionvalue(join(' ',@groupnums));
625 $error = $opt->replace;
626 die $error if $error;
630 $exports_in_use{ref $_} = 1 foreach qsearch('part_export', {});
631 foreach (keys(%exports_in_use)) {
632 $_->_upgrade_exporttype(%opts) if $_->can('_upgrade_exporttype');
636 #=item exporttype2svcdb EXPORTTYPE
638 #Returns the applicable I<svcdb> for an I<exporttype>.
642 #sub exporttype2svcdb {
643 # my $exporttype = $_[0];
644 # foreach my $svcdb ( keys %exports ) {
645 # return $svcdb if grep { $exporttype eq $_ } keys %{$exports{$svcdb}};
650 #false laziness w/part_pkg & cdr
651 foreach my $INC ( @INC ) {
652 foreach my $file ( glob("$INC/FS/part_export/*.pm") ) {
653 warn "attempting to load export info from $file\n" if $DEBUG;
654 $file =~ /\/(\w+)\.pm$/ or do {
655 warn "unrecognized file in $INC/FS/part_export/: $file\n";
659 my $info = eval "use FS::part_export::$mod; ".
660 "\\%FS::part_export::$mod\::info;";
662 die "error using FS::part_export::$mod (skipping): $@\n" if $@;
665 unless ( keys %$info ) {
666 warn "no %info hash found in FS::part_export::$mod, skipping\n"
667 unless $mod =~ /^(passwdfile|null|.+_Common)$/; #hack but what the heck
670 warn "got export info from FS::part_export::$mod: $info\n" if $DEBUG;
673 ref($info->{'svc'}) ? @{$info->{'svc'}} : $info->{'svc'}
676 warn "blank svc for FS::part_export::$mod (skipping)\n";
679 $exports{$svc}->{$mod} = $info;
686 =head1 NEW EXPORT CLASSES
688 A module should be added in FS/FS/part_export/ (an example may be found in
689 eg/export_template.pm)
693 Hmm... cust_export class (not necessarily a database table...) ... ?
699 L<FS::part_export_option>, L<FS::export_svc>, L<FS::svc_acct>,
701 L<FS::svc_forward>, L<FS::Record>, schema.html from the base documentation.