1 package FS::part_export::thirdlane;
3 use base qw( FS::part_export );
5 use vars qw(%info $me);
10 $me = '['.__PACKAGE__.']';
12 tie my %options, 'Tie::IxHash',
13 #'server' => { label => 'Thirdlane server name or IP address', },
14 'username' => { label => 'Thirdlane username', },
15 'password' => { label => 'Thirdlane password', },
16 'port' => { label => 'Port number if not 80', },
17 'prototype_tenant' => { label => 'Prototype tenant name', },
18 'debug' => { label => 'Checkbox label', type => 'checkbox' },
19 # 'select_option' => { label => 'Select option description',
20 # type => 'select', options=>[qw(chocolate vanilla)],
21 # default => 'vanilla',
23 # 'textarea_option' => { label => 'Textarea option description',
25 # default => 'Default text.',
30 'svc' => [qw( svc_pbx svc_phone svc_acct )],
32 'Export tenants, DIDs and admins to Thirdlane PBX manager',
33 'options' => \%options,
35 Exports tenants, DIDs and admins to Thirdlane PBX manager using the XML-RPC API.
39 sub rebless { shift; }
42 my($self, $svc_x) = (shift, shift);
44 if ( $svc_x->isa('FS::svc_pbx') ) {
46 return 'Name must be 19 characters or less (thirdlane restriction?)'
47 if length($svc_x->title) > 19;
49 return 'Name must consist of alphanumerics and spaces only (thirdlane restriction?)'
50 unless $svc_x->title =~ /^[\w\s]+$/;
53 'tenant' => $svc_x->title,
54 'maxusers' => $svc_x->max_extensions,
55 #others? will they not clone?
58 @what_to_clone = qw(routes schedules menus queues voiceprompts moh);
60 my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_create',
62 $self->option('prototype_tenant'),
67 #warn Dumper(\$result);
68 $result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_create)';
70 } elsif ( $svc_x->isa('FS::svc_phone') ) {
72 my $result = $self->_thirdlane_command(
73 'asterisk::rpc_did_create',
74 $svc_x->countrycode. $svc_x->phonenum,
78 #warn Dumper(\$result);
79 $result eq '0' or return 'Thirdlane API failure (rpc_did_create)';
81 return '' unless $svc_x->pbxsvc;
83 $result = $self->_thirdlane_command(
84 'asterisk::rpc_did_assign',
85 $svc_x->countrycode. $svc_x->phonenum,
90 #warn Dumper(\$result);
91 $result eq '0' ? '' : 'Thirdlane API failure (rpc_did_assign)';
93 } elsif ( $svc_x->isa('FS::svc_acct') ) {
95 return 'Must select a PBX' unless $svc_x->pbxsvc;
97 my $result = $self->_thirdlane_command(
98 'asterisk::rpc_admin_create',
105 #warn Dumper(\$result);
106 $result eq '0' ? '' : 'Thirdlane API failure (rpc_admin_create)';
109 die "guru meditation #10: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
114 sub _export_replace {
115 my($self, $new, $old) = (shift, shift, shift);
117 # #return "can't change username with thirdlane"
118 # # if $old->username ne $new->username;
119 # #return '' unless $old->_password ne $new->_password;
120 # $err_or_queue = $self->thirdlane_queue( $new->svcnum,
121 # 'replace', $new->username, $new->_password );
122 # ref($err_or_queue) ? '' : $err_or_queue;
124 if ( $new->isa('FS::svc_pbx') ) {
126 #need more info on how the API works for changing names.. can it?
127 return "can't change PBX name with thirdlane (yet?)"
128 if $old->title ne $new->title;
131 'tenant' => $old->title,
132 'maxusers' => $new->max_extensions,
133 #others? will they not clone?
136 my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_update',
141 #warn Dumper(\$result);
142 $result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_update)';
144 } elsif ( $new->isa('FS::svc_phone') ) {
146 return "can't change DID countrycode with thirdlane"
147 if $old->countrycode ne $new->countrycode;
148 return "can't change DID number with thirdlane"
149 if $old->phonenum ne $new->phonenum;
151 if ( $old->pbxsvc != $new->pbxsvc ) {
153 if ( $old->pbxsvc ) {
154 my $result = $self->_thirdlane_command(
155 'asterisk::rpc_did_unassign',
156 $new->countrycode. $new->phonenum,
158 $result eq '0' or return 'Thirdlane API failure (rpc_did_unassign)';
161 if ( $new->pbxsvc ) {
162 my $result = $self->_thirdlane_command(
163 'asterisk::rpc_did_assign',
164 $new->countrycode. $new->phonenum,
167 $result eq '0' or return 'Thirdlane API failure (rpc_did_assign)';
175 } elsif ( $new->isa('FS::svc_acct') ) {
177 return "can't change uesrname with thirdlane"
178 if $old->username ne $new->username;
180 return "can't change password with thirdlane"
181 if $old->_password ne $new->_password;
183 return "can't change PBX for user with thirdlane"
184 if $old->pbxsvc != $new->pbxsvc;
186 ''; #we don't care then
189 die "guru meditation #11: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
195 my($self, $svc_x) = (shift, shift);
196 #my( $self, $svc_something ) = (shift, shift);
197 #$err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
198 # 'delete', $svc_something->username );
199 #ref($err_or_queue) ? '' : $err_or_queue;
201 if ( $svc_x->isa('FS::svc_pbx') ) {
203 my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_delete',
208 #warn Dumper(\$result);
209 #$result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_delete)';
210 warn "Thirdlane API failure (rpc_tenant_delete); deleting anyway\n"
214 } elsif ( $svc_x->isa('FS::svc_phone') ) {
216 if ( $svc_x->pbxsvc ) {
217 my $result = $self->_thirdlane_command(
218 'asterisk::rpc_did_unassign',
219 $svc_x->countrycode. $svc_x->phonenum,
221 $result eq '0' or return 'Thirdlane API failure (rpc_did_unassign)';
224 my $result = $self->_thirdlane_command(
225 'asterisk::rpc_did_delete',
226 $svc_x->countrycode. $svc_x->phonenum,
228 $result eq '0' ? '' : 'Thirdlane API failure (rpc_did_delete)';
230 } elsif ( $svc_x->isa('FS::svc_acct') ) {
232 return '' unless $svc_x->pbxsvc; #error out? nah
234 my $result = $self->_thirdlane_command(
235 'asterisk::rpc_admin_delete',
241 #warn Dumper(\$result);
242 #$result eq '0' ? '' : 'Thirdlane API failure (rpc_admin_delete)';
243 warn "Thirdlane API failure (rpc_admin_delete); deleting anyway\n"
248 die "guru meditation #12: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
253 sub _thirdlane_command {
254 my($self, @param) = @_;
256 my $url = 'http://'. uri_escape($self->option('username')). ':'.
257 uri_escape($self->option('password')). '@'.
259 $url.= ':'. $self->option('port') if $self->option('port');
260 $url .= '/xmlrpc.cgi';
262 warn "$me connecting to $url\n"
263 if $self->option('debug');
264 my $conn = Frontier::Client->new( 'url' => $url,
265 #no, spews output to browser
266 #'debug' => $self->option('debug'),
269 warn "$me sending command: ". join(' ', @param). "\n"
270 if $self->option('debug');
275 #my( $self, $svc_something ) = (shift, shift);
276 #$err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
277 # 'delete', $svc_something->username );
278 #ref($err_or_queue) ? '' : $err_or_queue;
280 #these three are optional
281 ## fallback for svc_acct will change and restore password
282 #sub _export_suspend {
283 # my( $self, $svc_something ) = (shift, shift);
284 # $err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
285 # 'suspend', $svc_something->username );
286 # ref($err_or_queue) ? '' : $err_or_queue;
289 #sub _export_unsuspend {
290 # my( $self, $svc_something ) = (shift, shift);
291 # $err_or_queue = $self->thirdlane_queue( $svc_something->svcnum,
292 # 'unsuspend', $svc_something->username );
293 # ref($err_or_queue) ? '' : $err_or_queue;
297 # my($self, $svc_something, $arrayref) = (shift, shift, shift);
298 # #push @$arrayref, qq!<A HREF="http://example.com/~!. $svc_something->username.
299 # # qq!">!. $svc_something->username. qq!</A>!;
305 ##a good idea to queue anything that could fail or take any time
306 #sub thirdlane_queue {
307 # my( $self, $svcnum, $method ) = (shift, shift, shift);
308 # my $queue = new FS::queue {
309 # 'svcnum' => $svcnum,
310 # 'job' => "FS::part_export::thirdlane::thirdlane_$method",
312 # $queue->insert( @_ ) or $queue;
315 #sub thirdlane_insert { #subroutine, not method
316 # my( $username, $password ) = @_;
317 # #do things with $username and $password
320 #sub thirdlane_replace { #subroutine, not method
323 #sub thirdlane_delete { #subroutine, not method
324 # my( $username ) = @_;
325 # #do things with $username
328 #sub thirdlane_suspend { #subroutine, not method
331 #sub thirdlane_unsuspend { #subroutine, not method