]> git.evergreen-ils.org Git - Evergreen.git/blob - Open-ILS/src/offline/offline-lib.pl
allowing clients to create their own session names
[Evergreen.git] / Open-ILS / src / offline / offline-lib.pl
1 #!/usr/bin/perl
2 use strict; use warnings;
3 use CGI;
4 use OpenSRF::System;
5 use OpenSRF::Utils::Logger qw/$logger/;
6 use OpenILS::Application::AppUtils;
7 use OpenILS::Event;
8 use OpenSRF::EX qw/:try/;
9 use JSON;
10 use Data::Dumper;
11 use OpenILS::Utils::Fieldmapper;
12 use Digest::MD5 qw/md5_hex/;
13 use OpenSRF::Utils qw/:daemon/;
14 our $U = "OpenILS::Application::AppUtils";
15 our %config;
16
17
18 # --------------------------------------------------------------------
19 # Load the config options
20 # --------------------------------------------------------------------
21 my $time_delta;
22 my $cgi; 
23 my $base_dir; 
24 my $requestor; 
25 my $workstation;
26 my $org;
27 my $org_unit;
28 my $authtoken;
29 my $seskey;
30
31 # --------------------------------------------------------------------
32 # Define accessors for all of the shared vars
33 # --------------------------------------------------------------------
34 sub offline_requestor { return $requestor; }
35 sub offline_authtoken { return $authtoken; }
36 sub offline_workstation { return $workstation; }
37 sub offline_org { return $org; }
38 sub offline_org_unit { return $org_unit;}
39 sub offline_meta_file { return &offline_pending_dir . '/meta'; }
40 sub offline_lock_file { return &offline_pending_dir . '/lock'; }
41 sub offline_result_file { return &offline_pending_dir . '/results'; }
42 sub offline_archive_meta_file { return &offline_archive_dir . '/meta'; }
43 sub offline_archive_result_file { return &offline_archive_dir . '/results'; }
44 sub offline_base_dir { return $base_dir; }
45 sub offline_time_delta { return $time_delta; }
46 sub offline_config { return %config; }
47 sub offline_cgi { return $cgi; }
48 sub offline_seskey { return $seskey; }
49 sub offline_base_pending_dir { return $base_dir .'/pending/'; }
50 sub offline_base_archive_dir { return $base_dir .'/archive/'; }
51
52
53
54 # --------------------------------------------------------------------
55 # Load the config
56 # --------------------------------------------------------------------
57 #do '##CONFIG##/upload-server.pl';
58 do 'offline-config.pl';
59
60
61 # --------------------------------------------------------------------
62 # Set everything up
63 # --------------------------------------------------------------------
64 &initialize();
65
66
67
68
69
70
71 # --------------------------------------------------------------------
72 # Loads the necessary CGI params, connects to OpenSRF, and verifies
73 # the login session
74 # --------------------------------------------------------------------
75 sub initialize {
76
77         $base_dir       = $config{base_dir};
78         my $bsconfig    = $config{bootstrap};
79         my $evt;
80
81         # --------------------------------------------------------------------
82         # Connect to OpenSRF
83         # --------------------------------------------------------------------
84         OpenSRF::System->bootstrap_client(config_file => $bsconfig); 
85
86
87         # --------------------------------------------------------------------
88         # Load the required CGI params
89         # --------------------------------------------------------------------
90         $cgi = new CGI;
91
92         $authtoken      = $cgi->param('ses') 
93                 or handle_event(OpenILS::Event->new('NO_SESSION'));
94
95         $org = $cgi->param('org') || "";
96         if(!$org) {
97                 if(my $ws = $cgi->param('ws')) {
98                         $workstation = fetch_workstation($ws);
99                         $org = $workstation->owning_lib if $workstation;
100                 }
101         }
102
103         if($org) {
104                 ($org_unit, $evt) = $U->fetch_org_unit($org);   
105                 handle_event($evt) if $evt;
106         } 
107
108         ($requestor, $evt) = $U->checkses($authtoken);
109         handle_event($evt) if $evt;
110
111         $time_delta      = $cgi->param('delta') || "0";
112
113         $seskey = $cgi->param('seskey') || time . "_$$";
114         
115         if( $cgi->param('createses') ) {
116                 if( -e &offline_pending_dir || -e &offline_archive_dir ) {
117                         &handle_event(OpenILS::Event->new('OFFLINE_SESSION_EXISTS'));
118                 }
119                 handle_event(OpenILS::Event->new('OFFLINE_INVALID_SESSION')) unless $seskey =~ /^\w+$/;
120                 &offline_pending_dir(1);
121         }
122 }
123
124
125 # --------------------------------------------------------------------
126 # Print out a full HTML page and exits
127 # --------------------------------------------------------------------
128 sub print_html {
129
130         my %args        = @_;
131         my $body        = $args{body} || "";
132         my $res  = $args{result} || "";
133         my $on  = ($org_unit) ? $org_unit->name : "";
134
135         $authtoken      ||= "";
136         $org                    ||= "";
137         $seskey         ||= "";
138
139         my $html = <<"  HTML";
140                 <html>
141                         <head>
142                                 <script src='/opac/common/js/JSON.js'> </script>
143                                 <script>
144                                         function offline_complete(obj) { 
145                                                 if(!obj) return;
146                                                 try {
147                                                         xulG.handle_event(obj);
148                                                 } catch(e) {
149                                                         alert(js2JSON(obj)); 
150                                                 }
151                                         }
152                                 </script>
153                                 <style> 
154                                         a { margin: 6px; } 
155                                         div { margin: 10px; text-align: center; }
156                                 </style>
157                         </head>
158                         <body onload='offline_complete($res);'>
159                                 <div>
160                                         <div style='margin: 5px;'><b>$on</b></div>
161                                         <a href='offline-upload.pl?ses=$authtoken&org=$org'>Upload More Files</a>
162                                         <a href='offline-status.pl?ses=$authtoken&org=$org&seskey=$seskey'>Status Page</a>
163                                         <a href='offline-execute.pl?ses=$authtoken&org=$org&seskey=$seskey'>Execute Batch</a>
164                                 </div>
165                                 <hr/>
166                                 <div>$body</div>
167                         </body>
168                 </html>
169         HTML
170
171         if( &offline_cgi->param('raw') ) {
172                 print "content-type: text/plain\n\n";
173                 print $res;     
174
175         } else {
176                 print "content-type: text/html\n\n";
177                 print $html;
178         }
179
180         exit(0);
181 }
182
183
184 # --------------------------------------------------------------------
185 # Prints the JSON form of the event out to the client
186 # --------------------------------------------------------------------
187 sub handle_event { &offline_handle_json(@_); }
188
189 sub offline_handle_json {
190         my $obj = shift;
191         my $ischild = shift;
192         return unless $obj;
193         print_html(result => JSON->perl2JSON($obj)) unless $ischild;
194         append_result($obj) and exit;
195 }
196
197
198
199 sub handle_error { warn shift() . "\n"; }
200
201
202 # --------------------------------------------------------------------
203 # Fetches (and creates if necessary) the pending directory
204 # --------------------------------------------------------------------
205 sub offline_pending_dir {
206         my $create = shift;
207         my $dir = "$base_dir/pending/$org/$seskey/";
208
209         if( $create and ! -e $dir ) {
210                 $logger->debug("offline: creating pending directory $dir");
211                 qx/mkdir -p $dir/ and handle_error("Unable to create directory $dir");
212         }
213
214         return $dir;
215 }
216
217 sub _offline_date {
218         my (undef,undef, undef, $mday,$mon,$year) = localtime(time);
219         $mon++; $year   += 1900;
220         $mday   = "0$mday" unless $mday =~ /\d{2}/o;
221         $mon    = "0$mon" unless $mon   =~ /\d{2}/o;
222         return ($year, $mon, $mday);
223 }
224
225 # --------------------------------------------------------------------
226 # Fetches and creates if necessary the archive directory
227 # --------------------------------------------------------------------
228 sub offline_archive_dir { return create_archive_dir(@_); }
229 sub create_archive_dir {
230         my $create = shift;
231         my( $year, $mon, $mday) = &_offline_date;
232         my $dir = "$base_dir/archive/$org/${year}_${mon}_${mday}/$seskey/";
233
234         if( $create and ! -e $dir ) {
235                 $logger->debug("offline: creating archive directory $dir");
236                 qx/mkdir -p $dir/ and handle_error("Unable to create archive directory $dir");
237         }
238         return $dir;
239 }
240
241
242
243 # --------------------------------------------------------------------
244 # Fetches the workstation object by name
245 # --------------------------------------------------------------------
246 sub fetch_workstation {
247         my $name = shift;
248         $logger->debug("offline: Fetching workstation $name");
249         my $ws = $U->storagereq(
250                 'open-ils.storage.direct.actor.workstation.search.name', $name);
251         handle_event(OpenILS::Event->new('WORKSTATION_NOT_FOUND')) unless $ws;
252         return $ws;
253 }
254
255
256 # --------------------------------------------------------------------
257 # Read/Write to/from the essential files
258 # --------------------------------------------------------------------
259 sub append_meta { &_offline_file_append_perl( shift(), &offline_meta_file ); }
260 sub append_result { &_offline_file_append_perl( shift(), &offline_result_file ); }
261 sub _offline_file_append_perl {
262         my( $obj, $file ) = @_;
263         return unless $obj;
264         $obj = JSON->perl2JSON($obj);
265         open(F, ">>$file") or die
266                 "Unable to append data to file: $file [$! $@]\n";
267         print F "$obj\n";
268         close(F);
269 }
270
271
272 sub offline_read_meta { return &_offline_read_meta(&offline_meta_file); }
273 sub offline_read_archive_meta { return &_offline_read_meta(&offline_archive_meta_file); }
274 sub _offline_read_meta { return &_offline_file_to_perl(shift(), 'workstation'); }
275 sub offline_read_archive_results { return &_offline_read_results(&offline_archive_result_file); }
276 sub offline_read_results { return &_offline_read_results(&offline_result_file); }
277 sub _offline_read_results { return &_offline_file_to_perl(shift(), 'command'); }
278
279 sub _offline_file_to_perl {
280         my( $file, $exist_key ) = @_;
281         open(F,$file) or return [];
282         my @data = <F>;
283         close(F);
284         my @resp;
285         push(@resp, JSON->JSON2perl($_)) for @data;
286         @resp = grep { $_ and $_->{$exist_key} } @resp;
287         return \@resp;
288 }
289
290
291 sub log_to_wsname {
292         my $log = shift;
293         $log =~ s/\.log//og;
294         $log =~ s#/.*/(\w+)#$1#og;
295         return $log
296 }
297
298 sub offline_pending_orgs {
299         my $dir = &offline_base_pending_dir;
300         my @org;
301         for my $org (<$dir/*>) {
302                 $org =~ s#/.*/(\w+)#$1#og;
303                 push @org, $org;
304         }
305         return \@org;
306 }
307
308
309 # --------------------------------------------------------------------
310 # Returns a list of all pending org sessions as well as all complete
311 # org sessions for today only as [ $name, $directory ] pairs
312 # --------------------------------------------------------------------
313 sub offline_org_sessions {
314
315         my $org = shift;
316         my( $year, $mon, $mday) = &_offline_date;
317
318         my $pdir = &offline_base_pending_dir . '/' . &offline_org;
319         my $adir = &offline_base_archive_dir . 
320                 '/' . &offline_org . "/${year}_${mon}_${mday}/";
321
322         my @ses;
323         for my $ses (<$pdir/*>, <$adir/*>) {
324                 my $name = $ses;
325                 $name =~ s#/.*/(\w+)#$1#og;
326                 push @ses, [ $name, $ses ];
327         }
328         return \@ses;
329 }
330
331
332
333
334 1;