1 package FS::part_export::thirdlane;
3 use base qw( FS::part_export );
5 use vars qw(%info $me);
9 $me = '['.__PACKAGE__.']';
11 tie my %options, 'Tie::IxHash',
12 #'server' => { label => 'Thirdlane server name or IP address', },
13 'username' => { label => 'Thirdlane username', },
14 'password' => { label => 'Thirdlane password', },
15 'port' => { label => 'Port number if not 80', },
16 'prototype_tenant' => { label => 'Prototype tenant name', },
17 'debug' => { label => 'Checkbox label', type => 'checkbox' },
18 # 'select_option' => { label => 'Select option description',
19 # type => 'select', options=>[qw(chocolate vanilla)],
20 # default => 'vanilla',
22 # 'textarea_option' => { label => 'Textarea option description',
24 # default => 'Default text.',
29 'svc' => [qw( svc_pbx svc_phone svc_acct )],
31 'Export tenants, DIDs and admins to Thirdlane PBX manager',
32 'options' => \%options,
34 Exports tenants, DIDs and admins to Thirdlane PBX manager using the XML-RPC API.
38 sub rebless { shift; }
41 my($self, $svc_x) = (shift, shift);
43 if ( $svc_x->isa('FS::svc_pbx') ) {
45 return 'Name must be 19 characters or less (thirdlane restriction?)'
46 if length($svc_x->title) > 19;
48 return 'Name must consist of alphanumerics and spaces only (thirdlane restriction?)'
49 unless $svc_x->title =~ /^[\w\s]+$/;
52 'tenant' => $svc_x->title,
53 'maxusers' => $svc_x->max_extensions,
54 #others? will they not clone?
57 @what_to_clone = qw(routes schedules menus queues voiceprompts moh);
59 my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_create',
61 $self->option('prototype_tenant'),
66 #warn Dumper(\$result);
67 $result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_create)';
69 } elsif ( $svc_x->isa('FS::svc_phone') ) {
71 my $result = $self->_thirdlane_command(
72 'asterisk::rpc_did_create',
73 $svc_x->countrycode. $svc_x->phonenum,
77 #warn Dumper(\$result);
78 $result eq '0' or return 'Thirdlane API failure (rpc_did_create)';
80 return '' unless $svc_x->pbxsvc;
82 $result = $self->_thirdlane_command(
83 'asterisk::rpc_did_assign',
84 $svc_x->countrycode. $svc_x->phonenum,
89 #warn Dumper(\$result);
90 $result eq '0' ? '' : 'Thirdlane API failure (rpc_did_assign)';
92 } elsif ( $svc_x->isa('FS::svc_acct') ) {
94 return 'Must select a PBX' unless $svc_x->pbxsvc;
96 my $result = $self->_thirdlane_command(
97 'asterisk::rpc_admin_create',
104 #warn Dumper(\$result);
105 $result eq '0' ? '' : 'Thirdlane API failure (rpc_admin_create)';
108 die "guru meditation #10: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
113 sub _export_replace {
114 my($self, $new, $old) = (shift, shift, shift);
116 # #return "can't change username with thirdlane"
117 # # if $old->username ne $new->username;
118 # #return '' unless $old->_password ne $new->_password;
119 # $err_or_queue = $self->thirdlane_queue( $new->svcnum,
120 # 'replace', $new->username, $new->_password );
121 # ref($err_or_queue) ? '' : $err_or_queue;
123 if ( $new->isa('FS::svc_pbx') ) {
125 #need more info on how the API works for changing names.. can it?
126 return "can't change PBX name with thirdlane (yet?)"
127 if $old->title ne $new->title;
130 'tenant' => $old->title,
131 'maxusers' => $new->max_extensions,
132 #others? will they not clone?
135 my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_update',
140 #warn Dumper(\$result);
141 $result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_update)';
143 } elsif ( $new->isa('FS::svc_phone') ) {
145 return "can't change DID countrycode with thirdlane"
146 if $old->countrycode ne $new->countrycode;
147 return "can't change DID number with thirdlane"
148 if $old->phonenum ne $new->phonenum;
150 if ( $old->pbxsvc != $new->pbxsvc ) {
152 if ( $old->pbxsvc ) {
153 my $result = $self->_thirdlane_command(
154 'asterisk::rpc_did_unassign',
155 $new->countrycode. $new->phonenum,
157 $result eq '0' or return 'Thirdlane API failure (rpc_did_unassign)';
160 if ( $new->pbxsvc ) {
161 my $result = $self->_thirdlane_command(
162 'asterisk::rpc_did_assign',
163 $new->countrycode. $new->phonenum,
166 $result eq '0' or return 'Thirdlane API failure (rpc_did_assign)';
174 } elsif ( $new->isa('FS::svc_acct') ) {
176 return "can't change uesrname with thirdlane"
177 if $old->username ne $new->username;
179 return "can't change password with thirdlane"
180 if $old->_password ne $new->_password;
182 return "can't change PBX for user with thirdlane"
183 if $old->pbxsvc != $new->pbxsvc;
185 ''; #we don't care then
188 die "guru meditation #11: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
194 my($self, $svc_x) = (shift, shift);
195 #my( $self, $svc_something ) = (shift, shift);
196 #$err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
197 # 'delete', $svc_something->username );
198 #ref($err_or_queue) ? '' : $err_or_queue;
200 if ( $svc_x->isa('FS::svc_pbx') ) {
202 my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_delete',
207 #warn Dumper(\$result);
208 #$result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_delete)';
209 warn "Thirdlane API failure (rpc_tenant_delete); deleting anyway\n"
213 } elsif ( $svc_x->isa('FS::svc_phone') ) {
215 if ( $svc_x->pbxsvc ) {
216 my $result = $self->_thirdlane_command(
217 'asterisk::rpc_did_unassign',
218 $svc_x->countrycode. $svc_x->phonenum,
220 $result eq '0' or return 'Thirdlane API failure (rpc_did_unassign)';
223 my $result = $self->_thirdlane_command(
224 'asterisk::rpc_did_delete',
225 $svc_x->countrycode. $svc_x->phonenum,
227 $result eq '0' ? '' : 'Thirdlane API failure (rpc_did_delete)';
229 } elsif ( $svc_x->isa('FS::svc_acct') ) {
231 return '' unless $svc_x->pbxsvc; #error out? nah
233 my $result = $self->_thirdlane_command(
234 'asterisk::rpc_admin_delete',
240 #warn Dumper(\$result);
241 #$result eq '0' ? '' : 'Thirdlane API failure (rpc_admin_delete)';
242 warn "Thirdlane API failure (rpc_admin_delete); deleting anyway\n"
247 die "guru meditation #12: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
252 sub _thirdlane_command {
253 my($self, @param) = @_;
256 'http://'. $self->option('username'). ':'. $self->option('password'). '@'.
258 $url.= ':'. $self->option('port') if $self->option('port');
259 $url .= '/xmlrpc.cgi';
261 warn "$me connecting to $url\n"
262 if $self->option('debug');
263 my $conn = Frontier::Client->new( 'url' => $url,
264 #no, spews output to browser
265 #'debug' => $self->option('debug'),
268 warn "$me sending command: ". join(' ', @param). "\n"
269 if $self->option('debug');
274 #my( $self, $svc_something ) = (shift, shift);
275 #$err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
276 # 'delete', $svc_something->username );
277 #ref($err_or_queue) ? '' : $err_or_queue;
279 #these three are optional
280 ## fallback for svc_acct will change and restore password
281 #sub _export_suspend {
282 # my( $self, $svc_something ) = (shift, shift);
283 # $err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
284 # 'suspend', $svc_something->username );
285 # ref($err_or_queue) ? '' : $err_or_queue;
288 #sub _export_unsuspend {
289 # my( $self, $svc_something ) = (shift, shift);
290 # $err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
291 # 'unsuspend', $svc_something->username );
292 # ref($err_or_queue) ? '' : $err_or_queue;
296 # my($self, $svc_something, $arrayref) = (shift, shift, shift);
297 # #push @$arrayref, qq!<A HREF="http://example.com/~!. $svc_something->username.
298 # # qq!">!. $svc_something->username. qq!</A>!;
304 ##a good idea to queue anything that could fail or take any time
305 #sub thirdlane_queue {
306 # my( $self, $svcnum, $method ) = (shift, shift, shift);
307 # my $queue = new FS::queue {
308 # 'svcnum' => $svcnum,
309 # 'job' => "FS::part_export::thirdlane::thirdlane_$method",
311 # $queue->insert( @_ ) or $queue;
314 #sub thirdlane_insert { #subroutine, not method
315 # my( $username, $password ) = @_;
316 # #do things with $username and $password
319 #sub thirdlane_replace { #subroutine, not method
322 #sub thirdlane_delete { #subroutine, not method
323 # my( $username ) = @_;
324 # #do things with $username
327 #sub thirdlane_suspend { #subroutine, not method
330 #sub thirdlane_unsuspend { #subroutine, not method