update per netsapiens, RT#12447
[freeside.git] / FS / FS / part_export / netsapiens.pm
1 package FS::part_export::netsapiens;
2
3 use vars qw(@ISA $me %info);
4 use MIME::Base64;
5 use Tie::IxHash;
6 use FS::part_export;
7
8 @ISA = qw(FS::part_export);
9 $me = '[FS::part_export::netsapiens]';
10
11 tie my %options, 'Tie::IxHash',
12   'login'           => { label=>'NetSapiens tac2 User API username' },
13   'password'        => { label=>'NetSapiens tac2 User API password' },
14   'url'             => { label=>'NetSapiens tac2 User URL' },
15   'device_login'    => { label=>'NetSapiens tac2 Device API username' },
16   'device_password' => { label=>'NetSapiens tac2 Device API password' },
17   'device_url'      => { label=>'NetSapiens tac2 Device URL' },
18   'domain'          => { label=>'NetSapiens Domain' },
19   'debug'           => { label=>'Enable debugging', type=>'checkbox' },
20 ;
21
22 %info = (
23   'svc'      => [ 'svc_phone', ], # 'part_device',
24   'desc'     => 'Provision phone numbers to NetSapiens',
25   'options'  => \%options,
26   'notes'    => <<'END'
27 Requires installation of
28 <a href="http://search.cpan.org/dist/REST-Client">REST::Client</a>
29 from CPAN.
30 END
31 );
32
33 sub rebless { shift; }
34
35 sub ns_command {
36   my $self = shift;
37   $self->_ns_command('', @_);
38 }
39
40 sub ns_device_command { 
41   my $self = shift;
42   $self->_ns_command('device_', @_);
43 }
44
45 sub _ns_command {
46   my( $self, $prefix, $method, $command ) = splice(@_,0,4);
47
48   eval 'use REST::Client';
49   die $@ if $@;
50
51   my $ns = new REST::Client 'host'=>$self->option($prefix.'url');
52
53   my @args = ( $command );
54
55   if ( $method eq 'PUT' ) {
56     my $content = $ns->buildQuery( { @_ } );
57     $content =~ s/^\?//;
58     push @args, $content;
59   } elsif ( $method eq 'GET' ) {
60     $args[0] .= $ns->buildQuery( { @_ } );
61   }
62
63   warn "$me $method ". $self->option($prefix.'url'). join(', ', @args). "\n"
64     if $self->option('debug');
65
66   my $auth = encode_base64( $self->option($prefix.'login'). ':'.
67                             $self->option($prefix.'password')    );
68   push @args, { 'Authorization' => "Basic $auth" };
69
70   $ns->$method( @args );
71   $ns;
72 }
73
74 sub ns_domain {
75   my($self, $svc_phone) = (shift, shift);
76   $svc_phone->domain || $self->option('domain');
77 }
78
79 sub ns_subscriber {
80   my($self, $svc_phone) = (shift, shift);
81
82   my $domain = $self->ns_domain($svc_phone);
83   my $phonenum = $svc_phone->phonenum;
84
85   "/domains_config/$domain/subscriber_config/$phonenum";
86 }
87
88 sub ns_registrar {
89   my($self, $svc_phone) = (shift, shift);
90
91   $self->ns_subscriber($svc_phone).
92     '/registrar_config/'. $self->ns_devicename($svc_phone);
93 }
94
95 sub ns_devicename {
96   my( $self, $svc_phone ) = (shift, shift);
97
98   my $domain = $self->ns_domain($svc_phone);
99   #my $countrycode = $svc_phone->countrycode;
100   my $phonenum    = $svc_phone->phonenum;
101
102   #"sip:$countrycode$phonenum\@$domain";
103   "sip:$phonenum\@$domain";
104 }
105
106 sub ns_dialplan {
107   my($self, $svc_phone) = (shift, shift);
108
109   #my $countrycode = $svc_phone->countrycode;
110   my $phonenum    = $svc_phone->phonenum;
111
112   #"/dialplans/DID+Table/dialplan_config/sip:$countrycode$phonenum\@*"
113   "/domains_config/admin-only/dialplans/DID+Table/dialplan_config/sip:$phonenum\@*,*,*,*,*,*,*";
114 }
115
116 sub ns_device {
117   my($self, $svc_phone, $phone_device ) = (shift, shift, shift);
118
119   #my $countrycode = $svc_phone->countrycode;
120   #my $phonenum    = $svc_phone->phonenum;
121
122   "/phones_config/". lc($phone_device->mac_addr);
123 }
124
125 sub ns_create_or_update {
126   my($self, $svc_phone, $dial_policy) = (shift, shift, shift);
127
128   my $domain = $self->ns_domain($svc_phone);
129   #my $countrycode = $svc_phone->countrycode;
130   my $phonenum    = $svc_phone->phonenum;
131
132   my( $firstname, $lastname );
133   if ( $svc_phone->phone_name =~ /^\s*(\S+)\s+(\S.*\S)\s*$/ ) {
134     $firstname = $1;
135     $lastname  = $2;
136   } else {
137     #deal w/unaudited netsapiens services?
138     my $cust_main = $svc_phone->cust_svc->cust_pkg->cust_main;
139     $firstname = $cust_main->get('first');
140     $lastname  = $cust_main->get('last');
141   }
142
143   # Piece 1 (already done) - User creation
144
145   my $ns = $self->ns_command( 'PUT', $self->ns_subscriber($svc_phone), 
146     'subscriber_login' => $phonenum.'@'.$domain,
147     'firstname'        => $firstname,
148     'lastname'         => $lastname,
149     'subscriber_pin'   => $svc_phone->pin,
150     'dial_plan'        => 'Default', #config?
151     'dial_policy'      => $dial_policy,
152   );
153
154   if ( $ns->responseCode !~ /^2/ ) {
155      return $ns->responseCode. ' '.
156             join(', ', $self->ns_parse_response( $ns->responseContent ) );
157   }
158
159   #Piece 2 - sip device creation 
160
161   my $ns2 = $self->ns_command( 'PUT', $self->ns_registrar($svc_phone),
162     'termination_match' => $self->ns_devicename($svc_phone)
163   );
164
165   if ( $ns2->responseCode !~ /^2/ ) {
166      return $ns2->responseCode. ' '.
167             join(', ', $self->ns_parse_response( $ns2->responseContent ) );
168   }
169
170   #Piece 3 - DID mapping to user
171
172   my $ns3 = $self->ns_command( 'PUT', $self->ns_dialplan($svc_phone),
173     'to_user' => $phonenum,
174     'to_host' => $domain,
175   );
176
177   if ( $ns3->responseCode !~ /^2/ ) {
178      return $ns3->responseCode. ' '.
179             join(', ', $self->ns_parse_response( $ns3->responseContent ) );
180   }
181
182   '';
183 }
184
185 sub ns_delete {
186   my($self, $svc_phone) = (shift, shift);
187
188   my $ns = $self->ns_command( 'DELETE', $self->ns_subscriber($svc_phone) );
189
190   #delete other things?
191
192   if ( $ns->responseCode !~ /^2/ ) {
193      return $ns->responseCode. ' '.
194             join(', ', $self->ns_parse_response( $ns->responseContent ) );
195   }
196
197   '';
198
199 }
200
201 sub ns_parse_response {
202   my( $self, $content ) = ( shift, shift );
203
204   #try to screen-scrape something useful
205   tie my %hash, Tie::IxHash;
206   while ( $content =~ s/^.*?<p>\s*<b>(.+?)<\/b>\s*(.+?)\s*<\/p>//is ) {
207     ( $hash{$1} = $2 ) =~ s/^\s*<(\w+)>(.+?)<\/\1>/$2/is;
208   }
209
210   %hash;
211 }
212
213 sub _export_insert {
214   my($self, $svc_phone) = (shift, shift);
215   $self->ns_create_or_update($svc_phone, 'Permit All');
216 }
217
218 sub _export_replace {
219   my( $self, $new, $old ) = (shift, shift, shift);
220   return "can't change phonenum with NetSapiens (unprovision and reprovision?)"
221     if $old->phonenum ne $new->phonenum;
222   $self->_export_insert($new);
223 }
224
225 sub _export_delete {
226   my( $self, $svc_phone ) = (shift, shift);
227
228   $self->ns_delete($svc_phone);
229 }
230
231 sub _export_suspend {
232   my( $self, $svc_phone ) = (shift, shift);
233   $self->ns_create_or_update($svc_phone, 'Deny');
234 }
235
236 sub _export_unsuspend {
237   my( $self, $svc_phone ) = (shift, shift);
238   #$self->ns_create_or_update($svc_phone, 'Permit All');
239   $self->_export_insert($svc_phone);
240 }
241
242 sub export_device_insert {
243   my( $self, $svc_phone, $phone_device ) = (shift, shift, shift);
244
245   my $domain = $self->ns_domain($svc_phone);
246   my $countrycode = $svc_phone->countrycode;
247   my $phonenum    = $svc_phone->phonenum;
248
249   my $ns = $self->ns_device_command(
250     'PUT', $self->ns_device($svc_phone, $phone_device),
251       'line1_enable' => 'yes',
252       'device1'      => $self->ns_devicename($svc_phone),
253       'line1_ext'    => $phonenum,
254 ,
255       #'line2_enable' => 'yes',
256       #'device2'      =>
257       #'line2_ext'    =>
258
259       #'notes' => 
260       'server'       => 'SiPbx',
261       'domain'       => $domain,
262
263       'brand'        => $phone_device->part_device->devicename,
264       
265   );
266
267   if ( $ns->responseCode !~ /^2/ ) {
268      return $ns->responseCode. ' '.
269             join(', ', $self->ns_parse_response( $ns->responseContent ) );
270   }
271
272   '';
273
274 }
275
276 sub export_device_delete {
277   my( $self, $svc_phone, $phone_device ) = (shift, shift, shift);
278
279   my $ns = $self->ns_device_command(
280     'DELETE', $self->ns_device($svc_phone, $phone_device),
281   );
282
283   if ( $ns->responseCode !~ /^2/ ) {
284      return $ns->responseCode. ' '.
285             join(', ', $self->ns_parse_response( $ns->responseContent ) );
286   }
287
288   '';
289
290 }
291
292
293 sub export_device_replace {
294   my( $self, $svc_phone, $new_phone_device, $old_phone_device ) =
295     (shift, shift, shift, shift);
296
297   #?
298   $self->export_device_insert( $svc_phone, $new_phone_device );
299
300 }
301
302 sub export_links {
303   my($self, $svc_phone, $arrayref) = (shift, shift, shift);
304   #push @$arrayref, qq!<A HREF="http://example.com/~!. $svc_phone->username.
305   #                 qq!">!. $svc_phone->username. qq!</A>!;
306   '';
307 }
308
309 1;