Letters / alert system, continuing...
[koha.git] / updater / updatedatabase
1 #!/usr/bin/perl
2
3 # $Id$
4
5 # Database Updater
6 # This script checks for required updates to the database.
7
8 # Part of the Koha Library Software www.koha.org
9 # Licensed under the GPL.
10
11 # Bugs/ToDo:
12 # - Would also be a good idea to offer to do a backup at this time...
13
14 # NOTE:  If you do something more than once in here, make it table driven.
15 use strict;
16
17 # CPAN modules
18 use DBI;
19 use Getopt::Long;
20 # Koha modules
21 use C4::Context;
22
23 # FIXME - The user might be installing a new database, so can't rely
24 # on /etc/koha.conf anyway.
25
26 my $debug = 0;
27
28 my (
29     $sth, $sti,
30     $query,
31     %existingtables,    # tables already in database
32     %types,
33     $table,
34     $column,
35     $type, $null, $key, $default, $extra,
36     $prefitem,          # preference item in systempreferences table
37 );
38
39 my $silent;
40 GetOptions(
41         's' =>\$silent
42         );
43 my $dbh = C4::Context->dbh;
44 print "connected to your DB. Checking & modifying it\n" unless $silent;
45
46 #-------------------
47 # Defines
48
49 # Tables to add if they don't exist
50 my %requiretables = (
51     categorytable       => "(categorycode char(5) NOT NULL default '',
52                              description text default '',
53                              itemtypecodes text default '',
54                              PRIMARY KEY (categorycode)
55                             )",
56     subcategorytable       => "(subcategorycode char(5) NOT NULL default '',
57                              description text default '',
58                              itemtypecodes text default '',
59                              PRIMARY KEY (subcategorycode)
60                             )",
61     mediatypetable       => "(mediatypecode char(5) NOT NULL default '',
62                              description text default '',
63                              itemtypecodes text default '',
64                              PRIMARY KEY (mediatypecode)
65                             )",
66     action_logs         => "(
67                                     `timestamp` TIMESTAMP NOT NULL ,
68                                     `user` INT( 11 ) NOT NULL ,
69                                     `module` TEXT default '',
70                                     `action` TEXT default '' ,
71                                     `object` INT(11) default '' ,
72                                     `info` TEXT default '' ,
73                                     PRIMARY KEY ( `timestamp` , `user` )
74                             )",
75         letter          => "(
76                                         module varchar(20) NOT NULL default '',
77                                         code varchar(20) NOT NULL default '',
78                                         name varchar(100) NOT NULL default '',
79                                         title varchar(200) NOT NULL default '',
80                                         content text,
81                                         PRIMARY KEY  (module,code)
82                                 )",
83         alert           =>"(
84                                         alertid int(11) NOT NULL auto_increment,
85                                         borrowernumber int(11) NOT NULL default '0',
86                                         type varchar(10) NOT NULL default '',
87                                         externalid varchar(20) NOT NULL default '',
88                                         PRIMARY KEY  (alertid),
89                                         KEY borrowernumber (borrowernumber),
90                                         KEY type (type,externalid)
91                                 )"
92 );
93
94 my %requirefields = (
95         subscription => { 'letter' => 'char(20) NULL'},
96 #    tablename        => { 'field' => 'fieldtype' },
97 );
98
99 my %dropable_table = (
100 # tablename => 'tablename',
101 );
102
103 my %uselessfields = (
104 # tablename => "field1,field2",
105         );
106 # the other hash contains other actions that can't be done elsewhere. they are done
107 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
108
109 # The tabledata hash contains data that should be in the tables.
110 # The uniquefieldrequired hash entry is used to determine which (if any) fields
111 # must not exist in the table for this row to be inserted.  If the
112 # uniquefieldrequired entry is already in the table, the existing data is not
113 # modified, unless the forceupdate hash entry is also set.  Fields in the
114 # anonymous "forceupdate" hash will be forced to be updated to the default
115 # values given in the %tabledata hash.
116
117 my %tabledata = (
118 # tablename => [
119 #       {       uniquefielrequired => 'fieldname', # the primary key in the table
120 #               fieldname => fieldvalue,
121 #               fieldname2 => fieldvalue2,
122 #       },
123 # ],
124     systempreferences => [
125                 {
126             uniquefieldrequired => 'variable',
127             variable            => 'Activate_Log',
128             value               => 'On',
129             forceupdate         => { 'explanation' => 1,
130                                      'type' => 1},
131             explanation         => 'Turn Log Actions on DB On an Off',
132             type                => 'YesNo',
133         },
134                 {
135             uniquefieldrequired => 'variable',
136             variable            => 'ReturnBeforeExpiry',
137             value               => 'Off',
138             forceupdate         => { 'explanation' => 1,
139                                      'type' => 1},
140             explanation         => 'If Yes, Returndate on issuing can\'t be after borrower card expiry',
141             type                => 'YesNo',
142         },
143     ],
144
145 );
146
147 my %fielddefinitions = (
148 # fieldname => [
149 #       {                 field => 'fieldname',
150 #             type    => 'fieldtype',
151 #             null    => '',
152 #             key     => '',
153 #             default => ''
154 #         },
155 #     ],
156 );
157
158 #-------------------
159 # Initialize
160
161 # Start checking
162
163 # Get version of MySQL database engine.
164 my $mysqlversion = `mysqld --version`;
165 $mysqlversion =~ /Ver (\S*) /;
166 $mysqlversion = $1;
167 if ( $mysqlversion ge '3.23' ) {
168     print "Could convert to MyISAM database tables...\n" unless $silent;
169 }
170
171 #---------------------------------
172 # Tables
173
174 # Collect all tables into a list
175 $sth = $dbh->prepare("show tables");
176 $sth->execute;
177 while ( my ($table) = $sth->fetchrow ) {
178     $existingtables{$table} = 1;
179 }
180
181
182 # Now add any missing tables
183 foreach $table ( keys %requiretables ) {
184     unless ( $existingtables{$table} ) {
185         print "Adding $table table...\n" unless $silent;
186         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
187         $sth->execute;
188         if ( $sth->err ) {
189             print "Error : $sth->errstr \n";
190             $sth->finish;
191         }    # if error
192     }    # unless exists
193 }    # foreach
194
195 # now drop useless tables
196 foreach $table ( keys %dropable_table ) {
197         if ( $existingtables{$table} ) {
198                 print "Dropping unused table $table\n" if $debug and not $silent;
199                 $dbh->do("drop table $table");
200                 if ( $dbh->err ) {
201                         print "Error : $dbh->errstr \n";
202                 }
203         }
204 }
205
206 #---------------------------------
207 # Columns
208
209 foreach $table ( keys %requirefields ) {
210     print "Check table $table\n" if $debug and not $silent;
211     $sth = $dbh->prepare("show columns from $table");
212     $sth->execute();
213     undef %types;
214     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
215     {
216         $types{$column} = $type;
217     }    # while
218     foreach $column ( keys %{ $requirefields{$table} } ) {
219         print "  Check column $column  [$types{$column}]\n" if $debug and not $silent;
220         if ( !$types{$column} ) {
221
222             # column doesn't exist
223             print "Adding $column field to $table table...\n" unless $silent;
224             $query = "alter table $table
225                         add column $column " . $requirefields{$table}->{$column};
226             print "Execute: $query\n" if $debug;
227             my $sti = $dbh->prepare($query);
228             $sti->execute;
229             if ( $sti->err ) {
230                 print "**Error : $sti->errstr \n";
231                 $sti->finish;
232             }    # if error
233         }    # if column
234     }    # foreach column
235 }    # foreach table
236
237 foreach $table ( keys %fielddefinitions ) {
238         print "Check table $table\n" if $debug;
239         $sth = $dbh->prepare("show columns from $table");
240         $sth->execute();
241         my $definitions;
242         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
243         {
244                 $definitions->{$column}->{type}    = $type;
245                 $definitions->{$column}->{null}    = $null;
246                 $definitions->{$column}->{key}     = $key;
247                 $definitions->{$column}->{default} = $default;
248                 $definitions->{$column}->{extra}   = $extra;
249         }    # while
250         my $fieldrow = $fielddefinitions{$table};
251         foreach my $row (@$fieldrow) {
252                 my $field   = $row->{field};
253                 my $type    = $row->{type};
254                 my $null    = $row->{null};
255                 my $key     = $row->{key};
256                 my $default = $row->{default};
257                 $default="''" unless $default;
258                 my $extra   = $row->{extra};
259                 my $def     = $definitions->{$field};
260                 unless ( $type eq $def->{type}
261                         && $null eq $def->{null}
262                         && $key eq $def->{key}
263                         && $default eq $def->{default}
264                         && $extra eq $def->{extra} )
265                 {
266
267                         if ( $null eq '' ) {
268                                 $null = 'NOT NULL';
269                         }
270                         if ( $key eq 'PRI' ) {
271                                 $key = 'PRIMARY KEY';
272                         }
273                         unless ( $extra eq 'auto_increment' ) {
274                                 $extra = '';
275                         }
276                         # if it's a new column use "add", if it's an old one, use "change".
277                         my $action;
278                         if ($definitions->{$field}->{type}) {
279                                 $action="change $field"
280                         } else {
281                                 $action="add";
282                         }
283 # if it's a primary key, drop the previous pk, before altering the table
284                         my $sth;
285                         if ($key ne 'PRIMARY KEY') {
286                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
287                         } else {
288                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
289                         }
290                         $sth->execute($default);
291                         print "  Alter $field in $table\n" unless $silent;
292                 }
293         }
294 }
295
296
297 # Populate tables with required data
298 foreach my $table ( keys %tabledata ) {
299     print "Checking for data required in table $table...\n" unless $silent;
300     my $tablerows = $tabledata{$table};
301     foreach my $row (@$tablerows) {
302         my $uniquefieldrequired = $row->{uniquefieldrequired};
303         my $uniquevalue         = $row->{$uniquefieldrequired};
304         my $forceupdate         = $row->{forceupdate};
305         my $sth                 =
306           $dbh->prepare(
307 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
308         );
309         $sth->execute($uniquevalue);
310         if ($sth->rows) {
311             foreach my $field (keys %$forceupdate) {
312                 if ($forceupdate->{$field}) {
313                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
314                     $sth->execute($row->{$field}, $uniquevalue);
315                 }
316             }
317         } else {
318             print "Adding row to $table: " unless $silent;
319             my @values;
320             my $fieldlist;
321             my $placeholders;
322             foreach my $field ( keys %$row ) {
323                 next if $field eq 'uniquefieldrequired';
324                 next if $field eq 'forceupdate';
325                 my $value = $row->{$field};
326                 push @values, $value;
327                 print "  $field => $value" unless $silent;
328                 $fieldlist .= "$field,";
329                 $placeholders .= "?,";
330             }
331             print "\n" unless $silent;
332             $fieldlist    =~ s/,$//;
333             $placeholders =~ s/,$//;
334             my $sth =
335               $dbh->prepare(
336                 "insert into $table ($fieldlist) values ($placeholders)");
337             $sth->execute(@values);
338         }
339     }
340 }
341
342 # at last, remove useless fields
343 foreach $table ( keys %uselessfields ) {
344         my @fields = split /,/,$uselessfields{$table};
345         my $fields;
346         my $exists;
347         foreach my $fieldtodrop (@fields) {
348                 $fieldtodrop =~ s/\t//g;
349                 $fieldtodrop =~ s/\n//g;
350                 $exists =0;
351                 $sth = $dbh->prepare("show columns from $table");
352                 $sth->execute;
353                 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
354                 {
355                         $exists =1 if ($column eq $fieldtodrop);
356                 }
357                 if ($exists) {
358                         print "deleting $fieldtodrop field in $table...\n" unless $silent;
359                         my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
360                         $sth->execute;
361                 }
362         }
363 }    # foreach
364
365
366 $sth->finish;
367
368 exit;
369
370 # $Log$
371 # Revision 1.116  2005/08/04 08:55:54  tipaul
372 # Letters / alert system, continuing...
373 #
374 # * adding a package Letters.pm, that manages Letters & alerts.
375 # * adding feature : it's now possible to define a "letter" for any subscription created. If a letter is defined, users in OPAC can put an alert on the subscription. When an issue is marked "arrived", all users in the alert will recieve a mail (as defined in the "letter"). This last part (= send the mail) is not yet developped. (Should be done this week)
376 # * adding feature : it's now possible to "put to an alert" in OPAC, for any serial subscription. The alert is stored in a new table, called alert. An alert can be put only if the librarian has activated them in subscription (and they activate it just by choosing a "letter" to sent to borrowers on new issues)
377 # * adding feature : librarian can see in borrower detail which alerts they have put, and a user can see in opac-detail which alert they have put too.
378 #
379 # Note that the system should be generic enough to manage any type of alert.
380 # I plan to extend it soon to virtual shelves : a borrower will be able to put an alert on a virtual shelf, to be warned when something is changed in the virtual shelf (mail being sent once a day by cron, or manually by the shelf owner. Anyway, a mail won't be sent on every change, users would be spammed by Koha ;-) )
381 #
382 # Revision 1.115  2005/08/02 16:15:34  tipaul
383 # adding 2 fields to letter system :
384 # * module (acquisition, catalogue...) : it will be usefull to show the librarian only letters he may be interested by.
385 # * title, that will be used as mail subject.
386 #
387 # Revision 1.114  2005/07/28 15:10:13  tipaul
388 # Introducing new "Letters" system : Letters will be used everytime you want to sent something to someone (through mail or paper). For example, sending a mail for overdues use letter that you can put as parameters. Sending a mail to a borrower when a suggestion is validated uses a letter too.
389 # the letter table contains 3 fields :
390 # * code => the code of the letter
391 # * name => the complete name of the letter
392 # * content => the complete text. It's a TEXT field type, so has no limits.
393 #
394 # My next goal now is to work on point 2-I "serial issue alert"
395 # With this feature, in serials, a user can subscribe the "issue alert". For every issue arrived/missing, a mail is sent to all subscribers of this list. The mail warns the user that the issue is arrive or missing. Will be in head.
396 # (see mail on koha-devel, 2005/04/07)
397 #
398 # The "serial issue alert" will be the 1st to use this letter system that probably needs some tweaking ;-)
399 #
400 # Once it will be stabilised default letters (in any languages) could be added during installer to help the library begin with this new feature.
401 #
402 # Revision 1.113  2005/07/28 08:38:41  tipaul
403 # For instance, the return date does not rely on the borrower expiration date. A systempref will be added in Koha, to modify return date calculation schema :
404 # * ReturnBeforeExpiry = yes => return date can't be after expiry date
405 # * ReturnBeforeExpiry = no  => return date can be after expiry date
406 #
407 # Revision 1.112  2005/07/26 08:19:47  hdl
408 # Adding IndependantBranches System preference variable in order to manage Branch independancy.
409 #
410 # Revision 1.111  2005/07/25 15:35:38  tipaul
411 # we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
412 # So, the updatedatabase script can highly be cleaned (90% removed).
413 # Let's play with the new Koha DB structure now ;-)
414 #
415 #!/usr/bin/perl
416
417 # $Id$
418
419 # Database Updater
420 # This script checks for required updates to the database.
421
422 # Part of the Koha Library Software www.koha.org
423 # Licensed under the GPL.
424
425 # Bugs/ToDo:
426 # - Would also be a good idea to offer to do a backup at this time...
427
428 # NOTE:  If you do something more than once in here, make it table driven.
429 use strict;
430
431 # CPAN modules
432 use DBI;
433 use Getopt::Long;
434 # Koha modules
435 use C4::Context;
436
437 # FIXME - The user might be installing a new database, so can't rely
438 # on /etc/koha.conf anyway.
439
440 my $debug = 0;
441
442 my (
443     $sth, $sti,
444     $query,
445     %existingtables,    # tables already in database
446     %types,
447     $table,
448     $column,
449     $type, $null, $key, $default, $extra,
450     $prefitem,          # preference item in systempreferences table
451 );
452
453 my $silent;
454 GetOptions(
455         's' =>\$silent
456         );
457 my $dbh = C4::Context->dbh;
458 print "connected to your DB. Checking & modifying it\n" unless $silent;
459
460 #-------------------
461 # Defines
462
463 # Tables to add if they don't exist
464 my %requiretables = (
465     categorytable       => "(categorycode char(5) NOT NULL default '',
466                              description text default '',
467                              itemtypecodes text default '',
468                              PRIMARY KEY (categorycode)
469                             )",
470     subcategorytable       => "(subcategorycode char(5) NOT NULL default '',
471                              description text default '',
472                              itemtypecodes text default '',
473                              PRIMARY KEY (subcategorycode)
474                             )",
475     mediatypetable       => "(mediatypecode char(5) NOT NULL default '',
476                              description text default '',
477                              itemtypecodes text default '',
478                              PRIMARY KEY (mediatypecode)
479                             )",
480     action_logs         => "(
481                                     `timestamp` TIMESTAMP NOT NULL ,
482                                     `user` INT( 11 ) NOT NULL ,
483                                     `module` TEXT default '',
484                                     `action` TEXT default '' ,
485                                     `object` INT(11) default '' ,
486                                     `info` TEXT default '' ,
487                                     PRIMARY KEY ( `timestamp` , `user` )
488                             )",
489 );
490
491 my %requirefields = (
492 #    tablename        => { 'field' => 'fieldtype' },
493 );
494
495 my %dropable_table = (
496 # tablename => 'tablename',
497 );
498
499 my %uselessfields = (
500 # tablename => "field1,field2",
501         );
502 # the other hash contains other actions that can't be done elsewhere. they are done
503 # either BEFORE of AFTER everything else, depending on "when" entry (default => AFTER)
504
505 # The tabledata hash contains data that should be in the tables.
506 # The uniquefieldrequired hash entry is used to determine which (if any) fields
507 # must not exist in the table for this row to be inserted.  If the
508 # uniquefieldrequired entry is already in the table, the existing data is not
509 # modified, unless the forceupdate hash entry is also set.  Fields in the
510 # anonymous "forceupdate" hash will be forced to be updated to the default
511 # values given in the %tabledata hash.
512
513 my %tabledata = (
514 # tablename => [
515 #       {       uniquefielrequired => 'fieldname', # the primary key in the table
516 #               fieldname => fieldvalue,
517 #               fieldname2 => fieldvalue2,
518 #       },
519 # ],
520     systempreferences => [
521                 {
522             uniquefieldrequired => 'variable',
523             variable            => 'Activate_Log',
524             value               => 'On',
525             forceupdate         => { 'explanation' => 1,
526                                      'type' => 1},
527             explanation         => 'Turn Log Actions on DB On an Off',
528             type                => 'YesNo',
529         },
530         {
531             uniquefieldrequired => 'variable',
532             variable            => 'IndependantBranches',
533             value               => 0,
534             forceupdate         => { 'explanation' => 1,
535                                      'type' => 1},
536             explanation         => 'Turn Branch independancy management On an Off',
537             type                => 'YesNo',
538         },
539
540     ],
541
542 );
543
544 my %fielddefinitions = (
545 # fieldname => [
546 #       {                 field => 'fieldname',
547 #             type    => 'fieldtype',
548 #             null    => '',
549 #             key     => '',
550 #             default => ''
551 #         },
552 #     ],
553 );
554
555 #-------------------
556 # Initialize
557
558 # Start checking
559
560 # Get version of MySQL database engine.
561 my $mysqlversion = `mysqld --version`;
562 $mysqlversion =~ /Ver (\S*) /;
563 $mysqlversion = $1;
564 if ( $mysqlversion ge '3.23' ) {
565     print "Could convert to MyISAM database tables...\n" unless $silent;
566 }
567
568 #---------------------------------
569 # Tables
570
571 # Collect all tables into a list
572 $sth = $dbh->prepare("show tables");
573 $sth->execute;
574 while ( my ($table) = $sth->fetchrow ) {
575     $existingtables{$table} = 1;
576 }
577
578
579 # Now add any missing tables
580 foreach $table ( keys %requiretables ) {
581     unless ( $existingtables{$table} ) {
582         print "Adding $table table...\n" unless $silent;
583         my $sth = $dbh->prepare("create table $table $requiretables{$table}");
584         $sth->execute;
585         if ( $sth->err ) {
586             print "Error : $sth->errstr \n";
587             $sth->finish;
588         }    # if error
589     }    # unless exists
590 }    # foreach
591
592 # now drop useless tables
593 foreach $table ( keys %dropable_table ) {
594         if ( $existingtables{$table} ) {
595                 print "Dropping unused table $table\n" if $debug and not $silent;
596                 $dbh->do("drop table $table");
597                 if ( $dbh->err ) {
598                         print "Error : $dbh->errstr \n";
599                 }
600         }
601 }
602
603 #---------------------------------
604 # Columns
605
606 foreach $table ( keys %requirefields ) {
607     print "Check table $table\n" if $debug and not $silent;
608     $sth = $dbh->prepare("show columns from $table");
609     $sth->execute();
610     undef %types;
611     while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
612     {
613         $types{$column} = $type;
614     }    # while
615     foreach $column ( keys %{ $requirefields{$table} } ) {
616         print "  Check column $column  [$types{$column}]\n" if $debug and not $silent;
617         if ( !$types{$column} ) {
618
619             # column doesn't exist
620             print "Adding $column field to $table table...\n" unless $silent;
621             $query = "alter table $table
622                         add column $column " . $requirefields{$table}->{$column};
623             print "Execute: $query\n" if $debug;
624             my $sti = $dbh->prepare($query);
625             $sti->execute;
626             if ( $sti->err ) {
627                 print "**Error : $sti->errstr \n";
628                 $sti->finish;
629             }    # if error
630         }    # if column
631     }    # foreach column
632 }    # foreach table
633
634 foreach $table ( keys %fielddefinitions ) {
635         print "Check table $table\n" if $debug;
636         $sth = $dbh->prepare("show columns from $table");
637         $sth->execute();
638         my $definitions;
639         while ( ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
640         {
641                 $definitions->{$column}->{type}    = $type;
642                 $definitions->{$column}->{null}    = $null;
643                 $definitions->{$column}->{key}     = $key;
644                 $definitions->{$column}->{default} = $default;
645                 $definitions->{$column}->{extra}   = $extra;
646         }    # while
647         my $fieldrow = $fielddefinitions{$table};
648         foreach my $row (@$fieldrow) {
649                 my $field   = $row->{field};
650                 my $type    = $row->{type};
651                 my $null    = $row->{null};
652                 my $key     = $row->{key};
653                 my $default = $row->{default};
654                 $default="''" unless $default;
655                 my $extra   = $row->{extra};
656                 my $def     = $definitions->{$field};
657                 unless ( $type eq $def->{type}
658                         && $null eq $def->{null}
659                         && $key eq $def->{key}
660                         && $default eq $def->{default}
661                         && $extra eq $def->{extra} )
662                 {
663
664                         if ( $null eq '' ) {
665                                 $null = 'NOT NULL';
666                         }
667                         if ( $key eq 'PRI' ) {
668                                 $key = 'PRIMARY KEY';
669                         }
670                         unless ( $extra eq 'auto_increment' ) {
671                                 $extra = '';
672                         }
673                         # if it's a new column use "add", if it's an old one, use "change".
674                         my $action;
675                         if ($definitions->{$field}->{type}) {
676                                 $action="change $field"
677                         } else {
678                                 $action="add";
679                         }
680 # if it's a primary key, drop the previous pk, before altering the table
681                         my $sth;
682                         if ($key ne 'PRIMARY KEY') {
683                                 $sth =$dbh->prepare("alter table $table $action $field $type $null $key $extra default ?");
684                         } else {
685                                 $sth =$dbh->prepare("alter table $table drop primary key, $action $field $type $null $key $extra default ?");
686                         }
687                         $sth->execute($default);
688                         print "  Alter $field in $table\n" unless $silent;
689                 }
690         }
691 }
692
693
694 # Populate tables with required data
695 foreach my $table ( keys %tabledata ) {
696     print "Checking for data required in table $table...\n" unless $silent;
697     my $tablerows = $tabledata{$table};
698     foreach my $row (@$tablerows) {
699         my $uniquefieldrequired = $row->{uniquefieldrequired};
700         my $uniquevalue         = $row->{$uniquefieldrequired};
701         my $forceupdate         = $row->{forceupdate};
702         my $sth                 =
703           $dbh->prepare(
704 "select $uniquefieldrequired from $table where $uniquefieldrequired=?"
705         );
706         $sth->execute($uniquevalue);
707         if ($sth->rows) {
708             foreach my $field (keys %$forceupdate) {
709                 if ($forceupdate->{$field}) {
710                     my $sth=$dbh->prepare("update systempreferences set $field=? where $uniquefieldrequired=?");
711                     $sth->execute($row->{$field}, $uniquevalue);
712                 }
713             }
714         } else {
715             print "Adding row to $table: " unless $silent;
716             my @values;
717             my $fieldlist;
718             my $placeholders;
719             foreach my $field ( keys %$row ) {
720                 next if $field eq 'uniquefieldrequired';
721                 next if $field eq 'forceupdate';
722                 my $value = $row->{$field};
723                 push @values, $value;
724                 print "  $field => $value" unless $silent;
725                 $fieldlist .= "$field,";
726                 $placeholders .= "?,";
727             }
728             print "\n" unless $silent;
729             $fieldlist    =~ s/,$//;
730             $placeholders =~ s/,$//;
731             my $sth =
732               $dbh->prepare(
733                 "insert into $table ($fieldlist) values ($placeholders)");
734             $sth->execute(@values);
735         }
736     }
737 }
738
739 # at last, remove useless fields
740 foreach $table ( keys %uselessfields ) {
741         my @fields = split /,/,$uselessfields{$table};
742         my $fields;
743         my $exists;
744         foreach my $fieldtodrop (@fields) {
745                 $fieldtodrop =~ s/\t//g;
746                 $fieldtodrop =~ s/\n//g;
747                 $exists =0;
748                 $sth = $dbh->prepare("show columns from $table");
749                 $sth->execute;
750                 while ( my ( $column, $type, $null, $key, $default, $extra ) = $sth->fetchrow )
751                 {
752                         $exists =1 if ($column eq $fieldtodrop);
753                 }
754                 if ($exists) {
755                         print "deleting $fieldtodrop field in $table...\n" unless $silent;
756                         my $sth = $dbh->prepare("alter table $table drop $fieldtodrop");
757                         $sth->execute;
758                 }
759         }
760 }    # foreach
761
762
763 $sth->finish;
764
765 exit;
766
767 # $Log$
768 # Revision 1.116  2005/08/04 08:55:54  tipaul
769 # Letters / alert system, continuing...
770 #
771 # * adding a package Letters.pm, that manages Letters & alerts.
772 # * adding feature : it's now possible to define a "letter" for any subscription created. If a letter is defined, users in OPAC can put an alert on the subscription. When an issue is marked "arrived", all users in the alert will recieve a mail (as defined in the "letter"). This last part (= send the mail) is not yet developped. (Should be done this week)
773 # * adding feature : it's now possible to "put to an alert" in OPAC, for any serial subscription. The alert is stored in a new table, called alert. An alert can be put only if the librarian has activated them in subscription (and they activate it just by choosing a "letter" to sent to borrowers on new issues)
774 # * adding feature : librarian can see in borrower detail which alerts they have put, and a user can see in opac-detail which alert they have put too.
775 #
776 # Note that the system should be generic enough to manage any type of alert.
777 # I plan to extend it soon to virtual shelves : a borrower will be able to put an alert on a virtual shelf, to be warned when something is changed in the virtual shelf (mail being sent once a day by cron, or manually by the shelf owner. Anyway, a mail won't be sent on every change, users would be spammed by Koha ;-) )
778 #
779 # Revision 1.115  2005/08/02 16:15:34  tipaul
780 # adding 2 fields to letter system :
781 # * module (acquisition, catalogue...) : it will be usefull to show the librarian only letters he may be interested by.
782 # * title, that will be used as mail subject.
783 #
784 # Revision 1.114  2005/07/28 15:10:13  tipaul
785 # Introducing new "Letters" system : Letters will be used everytime you want to sent something to someone (through mail or paper). For example, sending a mail for overdues use letter that you can put as parameters. Sending a mail to a borrower when a suggestion is validated uses a letter too.
786 # the letter table contains 3 fields :
787 # * code => the code of the letter
788 # * name => the complete name of the letter
789 # * content => the complete text. It's a TEXT field type, so has no limits.
790 #
791 # My next goal now is to work on point 2-I "serial issue alert"
792 # With this feature, in serials, a user can subscribe the "issue alert". For every issue arrived/missing, a mail is sent to all subscribers of this list. The mail warns the user that the issue is arrive or missing. Will be in head.
793 # (see mail on koha-devel, 2005/04/07)
794 #
795 # The "serial issue alert" will be the 1st to use this letter system that probably needs some tweaking ;-)
796 #
797 # Once it will be stabilised default letters (in any languages) could be added during installer to help the library begin with this new feature.
798 #
799 # Revision 1.113  2005/07/28 08:38:41  tipaul
800 # For instance, the return date does not rely on the borrower expiration date. A systempref will be added in Koha, to modify return date calculation schema :
801 # * ReturnBeforeExpiry = yes => return date can't be after expiry date
802 # * ReturnBeforeExpiry = no  => return date can be after expiry date
803 #
804 # Revision 1.112  2005/07/26 08:19:47  hdl
805 # Adding IndependantBranches System preference variable in order to manage Branch independancy.
806 #
807 # Revision 1.111  2005/07/25 15:35:38  tipaul
808 # we have decided that moving to Koha 3.0 requires being already in Koha 2.2.x
809 # So, the updatedatabase script can highly be cleaned (90% removed).
810 # Let's play with the new Koha DB structure now ;-)
811 #