source: main/trunk/greenstone2/perllib/cgiactions/baseaction.pm@ 23438

Last change on this file since 23438 was 23438, checked in by davidb, 13 years ago

$self needs to be blessed early on in this constructor, so it can call 'check_installation' is needed.

File size: 13.5 KB
Line 
1###########################################################################
2#
3# baseaction.pm --
4# A component of the Greenstone digital library software
5# from the New Zealand Digital Library Project at the
6# University of Waikato, New Zealand.
7#
8# Copyright (C) 2009 New Zealand Digital Library Project
9#
10# This program is free software; you can redistr te it and/or modify
11# it under the terms of the GNU General Public License as published by
12# the Free Software Foundation; either version 2 of the License, or
13# (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18# GNU General Public License for more details.
19#
20# You should have received a copy of the GNU General Public License
21# along with this program; if not, write to the Free Software
22# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23#
24###########################################################################
25
26
27package baseaction;
28
29use strict;
30
31use inexport;
32
33our $authenication_enabled = 0;
34our $mail_enabled = 0;
35
36
37# change this to get these values from a config file
38my $mail_to_address = "user\@server"; # Set this appropriately
39my $mail_from_address = "user\@server"; # Set this appropriately
40my $mail_smtp_server = "smtp.server"; # Set this appropriately
41
42
43
44# Required CGI arguments: "a" for action
45# "c" for collection
46# Optional CGI arguemnts: "ts" for timestamp (auto generated is missing)
47# "site" (used by Greenstone3)
48
49# allow "un" for username to be optional for now
50
51sub new
52{
53 my $class = shift (@_);
54
55 my ($action_table,$gsdl_cgi,$iis6_mode) = @_;
56
57 my $self = { 'gsdl_cgi' => $gsdl_cgi,
58 'iis6_mode' => $iis6_mode,
59 'gsdlhome' => $ENV{'GSDLHOME'} };
60
61 # Retrieve the (required) command CGI argument
62 my $action = $gsdl_cgi->clean_param("a");
63
64 if (!defined $action) {
65 my $err_mess = "No action (a=...) specified.\n";
66 $err_mess .= "\nPossible actions are:\n";
67
68 $err_mess .= " check-installation\n\n";
69
70 foreach my $a (keys %$action_table) {
71 $err_mess .= " $a:\n";
72 $err_mess .= " Compulsory args: ";
73 $err_mess .= join(", ", ("c", "un"),
74 @{$action_table->{$a}->{'compulsory-args'}});
75 $err_mess .= "\n";
76
77 if (scalar(@{$action_table->{$a}->{'optional-args'}})>0) {
78
79 $err_mess .= " Optional args : ";
80 $err_mess .= join(", ", @{$action_table->{$a}->{'optional-args'}});
81 $err_mess .= "\n";
82 }
83 $err_mess .= "\n";
84 }
85
86 $gsdl_cgi->generate_message($err_mess);
87 exit(-1);
88
89 }
90 $gsdl_cgi->delete("a");
91
92 $self = bless $self, $class;
93
94 # The check-installation command has no arguments
95 if ($action eq "check-installation") {
96 $self->check_installation($gsdl_cgi,$iis6_mode);
97 return;
98 }
99
100
101 if (!defined $action_table->{$action}) {
102 my $valid_actions = join(", ", keys %$action_table);
103
104 my $err_mess = "Unrecognised action (a=$action) specified.\n";
105 $err_mess .= "Valid actions are: $valid_actions\n";
106
107 $gsdl_cgi->generate_error($err_mess);
108 }
109
110
111 my $collect = $gsdl_cgi->clean_param("c");
112 if ((!defined $collect) || ($collect =~ m/^\s*$/)) {
113 $gsdl_cgi->generate_error("No collection specified.");
114 }
115 $gsdl_cgi->delete("c");
116
117 # allow un to be optional for now
118 my $username = $gsdl_cgi->clean_param("un");
119
120
121 # Get then remove the ts (timestamp) argument (since this can mess up
122 # other scripts)
123 my $timestamp = $gsdl_cgi->clean_param("ts");
124 if ((!defined $timestamp) || ($timestamp =~ m/^\s*$/)) {
125 # Fall back to using the Perl time() function to generate a timestamp
126 $timestamp = time();
127 }
128 $gsdl_cgi->delete("ts");
129
130 my $site = undef;
131 if($gsdl_cgi->greenstone_version() != 2) {
132 # all GS versions after 2 may define site
133 $site = $gsdl_cgi->clean_param("site");
134 if (!defined $site) {
135 $gsdl_cgi->generate_error("No site specified.");
136 }
137 $gsdl_cgi->delete("site");
138 }
139
140 $self->{'action'} = $action;
141 $self->{'collect'} = $collect;
142 $self->{'username'} = $username;
143 $self->{'timestamp'} = $timestamp;
144 $self->{'site'} = $site;
145
146 # Locate and store compulsory arguments
147 my $comp_args = $action_table->{$action}->{'compulsory-args'};
148 foreach my $ca (@$comp_args) {
149 if (!defined $gsdl_cgi->param($ca)) {
150 $gsdl_cgi->generate_error("Compulsory argument '$ca' missing");
151 }
152 else {
153 $self->{$ca} = $gsdl_cgi->clean_param($ca);
154 $gsdl_cgi->delete($ca);
155 }
156 }
157
158 # Locate and store optional args if present
159 my $opt_args = $action_table->{$action}->{'optional-args'};
160 foreach my $oa (@$opt_args) {
161 if (defined $gsdl_cgi->param($oa)) {
162
163 $self->{$oa} = $gsdl_cgi->clean_param($oa);
164 $gsdl_cgi->delete($oa);
165 }
166 }
167
168
169 # Retrieve infodb-type
170 if (defined $collect) {
171 my $inexport = newCGI inexport("metadata-server",$collect);
172 my ($config_filename,$collect_cfg) = $inexport->read_collection_cfg($collect);
173 $self->{'infodbtype'} = $collect_cfg->{'infodbtype'};
174 }
175
176 return $self;
177}
178
179
180sub do_action
181{
182 my $self = shift @_;
183 my $action = $self->{'action'};
184
185 $action =~ s/-/_/g;
186
187
188 $self->$action();
189
190}
191
192
193
194
195sub authenticate_user
196{
197 my $self = shift @_;
198 my $username = shift(@_);
199 my $collection = shift(@_);
200
201 my $gsdl_cgi = $self->{'gsdl_cgi'};
202
203 # Remove the pw argument (since this can mess up other scripts)
204 my $user_password = $gsdl_cgi->clean_param("pw");
205 $gsdl_cgi->delete("pw");
206
207 if ((!defined $user_password) || ($user_password =~ m/^\s*$/)) {
208 $gsdl_cgi->generate_error("Authentication failed: no password specified.");
209 }
210
211 my $gsdlhome = $ENV{'GSDLHOME'};
212 my $etc_directory = &util::filename_cat($gsdlhome, "etc");
213 my $users_db_file_path = &util::filename_cat($etc_directory, "users.db");
214
215 # Use db2txt to get the user accounts information
216 my $users_db_content = "";
217 open(USERS_DB, "db2txt \"$users_db_file_path\" |");
218 while (<USERS_DB>) {
219 $users_db_content .= $_;
220 }
221
222 # Get the user account information from the users.db database
223 my %users_db_data = ();
224 foreach my $users_db_entry (split(/-{70}/, $users_db_content)) {
225 if ($users_db_entry =~ /\n?\[(.+)\]\n/) {
226 $users_db_data{$1} = $users_db_entry;
227 }
228 }
229
230 # Check username
231 my $user_data = $users_db_data{$username};
232 if (!defined $user_data) {
233 $gsdl_cgi->generate_error("Authentication failed: no account for user '$username'.");
234 }
235
236 # Check password
237 my ($valid_user_password) = ($user_data =~ /\<password\>(.*)/);
238 if ($user_password ne $valid_user_password) {
239 $gsdl_cgi->generate_error("Authentication failed: incorrect password.");
240 }
241
242 # Check group
243 my ($user_groups) = ($user_data =~ /\<groups\>(.*)/);
244 if ($collection eq "") {
245 # If we're not editing a collection then the user doesn't need to be in a particular group
246 return $user_groups; # Authentication successful
247 }
248 foreach my $user_group (split(/\,/, $user_groups)) {
249 # Does this user have access to all collections?
250 if ($user_group eq "all-collections-editor") {
251 return $user_groups; # Authentication successful
252 }
253 # Does this user have access to personal collections, and is this one?
254 if ($user_group eq "personal-collections-editor" && $collection =~ /^$username\-/) {
255 return $user_groups; # Authentication successful
256 }
257 # Does this user have access to this collection
258 if ($user_group eq "$collection-collection-editor") {
259 return $user_groups; # Authentication successful
260 }
261 }
262
263 $gsdl_cgi->generate_error("Authentication failed: user is not in the required group.");
264}
265
266
267
268sub check_installation
269{
270 my $self = shift @_;
271 my $iis6_mode = shift(@_);
272
273 my $gsdl_cgi = $self->{'gsdl_cgi'};
274
275 my $installation_ok = 1;
276 my $installation_status = "";
277
278 print STDOUT "Content-type:text/plain\n\n";
279
280 # Check that Java is installed and accessible
281 my $java = $gsdl_cgi->get_java_path();
282 my $java_command = "$java -version 2>&1";
283
284 # IIS 6: redirecting output from STDERR to STDOUT just doesn't work, so we have to let it go
285 # directly out to the page
286 if ($iis6_mode)
287 {
288 $java_command = "java -version";
289 }
290
291 my $java_output = `$java_command`;
292 my $java_status = $?;
293 if ($java_status < 0) {
294 # The Java command failed
295 $installation_status = "Java failed -- do you have the Java run-time installed?\n" . $gsdl_cgi->check_java_home() . "\n";
296 $installation_ok = 0;
297 }
298 else {
299 $installation_status = "Java found: $java_output";
300 }
301
302 # Show the values of some important environment variables
303 $installation_status .= "\n";
304 $installation_status .= "GSDLHOME: " . $ENV{'GSDLHOME'} . "\n";
305 $installation_status .= "GSDLOS: " . $ENV{'GSDLOS'} . "\n";
306 $installation_status .= "PATH: " . $ENV{'PATH'} . "\n";
307
308 if ($installation_ok) {
309 print STDOUT $installation_status . "\nInstallation OK!";
310 }
311 else {
312 print STDOUT $installation_status;
313 }
314}
315
316sub lock_collection
317{
318 my $self = shift @_;
319 my $username = shift(@_);
320 my $collection = shift(@_);
321
322 my $gsdl_cgi = $self->{'gsdl_cgi'};
323
324 my $steal_lock = $gsdl_cgi->clean_param("steal_lock");
325 $gsdl_cgi->delete("steal_lock");
326
327 if (!defined $username) {
328 # don't have any user details for current user to compare with
329 # even if there is a lock file
330 # For now, allow the current user access. Might want to
331 # revisit this in the future.
332 return;
333 }
334
335 my $gsdlhome = $ENV{'GSDLHOME'};
336 my $collection_directory = &util::filename_cat($gsdlhome, "collect", $collection);
337 $gsdl_cgi->checked_chdir($collection_directory);
338
339 # Check if a lock file already exists for this collection
340 my $lock_file_name = "gli.lck";
341 if (-e $lock_file_name) {
342 # A lock file already exists... check if it's ours
343 my $lock_file_content = "";
344 open(LOCK_FILE, "<$lock_file_name");
345 while (<LOCK_FILE>) {
346 $lock_file_content .= $_;
347 }
348 close(LOCK_FILE);
349
350 # Pick out the owner of the lock file
351 $lock_file_content =~ /\<User\>(.*?)\<\/User\>/;
352 my $lock_file_owner = $1;
353
354 # The lock file is ours, so there is no problem
355 if ($lock_file_owner eq $username) {
356 return;
357 }
358
359 # The lock file is not ours, so throw an error unless "steal_lock" is set
360 unless (defined $steal_lock) {
361 $gsdl_cgi->generate_error("Collection is locked by: $lock_file_owner");
362 }
363 }
364
365 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
366 my $current_time = sprintf("%02d/%02d/%d %02d:%02d:%02d", $mday, $mon + 1, $year + 1900, $hour, $min, $sec);
367
368 # Create a lock file for us (in the same format as the GLI) and we're done
369 open(LOCK_FILE, ">$lock_file_name");
370 print LOCK_FILE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
371 print LOCK_FILE "<LockFile>\n";
372 print LOCK_FILE " <User>" . $username . "</User>\n";
373 print LOCK_FILE " <Machine>(Remote)</Machine>\n";
374 print LOCK_FILE " <Date>" . $current_time . "</Date>\n";
375 print LOCK_FILE "</LockFile>\n";
376 close(LOCK_FILE);
377}
378
379
380# Release the gli.lck otherwise no one else will be able to use the collection again.
381sub unlock_collection
382{
383 my $self = shift @_;
384 my ($username, $collection) = @_;
385 my $gsdl_cgi = $self->{'gsdl_cgi'};
386
387 # Obtain the path to the collection GLI lock file
388 my $lock_file_path = &util::filename_cat($ENV{'GSDLHOME'}, "collect", $collection, "gli.lck");
389
390 # If the lock file does exist, check if it is ours
391 if (-e $lock_file_path)
392 {
393 my $lock_file_content = "";
394 open(LOCK_FILE, "<$lock_file_path");
395 while (<LOCK_FILE>) {
396 $lock_file_content .= $_;
397 }
398 close(LOCK_FILE);
399
400 # Pick out the owner of the lock file
401 $lock_file_content =~ /\<User\>(.*?)\<\/User\>/;
402 my $lock_file_owner = $1;
403
404 # If we are the owner of this lock, we have the right to delete it
405 if ($lock_file_owner eq $username) {
406 unlink($lock_file_path );
407 }
408 else {
409 $gsdl_cgi->generate_error("Collection is locked by: $lock_file_owner. Cannot be unlocked");
410 }
411 }
412}
413
414
415sub send_mail
416{
417 my $self = shift @_;
418
419 my ($mail_subject,$mail_content) = @_;
420
421 my $gsdl_cgi = $self->{'gsdl_cgi'};
422
423 my $sendmail_command = "perl -S sendmail.pl";
424 $sendmail_command .= " -to \"" . $mail_to_address . "\"";
425 $sendmail_command .= " -from \"" . $mail_from_address . "\"";
426 $sendmail_command .= " -smtp \"" . $mail_smtp_server . "\"";
427 $sendmail_command .= " -subject \"" . $mail_subject . "\"";
428
429 if (!open(POUT, "| $sendmail_command")) {
430 $gsdl_cgi->generate_error("Unable to execute command: $sendmail_command");
431 }
432 print POUT $mail_content . "\n";
433 close(POUT);
434}
435
436
437
438
439sub run_script
440{
441 my $self = shift @_;
442
443 my ($collect, $site, $script) = @_;
444
445 my $gsdl_cgi = $self->{'gsdl_cgi'};
446
447 my $perl_args = $collect;
448
449 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
450 $perl_args = "-collectdir \"$collect_dir\" " . $perl_args;
451
452 my $perl_command = "perl -S $script $perl_args";
453
454
455 # IIS 6: redirecting output from STDERR to STDOUT just doesn't work, so
456 # we have to let it go directly out to the page
457
458 if (!$self->{'iis6_mode'})
459 {
460 $perl_command .= " 2>&1";
461 }
462
463 if (!open(PIN, "$perl_command |")) {
464 $gsdl_cgi->generate_error("Unable to execute command: $perl_command");
465 }
466
467 print STDOUT "Content-type:text/plain\n\n";
468 print "$perl_command \n";
469
470 while (defined (my $perl_output_line = <PIN>)) {
471 print STDOUT $perl_output_line;
472 }
473 close(PIN);
474
475 my $perl_status = $?;
476 if ($perl_status > 0) {
477 $gsdl_cgi->generate_error("Perl failed: $perl_command\n--\nExit status: " . ($perl_status / 256));
478 }
479}
480
481
482
483
4841;
Note: See TracBrowser for help on using the repository browser.