Fix for installer languages so that only the staff client languages are visible to...
[koha_gimpoz] / installer / install.pl
index c210a04..41d04a7 100755 (executable)
@@ -1,12 +1,12 @@
 #!/usr/bin/perl -w # please develop with -w
 
-#use diagnostics;
+use diagnostics;
 
 # use Install;
 use InstallAuth;
 use C4::Context;
 use C4::Output;
-use C4::Languages;
+use C4::Languages qw(getAllLanguages getTranslatedLanguages);
 
 use strict;    # please develop with the strict pragma
 
@@ -40,13 +40,12 @@ $info{'dbms'} =
     ? C4::Context->config("db_scheme")
     : "mysql" );
 $info{'hostname'} = C4::Context->config("hostname");
-( $info{'hostname'}, $info{'port'} ) = ( $1, $2 )
-  if $info{'hostname'} =~ /([^:]*):([0-9]+)/;
+$info{'port'}     = C4::Context->config("port");
 $info{'user'}     = C4::Context->config("user");
 $info{'password'} = C4::Context->config("pass");
 my $dbh = DBI->connect(
-    "DBI:$info{dbms}:$info{dbname}:$info{hostname}"
-      . ( $info{port} ? ":$info{port}" : "" ),
+    "DBI:$info{dbms}:dbname=$info{dbname};host=$info{hostname}"
+      . ( $info{port} ? ";port=$info{port}" : "" ),
     $info{'user'}, $info{'password'}
 );
 
@@ -67,6 +66,9 @@ if ( $step && $step == 1 ) {
     unless ( eval { require ZOOM } ) {
         push @missing, { name => "ZOOM" };
     }
+    unless ( eval { require YAML::Syck } ) {
+        push @missing, { name => "YAML::Syck" };
+    }
     unless ( eval { require LWP::Simple } ) {
         push @missing, { name => "LWP::Simple" };
     }
@@ -88,10 +90,10 @@ if ( $step && $step == 1 ) {
     unless ( eval { require DBD::mysql } ) {
         push @missing, { name => "DBD::mysql" };
     }
-    unless ( eval { require HTML::Template } ) {
+    unless ( eval { require HTML::Template::Pro } ) {
         push @missing, { name => "HTML::Template::Pro" };
     }
-    unless ( eval { require HTML::Template } ) {
+    unless ( eval { require Date::Calc } ) {
         push @missing, { name => "Date::Calc" };
     }
     unless ( eval { require Digest::MD5 } ) {
@@ -141,7 +143,7 @@ if ( $step && $step == 1 ) {
             push @missing, { name => "PDF::Report", usagebarcode => 1 };
         }
     }
-    unless ( eval { require Net::LDAP } ) {
+    unless ( eval { require Algorithm::CheckDigits } ) {
         if ( $#missing >= 0 ) {   # only when $#missing >= 0 so this isn't fatal
             push @missing, { name => "Algorithm::CheckDigits", usagebarcode => 1 };
         }
@@ -166,9 +168,9 @@ elsif ( $step && $step == 2 ) {
 #STEP 2 Check Database connection and access
 #
     $template->param(%info);
-    my $checkmysql = $query->param("checkmysql");
-    $template->param( 'mysqlconnection' => $checkmysql );
-    if ($checkmysql) {
+    my $checkdb = $query->param("checkdb");
+    $template->param( 'dbconnection' => $checkdb );
+    if ($checkdb) {
         if ($dbh) {
 
             # Can connect to the mysql
@@ -189,7 +191,7 @@ elsif ( $step && $step == 2 ) {
                 my $grantaccess;
                 while ( my ($line) = $rq->fetchrow ) {
                     my $dbname = $info{dbname};
-                    if ( $line =~ m/$dbname/ || index( $line, '*.*' ) > 0 ) {
+                    if ( $line =~ m/^GRANT (.*?) ON `$dbname`\.\*/ || index( $line, '*.*' ) > 0 ) {
                         $grantaccess = 1
                           if (
                             index( $line, 'ALL PRIVILEGES' ) > 0
@@ -224,7 +226,23 @@ elsif ( $step && $step == 2 ) {
                     }
                 }
                 $template->param( "checkgrantaccess" => $grantaccess );
-            }
+            }  # End mysql connect check...
+           
+           elsif ( $info{dbms} eq "Pg" ) {
+               # Check if database has been created...
+               my $rv = $dbh->do( "SELECT * FROM pg_catalog.pg_database WHERE datname = \'$info{dbname}\';" );
+               if ( $rv == 1 ) {
+                       $template->param( 'checkdatabasecreated' => 1 );
+               }
+
+               # Check if user has all necessary grants on this database...
+               my $rq = $dbh->do( "SELECT u.usesuper
+                                   FROM pg_catalog.pg_user as u
+                                   WHERE u.usename = \'$info{user}\';" );
+               if ( $rq == 1 ) {
+                       $template->param( "checkgrantaccess" => 1 );
+               }
+            }  # End Pg connect check...
         }
         else {
             $template->param( "error" => DBI::err, "message" => DBI::errstr );
@@ -255,19 +273,20 @@ elsif ( $step && $step == 3 ) {
             $finish->execute($kohaversion);
         } else {
             warn "INSERT Version";
-            my $finish=$dbh->prepare("INSERT into systempreferences (variable,value,explanation) values ('Version',?,'The Koha database version. Don t change this value manually, it s holded by the webinstaller')");
+            my $finish=$dbh->prepare("INSERT into systempreferences (variable,value,explanation) values ('Version',?,'The Koha database version. WARNING: Do not change this value manually, it is maintained by the webinstaller')");
             $finish->execute($kohaversion);
         }
 
         # Installation is finished.
-        # We just deny anybody acess to install
+        # We just deny anybody access to install
         # And we redirect people to mainpage.
-        # The installer wil have to relogin since we donot pass cookie to redirection.
+        # The installer will have to relogin since we do not pass cookie to redirection.
         $template->param( "$op" => 1 );
     }
-    elsif ( $op && $op eq 'Nozebra' ) {
-        if ($query->param('Nozebra')) {
+    elsif ( $op && $op eq 'SetIndexingEngine' ) {
+        if ($query->param('NoZebra')) {
             $dbh->do("UPDATE systempreferences SET value=1 WHERE variable='NoZebra'");
+            $dbh->do("UPDATE systempreferences SET value=0 WHERE variable in ('QueryFuzzy','QueryWeightFields','QueryStemming')");
         } else {
             $dbh->do("UPDATE systempreferences SET value=0 WHERE variable='NoZebra'");
         }
@@ -286,26 +305,38 @@ elsif ( $step && $step == 3 ) {
         my @fnames = sort {
             my @aa = split /\/|\\/, ($a);
             my @bb = split /\/|\\/, ($b);
-            $aa[-1] lt $bb[-1]
+            $aa[-1] cmp $bb[-1]
         } $query->param('framework');
-        $dbh->do('SET FOREIGN_KEY_CHECKS=0');
         my $request =
           $dbh->prepare(
             "SELECT value FROM systempreferences WHERE variable='FrameworksLoaded'"
           );
         $request->execute;
         my ($systempreference) = $request->fetchrow;
+        $systempreference = '' unless defined $systempreference; # avoid warning
         foreach my $file (@fnames) {
 
             #      warn $file;
             undef $/;
-            my $strcmd = "mysql "
-              . ( $info{hostname} ? " -h $info{hostname} " : "" )
-              . ( $info{port}     ? " -P $info{port} "     : "" )
-              . ( $info{user}     ? " -u $info{user} "     : "" )
-              . ( $info{password} ? " -p$info{password}"   : "" )
-              . " $info{dbname} ";
-            my $error = qx($strcmd < $file 2>&1);
+           my $error;
+           if ( $info{dbms} eq 'mysql' ) {
+               my $strcmd = "mysql "
+                       . ( $info{hostname} ? " -h $info{hostname} " : "" )
+                       . ( $info{port}     ? " -P $info{port} "     : "" )
+                       . ( $info{user}     ? " -u $info{user} "     : "" )
+                       . ( $info{password} ? " -p'$info{password}'"   : "" )
+                       . " $info{dbname} ";
+               $error = qx($strcmd < $file 2>&1 1>/dev/null);                  # We want to send stdout to null and return only stderr... -fbcit
+           }
+           elsif ( $info{dbms} eq 'Pg' ) { 
+               my $strcmd = "psql "
+                       . ( $info{hostname} ? " -h $info{hostname} " : "" )
+                       . ( $info{port}     ? " -p $info{port} "     : "" )
+                       . ( $info{user}     ? " -U $info{user} "     : "" )
+#                               . ( $info{password} ? " -W $info{password}"   : "" )
+                       . " $info{dbname} ";
+               $error = qx($strcmd -f $file 2>&1 1>/dev/null);                 # ...even more so with psql...
+           }
             my @file = split qr(\/|\\), $file;
             $lang = $file[ scalar(@file) - 3 ] unless ($lang);
             my $level = $file[ scalar(@file) - 2 ];
@@ -350,7 +381,6 @@ elsif ( $step && $step == 3 ) {
             "list"        => \@list
         );
         $template->param( "$op" => 1 );
-        $dbh->do('SET FOREIGN_KEY_CHECKS=1');
     }
     elsif ( $op && $op eq 'selectframeworks' ) {
         #
@@ -373,10 +403,14 @@ elsif ( $step && $step == 3 ) {
         my $langchoice = $query->param('fwklanguage');
         $langchoice = $query->cookie('KohaOpacLanguage') unless ($langchoice);
         my $marcflavour = $query->param('marcflavour');
-        if ($marcflavour){    
+        if ($marcflavour){
+            # we can have some variants of marc flavour, by having different directories, like : unimarc_small and unimarc_full, for small and complete unimarc frameworks.
+            # marc_cleaned finds the marcflavour, without the variant.
+            my $marc_cleaned = 'MARC21';
+            $marc_cleaned = 'UNIMARC' if $marcflavour =~ /unimarc/i;
           my $request =
             $dbh->prepare(
-              "INSERT IGNORE INTO `systempreferences` (variable,value,explanation,options,type) VALUES('marcflavour','$marcflavour','Define global MARC flavor (MARC21 or UNIMARC) used for character encoding','MARC21|UNIMARC','Choice');"
+              "INSERT IGNORE INTO `systempreferences` (variable,value,explanation,options,type) VALUES('marcflavour','$marc_cleaned','Define global MARC flavor (MARC21 or UNIMARC) used for character encoding','MARC21|UNIMARC','Choice');"
             );     
           $request->execute;
         };    
@@ -385,9 +419,19 @@ elsif ( $step && $step == 3 ) {
     
         undef $/;
         my $dir =
-          C4::Context->config('intranetdir') . "/installer/data/$langchoice/marcflavour/".lc($marcflavour);
-        opendir( MYDIR, $dir ) || warn "no open $dir";
-        my @listdir = sort grep { !/^\.|CVS|marcflavour/ && -d "$dir/$_" } readdir(MYDIR);
+          C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/$langchoice/marcflavour/".lc($marcflavour);
+        unless (opendir( MYDIR, $dir )) {
+            if ($langchoice eq 'en') {
+                warn "cannot open MARC frameworks directory $dir";
+            } else {
+                # if no translated MARC framework is available,
+                # default to English
+                $dir = C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/en/marcflavour/".lc($marcflavour);
+                opendir(MYDIR, $dir) or warn "cannot open English MARC frameworks directory $dir";
+                $template->param('en_marc_frameworks' => 1);
+            }
+        }
+        my @listdir = sort grep { !/^\.|marcflavour/ && -d "$dir/$_" } readdir(MYDIR);
         closedir MYDIR;
                   
         my @fwklist;
@@ -397,6 +441,7 @@ elsif ( $step && $step == 3 ) {
           );
         $request->execute;
         my ($frameworksloaded) = $request->fetchrow;
+        $frameworksloaded = '' unless defined $frameworksloaded; # avoid warning
         my %frameworksloaded;
         foreach ( split( /\|/, $frameworksloaded ) ) {
             $frameworksloaded{$_} = 1;
@@ -405,14 +450,14 @@ elsif ( $step && $step == 3 ) {
         foreach my $requirelevel (@listdir) {
             opendir( MYDIR, "$dir/$requirelevel" );
             my @listname =
-              grep { !/^\.|CVS/ && -f "$dir/$requirelevel/$_" && $_ =~ m/\.sql$/ }
+              grep { !/^\./ && -f "$dir/$requirelevel/$_" && $_ =~ m/\.sql$/ }
               readdir(MYDIR);
             closedir MYDIR;
             my %cell;
             my @frameworklist;
             map {
                 my $name = substr( $_, 0, -4 );
-                open FILE, "< $dir/$requirelevel/$name.txt";
+                open FILE, "<:utf8","$dir/$requirelevel/$name.txt";
                 my $lines = <FILE>;
                 $lines =~ s/\n|\r/<br \/>/g;
                 use utf8;
@@ -432,7 +477,7 @@ elsif ( $step && $step == 3 ) {
                   };
             } @listname;
             my @fwks =
-              sort { $a->{'fwkname'} lt $b->{'fwkname'} } @frameworklist;
+              sort { $a->{'fwkname'} cmp $b->{'fwkname'} } @frameworklist;
 
 #             $cell{"mandatory"}=($requirelevel=~/(mandatory|requi|oblig|necess)/i);
             $cell{"frameworks"} = \@fwks;
@@ -444,22 +489,32 @@ elsif ( $step && $step == 3 ) {
         $template->param( "marcflavour" => ucfirst($marcflavour));
         
         $dir =
-          C4::Context->config('intranetdir') . "/installer/data/$langchoice";
-        opendir( MYDIR, $dir ) || warn "no open $dir";
-        @listdir = sort grep { !/^\.|CVS|marcflavour/ && -d "$dir/$_" } readdir(MYDIR);
+          C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/$langchoice";
+        unless (opendir( MYDIR, $dir )) {
+            if ($langchoice eq 'en') {
+                warn "cannot open sample data directory $dir";
+            } else {
+                # if no sample data is available,
+                # default to English
+                $dir = C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/en";
+                opendir(MYDIR, $dir) or warn "cannot open English sample data directory $dir";
+                $template->param('en_sample_data' => 1);
+            }
+        }
+        @listdir = sort grep { !/^\.|marcflavour/ && -d "$dir/$_" } readdir(MYDIR);
         closedir MYDIR;
         my @levellist;
         foreach my $requirelevel (@listdir) {
             opendir( MYDIR, "$dir/$requirelevel" );
             my @listname =
-              grep { !/^\.|CVS/ && -f "$dir/$requirelevel/$_" && $_ =~ m/\.sql$/ }
+              grep { !/^\./ && -f "$dir/$requirelevel/$_" && $_ =~ m/\.sql$/ }
               readdir(MYDIR);
             closedir MYDIR;
             my %cell;
             my @frameworklist;
             map {
                 my $name = substr( $_, 0, -4 );
-                open FILE, "< $dir/$requirelevel/$name.txt";
+                open FILE, "<:utf8","$dir/$requirelevel/$name.txt";
                 my $lines = <FILE>;
                 $lines =~ s/\n|\r/<br \/>/g;
                 use utf8;
@@ -479,7 +534,7 @@ elsif ( $step && $step == 3 ) {
                   };
             } @listname;
             my @fwks =
-              sort { $a->{'fwkname'} lt $b->{'fwkname'} } @frameworklist;
+              sort { $a->{'fwkname'} cmp $b->{'fwkname'} } @frameworklist;
 
 #             $cell{"mandatory"}=($requirelevel=~/(mandatory|requi|oblig|necess)/i);
             $cell{"frameworks"} = \@fwks;
@@ -498,7 +553,8 @@ elsif ( $step && $step == 3 ) {
         #
         
         #Choose Marc Flavour
-        #sql data are supposed to be located in installer/data/<language>/marcflavour/marcflavourname
+        #sql data are supposed to be located in installer/data/<dbms>/<language>/marcflavour/marcflavourname
+       # Where <dbms> is database type according to DBD syntax
         # Where <language> is en|fr or any international abbreviation (provided language hash is updated... This will be a problem with internationlisation.)
         # Where <level> is a category of requirement : required, recommended optional
         # level should contain :
@@ -510,9 +566,18 @@ elsif ( $step && $step == 3 ) {
         my $langchoice = $query->param('fwklanguage');
         $langchoice = $query->cookie('KohaOpacLanguage') unless ($langchoice);
         my $dir =
-          C4::Context->config('intranetdir') . "/installer/data/$langchoice/marcflavour";
-        opendir( MYDIR, $dir ) || warn "no open $dir";
-        my @listdir = grep { !/^\.|CVS/ && -d "$dir/$_" } readdir(MYDIR);
+          C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/$langchoice/marcflavour";
+        unless (opendir( MYDIR, $dir )) {
+            if ($langchoice eq 'en') {
+                warn "cannot open MARC frameworks directory $dir";
+            } else {
+                # if no translated MARC framework is available,
+                # default to English
+                $dir = C4::Context->config('intranetdir') . "/installer/data/$info{dbms}/en/marcflavour";
+                opendir(MYDIR, $dir) or warn "cannot open English MARC frameworks directory $dir";
+            }
+        }
+        my @listdir = grep { !/^\./ && -d "$dir/$_" } readdir(MYDIR);
         closedir MYDIR;
         my $marcflavour=C4::Context->preference("marcflavour");    
         my @flavourlist;
@@ -520,7 +585,7 @@ elsif ( $step && $step == 3 ) {
             my %cell=(    
             "label"=> ucfirst($marc),
             "code"=>uc($marc),
-            "checked"=>uc($marc) eq $marcflavour);      
+            "checked"=> defined($marcflavour) ? uc($marc) eq $marcflavour : 0);      
 #             $cell{"description"}= do { local $/ = undef; open INPUT "<$dir/$marc.txt"||"";<INPUT> };
             push @flavourlist, \%cell;
         }
@@ -533,22 +598,32 @@ elsif ( $step && $step == 3 ) {
         # 1st install, 1st "sub-step" : import kohastructure
         #
         #
-        my $dbh = DBI->connect(
-            "DBI:$info{dbms}:$info{dbname}:$info{hostname}"
-              . ( $info{port} ? ":$info{port}" : "" ),
-            $info{'user'}, $info{'password'}
-        );
-        open( INPUT, "<kohastructure.sql" );
-        my $file = do { local $/ = undef; <INPUT> };
-        my @commands = split( /;/, $file );
-        pop @commands;
-        map { $dbh->do($_) } @commands;
-        close(INPUT);
+       my $datadir = C4::Context->config('intranetdir') . "/installer/data/$info{dbms}";
+       my $error;
+        if ( $info{dbms} eq 'mysql' ) {
+           my $strcmd = "mysql "
+               . ( $info{hostname} ? " -h $info{hostname} " : "" )
+               . ( $info{port}     ? " -P $info{port} "     : "" )
+               . ( $info{user}     ? " -u $info{user} "     : "" )
+               . ( $info{password} ? " -p'$info{password}'"   : "" )
+               . " $info{dbname} ";
+           $error = qx($strcmd <$datadir/kohastructure.sql 2>&1 1>/dev/null);
+        }
+        elsif ( $info{dbms} eq 'Pg' ) { 
+            my $strcmd = "psql "
+                . ( $info{hostname} ? " -h $info{hostname} " : "" )
+                . ( $info{port}     ? " -p $info{port} "     : "" )
+                . ( $info{user}     ? " -U $info{user} "     : "" )
+#                . ( $info{password} ? " -W $info{password}"   : "" )          # psql will NOT accept a password, but prompts...
+                . " $info{dbname} ";                                           # Therefore, be sure to run 'trust' on localhost in pg_hba.conf -fbcit
+            $error = qx($strcmd -f $datadir/kohastructure.sql 2>&1 1>/dev/null);# Be sure to set 'client_min_messages = error' in postgresql.conf
+                                                                               # so that only true errors are returned to stderr or else the installer will
+                                                                               # report the import a failure although it really succeded -fbcit
+       }
         $template->param(
-            "error" => $dbh->errstr,
+            "error" => $error,
             "$op"   => 1,
         );
-        $dbh->disconnect;
     }
     elsif ( $op && $op eq 'updatestructure' ) {
         #
@@ -556,9 +631,9 @@ elsif ( $step && $step == 3 ) {
         #
         #Do updatedatabase And report
         my $execstring =
-          C4::Context->config("intranetdir") . "/updater/updatedatabase";
+          C4::Context->config("intranetdir") . "/installer/data/$info{dbms}/updatedatabase.pl";
         undef $/;
-        my $string = qx|$execstring 2>&1|;
+        my $string = qx($execstring 2>&1 1>/dev/null);                         # added '1>/dev/null' to return only stderr in $string. Needs testing here. -fbcit
         if ($string) {
             $string =~ s/\n|\r/<br \/>/g;
             $string =~
@@ -575,11 +650,15 @@ elsif ( $step && $step == 3 ) {
         # Paul has cleaned up tables so reduced the count
         #I put it there because it implied a data import if condition was not satisfied.
         my $dbh = DBI->connect(
-            "DBI:$info{dbms}:$info{dbname}:$info{hostname}"
-              . ( $info{port} ? ":$info{port}" : "" ),
-            $info{'user'}, $info{'password'}
+               "DBI:$info{dbms}:dbname=$info{dbname};host=$info{hostname}"
+               . ( $info{port} ? ";port=$info{port}" : "" ),
+               $info{'user'}, $info{'password'}
         );
-        my $rq = $dbh->prepare( "SHOW TABLES FROM " . $info{'dbname'} );
+       my $rq;
+        if ( $info{dbms} eq 'mysql' ) { $rq = $dbh->prepare( "SHOW TABLES FROM " . $info{'dbname'} ); }
+       elsif ( $info{dbms} eq 'Pg' ) { $rq = $dbh->prepare( "SELECT *
+                                                               FROM information_schema.tables
+                                                               WHERE table_schema='public' and table_type='BASE TABLE';" ); }
         $rq->execute;
         my $data = $rq->fetchall_arrayref( {} );
         my $count = scalar(@$data);
@@ -617,19 +696,8 @@ else {
 
     # LANGUAGE SELECTION page by default
     # using opendir + language Hash
-
-    my $langavail = getTranslatedLanguages();
-
-    my @languages;
-    foreach (@$langavail) {
-        push @languages,
-          {
-            'value'       => $_->{'language_code'},
-            'description' => $_->{'language_name'}
-          }
-          if ( $_->{'language_code'} );
-    }
-    $template->param( languages => \@languages );
+    my $languages_loop = getTranslatedLanguages('intranet');
+    $template->param( installer_languages_loop => $languages_loop );
     if ($dbh) {
         my $rq =
           $dbh->prepare(
@@ -638,6 +706,7 @@ else {
             my ($version) = $rq->fetchrow;
             if ($version) {
                 $query->redirect("install.pl?step=3");
+                               exit;
             }
         }
     }