Bug 18228: Adjust Virtualshelves.t
[koha.git] / misc / admin / koha-preferences
1 #!/usr/bin/perl
2 #
3 # Copyright 2010 Jesse Weaver, Koha Dev Team
4 #
5 # This file is part of Koha.
6 #
7 # Koha is free software; you can redistribute it and/or modify it
8 # under the terms of the GNU General Public License as published by
9 # the Free Software Foundation; either version 3 of the License, or
10 # (at your option) any later version.
11 #
12 # Koha is distributed in the hope that it will be useful, but
13 # WITHOUT ANY WARRANTY; without even the implied warranty of
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 # GNU General Public License for more details.
16 #
17 # You should have received a copy of the GNU General Public License
18 # along with Koha; if not, see <http://www.gnu.org/licenses>.
19 #
20
21 use C4::Boolean;
22 use C4::Context;
23 use C4::Debug;
24 use C4::Log;
25 use Getopt::Long;
26 use Pod::Usage;
27 use YAML::Syck qw();
28 $YAML::Syck::ImplicitTyping = 1;
29 $YAML::Syck::SortKeys = 1;
30 our %NOT_SET_PREFS = map { $_, 1 } qw( Version );
31
32 =head1 NAME
33
34 koha-preferences - Get, set, dump and load Koha system preferences
35
36 =head1 SYNOPSIS
37
38 misc/admin/koha-preferences COMMAND ...
39
40 =cut
41
42 sub print_usage {
43     my ( $annoyed ) = @_;
44
45     if ( $annoyed ) {
46         pod2usage( -verbose => 1, -exitval => 1, -output => \*STDERR );
47     } else {
48         pod2usage( -verbose => 1, -exitval => 0 );
49     }
50 }
51
52 sub _debug {
53     my ( $message ) = @_;
54
55     print STDERR $message . "\n" if ( $C4::Debug::debug );
56 }
57
58 sub _normalize_value {
59     my ($row) = @_;
60
61     # AFAIK, there are no sysprefs where NULL has a different meaning than ''.
62     return ( $row->{'value'} || '' ) unless ( $row->{'type'} eq 'YesNo' );
63
64     #
65     # In theory, YesNo sysprefs should always contain 1/0.
66     # In practice, however, they don't.
67     # - Yogi Berra
68     #
69     my $bool_value = eval {
70         return C4::Boolean::true_p( $row->{'value'} ) ? 1 : 0;
71     };
72     if ( $@ ) {
73         return 0;
74     } else {
75         return $bool_value;
76     }
77 }
78
79 sub _set_preference {
80     my ( $preference, $value ) = @_;
81
82     _debug( "Setting $preference to $value" );
83
84     C4::Context->set_preference( $preference, $value );
85 }
86
87 sub GetPreferences {
88     my $dbh = C4::Context->dbh;
89
90     return {
91         map { $_->{'variable'},  _normalize_value($_) }
92         @{ $dbh->selectall_arrayref( "
93             SELECT
94               variable, value, type
95               FROM systempreferences
96         ", { Slice => {} } ) }
97     };
98 }
99
100 sub SetPreferences {
101     my ( %preferences ) = @_;
102
103     my $dbh = C4::Context->dbh;
104
105     # First, a quick check to make sure all of the system preferences exist
106     my $current_state = $dbh->selectall_arrayref( "
107         SELECT
108           variable, type, value
109           FROM systempreferences
110           WHERE variable IN (" . join( ', ', map( "?", keys %preferences ) ) . ")
111     ", { Slice => {} }, keys %preferences );
112
113     exit 2 if ( scalar( @$current_state ) != scalar( keys %preferences ) );
114
115     foreach my $row ( @$current_state ) {
116         # YAML::Syck encodes no as '', so deal with that
117         $preferences{$row->{'variable'}} = $preferences{$row->{'variable'}} eq '' ? 0 : C4::Boolean::true_p( $preferences{$row->{'variable'}} ) if ( $row->{'type'} eq 'YesNo' );
118     }
119
120     # Iterate through again, now that we've checked all of the YesNo sysprefs
121
122     foreach my $row ( @$current_state ) {
123         next if ( $preferences{$row->{'variable'}} eq $row->{'value'} );
124
125         _set_preference( $row->{'variable'}, $preferences{$row->{'variable'}} );
126     }
127
128     # FIXME This may be not needed
129     C4::Context->clear_syspref_cache();
130 }
131
132 sub _fetch_preference {
133     my ( $preference ) = @_;
134
135     my $dbh = C4::Context->dbh;
136
137     my $row = $dbh->selectrow_hashref( "
138         SELECT
139           variable, value, type
140           FROM systempreferences
141           WHERE variable = ?
142           LIMIT 1
143     ", {}, $preference );
144
145     exit 2 unless ( $row );
146
147     return $row;
148 }
149
150 sub GetPreference {
151     my ( $preference ) = @_;
152
153     my $row = _fetch_preference( $preference );
154
155     return _normalize_value( $row );
156 }
157
158 sub SetPreference {
159     my ( $preference, $value ) = @_;
160
161     my $row = _fetch_preference( $preference );
162
163     $value = C4::Boolean::true_p($value) ? 1 : 0 if ( $row->{'type'} eq 'YesNo' );
164
165     exit 3 if ( $value eq $row->{'value'} );
166
167     _set_preference( $preference, $value );
168 }
169
170 sub ClearPreference {
171     my ( $preference ) = @_;
172
173     my $value = '';
174
175     my $row = _fetch_preference( $preference );
176
177     $value = 0 if ( $row->{'type'} eq 'YesNo' );
178
179     exit 3 if ( $value eq $row->{'value'} );
180
181     _set_preference( $preference, $value );
182 }
183
184 =head1 OPTIONS
185
186 COMMAND can be any of the following:
187
188 =over
189
190 =item B<dump> [ -o I<OUTFILE> ]
191
192 Dump all of Koha's system preferences as a simple YAML mapping into OUTFILE or
193 STDOUT.
194
195 =item B<load> [ -i I<INFILE> ] [ -f|--force ]
196
197 Reads system preferences specified in YAML in INFILE or STDIN.  Will exit with a
198 status of 2, without setting any sysprefs, if any of the sysprefs do not exist.
199 Will also exit if any of the sysprefs are YesNo and have an invalid value.
200
201 If there is a Version syspref in the input, it will not be set in the database,
202 but it will be checked to make sure the running Koha version is equal or higher.
203 The script will exit with a status of 4 if this is not true. Pass the -f option
204 to skip this check.
205
206 =item B<get> I<PREFERENCE>
207
208 Print the value of the system preference PREFERENCE, followed by a newline.  If
209 no such syspref exists, will exit with a status of 2.
210
211 =item B<set> I<PREFERENCE> I<VALUE>
212
213 Set the system preference PREFERENCE to the value VALUE. If no such syspref
214 exists, will exit with a status of 2. If the syspref already has that value,
215 will exit with a status of 3.
216
217 If the syspref is YesNo, will accept only a boolean value, but the syntax for
218 these is fairly lax (yes/no, on/off, 1/0, n/y, true/false are all accepted).
219
220 =item B<clear> I<PREFERENCE>
221
222 Clears the value of the system preference PREFERENCE. If no such syspref exists,
223 will exit with a status of 2. Will set YesNo sysprefs to 'false'.
224
225 =item B<manual>
226
227 Print a longer, more detailed manual.
228
229 =cut
230
231 my %commands = (
232     dump => sub{
233         my ( $outfile );
234
235         GetOptions(
236             'o:s' => \$outfile
237         ) || _print_usage( 1 );
238
239         if ( $outfile ) {
240             YAML::Syck::DumpFile( $outfile, GetPreferences() );
241         } else {
242             print YAML::Syck::Dump( GetPreferences() );
243         }
244     },
245     load => sub {
246         my ( $infile, $force_version );
247
248         GetOptions(
249             'i:s' => \$infile,
250             'f' => \$force_version,
251         );
252
253         my $preferences = YAML::Syck::LoadFile($infile || \*STDIN);
254
255         die "Expected a YAML mapping" if ( ref($preferences) ne 'HASH' );
256
257         die "Tried to load preferences for version " . $preferences->{'Version'} . ", we are " . C4::Context->preference( 'Version' ) if ( $preferences->{'Version'} && C4::Context->preference( 'Version' ) < $preferences->{'Version'} );
258
259         my %prefs_to_set = (
260             map { $_, $preferences->{$_} }
261             grep { !$NOT_SET_PREFS{$_} }
262             keys %$preferences
263         );
264
265         SetPreferences( %prefs_to_set );
266     },
267     get => sub {
268         my ( $preference ) = @_;
269
270         print_usage() unless ( $preference );
271
272         print GetPreference( $preference ) . "\n";
273     },
274     set => sub {
275         my ( $preference, $value ) = @_;
276
277         print_usage() unless ( $preference && defined($value) );
278
279         SetPreference( $preference, $value );
280     },
281     clear => sub {
282         my ( $preference ) = @_;
283
284         print_usage() unless ( $preference );
285
286         ClearPreference( $preference );
287     },
288     manual => sub {
289         pod2usage( -verbose => 2 );
290     }
291 );
292
293 print_usage() if ( $ARGV[0] =~ /^(-h|--help|-help|help)$/ );
294
295 print_usage( 1 ) if ( !$ARGV[0] || ref($commands{$ARGV[0]}) ne 'CODE' );
296
297 $command = $commands{$ARGV[0]};
298 shift @ARGV;
299 $command->(@ARGV);
300
301 =item B<help>
302
303 Print a short usage message.
304
305 =back
306
307 =head1 EXAMPLES
308
309   $ export KOHA_DEBUG=1 # Used here to show what is being stored
310   $ misc/admin/koha-preferences get viewISBD
311   0
312   $ misc/admin/koha-preferences set viewISBD on
313   Setting viewISBD to 1
314   $ misc/admin/koha-preferences dump -o preferences.yaml
315   $ [ edit preferences.yaml ]
316   $ misc/admin/koha-preferences load -i preferences.yaml
317   $ misc/admin/koha-preferences load -i preferences-too-new.yaml
318   Tried to load preferences for version 3.0500012, we are 3.0300009 at misc/admin/koha-preferences line 255
319   $ misc/admin/koha-preferences load # Can also work from STDIN
320   XISBN: false
321   viewMARC: y
322   [ Control-D ]
323   Setting viewMARC to 1
324   Setting XISBN to 0
325
326 =cut