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

(-)a/t/db_dependent/selenium/administration_tasks.t (-73 / +30 lines)
Lines 30-35 use C4::Biblio qw( AddBiblio ); # We shouldn't use it Link Here
30
use Test::More tests => 1;
30
use Test::More tests => 1;
31
use MARC::Record;
31
use MARC::Record;
32
use MARC::Field;
32
use MARC::Field;
33
use t::lib::Selenium;
33
34
34
my $dbh = C4::Context->dbh;
35
my $dbh = C4::Context->dbh;
35
my $login = 'koha';
36
my $login = 'koha';
Lines 37-42 my $password = 'koha'; Link Here
37
my $base_url= 'http://'.C4::Context->preference("staffClientBaseURL")."/cgi-bin/koha/";
38
my $base_url= 'http://'.C4::Context->preference("staffClientBaseURL")."/cgi-bin/koha/";
38
my $opac_url= C4::Context->preference("OPACBaseURL");
39
my $opac_url= C4::Context->preference("OPACBaseURL");
39
40
41
my $number_of_biblios_to_insert = 0;
40
our $sample_data = {
42
our $sample_data = {
41
    category => {
43
    category => {
42
        categorycode    => 'test_cat',
44
        categorycode    => 'test_cat',
Lines 71-98 SKIP: { Link Here
71
    $prev_time = $start;
73
    $prev_time = $start;
72
    $driver->get($base_url."mainpage.pl");
74
    $driver->get($base_url."mainpage.pl");
73
    like( $driver->get_title(), qr(Log in to Koha), );
75
    like( $driver->get_title(), qr(Log in to Koha), );
74
    auth( $driver, $login, $password );
76
    t::lib::Selenium::auth( $driver, $login, $password );
75
    time_diff("main");
77
    t::lib::Selenium::time_diff($prev_time, "main");
76
78
77
    # Navigate to the Administration area and create an item type
79
    # Navigate to the Administration area and create an item type
78
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[1]/div[2]/div/ul/li[5]/a')->click;
80
    $driver->find_element('//a[@href="/cgi-bin/koha/admin/admin-home.pl"]')->click;
81
#    t::lib::Selenium::pause_driver($driver, '/html/body/div[4]/div/div/div[2]/div[1]/dl[1]/dt[2]/a');
82
#   $driver->pause(20000);
79
    $driver->pause(20000);
83
    $driver->pause(20000);
80
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[1]/dt[2]/a')->click;
84
#    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[1]/dt[2]/a')->click;
85
#   $$driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[1]/dt[2]/a')->click;
81
    $driver->pause(20000);
86
    $driver->pause(20000);
82
    $driver->find_element('//a[@id="newitemtype"]')->click;
87
    $driver->find_element('//a[@id="newitemtype"]')->click;
83
    $driver->pause(20000);
88
    $driver->pause(20000);
84
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol[1]/li[1]/input')->send_keys("DVD");
89
    $driver->find_element('//input[@id="itemtype"]')->send_keys("DVD");
85
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol[1]/li[2]/input')->send_keys("Digital Optical Disc");
90
    $driver->find_element('//input[@id="description"]')->send_keys("Digital Optical Disc");
86
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
91
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
87
    if ( $driver->find_element('//a[@href="/cgi-bin/koha/admin/itemtypes.pl?op=add_form&itemtype=DVD"]')) {
92
    if ( $driver->find_element('//a[@href="/cgi-bin/koha/admin/itemtypes.pl?op=add_form&itemtype=DVD"]')) {
88
       time_diff("Item type successfully added");
93
        t::lib::Selenium::time_diff($prev_time, "Item type successfully added");
89
    } else {
94
    } else {
90
       time_diff("Item type not added successfully");
95
        t::lib::Selenium::time_diff($prev_time, "Item type not added successfully");
91
    }
96
    }
92
97
93
    # Add circulation/fine rules
98
    # Add circulation/fine rules
94
    $driver->pause(20000);
99
    $driver->pause(20000);
95
    $driver->find_element_by_xpath('/html/body/div[3]/a[2]')->click;
100
    $driver->find_element('//input[@href="/cgi-bin/koha/admin/admin-home.pl"]')->click;
96
    $driver->pause(20000);
101
    $driver->pause(20000);
97
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[2]/dt[2]/a')->click;
102
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[2]/dt[2]/a')->click;
98
    $driver->pause(20000);
103
    $driver->pause(20000);
Lines 103-109 SKIP: { Link Here
103
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/form[3]/table/tbody/tr[2]/td[22]/input')->send_keys("4");
108
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/form[3]/table/tbody/tr[2]/td[22]/input')->send_keys("4");
104
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/form[3]/table/tbody/tr[2]/td[23]/input')->send_keys("4");
109
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/form[3]/table/tbody/tr[2]/td[23]/input')->send_keys("4");
105
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/form[3]/table/tbody/tr[2]/td[28]/button[1]')->click;
110
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/form[3]/table/tbody/tr[2]/td[28]/button[1]')->click;
106
    time_diff("Circulation rule added");
111
    t::lib::Selenium::time_diff($prev_time, "Circulation rule added");
107
112
108
    # Modify frameworks
113
    # Modify frameworks
109
    $driver->pause(20000);
114
    $driver->pause(20000);
Lines 111-117 SKIP: { Link Here
111
    $driver->pause(20000);
116
    $driver->pause(20000);
112
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[2]/dl[1]/dt[1]/a')->click;
117
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[2]/dl[1]/dt[1]/a')->click;
113
    $driver->pause(20000);
118
    $driver->pause(20000);
114
    warn $driver->get_title();
115
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/table/tbody/tr[5]/td[3]/div/a')->click;
119
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/table/tbody/tr[5]/td[3]/div/a')->click;
116
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/table/tbody/tr[5]/td[3]/div/ul/li[1]/a')->click;
120
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/table/tbody/tr[5]/td[3]/div/ul/li[1]/a')->click;
117
    $driver->pause(20000);
121
    $driver->pause(20000);
Lines 128-134 SKIP: { Link Here
128
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol/li[3]/input')->send_keys("Local Dewey");
132
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol/li[3]/input')->send_keys("Local Dewey");
129
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
133
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
130
    $driver->pause(20000);
134
    $driver->pause(20000);
131
    time_diff("Added subfield to framework");
135
    t::lib::Selenium::time_diff($prev_time, "Added subfield to framework");
132
136
133
    #Add library
137
    #Add library
134
    $driver->get_title();
138
    $driver->get_title();
Lines 147-155 SKIP: { Link Here
147
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[3]/div[1]/div[2]/label/select')->click;
151
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[3]/div[1]/div[2]/label/select')->click;
148
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[3]/div[1]/div[2]/label/select/option[3]')->click;
152
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[3]/div[1]/div[2]/label/select/option[3]')->click;
149
    if ($driver->find_element('//td[text()="Test library"]')) {
153
    if ($driver->find_element('//td[text()="Test library"]')) {
150
        time_diff("Library successfully added");
154
        t::lib::Selenium::time_diff($prev_time, "Library successfully added");
151
    } else {
155
    } else {
152
        time_diff("Library not successfully added");
156
        t::lib::Selenium::time_diff($prev_time, "Library not successfully added");
153
    }
157
    }
154
158
155
159
Lines 168-176 SKIP: { Link Here
168
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol/li[4]/input')->send_keys("Hardcover");
172
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol/li[4]/input')->send_keys("Hardcover");
169
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input[2]')->click;
173
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input[2]')->click;
170
    if ($driver->find_element('//td[text()="HBK"]')) {
174
    if ($driver->find_element('//td[text()="HBK"]')) {
171
        time_diff("Authorised value successfully added");
175
        t::lib::Selenium::time_diff($prev_time, "Authorised value successfully added");
172
    } else {
176
    } else {
173
        time_diff("Authorised value not successfully added");
177
        t::lib::Seleniumtime_diff($prev_time, "Authorised value not successfully added");
174
    }
178
    }
175
179
176
#Patron category
180
#Patron category
Lines 188-196 SKIP: { Link Here
188
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
192
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
189
    $driver->pause(20000);
193
    $driver->pause(20000);
190
    if ($driver->find_element('//td[text()="AD"]')) {
194
    if ($driver->find_element('//td[text()="AD"]')) {
191
        time_diff("Patron category successfully added");
195
        t::lib::Selenium::time_diff($prev_time, "Patron category successfully added");
192
    } else {
196
    } else {
193
        time_diff("Patron category not successfully added");
197
        t::lib::Selenium::time_diff(i$prev_time, "Patron category not successfully added");
194
    }
198
    }
195
199
196
#Add patron attribute type
200
#Add patron attribute type
Lines 206-216 SKIP: { Link Here
206
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol/li[11]/select/option[2]')->click;
210
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[1]/ol/li[11]/select/option[2]')->click;
207
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
211
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
208
    $driver->pause(20000);
212
    $driver->pause(20000);
209
    warn $driver->get_title();
210
    if ($driver->find_element('//td[text()="DL"]')) {
213
    if ($driver->find_element('//td[text()="DL"]')) {
211
        time_diff("Patron attribute type successfully added");
214
        t::lib::Selenium::time_diff($prev_time, "Patron attribute type successfully added");
212
    } else {
215
    } else {
213
        time_diff("Patron attribute type not successfully added");
216
        t::lib::Selenium::time_diff($prev_time, "Patron attribute type not successfully added");
214
    }
217
    }
215
218
216
#Add Z39.50 target server
219
#Add Z39.50 target server
Lines 229-237 SKIP: { Link Here
229
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
232
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
230
    $driver->pause(20000);
233
    $driver->pause(20000);
231
    if ($driver->find_element('//td[text()="consull.ull.ac.uk:210"]')) {
234
    if ($driver->find_element('//td[text()="consull.ull.ac.uk:210"]')) {
232
        time_diff("Z39.50 target successfully added");
235
        t::lib::Selenium::time_diff($prev_time, "Z39.50 target successfully added");
233
    } else {
236
    } else {
234
        time_diff("Z39.50 target not successfully added");
237
        t::lib::Selenium::time_diff($prev_time, "Z39.50 target not successfully added");
235
    }
238
    }
236
239
237
#Add item circulation alerts
240
#Add item circulation alerts
Lines 240-246 SKIP: { Link Here
240
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[2]/dt[6]/a')->click;
243
    $driver->find_element_by_xpath('/html/body/div[4]/div/div/div[2]/div[1]/dl[2]/dt[6]/a')->click;
241
    $driver->pause(20000);
244
    $driver->pause(20000);
242
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/div[1]/table/tbody/tr[1]/td[1]')->click;
245
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/div[2]/div[1]/table/tbody/tr[1]/td[1]')->click;
243
    time_diff("Added item circulation alert");
246
    t::lib::Selenium::time_diff($prev_time, "Added item circulation alert");
244
247
245
#Add city
248
#Add city
246
    $driver->find_element_by_xpath('/html/body/div[3]/a[2]')->click;
249
    $driver->find_element_by_xpath('/html/body/div[3]/a[2]')->click;
Lines 255-263 SKIP: { Link Here
255
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
258
    $driver->find_element_by_xpath('/html/body/div[4]/div/div[1]/div/form/fieldset[2]/input')->click;
256
    $driver->pause(20000);
259
    $driver->pause(20000);
257
    if ($driver->find_element('//td[text()="Wellington"]')) {
260
    if ($driver->find_element('//td[text()="Wellington"]')) {
258
        time_diff("City successfully added");
261
        t::lib::Selenium::time_diff($prev_time, "City successfully added");
259
    } else {
262
    } else {
260
        time_diff("City not successfully added");
263
        t::lib::Selenium::time_diff($prev_time, "City not successfully added");
261
    }
264
    }
262
265
263
    close $fh;
266
    close $fh;
Lines 265-316 SKIP: { Link Here
265
};
268
};
266
269
267
END {
270
END {
268
    cleanup() if $cleanup_needed;
271
    t::lib::Selenium::cleanup($sample_data,$number_of_biblios_to_insert,$borrowernumber) if $cleanup_needed;
269
};
272
};
270
273
271
sub auth {
272
    my ( $driver, $login, $password) = @_;
273
    fill_form( $driver, { userid => 'koha', password => 'koha' } );
274
    my $login_button = $driver->find_element('//input[@id="submit"]');
275
    $login_button->submit();
276
}
277
278
sub patron_auth {
279
    my ( $driver,$patronusername, $patronpassword) = @_;
280
    fill_form( $driver, { userid => $patronusername, password => $patronpassword } );
281
    my $login_button = $driver->find_element('//input[@id="submit"]');
282
    $login_button->submit();
283
}
284
285
sub patron_opac_auth {
286
    my ( $driver,$patronusername, $patronpassword) = @_;
287
    fill_form( $driver, { userid => $patronusername, password => $patronpassword } );
288
    my $login_button = $driver->find_element('//input[@value="Log in"]');
289
    $login_button->submit();
290
}
291
292
sub fill_form {
293
    my ( $driver, $values ) = @_;
294
    while ( my ( $id, $value ) = each %$values ) {
295
        my $element = $driver->find_element('//*[@id="'.$id.'"]');
296
        my $tag = $element->get_tag_name();
297
        if ( $tag eq 'input' ) {
298
            $driver->find_element('//input[@id="'.$id.'"]')->send_keys($value);
299
        } elsif ( $tag eq 'select' ) {
300
            $driver->find_element('//select[@id="'.$id.'"]/option[@value="'.$value.'"]')->click;
301
        }
302
    }
303
}
304
305
sub cleanup {
306
    my $dbh = C4::Context->dbh;
307
    $dbh->do(q|DELETE FROM categories WHERE categorycode = ?|, {}, $sample_data->{category}{categorycode});
308
    $dbh->do(q|DELETE FROM borrowers WHERE userid = ?|, {}, $sample_data->{patron}{userid});
309
}
310
311
sub time_diff {
312
    my $lib = shift;
313
    my $now = gettimeofday;
314
    warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";
315
    $prev_time = $now;
316
}
(-)a/t/lib/Selenium.pm (+185 lines)
Line 0 Link Here
1
package t::lib::Selenium;
2
3
use Modern::Perl;
4
5
use Koha::Database;
6
7
use Carp;
8
use Module::Load;
9
use String::Random;
10
use Time::HiRes qw(gettimeofday);
11
use Selenium::Waiter qw/wait_until/;
12
use Try::Tiny;
13
14
my $dbh = C4::Context->dbh;
15
my $login = 'koha';
16
my $password = 'koha';
17
my $base_url= 'http://'.C4::Context->preference("staffClientBaseURL")."/cgi-bin/koha/";
18
19
sub auth {
20
    my ( $driver, $login, $password) = @_;
21
    fill_form( $driver, { userid => 'koha', password => 'koha' } );
22
    my $login_button = $driver->find_element('//input[@id="submit"]');
23
    $login_button->submit();
24
}
25
26
sub patron_auth {
27
    my ( $driver,$patronusername, $patronpassword) = @_;
28
    fill_form( $driver, { userid => $patronusername, password => $patronpassword } );
29
    my $login_button = $driver->find_element('//input[@id="submit"]');
30
    $login_button->submit();
31
}
32
33
sub patron_opac_auth {
34
    my ( $driver,$patronusername, $patronpassword) = @_;
35
    fill_form( $driver, { userid => $patronusername, password => $patronpassword } );
36
    my $login_button = $driver->find_element('//input[@value="Log in"]');
37
    $login_button->submit();
38
}
39
40
sub fill_form {
41
    my ( $driver, $values ) = @_;
42
    while ( my ( $id, $value ) = each %$values ) {
43
        my $element = $driver->find_element('//*[@id="'.$id.'"]');
44
        my $tag = $element->get_tag_name();
45
        if ( $tag eq 'input' ) {
46
             $driver->find_element('//input[@id="'.$id.'"]')->send_keys($value);
47
        } elsif ( $tag eq 'select' ) {
48
             $driver->find_element('//select[@id="'.$id.'"]/option[@value="'.$value.'"]')->click;
49
        }
50
    }
51
}
52
53
sub cleanup {
54
    my ($sample_data, $number_of_biblios_to_insert,$borrowernumber)  = @_;
55
    my $dbh = C4::Context->dbh;
56
    $dbh->do(q|DELETE FROM categories WHERE categorycode = ?|, {},     $sample_data->{category}{categorycode});
57
    $dbh->do(q|DELETE FROM borrowers WHERE userid = ?|, {}, $sample_data->{patron}{userid});
58
    for my $i ( 1 .. $number_of_biblios_to_insert ) {
59
        $dbh->do(qq|DELETE FROM biblio WHERE title = "test biblio $i"|);
60
    };
61
62
    $dbh->do(q|DELETE FROM issues where borrowernumber=?|, {}, $borrowernumber);
63
    $dbh->do(q|DELETE FROM old_issues where borrowernumber=?|, {},$borrowernumber);
64
    for my $i ( 1 .. $number_of_biblios_to_insert ) {
65
        $dbh->do(qq|DELETE items, biblio FROM biblio INNER JOIN items ON biblio.biblionumber = items.biblionumber WHERE biblio.title ="test biblio$i"|);
66
    };
67
}
68
69
sub time_diff {
70
    my ($prev_time, $lib) = (@_);
71
    my $now = gettimeofday;
72
    warn "CP $lib = " . sprintf("%.2f", $now - $prev_time ) . "\n";
73
   $prev_time = $now;
74
}
75
76
sub pause_driver {
77
    my ($driver, $element) = @_;
78
    $driver->set_implicit_wait_timeout(30000);
79
    my $elem_exists = wait_until {$driver->find_element_by_xpath('$element')};
80
81
    if ($elem_exists) {
82
      $driver->find_element_by_xpath('$element')->click;
83
    }
84
}
85
86
87
=head1 NAME
88
89
t::lib::Selenium.pm - Koha module for common Selenium functions
90
91
=head1 SYNOPSIS
92
93
94
=head1 DESCRIPTION
95
96
This Perl module 
97
98
99
This module automatically creates database records for you.
100
If needed, records for foreign keys are created too.
101
Values will be randomly generated if not passed to TestBuilder.
102
Note that you should wrap these actions in a transaction yourself.
103
104
=head1 METHODS
105
106
=head2 new
107
108
    my $builder = t::lib::TestBuilder->new;
109
110
    Constructor - Returns the object TestBuilder
111
112
=head2 schema
113
114
    my $schema = $builder->schema;
115
116
    Getter - Returns the schema of DBIx::Class
117
118
=head2 delete
119
120
    $builder->delete({
121
        source => $source,
122
        records => $patron, # OR: records => [ $patron, ... ],
123
    });
124
125
    Delete individual records, created by builder.
126
    Returns the number of delete attempts, or undef.
127
128
=head2 build
129
130
    $builder->build({ source  => $source_name, value => $value });
131
132
    Create a test record in the table, represented by $source_name.
133
    The name is required and must conform to the DBIx::Class schema.
134
    Values may be specified by the optional $value hashref. Will be
135
    randomized otherwise.
136
    If needed, TestBuilder creates linked records for foreign keys.
137
    Returns the values of the new record as a hashref, or undef if
138
    the record could not be created.
139
140
    Note that build also supports recursive hash references inside the
141
    value hash for foreign key columns, like:
142
        value => {
143
            column1 => 'some_value',
144
            fk_col2 => {
145
                columnA => 'another_value',
146
            }
147
        }
148
    The hash for fk_col2 here means: create a linked record with build
149
    where columnA has this value. In case of a composite FK the hashes
150
    are merged.
151
152
    Realize that passing primary key values to build may result in undef
153
    if a record with that primary key already exists.
154
155
=head2 build_object
156
157
Given a plural Koha::Object-derived class, it creates a random element, and
158
returns the corresponding Koha::Object.
159
160
    my $patron = $builder->build_object({ class => 'Koha::Patrons' [, value => { ... }] });
161
162
=head1 AUTHOR
163
164
Alex Buckley <alexbuckley@catalyst.net.nz>
165
166
Catalyst Koha Development Team
167
168
=head1 COPYRIGHT
169
170
Copyright 2017 - Catalyst IT
171
172
=head1 LICENSE
173
174
This file is part of Koha.
175
176
Koha is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by
177
the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
178
179
Koha is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
180
181
You should have received a copy of the GNU General Public License along with Koha; if not, see <http://www.gnu.org/licenses>.
182
183
=cut
184
185
1;

Return to bug 19243