source: gsdl/trunk/perllib/cgiactions/baseaction.pm@ 19499

Last change on this file since 19499 was 19499, checked in by davidb, 15 years ago

Additional work on supporting Greenstone CGI-based API

File size: 12.2 KB
RevLine 
[19293]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
29
30use strict;
31
32our $authenication_enabled = 0;
33our $mail_enabled = 0;
34
35
36# change this to get these values from a config file
37my $mail_to_address = "user\@server"; # Set this appropriately
38my $mail_from_address = "user\@server"; # Set this appropriately
39my $mail_smtp_server = "smtp.server"; # Set this appropriately
40
41
42
43# Required CGI arguments: "a" for action
44# "c" for collection
45# Optional CGI arguemnts: "ts" for timestamp (auto generated is missing)
46# "site" (used by Greenstone3)
47
48# allow "un" for username to be optional for now
49
50sub new
51{
52 my $class = shift (@_);
53
54 my ($action_table,$gsdl_cgi,$iis6_mode) = @_;
55
56 my $self = { 'gsdl_cgi' => $gsdl_cgi,
57 'iis6_mode' => $iis6_mode,
58 'gsdlhome' => $ENV{'GSDLHOME'} };
59
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
[19499]68 $err_mess .= " check-installation\n\n";
[19293]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
93 # The check-installation command has no arguments
94 if ($action eq "check-installation") {
[19499]95 $self->check_installation($gsdl_cgi,$iis6_mode);
[19293]96 return;
97 }
98
99
100 if (!defined $action_table->{$action}) {
101 my $valid_actions = join(", ", keys %$action_table);
102
103 my $err_mess = "Unrecognised action (a=$action) specified.\n";
104 $err_mess .= "Valid actions are: $valid_actions\n";
105
106 $gsdl_cgi->generate_error($err_mess);
107 }
108
109
110 my $collect = $gsdl_cgi->clean_param("c");
111 if ((!defined $collect) || ($collect =~ m/^\s*$/)) {
112 $gsdl_cgi->generate_error("No collection specified.");
113 }
114 $gsdl_cgi->delete("c");
115
116 # allow un to be optional for now
117 my $username = $gsdl_cgi->clean_param("un");
118
119
120 # Get then remove the ts (timestamp) argument (since this can mess up
121 # other scripts)
122 my $timestamp = $gsdl_cgi->clean_param("ts");
123 if ((!defined $timestamp) || ($timestamp =~ m/^\s*$/)) {
124 # Fall back to using the Perl time() function to generate a timestamp
125 $timestamp = time();
126 }
127 $gsdl_cgi->delete("ts");
128
129 my $site = undef;
130 if($gsdl_cgi->greenstone_version() != 2) {
131 # all GS versions after 2 may define site
132 $site = $gsdl_cgi->clean_param("site");
133 if (!defined $site) {
134 $gsdl_cgi->generate_error("No site specified.");
135 }
136 $gsdl_cgi->delete("site");
137 }
138
139 $self->{'action'} = $action;
140 $self->{'collect'} = $collect;
141 $self->{'username'} = $username;
142 $self->{'timestamp'} = $timestamp;
143 $self->{'site'} = $site;
144
145 # Locate and store compulsory arguments
146 my $comp_args = $action_table->{$action}->{'compulsory-args'};
147 foreach my $ca (@$comp_args) {
148 if (!defined $gsdl_cgi->{$ca}) {
149 $gsdl_cgi->generate_error("Compulsory argument '$ca' missing");
150 }
151 else {
152 $self->{$ca} = $gsdl_cgi->clean_param($ca);
153 $gsdl_cgi->delete($ca);
154 }
155 }
156
157 # Locate and store optional args if present
[19499]158 my $opt_args = $action_table->{$action}->{'optional-args'};
[19293]159 foreach my $oa (@$opt_args) {
160 if (defined $gsdl_cgi->{$oa}) {
161
162 $self->{$oa} = $gsdl_cgi->clean_param($oa);
163 $gsdl_cgi->delete($oa);
164 }
165 }
166
167
168 return bless $self, $class;
169}
170
171
172sub do_action
173{
174 my $self = shift @_;
175 my $action = $self->{'action'};
176
177 $action =~ s/-/_/g;
178
179
180 $self->$action();
181
182}
183
184
185
186
187sub authenticate_user
188{
189 my $self = shift @_;
190 my ($username,$collection) = shift(@_);
191
192 my $gsdl_cgi = $self->{'gsdl_cgi'};
193
194 # Remove the pw argument (since this can mess up other scripts)
195 my $user_password = $gsdl_cgi->clean_param("pw");
196 $gsdl_cgi->delete("pw");
197
198 if ((!defined $user_password) || ($user_password =~ m/^\s*$/)) {
199 $gsdl_cgi->generate_error("Authentication failed: no password specified.");
200 }
201
202 my $gsdlhome = $ENV{'GSDLHOME'};
203 my $etc_directory = &util::filename_cat($gsdlhome, "etc");
204 my $users_db_file_path = &util::filename_cat($etc_directory, "users.db");
205
206 # Use db2txt instead of GDBM_File to get the user accounts information
207 my $users_db_content = "";
208 open(USERS_DB, "db2txt \"$users_db_file_path\" |");
209 while (<USERS_DB>) {
210 $users_db_content .= $_;
211 }
212
213 # Get the user account information from the users.db database
214 my %users_db_data = ();
215 foreach my $users_db_entry (split(/-{70}/, $users_db_content)) {
216 if ($users_db_entry =~ /\n?\[(.+)\]\n/) {
217 $users_db_data{$1} = $users_db_entry;
218 }
219 }
220
221 # Check username
222 my $user_data = $users_db_data{$username};
223 if (!defined $user_data) {
224 $gsdl_cgi->generate_error("Authentication failed: no account for user '$username'.");
225 }
226
227 # Check password
228 my ($valid_user_password) = ($user_data =~ /\<password\>(.*)/);
229 if ($user_password ne $valid_user_password) {
230 $gsdl_cgi->generate_error("Authentication failed: incorrect password.");
231 }
232
233 # Check group
234 my ($user_groups) = ($user_data =~ /\<groups\>(.*)/);
235 if ($collection eq "") {
236 # If we're not editing a collection then the user doesn't need to be in a particular group
237 return $user_groups; # Authentication successful
238 }
239 foreach my $user_group (split(/\,/, $user_groups)) {
240 # Does this user have access to all collections?
241 if ($user_group eq "all-collections-editor") {
242 return $user_groups; # Authentication successful
243 }
244 # Does this user have access to personal collections, and is this one?
245 if ($user_group eq "personal-collections-editor" && $collection =~ /^$username\-/) {
246 return $user_groups; # Authentication successful
247 }
248 # Does this user have access to this collection
249 if ($user_group eq "$collection-collection-editor") {
250 return $user_groups; # Authentication successful
251 }
252 }
253
254 $gsdl_cgi->generate_error("Authentication failed: user is not in the required group.");
255}
256
257
258
259sub check_installation
260{
261 my $self = shift @_;
262 my ($iis6_mode) = @_;
263
264 my $gsdl_cgi = $self->{'gsdl_cgi'};
265
266 my $installation_ok = 1;
267 my $installation_status = "";
268
269 print STDOUT "Content-type:text/plain\n\n";
270
271 # Check that Java is installed and accessible
272 my $java = $gsdl_cgi->get_java_path();
273 my $java_command = "$java -version 2>&1";
274
275 # IIS 6: redirecting output from STDERR to STDOUT just doesn't work, so we have to let it go
276 # directly out to the page
277 if ($iis6_mode)
278 {
279 $java_command = "java -version";
280 }
281
282 my $java_output = `$java_command`;
283 my $java_status = $?;
284 if ($java_status < 0) {
285 # The Java command failed
286 $installation_status = "Java failed -- do you have the Java run-time installed?\n" . $gsdl_cgi->check_java_home() . "\n";
287 $installation_ok = 0;
288 }
289 else {
290 $installation_status = "Java found: $java_output";
291 }
292
293 # Show the values of some important environment variables
294 $installation_status .= "\n";
295 $installation_status .= "GSDLHOME: " . $ENV{'GSDLHOME'} . "\n";
296 $installation_status .= "GSDLOS: " . $ENV{'GSDLOS'} . "\n";
297 $installation_status .= "PATH: " . $ENV{'PATH'} . "\n";
298
299 if ($installation_ok) {
300 print STDOUT $installation_status . "\nInstallation OK!";
301 }
302 else {
303 print STDOUT $installation_status;
304 }
305}
306
307sub lock_collection
308{
309 my $self = shift @_;
310
311 my ($username,$collection) = shift(@_);
312
313 my $gsdl_cgi = $self->{'gsdl_cgi'};
314
315 my $steal_lock = $gsdl_cgi->clean_param("steal_lock");
316 $gsdl_cgi->delete("steal_lock");
317
318 if (!defined $username) {
319 # don't have any user details for current user to compare with
320 # even if there is a lock file
321 # For now, allow the current user access. Might want to
322 # revisit this in the future.
323 return;
324 }
325
326 my $gsdlhome = $ENV{'GSDLHOME'};
327 my $collection_directory = &util::filename_cat($gsdlhome, "collect", $collection);
328 $gsdl_cgi->checked_chdir($collection_directory);
329
330 # Check if a lock file already exists for this collection
331 my $lock_file_name = "gli.lck";
332 if (-e $lock_file_name) {
333 # A lock file already exists... check if it's ours
334 my $lock_file_content = "";
335 open(LOCK_FILE, "<$lock_file_name");
336 while (<LOCK_FILE>) {
337 $lock_file_content .= $_;
338 }
339 close(LOCK_FILE);
340
341 # Pick out the owner of the lock file
342 $lock_file_content =~ /\<User\>(.*?)\<\/User\>/;
343 my $lock_file_owner = $1;
344
345 # The lock file is ours, so there is no problem
346 if ($lock_file_owner eq $username) {
347 return;
348 }
349
350 # The lock file is not ours, so throw an error unless "steal_lock" is set
351 unless (defined $steal_lock) {
352 $gsdl_cgi->generate_error("Collection is locked by: $lock_file_owner");
353 }
354 }
355
356 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
357 my $current_time = sprintf("%02d/%02d/%d %02d:%02d:%02d", $mday, $mon + 1, $year + 1900, $hour, $min, $sec);
358
359 # Create a lock file for us (in the same format as the GLI) and we're done
360 open(LOCK_FILE, ">$lock_file_name");
361 print LOCK_FILE "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
362 print LOCK_FILE "<LockFile>\n";
363 print LOCK_FILE " <User>" . $username . "</User>\n";
364 print LOCK_FILE " <Machine>(Remote)</Machine>\n";
365 print LOCK_FILE " <Date>" . $current_time . "</Date>\n";
366 print LOCK_FILE "</LockFile>\n";
367 close(LOCK_FILE);
368}
369
370
371sub send_mail
372{
373 my $self = shift @_;
374
375 my ($mail_subject,$mail_content) = @_;
376
377 my $gsdl_cgi = $self->{'gsdl_cgi'};
378
379 my $sendmail_command = "perl -S sendmail.pl";
380 $sendmail_command .= " -to \"" . $mail_to_address . "\"";
381 $sendmail_command .= " -from \"" . $mail_from_address . "\"";
382 $sendmail_command .= " -smtp \"" . $mail_smtp_server . "\"";
383 $sendmail_command .= " -subject \"" . $mail_subject . "\"";
384
385 if (!open(POUT, "| $sendmail_command")) {
386 $gsdl_cgi->generate_error("Unable to execute command: $sendmail_command");
387 }
388 print POUT $mail_content . "\n";
389 close(POUT);
390}
391
392
393
394
395sub run_script
396{
397 my $self = shift @_;
398
399 my ($collect, $site, $script) = @_;
400
401 my $gsdl_cgi = $self->{'gsdl_cgi'};
402
403 my $perl_args = $collect;
404
405 my $collect_dir = $gsdl_cgi->get_collection_dir($site);
406 $perl_args = "-collectdir \"$collect_dir\" " . $perl_args;
407
408 my $perl_command = "perl -S $script $perl_args";
409
410
411 # IIS 6: redirecting output from STDERR to STDOUT just doesn't work, so
412 # we have to let it go directly out to the page
413
414 if (!$self->{'iis6_mode'})
415 {
416 $perl_command .= " 2>&1";
417 }
418
419 if (!open(PIN, "$perl_command |")) {
420 $gsdl_cgi->generate_error("Unable to execute command: $perl_command");
421 }
422
423 print STDOUT "Content-type:text/plain\n\n";
424 print "$perl_command \n";
425
426 while (defined (my $perl_output_line = <PIN>)) {
427 print STDOUT $perl_output_line;
428 }
429 close(PIN);
430
431 my $perl_status = $?;
432 if ($perl_status > 0) {
433 $gsdl_cgi->generate_error("Perl failed: $perl_command\n--\nExit status: " . ($perl_status / 256));
434 }
435}
436
437
438
439
4401;
Note: See TracBrowser for help on using the repository browser.