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