Bug 11998: Use Koha::Cache to cache sysprefs
[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     C4::Context->clear_syspref_cache();
129 }
130
131 sub _fetch_preference {
132     my ( $preference ) = @_;
133
134     my $dbh = C4::Context->dbh;
135
136     my $row = $dbh->selectrow_hashref( "
137         SELECT
138           variable, value, type
139           FROM systempreferences
140           WHERE variable = ?
141           LIMIT 1
142     ", {}, $preference );
143
144     exit 2 unless ( $row );
145
146     return $row;
147 }
148
149 sub GetPreference {
150     my ( $preference ) = @_;
151
152     my $row = _fetch_preference( $preference );
153
154     return _normalize_value( $row );
155 }
156
157 sub SetPreference {
158     my ( $preference, $value ) = @_;
159
160     my $row = _fetch_preference( $preference );
161
162     $value = C4::Boolean::true_p($value) ? 1 : 0 if ( $row->{'type'} eq 'YesNo' );
163
164     exit 3 if ( $value eq $row->{'value'} );
165
166     _set_preference( $preference, $value );
167 }
168
169 sub ClearPreference {
170     my ( $preference ) = @_;
171
172     my $value = '';
173
174     my $row = _fetch_preference( $preference );
175
176     $value = 0 if ( $row->{'type'} eq 'YesNo' );
177
178     exit 3 if ( $value eq $row->{'value'} );
179
180     _set_preference( $preference, $value );
181 }
182
183 =head1 OPTIONS
184
185 COMMAND can be any of the following:
186
187 =over
188
189 =item B<dump> [ -o I<OUTFILE> ]
190
191 Dump all of Koha's system preferences as a simple YAML mapping into OUTFILE or
192 STDOUT.
193
194 =item B<load> [ -i I<INFILE> ] [ -f|--force ]
195
196 Reads system preferences specified in YAML in INFILE or STDIN.  Will exit with a
197 status of 2, without setting any sysprefs, if any of the sysprefs do not exist.
198 Will also exit if any of the sysprefs are YesNo and have an invalid value.
199
200 If there is a Version syspref in the input, it will not be set in the database,
201 but it will be checked to make sure the running Koha version is equal or higher.
202 The script will exit with a status of 4 if this is not true. Pass the -f option
203 to skip this check.
204
205 =item B<get> I<PREFERENCE>
206
207 Print the value of the system preference PREFERENCE, followed by a newline.  If
208 no such syspref exists, will exit with a status of 2.
209
210 =item B<set> I<PREFERENCE> I<VALUE>
211
212 Set the system preference PREFERENCE to the value VALUE. If no such syspref
213 exists, will exit with a status of 2. If the syspref already has that value,
214 will exit with a status of 3.
215
216 If the syspref is YesNo, will accept only a boolean value, but the syntax for
217 these is fairly lax (yes/no, on/off, 1/0, n/y, true/false are all accepted).
218
219 =item B<clear> I<PREFERENCE>
220
221 Clears the value of the system preference PREFERENCE. If no such syspref exists,
222 will exit with a status of 2. Will set YesNo sysprefs to 'false'.
223
224 =item B<manual>
225
226 Print a longer, more detailed manual.
227
228 =cut
229
230 my %commands = (
231     dump => sub{
232         my ( $outfile );
233
234         GetOptions(
235             'o:s' => \$outfile
236         ) || _print_usage( 1 );
237
238         if ( $outfile ) {
239             YAML::Syck::DumpFile( $outfile, GetPreferences() );
240         } else {
241             print YAML::Syck::Dump( GetPreferences() );
242         }
243     },
244     load => sub {
245         my ( $infile, $force_version );
246
247         GetOptions(
248             'i:s' => \$infile,
249             'f' => \$force_version,
250         );
251
252         my $preferences = YAML::Syck::LoadFile($infile || \*STDIN);
253
254         die "Expected a YAML mapping" if ( ref($preferences) ne 'HASH' );
255
256         die "Tried to load preferences for version " . $preferences->{'Version'} . ", we are " . C4::Context->preference( 'Version' ) if ( $preferences->{'Version'} && C4::Context->preference( 'Version' ) < $preferences->{'Version'} );
257
258         my %prefs_to_set = (
259             map { $_, $preferences->{$_} }
260             grep { !$NOT_SET_PREFS{$_} }
261             keys %$preferences
262         );
263
264         SetPreferences( %prefs_to_set );
265     },
266     get => sub {
267         my ( $preference ) = @_;
268
269         print_usage() unless ( $preference );
270
271         print GetPreference( $preference ) . "\n";
272     },
273     set => sub {
274         my ( $preference, $value ) = @_;
275
276         print_usage() unless ( $preference && defined($value) );
277
278         SetPreference( $preference, $value );
279     },
280     clear => sub {
281         my ( $preference ) = @_;
282
283         print_usage() unless ( $preference );
284
285         ClearPreference( $preference );
286     },
287     manual => sub {
288         pod2usage( -verbose => 2 );
289     }
290 );
291
292 print_usage() if ( $ARGV[0] =~ /^(-h|--help|-help|help)$/ );
293
294 print_usage( 1 ) if ( !$ARGV[0] || ref($commands{$ARGV[0]}) ne 'CODE' );
295
296 $command = $commands{$ARGV[0]};
297 shift @ARGV;
298 $command->(@ARGV);
299
300 =item B<help>
301
302 Print a short usage message.
303
304 =back
305
306 =head1 EXAMPLES
307
308   $ export KOHA_DEBUG=1 # Used here to show what is being stored
309   $ misc/admin/koha-preferences get viewISBD
310   0
311   $ misc/admin/koha-preferences set viewISBD on
312   Setting viewISBD to 1
313   $ misc/admin/koha-preferences dump -o preferences.yaml
314   $ [ edit preferences.yaml ]
315   $ misc/admin/koha-preferences load -i preferences.yaml
316   $ misc/admin/koha-preferences load -i preferences-too-new.yaml
317   Tried to load preferences for version 3.0500012, we are 3.0300009 at misc/admin/koha-preferences line 255
318   $ misc/admin/koha-preferences load # Can also work from STDIN
319   XISBN: false
320   viewMARC: y
321   [ Control-D ]
322   Setting viewMARC to 1
323   Setting XISBN to 0
324
325 =cut