add port option, RT#7051
[freeside.git] / FS / FS / part_export / thirdlane.pm
1 package FS::part_export::thirdlane;
2
3 use base qw( FS::part_export );
4
5 use vars qw(%info $me);
6 use Tie::IxHash;
7 use Frontier::Client;
8
9 $me = '['.__PACKAGE__.']';
10
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',
21 #                       },
22 #  'textarea_option' => { label   => 'Textarea option description',
23 #                         type    => 'textarea',
24 #                         default => 'Default text.',
25 #                      },
26 ;
27
28 %info = (
29   'svc'      => [qw( svc_pbx svc_phone svc_acct )],
30   'desc'     =>
31     'Export tenants, DIDs and admins to Thirdlane PBX manager',
32   'options'  => \%options,
33   'notes'    => <<'END'
34 Exports tenants, DIDs and admins to Thirdlane PBX manager using the XML-RPC API.
35 END
36 );
37
38 sub rebless { shift; }
39
40 sub _export_insert {
41   my($self, $svc_x) = (shift, shift);
42
43   if ( $svc_x->isa('FS::svc_pbx') ) {
44
45     return 'Name must be 19 characters or less (thirdlane restriction?)'
46       if length($svc_x->title) > 19;
47
48     return 'Name must consist of alphanumerics and spaces only (thirdlane restriction?)'
49       unless $svc_x->title =~ /^[\w\s]+$/;
50
51     my $tenant = {
52       'tenant'   => $svc_x->title,
53       'maxusers' => $svc_x->max_extensions,
54       #others?  will they not clone?
55     };
56
57     @what_to_clone = qw(routes schedules menus queues voiceprompts moh);
58
59     my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_create',
60                                             $tenant,
61                                             $self->option('prototype_tenant'),
62                                             \@what_to_clone,
63                                           );
64
65     #use Data::Dumper;
66     #warn Dumper(\$result);
67     $result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_create)';
68
69   } elsif ( $svc_x->isa('FS::svc_phone') ) {
70
71     my $result = $self->_thirdlane_command(
72       'asterisk::rpc_did_create',
73       $svc_x->countrycode. $svc_x->phonenum,
74     );
75
76     #use Data::Dumper;
77     #warn Dumper(\$result);
78     $result eq '0' or return 'Thirdlane API failure (rpc_did_create)';
79
80     return '' unless $svc_x->pbxsvc;
81
82     $result = $self->_thirdlane_command(
83       'asterisk::rpc_did_assign',
84       $svc_x->countrycode. $svc_x->phonenum,
85       $svc_x->pbx_title,
86     );
87
88     #use Data::Dumper;
89     #warn Dumper(\$result);
90     $result eq '0' ? '' : 'Thirdlane API failure (rpc_did_assign)';
91
92   } elsif ( $svc_x->isa('FS::svc_acct') ) {
93
94     return 'Must select a PBX' unless $svc_x->pbxsvc;
95
96     my $result = $self->_thirdlane_command(
97       'asterisk::rpc_admin_create',
98       $svc_x->username,
99       $svc_x->_password,
100       $svc_x->pbx_title,
101     );
102
103     #use Data::Dumper;
104     #warn Dumper(\$result);
105     $result eq '0' ? '' : 'Thirdlane API failure (rpc_admin_create)';
106
107   } else {
108     die "guru meditation #10: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
109   }
110
111 }
112
113 sub _export_replace {
114   my($self, $new, $old) = (shift, shift, shift);
115
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;
122
123   if ( $new->isa('FS::svc_pbx') ) {
124
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;
128
129     my $tenant = {
130       'tenant'   => $old->title,
131       'maxusers' => $new->max_extensions,
132       #others?  will they not clone?
133     };
134
135     my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_update',
136                                             $tenant
137                                           );
138
139     #use Data::Dumper;
140     #warn Dumper(\$result);
141     $result eq '0' ? '' : 'Thirdlane API failure (rpc_tenant_update)';
142
143   } elsif ( $new->isa('FS::svc_phone') ) {
144
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;
149
150     if ( $old->pbxsvc != $new->pbxsvc ) {
151
152       if ( $old->pbxsvc ) {
153         my $result = $self->_thirdlane_command(
154           'asterisk::rpc_did_unassign',
155           $new->countrycode. $new->phonenum,
156         );
157         $result eq '0' or return 'Thirdlane API failure (rpc_did_unassign)';
158       }
159
160       if ( $new->pbxsvc ) {
161         my $result = $self->_thirdlane_command(
162           'asterisk::rpc_did_assign',
163           $new->countrycode. $new->phonenum,
164           $new->pbx_title,
165         );
166         $result eq '0' or return 'Thirdlane API failure (rpc_did_assign)';
167       }
168
169
170     }
171
172     '';
173
174   } elsif ( $new->isa('FS::svc_acct') ) {
175
176     return "can't change uesrname with thirdlane"
177       if $old->username ne $new->username;
178
179     return "can't change password with thirdlane"
180       if $old->_password ne $new->_password;
181
182     return "can't change PBX for user with thirdlane"
183       if $old->pbxsvc != $new->pbxsvc;
184
185     ''; #we don't care then
186
187   } else {
188     die "guru meditation #11: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
189   }
190
191 }
192
193 sub _export_delete {
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;
199
200   if ( $svc_x->isa('FS::svc_pbx') ) {
201
202     my $result = $self->_thirdlane_command( 'asterisk::rpc_tenant_delete',
203                                             $svc_x->title,
204                                           );
205
206     #use Data::Dumper;
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"
210       if $result ne '0';
211     '';
212
213   } elsif ( $svc_x->isa('FS::svc_phone') ) {
214
215     if ( $svc_x->pbxsvc ) {
216       my $result = $self->_thirdlane_command(
217         'asterisk::rpc_did_unassign',
218         $svc_x->countrycode. $svc_x->phonenum,
219       );
220       $result eq '0' or return 'Thirdlane API failure (rpc_did_unassign)';
221     }
222
223     my $result = $self->_thirdlane_command(
224       'asterisk::rpc_did_delete',
225       $svc_x->countrycode. $svc_x->phonenum,
226     );
227     $result eq '0' ? '' : 'Thirdlane API failure (rpc_did_delete)';
228
229   } elsif ( $svc_x->isa('FS::svc_acct') ) {
230
231     return '' unless $svc_x->pbxsvc; #error out?  nah
232
233     my $result = $self->_thirdlane_command(
234       'asterisk::rpc_admin_delete',
235       $svc_x->username,
236       $svc_x->pbx_title,
237     );
238
239     #use Data::Dumper;
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"
243       if $result ne '0';
244     '';
245
246   } else {
247     die "guru meditation #12: $svc_x is not FS::svc_pbx, FS::svc_phone or FS::svc_acct";
248   }
249
250 }
251
252 sub _thirdlane_command {
253   my($self, @param) = @_;
254
255   my $url =
256     'http://'. $self->option('username'). ':'. $self->option('password'). '@'.
257     $self->machine;
258   $url.= ':'. $self->option('port') if $self->option('port');
259   $url .= '/xmlrpc.cgi';
260
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'),
266                                   );
267
268   warn "$me sending command: ". join(' ', @param). "\n"
269     if $self->option('debug');
270   $conn->call(@param);
271   
272 }
273
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;
278
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;
286 #}
287 #
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;
293 #}
294 #
295 #sub export_links {
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>!;
299 #  '';
300 #}
301
302 ####
303 #
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",
310 #  };
311 #  $queue->insert( @_ ) or $queue;
312 #}
313 #
314 #sub thirdlane_insert { #subroutine, not method
315 #  my( $username, $password ) = @_;
316 #  #do things with $username and $password
317 #}
318 #
319 #sub thirdlane_replace { #subroutine, not method
320 #}
321 #
322 #sub thirdlane_delete { #subroutine, not method
323 #  my( $username ) = @_;
324 #  #do things with $username
325 #}
326 #
327 #sub thirdlane_suspend { #subroutine, not method
328 #}
329 #
330 #sub thirdlane_unsuspend { #subroutine, not method
331 #}
332
333 1;