View | Details | Raw Unified | Return to bug 7167
Collapse All | Expand All

(-)a/C4/Auth.pm (-71 / +11 lines)
Lines 42-48 BEGIN { Link Here
42
	else { exit }
42
	else { exit }
43
    }
43
    }
44
44
45
    $VERSION     = 3.02;                                                                                                            # set version for version checking
46
    $debug       = $ENV{DEBUG};
45
    $debug       = $ENV{DEBUG};
47
    @ISA         = qw(Exporter);
46
    @ISA         = qw(Exporter);
48
    @EXPORT      = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
47
    @EXPORT      = qw(&checkauth &get_template_and_user &haspermission &get_user_subpermissions);
Lines 550-598 has authenticated. Link Here
550
549
551
=cut
550
=cut
552
551
553
sub _version_check ($$) {
554
    my $type = shift;
555
    my $query = shift;
556
    my $version;
557
    # If Version syspref is unavailable, it means Koha is beeing installed,
558
    # and so we must redirect to OPAC maintenance page or to the WebInstaller
559
	# also, if OpacMaintenance is ON, OPAC should redirect to maintenance
560
	if (C4::Context->preference('OpacMaintenance') && $type eq 'opac') {
561
        warn "OPAC Install required, redirecting to maintenance";
562
        print $query->redirect("/cgi-bin/koha/maintenance.pl");
563
    }
564
    unless ( $version = C4::Context->preference('Version') ) {    # assignment, not comparison
565
        if ( $type ne 'opac' ) {
566
            warn "Install required, redirecting to Installer";
567
            print $query->redirect("/cgi-bin/koha/installer/install.pl");
568
        } else {
569
            warn "OPAC Install required, redirecting to maintenance";
570
            print $query->redirect("/cgi-bin/koha/maintenance.pl");
571
        }
572
        safe_exit;
573
    }
574
575
    # check that database and koha version are the same
576
    # there is no DB version, it's a fresh install,
577
    # go to web installer
578
    # there is a DB version, compare it to the code version
579
    my $kohaversion=C4::Context::KOHAVERSION;
580
    # remove the 3 last . to have a Perl number
581
    $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
582
    $debug and print STDERR "kohaversion : $kohaversion\n";
583
    if ($version < $kohaversion){
584
        my $warning = "Database update needed, redirecting to %s. Database is $version and Koha is $kohaversion";
585
        if ($type ne 'opac'){
586
            warn sprintf($warning, 'Installer');
587
            print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
588
        } else {
589
            warn sprintf("OPAC: " . $warning, 'maintenance');
590
            print $query->redirect("/cgi-bin/koha/maintenance.pl");
591
        }
592
        safe_exit;
593
    }
594
}
595
596
sub _session_log {
552
sub _session_log {
597
    (@_) or return 0;
553
    (@_) or return 0;
598
    open L, ">>/tmp/sessionlog" or warn "ERROR: Cannot append to /tmp/sessionlog";
554
    open L, ">>/tmp/sessionlog" or warn "ERROR: Cannot append to /tmp/sessionlog";
Lines 616-623 sub checkauth { Link Here
616
        $timeout = $1 * 86400;
572
        $timeout = $1 * 86400;
617
    };
573
    };
618
    $timeout = 600 unless $timeout;
574
    $timeout = 600 unless $timeout;
575
    # check we have a Version. Otherwise => go to installer
576
    unless ( C4::Context->preference('Version') ) {    # assignment, not comparison
577
        if ( $type ne 'opac' ) {
578
            $debug && warn "Install required, redirecting to Installer";
579
            print $query->redirect("/cgi-bin/koha/installer/install.pl");
580
        } else {
581
            $debug && warn "OPAC Install required, redirecting to maintenance";
582
            print $query->redirect("/cgi-bin/koha/maintenance.pl");
583
        }
584
        safe_exit;
585
    }
619
586
620
    _version_check($type,$query);
621
    # state variables
587
    # state variables
622
    my $loggedin = 0;
588
    my $loggedin = 0;
623
    my %info;
589
    my %info;
Lines 1060-1078 sub check_api_auth { Link Here
1060
    my $timeout = C4::Context->preference('timeout');
1026
    my $timeout = C4::Context->preference('timeout');
1061
    $timeout = 600 unless $timeout;
1027
    $timeout = 600 unless $timeout;
1062
1028
1063
    unless (C4::Context->preference('Version')) {
1064
        # database has not been installed yet
1065
        return ("maintenance", undef, undef);
1066
    }
1067
    my $kohaversion=C4::Context::KOHAVERSION;
1068
    $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
1069
    if (C4::Context->preference('Version') < $kohaversion) {
1070
        # database in need of version update; assume that
1071
        # no API should be called while databsae is in
1072
        # this condition.
1073
        return ("maintenance", undef, undef);
1074
    }
1075
1076
    # FIXME -- most of what follows is a copy-and-paste
1029
    # FIXME -- most of what follows is a copy-and-paste
1077
    # of code from checkauth.  There is an obvious need
1030
    # of code from checkauth.  There is an obvious need
1078
    # for refactoring to separate the various parts of
1031
    # for refactoring to separate the various parts of
Lines 1293-1311 sub check_cookie_auth { Link Here
1293
    my $timeout = C4::Context->preference('timeout');
1246
    my $timeout = C4::Context->preference('timeout');
1294
    $timeout = 600 unless $timeout;
1247
    $timeout = 600 unless $timeout;
1295
1248
1296
    unless (C4::Context->preference('Version')) {
1297
        # database has not been installed yet
1298
        return ("maintenance", undef);
1299
    }
1300
    my $kohaversion=C4::Context::KOHAVERSION;
1301
    $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
1302
    if (C4::Context->preference('Version') < $kohaversion) {
1303
        # database in need of version update; assume that
1304
        # no API should be called while databsae is in
1305
        # this condition.
1306
        return ("maintenance", undef);
1307
    }
1308
1309
    # FIXME -- most of what follows is a copy-and-paste
1249
    # FIXME -- most of what follows is a copy-and-paste
1310
    # of code from checkauth.  There is an obvious need
1250
    # of code from checkauth.  There is an obvious need
1311
    # for refactoring to separate the various parts of
1251
    # for refactoring to separate the various parts of
(-)a/C4/Config/File/YAML.pm (+59 lines)
Line 0 Link Here
1
package C4::Config::File::YAML;
2
# Copyright 2011 BibLibre
3
#
4
# This file is part of Koha.
5
#
6
# Koha is free software; you can redistribute it and/or modify it under the
7
# terms of the GNU General Public License as published by the Free Software
8
# Foundation; either version 2 of the License, or (at your option) any later
9
# version.
10
#
11
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
12
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License along
16
# with Koha; if not, write to the Free Software Foundation, Inc.,
17
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18
19
use Modern::Perl;
20
use YAML;
21
22
sub _fileload{
23
    my ($filename)=shift;
24
    return YAML::LoadFile($filename);
25
}
26
27
sub _dirload{
28
    my $dirname=shift;
29
    my $result;
30
    opendir D, $dirname;
31
    for my $name (readdir(D)){
32
        next if $name=~/^\./;
33
        if (-d $name){
34
            $result->{$name}=_dirload($dirname."/".$name);
35
        }
36
        if ((-e $dirname."/".$name) and ($name=~/\.ya?ml/) ){
37
            $result=($result
38
                    ? [%$result,%{_fileload($dirname."/".$name)}]
39
                    : _fileload($dirname."/".$name));
40
        }
41
    }
42
    close D;
43
    return $result;
44
}
45
46
47
sub new{
48
    my $config;
49
    my $self=shift;
50
    my $name=shift;
51
    if (-f $name){
52
        $config=_fileload($name);
53
    }
54
    if (-d $name){
55
        $config->{$name}=_dirload($name);
56
    }
57
    return $config;
58
}
59
1;
(-)a/C4/Installer.pm (-1 / +10 lines)
Lines 22-27 use strict; Link Here
22
22
23
our $VERSION = 3.00;
23
our $VERSION = 3.00;
24
use C4::Context;
24
use C4::Context;
25
use C4::Update::Database;
25
use C4::Installer::PerlModules 1.000000;
26
use C4::Installer::PerlModules 1.000000;
26
27
27
=head1 NAME
28
=head1 NAME
Lines 466-472 Koha software version. Link Here
466
467
467
sub set_version_syspref {
468
sub set_version_syspref {
468
    my $self = shift;
469
    my $self = shift;
469
470
    # get all updatedatabase, and mark them as passed, as it's a fresh install
471
    my $versions = C4::Update::Database::list_versions_availables();
472
    for my $v ( @$versions ) {
473
        my $queries;
474
        $queries->{queries} = ["initial setup"];
475
        $queries->{comments} = ["initial setup"];
476
        C4::Update::Database::set_infos($v,$queries,undef,undef);
477
    }
478
    # mark the "old" 3.6 version number
470
    my $kohaversion=C4::Context::KOHAVERSION;
479
    my $kohaversion=C4::Context::KOHAVERSION;
471
    # remove the 3 last . to have a Perl number
480
    # remove the 3 last . to have a Perl number
472
    $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
481
    $kohaversion =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
(-)a/C4/Update/Database.pm (+502 lines)
Line 0 Link Here
1
package C4::Update::Database;
2
3
# Copyright 2011 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
use Modern::Perl;
21
22
use C4::Context;
23
use C4::Config::File::YAML;
24
25
use File::Basename;
26
use Digest::MD5;
27
use List::MoreUtils qw/uniq/;
28
29
=head1 NAME
30
31
C4::Update::Database.pm
32
33
=head1 SYNOPSIS
34
35
  use C4::Update::Database;
36
37
  This package is used by admin/updatedatabase.pl, to manage DB updates
38
39
=head1 FUNCTIONS
40
41
=cut
42
my $config = C4::Config::File::YAML->new( C4::Context->config("intranetdir") . qq{/etc/update/database/config.yaml} );
43
my $VERSIONS_PATH = C4::Context->config('intranetdir') . '/' . $config->{versions_dir};
44
45
my $version;
46
my $list;
47
48
my $dbh = C4::Context->dbh;
49
50
=head2
51
52
  my $file = get_filepath($version);
53
  this sub will return the full path of a given DB update number
54
55
=cut
56
57
sub get_filepath {
58
    my ( $version ) = @_;
59
    my @files = <$VERSIONS_PATH/$version*>;
60
    if ( scalar @files != 1 ) {
61
        die "This version ($version) returned has ".scalar @files." corresponding, need only 1";
62
    }
63
64
    return $files[0];
65
}
66
67
=head2 get_md5
68
69
  my $md5 = get_md5($filepath)
70
  returns the md5sum of the selected file.
71
  This is used to check consistency of updates
72
73
=cut
74
sub get_md5 {
75
    my ( $filepath ) = @_;
76
    open(FILE, $filepath);
77
78
    my $ctx = Digest::MD5->new;
79
    $ctx->addfile(*FILE);
80
    my $md5 = $ctx->hexdigest;
81
    close(FILE);
82
    return $md5;
83
}
84
85
=head2 execute_version
86
87
  $result = execute_version($version_number);
88
  Execute an update.
89
  This sub will detect if the number is made through a .pl or a .sql, and behave accordingly
90
  if there is more than 1 file with the same number, an error will be issued
91
  if you try to execute a version_number that has already be executed, then it will also issue an error
92
  the sub return an result hash, with the version number and the result
93
94
=cut
95
96
sub execute_version {
97
    my ( $version ) = @_;
98
    my $report;
99
100
    my $filepath;
101
    eval {
102
        $filepath = get_filepath $version;
103
    };
104
    if ( $@ ) {
105
        return { $version => $@ };
106
    }
107
108
    my @file_infos = fileparse( $filepath, qr/\.[^.]*/ );
109
    my $extension = $file_infos[2];
110
    my $filename = $version . $extension;
111
112
    my $md5 = get_md5 $filepath;
113
    my $r = md5_already_exists( $md5 );
114
    if ( scalar @$r ) {
115
        my $p = @$r[0];
116
        $report->{$version} = "This file ( $filepath ) still already execute in version " . @$r[0]->{version} . " : same md5 (" . @$r[0]->{md5} . ")";
117
        return $report;
118
    }
119
120
    my $queries;
121
    given ( $extension ) {
122
        when ( /.sql/ ) {
123
            $queries = get_queries ( $filepath );
124
        }
125
        when ( /.pl/ ) {
126
            my $versions_dir = C4::Context->intranetdir . '/installer/data/mysql/versions/';
127
            my $version_file = $versions_dir . $filename;
128
            if ( do $version_file ) {
129
                $queries = _get_queries();
130
            } else {
131
                $report->{$version} = "Load functions in $filename failed";
132
            }
133
        }
134
        default {
135
            $report->{$version} = "This extension ($extension) is not take into account (only .pl or .sql)";
136
        }
137
    }
138
139
    return $report
140
        if ( defined $report->{$version} );
141
142
    my $errors;
143
    for my $query ( @{$queries->{queries}} ) {
144
        eval {
145
            check_coherency( $query );
146
        };
147
        if ( $@ ) {
148
            push @$errors, $@
149
        }
150
    }
151
152
    if ( $errors ) {
153
        $_ =~ s/at [^ ]* line \d*\.$// for @$errors;
154
        $report->{$version} = $errors;
155
        return $report;
156
    }
157
158
    $errors = execute ( $queries );
159
    $report->{$version} = scalar( @$errors ) ? $errors : "OK";
160
    set_infos ( $version, $queries, $errors, $md5 );
161
    return $report;
162
}
163
164
=head2 list_versions_availables
165
166
  my @versions = list_versions_availables;
167
  return an array with all version available
168
  This list is retrieved from the directory defined in the etc/update/database/config.yaml, versions_dir parameter
169
170
=cut
171
172
sub list_versions_availables {
173
    my @versions;
174
    opendir DH, $VERSIONS_PATH or die "Cannot open directory ($!)";
175
    my @files = grep { !/^\.\.?$/ and /^.*\.(sql|pl)$/ and !/^skeleton/ } readdir DH;
176
    for my $f ( @files ) {
177
        my @file_infos = fileparse( $f, qr/\.[^.]*/ );
178
        push @versions, $file_infos[0];
179
    }
180
    @versions = uniq @versions;
181
    closedir DH;
182
    return \@versions;
183
}
184
185
=head2 list_versions_already_knows
186
187
  my @versions = list_versions_availables;
188
  return an array with all version that have already been applied
189
  This sub check first that the updatedb tables exist and create them if needed
190
191
=cut
192
193
sub list_versions_already_knows {
194
    # 1st check if tables exist, otherwise create them
195
        $dbh->do(qq{
196
                CREATE TABLE IF NOT EXISTS `updatedb_error` ( `version` varchar(32) DEFAULT NULL, `error` text ) ENGINE=InnoDB CHARSET=utf8;
197
        });
198
            $dbh->do(qq{
199
            CREATE TABLE  IF NOT EXISTS `updatedb_query` ( `version` varchar(32) DEFAULT NULL, `query` text ) ENGINE=InnoDB CHARSET=utf8;
200
        });
201
        $dbh->do(qq{
202
            CREATE TABLE  IF NOT EXISTS `updatedb_report` ( `version` text, `md5` varchar(50) DEFAULT NULL, `comment` text, `status` int(1) DEFAULT NULL ) ENGINE=InnoDB CHARSET=utf8;
203
        });
204
205
    my $query = qq/ SELECT version, comment, status FROM updatedb_report ORDER BY version/;
206
    my $sth = $dbh->prepare( $query );
207
    $sth->execute;
208
    my $versions = $sth->fetchall_arrayref( {} );
209
    map {
210
        my $version = $_;
211
        my @comments = defined $_->{comment} ? split '\\\n', $_->{comment} : "";
212
        push @{ $version->{comments} }, { comment => $_ } for @comments;
213
        delete $version->{comment};
214
    } @$versions;
215
    $sth->finish;
216
    for my $version ( @$versions ) {
217
        $query = qq/ SELECT query FROM updatedb_query WHERE version = ? ORDER BY version/;
218
        $sth = $dbh->prepare( $query );
219
        $sth->execute( $version->{version} );
220
        $version->{queries} = $sth->fetchall_arrayref( {} );
221
        $sth->finish;
222
        $query = qq/ SELECT error FROM updatedb_error WHERE version = ? ORDER BY version/;
223
        $sth = $dbh->prepare( $query );
224
        $sth->execute( $version->{version} );
225
        $version->{errors} = $sth->fetchall_arrayref( {} );
226
        $sth->finish;
227
    }
228
    return $versions;
229
}
230
231
=head2 execute
232
233
  my @errors = $execute(\@queries);
234
  This sub will execute queries coming from an execute_version based on a .sql file
235
236
=cut
237
238
sub execute {
239
    my ( $queries ) = @_;
240
    my @errors;
241
    for my $query ( @{$queries->{queries}} ) {
242
        eval {
243
            $dbh->do( $query );
244
        };
245
        push @errors, get_error();
246
    }
247
    return \@errors;
248
}
249
250
=head2 get_tables_name
251
252
  my $tables = get_tables_name;
253
  return an array with all Koha mySQL table names
254
255
=cut
256
257
sub get_tables_name {
258
    my $sth = $dbh->prepare("SHOW TABLES");
259
    $sth->execute();
260
    my @tables;
261
    while ( my ( $table ) = $sth->fetchrow_array ) {
262
        push @tables, $table;
263
    }
264
    return \@tables;
265
}
266
my $tables;
267
268
=head2 check_coherency
269
270
  my $errors = check_coherency($query);
271
  This sub will try to check if a SQL query is useless or no.
272
  for queries that are CREATE TABLE, it will check if the table already exists
273
  for queries that are ALTER TABLE, it will search if the modification has already been made
274
  for queries that are INSERT, it will search if the insert has already been made if it's a syspref or a permission
275
276
  Those test cover 90% of the updatedatabases cases. That will help finding duplicate or inconsistencies
277
278
=cut
279
280
sub check_coherency {
281
    my ( $query ) = @_;
282
    $tables = get_tables_name() if not $tables;
283
284
    given ( $query ) {
285
        when ( /CREATE TABLE(?:.*?)? `?(\w+)`?/ ) {
286
            my $table_name = $1;
287
            if ( grep { /$table_name/ } @$tables ) {
288
                die "COHERENCY: Table $table_name already exists";
289
            }
290
        }
291
292
        when ( /ALTER TABLE *`?(\w+)`? *ADD *(?:COLUMN)? `?(\w+)`?/ ) {
293
            my $table_name = $1;
294
            my $column_name = $2;
295
            next if $column_name =~ /(UNIQUE|CONSTRAINT|INDEX|KEY|FOREIGN)/;
296
            if ( not grep { /$table_name/ } @$tables ) {
297
                return "COHERENCY: Table $table_name does not exist";
298
            } else {
299
                my $sth = $dbh->prepare( "DESC $table_name $column_name" );
300
                my $rv = $sth->execute;
301
                if ( $rv > 0 ) {
302
                    die "COHERENCY: Field $table_name.$column_name already exists";
303
                }
304
            }
305
        }
306
307
        when ( /INSERT INTO `?(\w+)`?.*?VALUES *\((.*?)\)/ ) {
308
            my $table_name = $1;
309
            my @values = split /,/, $2;
310
            s/^ *'// foreach @values;
311
            s/' *$// foreach @values;
312
            given ( $table_name ) {
313
                when ( /systempreferences/ ) {
314
                    my $syspref = $values[0];
315
                    my $sth = $dbh->prepare( "SELECT COUNT(*) FROM systempreferences WHERE variable = ?" );
316
                    $sth->execute( $syspref );
317
                    if ( ( my $count = $sth->fetchrow_array ) > 0 ) {
318
                        die "COHERENCY: Syspref $syspref already exists";
319
                    }
320
                }
321
322
                when ( /permissions/){
323
                    my $module_bit = $values[0];
324
                    my $code = $values[1];
325
                    my $sth = $dbh->prepare( "SELECT COUNT(*) FROM permissions WHERE module_bit = ? AND code = ?" );
326
                    $sth->execute($module_bit, $code);
327
                    if ( ( my $count = $sth->fetchrow_array ) > 0 ) {
328
                        die "COHERENCY: Permission $code already exists";
329
                    }
330
                }
331
            }
332
        }
333
    }
334
    return 1;
335
}
336
337
=head2 get_error
338
339
  my $errors = get_error()
340
  This sub will return any mySQL error that occured during an update
341
342
=cut
343
344
sub get_error {
345
    my @errors = $dbh->selectrow_array(qq{SHOW ERRORS}); # Get errors
346
    my @warnings = $dbh->selectrow_array(qq{SHOW WARNINGS}); # Get warnings
347
    if ( @errors ) { # Catch specifics errors
348
        return qq{$errors[0] : $errors[1] => $errors[2]};
349
    } elsif ( @warnings ) {
350
        return qq{$warnings[0] : $warnings[1] => $warnings[2]}
351
            if $warnings[0] ne 'Note';
352
    }
353
    return;
354
}
355
356
=head2
357
358
  my $result = get_queries($filepath);
359
  this sub will return a hashref with 2 entries:
360
    $result->{queries} is an array with all queries to execute
361
    $result->{comments} is an array with all comments in the .sql file
362
363
=cut
364
365
sub get_queries {
366
    my ( $filepath ) = @_;
367
    open my $fh, "<", $filepath;
368
    my @queries;
369
    my @comments;
370
    my $old_delimiter = $/;
371
    while ( <$fh> ) {
372
        my $line = $_;
373
        chomp $line;
374
        $line =~ s/^\s*//;
375
        if ( $line =~ s/^--(.*)$// ) {
376
            push @comments, $1;
377
            next;
378
        }
379
        if ( $line =~ /^delimiter (.*)$/i ) {
380
            $/ = $1;
381
            next;
382
        }
383
        $line =~ s#$/##;
384
        push @queries, $line if not $line =~ /^\s*$/; # Push if query is not empty
385
    }
386
    $/ = $old_delimiter;
387
    close $fh;
388
389
    return { queries => \@queries, comments => \@comments };
390
}
391
392
=head2 md5_already_exists
393
394
  my $result = md5_already_exists($md5);
395
  check if the md5 of an update has already been applied on the database.
396
  If yes, it will return a hash with the version related to this md5
397
398
=cut
399
400
sub md5_already_exists {
401
    my ( $md5 ) = @_;
402
    my $query = qq/SELECT version, md5 FROM updatedb_report WHERE md5 = ?/;
403
    my $sth = $dbh->prepare( $query );
404
    $sth->execute( $md5 );
405
    my @r;
406
    while ( my ( $version, $md5 ) = $sth->fetchrow ) {
407
        push @r, { version => $version, md5 => $md5 };
408
    }
409
    $sth->finish;
410
    return \@r;
411
}
412
413
=head2 set_infos
414
415
  set_info($version,$queries, $error, $md5);
416
  this sub will insert into the updatedb tables what has been made on the database (queries, errors, result)
417
418
=cut
419
sub set_infos {
420
    my ( $version, $queries, $errors, $md5 ) = @_;
421
    #SetVersion($DBversion) if not -s $errors;
422
    for my $query ( @{ $queries->{queries} } ) {
423
        my $sth = $dbh->prepare("INSERT INTO updatedb_query(version, query) VALUES (?, ?)");
424
        $sth->execute( $version, $query );
425
        $sth->finish;
426
    }
427
    for my $error ( @$errors ) {
428
        my $sth = $dbh->prepare("INSERT INTO updatedb_error(version, error) VALUES (?, ?)");
429
        $sth->execute( $version, $error );
430
    }
431
    my $sth = $dbh->prepare("INSERT INTO updatedb_report(version, md5, comment, status) VALUES (?, ?, ?, ?)");
432
    $sth->execute(
433
        $version,
434
        $md5,
435
        join ('\n', @{ $queries->{comments} }),
436
        ( @$errors > 0 ) ? 0 : 1
437
    );
438
}
439
440
=head2 mark_as_ok
441
442
  $mark_as_ok($version);
443
  this sub will force to mark as "OK" an update that has failed
444
  once this has been made, the status will look as "forced OK", and appear in green like versions that have been applied without any problem
445
446
=cut
447
sub mark_as_ok {
448
    my ( $version ) = @_;
449
    my $sth = $dbh->prepare( "UPDATE updatedb_report SET status = 2 WHERE version=?" );
450
    my $affected = $sth->execute( $version );
451
    if ( $affected < 1 ) {
452
        # For "Coherency"
453
        my $filepath = get_filepath $version;
454
        my $queries = get_queries $filepath;
455
        my $errors;
456
        for my $query ( @{$queries->{queries}} ) {
457
            eval {
458
                check_coherency( $query );
459
            };
460
            if ( $@ ) {
461
                push @$errors, $@
462
            }
463
        }
464
465
        $_ =~ s/at [^ ]* line \d*\.$// for @$errors;
466
        my $md5 = get_md5 $filepath;
467
        set_infos $version, $queries, $errors, $md5;
468
469
        $sth->execute( $version );
470
    }
471
    $sth->finish;
472
}
473
474
=head2 TransformToNum
475
476
  Transform the Koha version from a 4 parts string
477
  to a number, with just 1 . (ie: it's a number)
478
479
=cut
480
481
sub TransformToNum {
482
    my $version = shift;
483
484
    # remove the 3 last . to have a Perl number
485
    $version =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
486
    return $version;
487
}
488
489
sub SetVersion {
490
    my $kohaversion = TransformToNum(shift);
491
    if ( C4::Context->preference('Version') ) {
492
        my $finish = $dbh->prepare("UPDATE systempreferences SET value=? WHERE variable='Version'");
493
        $finish->execute($kohaversion);
494
    } else {
495
        my $finish = $dbh->prepare(
496
"INSERT IGNORE INTO systempreferences (variable,value,explanation) values ('Version',?,'The Koha database version. WARNING: Do not change this value manually, it is maintained by the webinstaller')"
497
        );
498
        $finish->execute($kohaversion);
499
    }
500
}
501
502
1;
(-)a/about.pl (-1 / +39 lines)
Lines 32-37 use C4::Output; Link Here
32
use C4::Auth;
32
use C4::Auth;
33
use C4::Context;
33
use C4::Context;
34
use C4::Installer;
34
use C4::Installer;
35
use C4::Update::Database;
35
36
36
#use Smart::Comments '####';
37
#use Smart::Comments '####';
37
38
Lines 47-53 my ( $template, $loggedinuser, $cookie ) = get_template_and_user( Link Here
47
    }
48
    }
48
);
49
);
49
50
50
my $kohaVersion   = C4::Context::KOHAVERSION;
51
my $kohaVersion   = C4::Context->preference("Version");
52
# restore ., for display consistency
53
$kohaVersion =~ /(.)\.(..)(..)(...)/;
54
$kohaVersion = "$1.$2.$3.$4";
55
# the $kohaVersion is duplicated since 3.7: the 3.6 (that uses the old mechanism) and the 3.7 (new mechanism).
56
# Both versions reflects how the database has been upgraded
57
my $already_knows = C4::Update::Database::list_versions_already_knows();
58
# $last_known contains the previous DBrev applied number (all . removed). It's used to have a . instead of a number in case of continuous updates
59
my $last_known=0;
60
# $last_known_sep contains the previous DBrev applied with the separator (used for display)
61
my $last_known_sep="";
62
for my $v ( @$already_knows ) {
63
    my $current = $v->{version};
64
    $current =~s/\.//g;
65
    # if the current number is the previous one +1, then just add a ., for a better display N.........N+10, for example
66
    # (instead of N / N+1 / N+2 / ...)
67
    if ($current==$last_known+1) {
68
        $kohaVersion.=".";
69
    } else { # we're not N+1, start a new range
70
        # if version don't end by a ., no need to add the current loop number
71
        # this avoid having N...N (in case of an isolated BDrev number)
72
        if ($last_known & $kohaVersion =~ /\.$/) {
73
            $kohaVersion .= "...".$last_known_sep;
74
        }
75
        # start a new range
76
        $kohaVersion .= " / ".$v->{version};
77
    }
78
    $last_known= $current;
79
    $last_known_sep=$v->{version};
80
}
81
# add the last DB rev number, we don't want to end with "..."
82
if ($kohaVersion =~ /\.$/) {
83
    $kohaVersion .= "...".$last_known_sep;
84
}
85
86
# remove any 0 just after a . for better readability (3.06.02.001 will become 3.6.2.1)
87
$kohaVersion =~ s/\.0+/\./g;
88
51
my $osVersion     = `uname -a`;
89
my $osVersion     = `uname -a`;
52
my $perl_path = $^X;
90
my $perl_path = $^X;
53
if ($^O ne 'VMS') {
91
if ($^O ne 'VMS') {
(-)a/admin/ajax-updatedb-getinfos.pl (+61 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# Copyright 2011 BibLibre
4
#
5
# This file is part of Koha.
6
#
7
# Koha is free software; you can redistribute it and/or modify it under the
8
# terms of the GNU General Public License as published by the Free Software
9
# Foundation; either version 2 of the License, or (at your option) any later
10
# version.
11
#
12
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
13
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
15
#
16
# You should have received a copy of the GNU General Public License along
17
# with Koha; if not, write to the Free Software Foundation, Inc.,
18
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19
20
=head1 NAME
21
22
ajax-updatedb-getinfos.pl
23
24
=head1 DESCRIPTION
25
this script returns comments for a updatedatabase version
26
27
=back
28
29
=cut
30
31
use Modern::Perl;
32
use CGI;
33
use C4::Update::Database;
34
35
my $input = new CGI;
36
my $version = $input->param('version');
37
38
binmode STDOUT, ":utf8";
39
print $input->header(-type => 'text/plain', -charset => 'UTF-8');
40
my $filepath;
41
my $queries;
42
eval {
43
    $filepath = C4::Update::Database::get_filepath( $version );
44
    $queries = C4::Update::Database::get_queries( $filepath );
45
};
46
if ( $@ ){
47
    print $@;
48
    exit;
49
}
50
51
if ( @{ $$queries{comments} } ) {
52
    print "Comments : <br/>" . join ( "<br/>", @{ $$queries{comments} } );
53
} else {
54
    print "No comment <br/>";
55
}
56
57
if ( @{ $$queries{queries} } ) {
58
    print "<br/><br/>Queries : <br/>" . join ( "<br/>", @{ $$queries{queries} } );
59
} else {
60
    print "<br/>No queries";
61
}
(-)a/admin/updatedatabase.pl (+103 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it under the
6
# terms of the GNU General Public License as published by the Free Software
7
# Foundation; either version 2 of the License, or (at your option) any later
8
# version.
9
#
10
# Koha is distributed in the hope that it will be useful, but WITHOUT ANY
11
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
12
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
13
#
14
# You should have received a copy of the GNU General Public License along
15
# with Koha; if not, write to the Free Software Foundation, Inc.,
16
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17
18
use Modern::Perl;
19
use strict;
20
use CGI;
21
use C4::Auth;
22
use C4::Output;
23
use C4::Update::Database;
24
25
my $query = new CGI;
26
my $op = $query->param('op') || 'list';
27
28
my ( $template, $borrowernumber, $cookie ) = get_template_and_user(
29
    {   template_name   => "admin/updatedatabase.tmpl",
30
        query           => $query,
31
        type            => "intranet",
32
        authnotrequired => 0,
33
        flagsrequired   => { parameters => 1 }, # FIXME Add a new flag
34
    }
35
);
36
37
if ( $op eq 'update' ) {
38
    my @versions = $query->param('version');
39
    @versions = sort {
40
        C4::Update::Database::TransformToNum( $a ) <=> C4::Update::Database::TransformToNum( $b )
41
    } @versions;
42
43
    my @reports;
44
    for my $version ( @versions ) {
45
        push @reports, C4::Update::Database::execute_version $version;
46
    }
47
48
    my @report_loop = map {
49
        my ( $v, $r ) = each %$_;
50
        my @errors = ref ( $r ) eq 'ARRAY'
51
            ?
52
                map {
53
                    { error => $_ }
54
                } @$r
55
            :
56
                { error => $r };
57
        {
58
            version => $v,
59
            report  => \@errors,
60
            coherency => ( ref ( $r ) eq 'ARRAY'
61
                ? @$r[0] =~ /COHERENCY/ ? 1 : 0
62
                : $r =~ /COHERENCY/ ? 1 : 0 )
63
        }
64
    } @reports;
65
    $template->param( report_loop => \@report_loop );
66
67
    $op = 'list';
68
}
69
70
if ( $op eq 'mark_as_ok' ) {
71
    my @versions = $query->param('version');
72
    C4::Update::Database::mark_as_ok $_ for @versions;
73
    $op = 'list';
74
}
75
76
if ( $op eq 'list' ) {
77
    my $versions_availables = C4::Update::Database::list_versions_availables;
78
    my $versions = C4::Update::Database::list_versions_already_knows;
79
80
    for my $v ( @$versions_availables ) {
81
        if ( not grep { $v eq $$_{version} } @$versions ) {
82
            push @$versions, {
83
                version => $v,
84
                available => 1
85
            };
86
        }
87
    }
88
    my @sorted = sort {
89
        C4::Update::Database::TransformToNum( $$a{version} ) <=> C4::Update::Database::TransformToNum( $$b{version} )
90
    } @$versions;
91
92
    my @availables = grep { defined $$_{available} and $$_{available} == 1 } @sorted;
93
    my @v_availables = map { {version => $$_{version}} } @availables;
94
95
    $template->param(
96
        dev_mode => $ENV{DEBUG},
97
        versions => \@sorted,
98
        nb_availables => scalar @availables,
99
        availables => [ map { {version => $$_{version}} } @availables ],
100
    );
101
}
102
103
output_html_with_http_headers $query, $cookie, $template->output;
(-)a/etc/update/database/config.yaml (+1 lines)
Line 0 Link Here
1
versions_dir: installer/data/mysql/versions
(-)a/installer/data/mysql/kohastructure.sql (+21 lines)
Lines 1981-1986 CREATE TABLE `tags_index` ( Link Here
1981
        REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE
1981
        REFERENCES `biblio` (`biblionumber`) ON DELETE CASCADE ON UPDATE CASCADE
1982
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1982
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1983
1983
1984
1985
--
1986
-- Table structure for database updates
1987
--
1988
CREATE TABLE`updatedb_error` (
1989
    `version` varchar(32) DEFAULT NULL,
1990
    `error` text
1991
) ENGINE=InnoDB CHARSET=utf8;
1992
1993
CREATE TABLE `updatedb_query` (
1994
    `version` varchar(32) DEFAULT NULL,
1995
    `query` text
1996
) ENGINE=InnoDB CHARSET=utf8;
1997
1998
CREATE TABLE `updatedb_report` (
1999
    `version` text,
2000
    `md5` varchar(50) DEFAULT NULL,
2001
    `comment` text,
2002
    `status` int(1) DEFAULT NULL
2003
) ENGINE=InnoDB CHARSET=utf8;
2004
1984
--
2005
--
1985
-- Table structure for table `userflags`
2006
-- Table structure for table `userflags`
1986
--
2007
--
(-)a/installer/data/mysql/update.pl (+28 lines)
Line 0 Link Here
1
use Modern::Perl;
2
3
use C4::Context;
4
use C4::Update::Database;
5
use Getopt::Long;
6
7
8
my $version;
9
my $list;
10
11
GetOptions(
12
    'm:s' => \$version,
13
    'l'   => \$list,
14
);
15
16
if ( $version ) {
17
    my $report = C4::Update::Database::execute_version($version);
18
}
19
20
if ( $list ) {
21
    my $versions = C4::Update::Database::list_versions_availables();
22
    say "Versions availables:";
23
    say "\t- $_" for @$versions;
24
    $versions = C4::Update::Database::list_versions_already_knows();
25
    say "Versions already knows:";
26
    say "\t- $$_{version}" for @$versions;
27
28
}
(-)a/installer/data/mysql/versions/skeleton.pl (+17 lines)
Line 0 Link Here
1
#!/usr/bin/perl
2
3
use Modern::Perl;
4
use C4::Update::Database;
5
6
sub _get_queries {
7
    my @queries = (
8
        qq{INSERT INTO foo VALUES ('bar1')},
9
        qq{INSERT INTO foo VALUES ('bar2')},
10
    );
11
    my @comments = (
12
        qq{This is a test},
13
    );
14
    return { queries => \@queries, comments => \@comments };
15
}
16
17
1;
(-)a/installer/data/mysql/versions/skeleton.sql (+3 lines)
Line 0 Link Here
1
-- This is a comment
2
DELIMITER ;
3
INSERT INTO foo values("bar");
(-)a/koha-tmpl/intranet-tmpl/prog/en/css/staff-global.css (+3 lines)
Lines 2144-2147 a.localimage img { Link Here
2144
}
2144
}
2145
div.pager p {
2145
div.pager p {
2146
	margin: 0;
2146
	margin: 0;
2147
2148
.underline {
2149
    text-decoration : underline;
2147
}
2150
}
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/admin-home.tt (+7 lines)
Lines 98-103 Link Here
98
	<dt><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50 Client Targets</a></dt>
98
	<dt><a href="/cgi-bin/koha/admin/z3950servers.pl">Z39.50 Client Targets</a></dt>
99
	<dd>Define which servers to query for MARC data in the integrated Z39.50 client.</dd>
99
	<dd>Define which servers to query for MARC data in the integrated Z39.50 client.</dd>
100
</dl>
100
</dl>
101
102
<h3>Update Database</h3>
103
<dl>
104
    <dt><a href="/cgi-bin/koha/admin/updatedatabase.pl">Check your updates</a></dt>
105
    <dd>Verify your database versions and execute new updates</dd>
106
</dl>
107
101
</div>
108
</div>
102
109
103
</div>
110
</div>
(-)a/koha-tmpl/intranet-tmpl/prog/en/modules/admin/updatedatabase.tt (+172 lines)
Line 0 Link Here
1
[% INCLUDE 'doc-head-open.inc' %]
2
<title>Koha &rsaquo; Administration &rsaquo; Update Database</title>
3
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
4
[% INCLUDE 'doc-head-close.inc' %]
5
<link rel="stylesheet" type="text/css" href="[% themelang %]/css/datatables.css" />
6
<script type="text/javascript" src="[% themelang %]/lib/jquery/plugins/jquery.dataTables.min.js"></script>
7
<script type="text/javascript" src="[% themelang %]/js/datatables.js"></script>
8
<script type="text/javascript">
9
 //<![CDATA[
10
    $(document).ready(function() {
11
        $("#versionst").dataTable($.extend(true, {}, dataTablesDefaults, {
12
        "sPaginationType": "four_button",
13
        } );
14
    } );
15
    function see_details(a){
16
        var div = $(a).siblings('div');
17
        $(div).slideToggle("fast", function() {
18
            var isVisible = $(div).is(":visible");
19
            if ( isVisible ){$(a).text("Hide details");}else{$(a).text("Show details");}
20
        } );
21
    }
22
    function get_infos(version, node){
23
        $.ajax({
24
            url: "/cgi-bin/koha/admin/ajax-updatedb-getinfos.pl",
25
            data: {
26
                version: version
27
            },
28
            success: function(data){
29
                $(node).replaceWith(data);
30
            },
31
        });
32
    }
33
//]]>
34
</script>
35
</head>
36
<body>
37
[% INCLUDE 'header.inc' %]
38
[% INCLUDE 'cat-search.inc' %]
39
40
<div id="breadcrumbs"><a href="/cgi-bin/koha/mainpage.pl">Home</a> &rsaquo; <a href="/cgi-bin/koha/admin/admin-home.pl">Administration</a> &rsaquo; Database update</div>
41
42
<div id="doc3" class="yui-t2">
43
44
   <div id="bd">
45
    <div id="yui-main">
46
    <div class="yui-b">
47
48
    <h2>Database update</h2>
49
    [% IF report_loop %]
50
    <div class="report" style="display:block; margin:1em;">
51
        Report :
52
        <ul>
53
        [% FOREACH report_loo IN report_loop %]
54
            <li>
55
                [% report_loo.version %] --
56
                [% FOREACH r IN report_loo.report %]
57
                    [% r.error %];
58
                [% END %]
59
                [% IF report_loo.coherency %]
60
                    [<a href="/cgi-bin/koha/admin/updatedatabase.pl?op=mark_as_ok&version=[% report_loo.version %]">Mark as OK</a>]
61
                [% END %]
62
            </li>
63
        [% END %]
64
        </ul>
65
    </div>
66
    [% END %]
67
    <span class="infos" style="display:block; margin:1em;">
68
        [% IF nb_availables %]
69
            [% nb_availables %] update(s) available [ <a href="/cgi-bin/koha/admin/updatedatabase.pl?op=update[% FOREACH av IN availables %]&version=[% av.version %][% END %]">UPDATE</a> ]
70
        [% ELSE %]
71
            Your database is up to date
72
        [% END %]
73
    </span>
74
75
    <table id="versionst">
76
        <thead>
77
            <tr>
78
                <th>DB revision</th>
79
                <th>Comments</th>
80
                <th>Status</th>
81
                <th>Availability</th>
82
                <th>Details</th>
83
            </tr>
84
        </thead>
85
        <tbody>
86
        [% FOREACH v IN versions %]
87
            <tr>
88
                <td>[% v.version %]</td>
89
                <td>
90
                    <ul class="comments">
91
                    [% FOREACH c IN v.comments %]
92
                        <li>[% c.comment %]</li>
93
                    [% END %]
94
                    </ul>
95
                </td>
96
                <td>
97
                    [% IF v.available %]
98
                        Unknown
99
                    [% ELSE %]
100
                        [% IF v.status %]
101
                            <span style="color:green;">OK</span>
102
                            [% IF v.status == 2 %]
103
                                [FORCED]
104
                            [% END %]
105
                        [% ELSE %]
106
                            <span style="color:red;">Failed</span>
107
                        [% END %]
108
                    [% END %]
109
                </td>
110
                <td>
111
                    [% IF v.available %]
112
                        Available
113
                        [% IF (dev_mode) %]
114
                        [<a href="/cgi-bin/koha/admin/updatedatabase.pl?op=update&version=[% v.version %]">Execute</a>]
115
                        [% END %]
116
                    [% ELSE %]
117
                        Already executed
118
                    [% END %]
119
                </td>
120
                <td>
121
                    <div class="details" style="display:none;">
122
                        [% IF v.available %]
123
                            Unknown
124
                            <span style="display:block;"><a href="#" onclick="get_infos('[% v.version %]', this); return false;">Get comments</a></span>
125
                        [% ELSE %]
126
                            <div class="queries" style="display:block;">
127
                                <span class="underline">Queries</span> :
128
                                <ul>
129
                                [% FOREACH q IN v.queries %]
130
                                    <li>[% q.query %]</li>
131
                                [% END %]
132
                                </ul>
133
                            </div>
134
                            [% IF v.status == 1 %]
135
                                <div class="status" style="display:block;">
136
                                    <span class="underline">Status</span> :
137
                                    <span style="color:green;">OK</span>
138
                                </div>
139
                            [% ELSE %]
140
                                <div class="status" style="display:block;">
141
                                    <span class="underline">Status</span> :
142
                                    [% IF v.status == 2 %]
143
                                        <span style="color:green;">OK</span>
144
                                        [FORCED]
145
                                    [% ELSE %]
146
                                        <span style="color:red;">Failed</span>
147
                                        [<a href="/cgi-bin/koha/admin/updatedatabase.pl?op=mark_as_ok&version=[% v.version %]">Mark as OK</a>]
148
                                    [% END %]
149
                                </div>
150
                                <div class="errors" style="display:block;">
151
                                    <span class="underline">Errors</span> :
152
                                    <ul class="errors">
153
                                    [% FOREACH e IN v.errors %]
154
                                        <li>[% e.error %]</li>
155
                                    [% END %]
156
                                    </ul>
157
                                </div>
158
                            [% END %]
159
                        [% END %]
160
                    </div>
161
                    <a href="#" onclick="see_details(this);return false;">Show details</a>
162
                </td>
163
            </tr>
164
        [% END %]
165
        </tbody>
166
    </table>
167
168
    </div>
169
    </div>
170
    </div>
171
    </div>
172
    </div>
(-)a/mainpage.pl (-1 / +26 lines)
Lines 28-33 use C4::NewsChannels; Link Here
28
use C4::Review qw/numberofreviews/;
28
use C4::Review qw/numberofreviews/;
29
use C4::Suggestions qw/CountSuggestion/;
29
use C4::Suggestions qw/CountSuggestion/;
30
use C4::Tags qw/get_count_by_tag_status/;
30
use C4::Tags qw/get_count_by_tag_status/;
31
use C4::Update::Database;
32
31
my $query     = new CGI;
33
my $query     = new CGI;
32
34
33
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
35
my ( $template, $loggedinuser, $cookie ) = get_template_and_user(
Lines 42-47 my ( $template, $loggedinuser, $cookie ) = get_template_and_user( Link Here
42
    }
44
    }
43
);
45
);
44
46
47
#
48
# check if you're uptodate, and if you're not, head to updater
49
#
50
my $koha36= C4::Context::KOHAVERSION;
51
$koha36 =~ s/(.*\..*)\.(.*)\.(.*)/$1$2$3/;
52
53
if (C4::Context->preference('Version') < $koha36) {
54
    print $query->redirect("/cgi-bin/koha/installer/install.pl?step=3");
55
    exit;
56
}
57
my $versions_availables = C4::Update::Database::list_versions_availables;
58
my $versions = C4::Update::Database::list_versions_already_knows;
59
my $uptodate=1;
60
for my $v ( @$versions_availables ) {
61
    if ( not grep { $v eq $$_{version} } @$versions ) {
62
        $uptodate=0;
63
    }
64
}
65
unless ($uptodate) {
66
    # not uptodate, redirect to updatedatabase page
67
    print $query->redirect("/cgi-bin/koha/admin/updatedatabase.pl");
68
    exit;
69
}
70
45
my $all_koha_news   = &GetNewsToDisplay("koha");
71
my $all_koha_news   = &GetNewsToDisplay("koha");
46
my $koha_news_count = scalar @$all_koha_news;
72
my $koha_news_count = scalar @$all_koha_news;
47
73
48
- 

Return to bug 7167