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

(-)a/Koha/REST/V1/Library.pm (+147 lines)
Line 0 Link Here
1
package Koha::REST::V1::Library;
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 3 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
20
use Mojo::Base 'Mojolicious::Controller';
21
use Koha::Libraries;
22
23
use Scalar::Util qw( blessed );
24
25
use Try::Tiny;
26
27
sub list {
28
    my ($c, $args, $cb) = @_;
29
30
    my $libraries;
31
    my $filter;
32
    $args //= {};
33
34
    for my $filter_param ( keys %$args ) {
35
        $filter->{$filter_param} = { LIKE => $args->{$filter_param} . "%" };
36
    }
37
38
    return try {
39
        my $libraries = Koha::Libraries->search($filter);
40
        return $c->$cb($libraries, 200);
41
    }
42
    catch {
43
        unless (blessed($_)) {
44
            return $c->$cb(
45
                { error => "Something went wrong, check the logs." }, 500 );
46
        }
47
        if ( $_->isa('DBIx::Class::Exception') ) {
48
            return $c->$cb( { error => $_->{msg} }, 500 );
49
        }
50
        else {
51
            return $c->$cb(
52
                { error => "Something went wrong, check the logs." }, 500 );
53
        }
54
    };
55
}
56
57
sub get {
58
    my ($c, $args, $cb) = @_;
59
60
    my $branchcode = $c->param('branchcode');
61
    my $library = Koha::Libraries->find({ branchcode => $branchcode });
62
    unless ($library) {
63
        return $c->$cb({error => "Library not found"}, 404);
64
    }
65
66
    return $c->$cb($library, 200);
67
}
68
69
sub add {
70
    my ($c, $args, $cb) = @_;
71
72
    return try {
73
        if (Koha::Libraries->find($c->req->json->{branchcode})) {
74
            return $c->$cb(
75
                { error => 'Library already exists' }, 400);
76
        }
77
        my $library = Koha::Library->new($args->{body})->store;
78
        my $branchcode = $library->branchcode;
79
        $c->res->headers->location($c->req->url->to_string.'/'.$branchcode);
80
        return $c->$cb($library, 201);
81
    }
82
    catch {
83
        unless (blessed($_)) {
84
            return $c->$cb(
85
                { error => "Something went wrong, check the logs." }, 500 );
86
        }
87
        if ( $_->isa('DBIx::Class::Exception') ) {
88
            return $c->$cb( { error => $_->{msg} }, 500 );
89
        }
90
        else {
91
            return $c->$cb(
92
                { error => "Something went wrong, check the logs." }, 500 );
93
        }
94
    };
95
}
96
97
sub update {
98
    my ($c, $args, $cb) = @_;
99
100
    my $library;
101
    return try {
102
        $library = Koha::Libraries->find($args->{branchcode});
103
        $library->set($args->{body})->store;
104
        return $c->$cb($library, 200);
105
    }
106
    catch {
107
        if ( not defined $library ) {
108
            return $c->$cb( { error => "Object not found" }, 404 );
109
        }
110
        unless (blessed($_)) {
111
            return $c->$cb(
112
                { error => "Something went wrong, check the logs." }, 500 );
113
        }
114
        else {
115
            return $c->$cb(
116
                { error => "Something went wrong, check the logs." }, 500 );
117
        }
118
    };
119
}
120
121
sub delete {
122
    my ($c, $args, $cb) = @_;
123
124
    my $library;
125
    return try {
126
        $library = Koha::Libraries->find($args->{branchcode})->delete;
127
        return $c->$cb('', 204);
128
    }
129
    catch {
130
        if ( not defined $library ) {
131
            return $c->$cb( { error => "Object not found" }, 404 );
132
        }
133
        unless (blessed($_)) {
134
            return $c->$cb(
135
                { error => "Something went wrong, check the logs." }, 500 );
136
        }
137
        elsif ( $_->isa('DBIx::Class::Exception') ) {
138
            return $c->$cb( { error => $_->{msg} }, 500 );
139
        }
140
        else {
141
            return $c->$cb(
142
                { error => "Something went wrong, check the logs." }, 500 );
143
        }
144
    };
145
}
146
147
1;
(-)a/api/v1/swagger/definitions.json (+3 lines)
Lines 11-16 Link Here
11
  "hold": {
11
  "hold": {
12
    "$ref": "definitions/hold.json"
12
    "$ref": "definitions/hold.json"
13
  },
13
  },
14
  "library": {
15
    "$ref": "definitions/library.json"
16
  },
14
  "error": {
17
  "error": {
15
    "$ref": "definitions/error.json"
18
    "$ref": "definitions/error.json"
16
  }
19
  }
(-)a/api/v1/swagger/definitions/library.json (+86 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "branchcode": {
5
      "$ref": "../x-primitives.json#/branchcode"
6
    },
7
    "branchname": {
8
      "type": "string",
9
      "description": "Printable name of library"
10
    },
11
    "branchaddress1": {
12
      "type": ["string", "null"],
13
      "description": "the first address line of the library"
14
    },
15
    "branchaddress2": {
16
      "type": ["string", "null"],
17
      "description": "the second address line of the library"
18
    },
19
    "branchaddress3": {
20
      "type": ["string", "null"],
21
      "description": "the third address line of the library"
22
    },
23
    "branchzip": {
24
      "type": ["string", "null"],
25
      "description": "the zip or postal code of the library"
26
    },
27
    "branchcity": {
28
      "type": ["string", "null"],
29
      "description": "the city or province of the library"
30
    },
31
    "branchstate": {
32
      "type": ["string", "null"],
33
      "description": "the reqional state of the library"
34
    },
35
    "branchcountry": {
36
      "type": ["string", "null"],
37
      "description": "the county of the library"
38
    },
39
    "branchphone": {
40
      "type": ["string", "null"],
41
      "description": "the primary phone of the library"
42
    },
43
    "branchfax": {
44
      "type": ["string", "null"],
45
      "description": "the fax number of the library"
46
    },
47
    "branchemail": {
48
      "type": ["string", "null"],
49
      "description": "the primary email address of the library"
50
    },
51
    "branchreplyto": {
52
      "type": ["string", "null"],
53
      "description": "the email to be used as a Reply-To"
54
    },
55
    "branchreturnpath": {
56
      "type": ["string", "null"],
57
      "description": "the email to be used as Return-Path"
58
    },
59
    "branchurl": {
60
      "type": ["string", "null"],
61
      "description": "the URL for your library or branch's website"
62
    },
63
    "issuing": {
64
      "type": ["integer", "null"],
65
      "description": "unused in Koha"
66
    },
67
    "branchip": {
68
      "type": ["string", "null"],
69
      "description": "the IP address for your library or branch"
70
    },
71
    "branchprinter": {
72
      "type": ["string", "null"],
73
      "description": "unused in Koha"
74
    },
75
    "branchnotes": {
76
      "type": ["string", "null"],
77
      "description": "notes related to your library or branch"
78
    },
79
    "opac_info": {
80
      "type": ["string", "null"],
81
      "description": "HTML that displays in OPAC"
82
    }
83
  },
84
  "additionalProperties": false,
85
  "required": ["branchcode", "branchname"]
86
}
(-)a/api/v1/swagger/parameters.json (+3 lines)
Lines 5-10 Link Here
5
  "borrowernumberQueryParam": {
5
  "borrowernumberQueryParam": {
6
    "$ref": "parameters/patron.json#/borrowernumberQueryParam"
6
    "$ref": "parameters/patron.json#/borrowernumberQueryParam"
7
  },
7
  },
8
  "branchcodePathParam": {
9
    "$ref": "parameters/library.json#/branchcodePathParam"
10
  },
8
  "cityidPathParam": {
11
  "cityidPathParam": {
9
    "$ref": "parameters/city.json#/cityidPathParam"
12
    "$ref": "parameters/city.json#/cityidPathParam"
10
  },
13
  },
(-)a/api/v1/swagger/parameters/library.json (+9 lines)
Line 0 Link Here
1
{
2
  "branchcodePathParam": {
3
    "name": "branchcode",
4
    "in": "path",
5
    "description": "Branch identifier code",
6
    "required": true,
7
    "type": "string"
8
  }
9
}
(-)a/api/v1/swagger/paths.json (+6 lines)
Lines 11-16 Link Here
11
  "/holds/{reserve_id}": {
11
  "/holds/{reserve_id}": {
12
    "$ref": "paths/holds.json#/~1holds~1{reserve_id}"
12
    "$ref": "paths/holds.json#/~1holds~1{reserve_id}"
13
  },
13
  },
14
  "/libraries": {
15
    "$ref": "paths/libraries.json#/~1libraries"
16
  },
17
  "/libraries/{branchcode}": {
18
    "$ref": "paths/libraries.json#/~1libraries~1{branchcode}"
19
  },
14
  "/patrons": {
20
  "/patrons": {
15
    "$ref": "paths/patrons.json#/~1patrons"
21
    "$ref": "paths/patrons.json#/~1patrons"
16
  },
22
  },
(-)a/api/v1/swagger/paths/libraries.json (+336 lines)
Line 0 Link Here
1
{
2
  "/libraries": {
3
    "get": {
4
      "operationId": "listLibrary",
5
      "tags": ["library"],
6
      "parameters": [{
7
        "name": "branchname",
8
        "in": "query",
9
        "description": "Case insensitive 'starts-with' search on name",
10
        "required": false,
11
        "type": "string"
12
      }, {
13
        "name": "branchaddress1",
14
        "in": "query",
15
        "description": "Case insensitive 'starts-with' search on address1",
16
        "required": false,
17
        "type": "string"
18
      }, {
19
        "name": "branchaddress2",
20
        "in": "query",
21
        "description": "Case insensitive 'starts-with' search on address2",
22
        "required": false,
23
        "type": "string"
24
      }, {
25
        "name": "branchaddress3",
26
        "in": "query",
27
        "description": "Case insensitive 'starts-with' search on address3",
28
        "required": false,
29
        "type": "string"
30
      }, {
31
        "name": "branchzip",
32
        "in": "query",
33
        "description": "Case insensitive 'starts-with' search on zipcode",
34
        "required": false,
35
        "type": "string"
36
      }, {
37
        "name": "branchcity",
38
        "in": "query",
39
        "description": "Case insensitive 'starts-with' search on city",
40
        "required": false,
41
        "type": "string"
42
      }, {
43
        "name": "branchstate",
44
        "in": "query",
45
        "description": "Case insensitive 'starts-with' search on state",
46
        "required": false,
47
        "type": "string"
48
      }, {
49
        "name": "branchcountry",
50
        "in": "query",
51
        "description": "Case insensitive 'starts_with' search on country",
52
        "required": false,
53
        "type": "string"
54
      }, {
55
        "name": "branchphone",
56
        "in": "query",
57
        "description": "Case insensitive 'starts_with' search on phone number",
58
        "required": false,
59
        "type": "string"
60
      }, {
61
        "name": "branchfax",
62
        "in": "query",
63
        "description": "Case insensitive 'starts_with' search on fax number",
64
        "required": false,
65
        "type": "string"
66
      }, {
67
        "name": "branchemail",
68
        "in": "query",
69
        "description": "Case insensitive 'starts_with' search on email address",
70
        "required": false,
71
        "type": "string"
72
      }, {
73
        "name": "branchreplyto",
74
        "in": "query",
75
        "description": "Case insensitive 'starts_with' search on Reply-To email address",
76
        "required": false,
77
        "type": "string"
78
      }, {
79
        "name": "branchreturnpath",
80
        "in": "query",
81
        "description": "Case insensitive 'starts_with' search on Return-Path email address",
82
        "required": false,
83
        "type": "string"
84
      }, {
85
        "name": "branchurl",
86
        "in": "query",
87
        "description": "Case insensitive 'starts_with' search on website URL",
88
        "required": false,
89
        "type": "string"
90
      }, {
91
        "name": "issuing",
92
        "in": "query",
93
        "description": "Unused in Koha",
94
        "required": false,
95
        "type": "integer"
96
      }, {
97
        "name": "branchip",
98
        "in": "query",
99
        "description": "Case insensitive 'starts_with' search on IP address",
100
        "required": false,
101
        "type": "string"
102
      }, {
103
        "name": "branchprinter",
104
        "in": "query",
105
        "description": "Unused in Koha",
106
        "required": false,
107
        "type": "string"
108
      }, {
109
        "name": "branchnotes",
110
        "in": "query",
111
        "description": "Case insensitive 'starts_with' search on notes",
112
        "required": false,
113
        "type": "string"
114
      }, {
115
        "name": "opac_info",
116
        "in": "query",
117
        "description": "Case insensitive 'starts-with' search on OPAC info",
118
        "required": false,
119
        "type": "string"
120
      }],
121
      "produces": [
122
        "application/json"
123
      ],
124
      "responses": {
125
        "200": {
126
          "description": "A list of libraries",
127
          "schema": {
128
            "type": "array",
129
            "items": {
130
              "$ref": "../definitions.json#/library"
131
            }
132
          }
133
        },
134
        "500": {
135
          "description": "Internal error",
136
          "schema": {
137
            "$ref": "../definitions.json#/error"
138
          }
139
        }
140
      }
141
    },
142
    "post": {
143
      "x-mojo-controller": "Koha::REST::V1::Library",
144
      "operationId": "add",
145
      "tags": ["library"],
146
      "parameters": [{
147
        "name": "body",
148
        "in": "body",
149
        "description": "A JSON object containing informations about the new library",
150
        "required": true,
151
        "schema": {
152
          "$ref": "../definitions.json#/library"
153
        }
154
      }],
155
      "produces": [
156
        "application/json"
157
      ],
158
      "responses": {
159
        "201": {
160
          "description": "Library added",
161
          "schema": {
162
            "$ref": "../definitions.json#/library"
163
          }
164
        },
165
        "400": {
166
          "description": "Bad request",
167
          "schema": {
168
            "$ref": "../definitions.json#/error"
169
          }
170
        },
171
        "401": {
172
          "description": "Authentication required",
173
          "schema": {
174
            "$ref": "../definitions.json#/error"
175
          }
176
        },
177
        "403": {
178
          "description": "Access forbidden",
179
          "schema": {
180
            "$ref": "../definitions.json#/error"
181
          }
182
        },
183
        "500": {
184
          "description": "Internal error",
185
          "schema": {
186
            "$ref": "../definitions.json#/error"
187
          }
188
        }
189
      },
190
      "x-koha-authorization": {
191
        "permissions": {
192
          "parameters": "parameters_remaining_permissions"
193
        }
194
      }
195
    }
196
  },
197
  "/libraries/{branchcode}": {
198
    "get": {
199
      "operationId": "getLibrary",
200
      "tags": ["library"],
201
      "parameters": [
202
        {
203
          "$ref": "../parameters.json#/branchcodePathParam"
204
        }
205
      ],
206
      "produces": [
207
        "application/json"
208
      ],
209
      "responses": {
210
        "200": {
211
          "description": "A library",
212
          "schema": {
213
            "$ref": "../definitions.json#/library"
214
          }
215
        },
216
        "404": {
217
          "description": "Library not found",
218
          "schema": {
219
            "$ref": "../definitions.json#/error"
220
          }
221
        }
222
      }
223
    },
224
    "put": {
225
      "x-mojo-controller": "Koha::REST::V1::Library",
226
      "operationId": "update",
227
      "tags": ["library"],
228
      "parameters": [{
229
        "$ref": "../parameters.json#/branchcodePathParam"
230
      }, {
231
        "name": "body",
232
        "in": "body",
233
        "description": "A JSON object containing information on the library",
234
        "required": true,
235
        "schema": {
236
          "$ref": "../definitions.json#/library"
237
        }
238
      }],
239
      "consumes": [
240
        "application/json"
241
      ],
242
      "produces": [
243
        "application/json"
244
      ],
245
      "responses": {
246
        "200": {
247
          "description": "A library",
248
          "schema": {
249
            "$ref": "../definitions.json#/library"
250
          }
251
        },
252
        "400": {
253
          "description": "Bad request",
254
          "schema": {
255
            "$ref": "../definitions.json#/error"
256
          }
257
        },
258
        "401": {
259
          "description": "Authentication required",
260
          "schema": {
261
            "$ref": "../definitions.json#/error"
262
          }
263
        },
264
        "403": {
265
          "description": "Access forbidden",
266
          "schema": {
267
            "$ref": "../definitions.json#/error"
268
          }
269
        },
270
        "404": {
271
          "description": "Library not found",
272
          "schema": {
273
            "$ref": "../definitions.json#/error"
274
          }
275
        },
276
        "500": {
277
          "description": "Internal error",
278
          "schema": {
279
            "$ref": "../definitions.json#/error"
280
          }
281
        }
282
      },
283
      "x-koha-authorization": {
284
        "permissions": {
285
          "parameters": "parameters_remaining_permissions"
286
        }
287
      }
288
    },
289
    "delete": {
290
      "x-mojo-controller": "Koha::REST::V1::Library",
291
      "operationId": "delete",
292
      "tags": ["library"],
293
      "parameters": [{
294
        "$ref": "../parameters.json#/branchcodePathParam"
295
      }],
296
      "produces": [
297
        "application/json"
298
      ],
299
      "responses": {
300
        "204": {
301
          "description": "Library deleted",
302
          "schema": { "type": "string" }
303
        },
304
        "401": {
305
          "description": "Authentication required",
306
          "schema": {
307
            "$ref": "../definitions.json#/error"
308
          }
309
        },
310
        "403": {
311
          "description": "Access forbidden",
312
          "schema": {
313
            "$ref": "../definitions.json#/error"
314
          }
315
        },
316
        "404": {
317
          "description": "Library not found",
318
          "schema": {
319
            "$ref": "../definitions.json#/error"
320
          }
321
        },
322
        "500": {
323
          "description": "Internal error",
324
          "schema": {
325
            "$ref": "../definitions.json#/error"
326
          }
327
        }
328
      },
329
      "x-koha-authorization": {
330
        "permissions": {
331
          "parameters": "parameters_remaining_permissions"
332
        }
333
      }
334
    }
335
  }
336
}
(-)a/api/v1/swagger/x-primitives.json (+6 lines)
Lines 7-12 Link Here
7
    "type": "integer",
7
    "type": "integer",
8
    "description": "internally assigned user identifier"
8
    "description": "internally assigned user identifier"
9
  },
9
  },
10
  "branchcode": {
11
    "type": "string",
12
    "description": "internally assigned library identifier",
13
    "maxLength": 10,
14
    "minLength": 1
15
  },
10
  "cardnumber": {
16
  "cardnumber": {
11
    "type": ["string", "null"],
17
    "type": ["string", "null"],
12
    "description": "library assigned user identifier"
18
    "description": "library assigned user identifier"
(-)a/t/db_dependent/api/v1/libraries.t (-1 / +413 lines)
Line 0 Link Here
0
- 
1
#!/usr/bin/env 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 3 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
20
use Test::More tests => 5;
21
use Test::Mojo;
22
use Test::Warn;
23
24
use t::lib::TestBuilder;
25
use t::lib::Mocks;
26
27
use C4::Auth;
28
use Koha::Libraries;
29
use Koha::Database;
30
31
my $schema  = Koha::Database->new->schema;
32
my $builder = t::lib::TestBuilder->new;
33
34
# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling
35
# this affects the other REST api tests
36
t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' );
37
38
my $remote_address = '127.0.0.1';
39
my $t              = Test::Mojo->new('Koha::REST::V1');
40
41
subtest 'list() tests' => sub {
42
    plan tests => 8;
43
44
    $schema->storage->txn_begin;
45
46
    # Create test context
47
    my $library = $builder->build( { source => 'Branch' } );
48
    my $another_library = { %$library };   # create a copy of $library but make
49
    delete $another_library->{branchcode}; # sure branchcode will be regenerated
50
    $another_library = $builder->build(
51
        { source => 'Branch', value => $another_library } );
52
    my ( $borrowernumber, $session_id ) =
53
      create_user_and_session( { authorized => 0 } );
54
55
    ## Authorized user tests
56
    my $count_of_libraries = Koha::Libraries->search->count;
57
    # Make sure we are returned with the correct amount of libraries
58
    my $tx = $t->ua->build_tx( GET => '/api/v1/libraries' );
59
    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
60
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
61
    $t->request_ok($tx)
62
      ->status_is(200)
63
      ->json_has('/'.($count_of_libraries-1).'/branchcode')
64
      ->json_hasnt('/'.($count_of_libraries).'/branchcode');
65
66
    subtest 'query parameters' => sub {
67
        my @fields = qw(
68
        branchname       branchaddress1 branchaddress2 branchaddress3
69
        branchzip        branchcity     branchstate    branchcountry
70
        branchphone      branchfax      branchemail    branchreplyto
71
        branchreturnpath branchurl      issuing        branchip
72
        branchprinter    branchnotes    opac_info
73
        );
74
        plan tests => scalar(@fields)*3;
75
76
        foreach my $field (@fields) {
77
            $tx = $t->ua->build_tx( GET =>
78
                         "/api/v1/libraries?$field=$library->{$field}" );
79
            $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
80
            $tx->req->env( { REMOTE_ADDR => $remote_address } );
81
            my $result =
82
            $t->request_ok($tx)
83
              ->status_is(200)
84
              ->json_has( [ $library, $another_library ] );
85
        }
86
    };
87
88
    # Warn on unsupported query parameter
89
    $tx = $t->ua->build_tx( GET => '/api/v1/libraries?library_blah=blah' );
90
    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
91
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
92
    $t->request_ok($tx)
93
      ->status_is(400)
94
      ->json_is( [{ path => '/query/library_blah', message => 'Malformed query string'}] );
95
96
    $schema->storage->txn_rollback;
97
};
98
99
subtest 'get() tests' => sub {
100
101
    plan tests => 6;
102
103
    $schema->storage->txn_begin;
104
105
    my $library = $builder->build( { source => 'Branch' } );
106
    my ( $borrowernumber, $session_id ) =
107
      create_user_and_session( { authorized => 0 } );
108
109
    my $tx = $t->ua->build_tx( GET => "/api/v1/libraries/" . $library->{branchcode} );
110
    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
111
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
112
    $t->request_ok($tx)
113
      ->status_is(200)
114
      ->json_is($library);
115
116
    my $non_existent_code = 'non_existent'.int(rand(10000));
117
    $tx = $t->ua->build_tx( GET => "/api/v1/libraries/" . $non_existent_code );
118
    $tx->req->cookies( { name => 'CGISESSID', value => $session_id } );
119
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
120
    $t->request_ok($tx)
121
      ->status_is(404)
122
      ->json_is( '/error' => 'Library not found' );
123
124
    $schema->storage->txn_rollback;
125
};
126
127
subtest 'add() tests' => sub {
128
    plan tests => 31;
129
130
    $schema->storage->txn_begin;
131
132
    my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
133
      create_user_and_session( { authorized => 0 } );
134
    my ( $authorized_borrowernumber, $authorized_session_id ) =
135
      create_user_and_session( { authorized => 1 } );
136
    my $library = {
137
        branchcode       => "LIBRARYBR1",
138
        branchname       => "Library Name",
139
        branchaddress1   => "Library Address1",
140
        branchaddress2   => "Library Address2",
141
        branchaddress3   => "Library Address3",
142
        branchzip        => "Library Zipcode",
143
        branchcity       => "Library City",
144
        branchstate      => "Library State",
145
        branchcountry    => "Library Country",
146
        branchphone      => "Library Phone",
147
        branchfax        => "Library Fax",
148
        branchemail      => "Library Email",
149
        branchreplyto    => "Library Reply-To",
150
        branchreturnpath => "Library Return-Path",
151
        branchurl        => "http://library.url",
152
        issuing          => undef,                  # unused in Koha
153
        branchip         => "127.0.0.1",
154
        branchprinter    => "Library Printer",      # unused in Koha
155
        branchnotes      => "Library Notes",
156
        opac_info        => "<p>Library OPAC info</p>",
157
    };
158
159
    # Unauthorized attempt to write
160
    my $tx = $t->ua->build_tx( POST => "/api/v1/libraries" => json => $library );
161
    $tx->req->cookies(
162
        { name => 'CGISESSID', value => $unauthorized_session_id } );
163
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
164
    $t->request_ok($tx)
165
      ->status_is(403);
166
167
    # Authorized attempt to write invalid data
168
    my $library_with_invalid_field = { %$library };
169
    $library_with_invalid_field->{'branchinvalid'} = 'Library invalid';
170
171
    $tx = $t->ua->build_tx(
172
        POST => "/api/v1/libraries" => json => $library_with_invalid_field );
173
    $tx->req->cookies(
174
        { name => 'CGISESSID', value => $authorized_session_id } );
175
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
176
    $t->request_ok($tx)
177
      ->status_is(400)
178
      ->json_is(
179
        "/errors" => [
180
            {
181
                message => "Properties not allowed: branchinvalid.",
182
                path    => "/body"
183
            }
184
        ]
185
    );
186
187
    # Authorized attempt to write
188
    $tx = $t->ua->build_tx( POST => "/api/v1/libraries" => json => $library );
189
    $tx->req->cookies(
190
        { name => 'CGISESSID', value => $authorized_session_id } );
191
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
192
    my $branchcode = $t->request_ok($tx)
193
      ->status_is(201)
194
      ->json_is( '/branchname'       => $library->{branchname} )
195
      ->json_is( '/branchaddress1'   => $library->{branchaddress1} )
196
      ->json_is( '/branchaddress2'   => $library->{branchaddress2} )
197
      ->json_is( '/branchaddress3'   => $library->{branchaddress3} )
198
      ->json_is( '/branchzip'        => $library->{branchzip} )
199
      ->json_is( '/branchcity'       => $library->{branchcity} )
200
      ->json_is( '/branchstate'      => $library->{branchstate} )
201
      ->json_is( '/branchcountry'    => $library->{branchcountry} )
202
      ->json_is( '/branchphone'      => $library->{branchphone} )
203
      ->json_is( '/branchfax'        => $library->{branchfax} )
204
      ->json_is( '/branchemail'      => $library->{branchemail} )
205
      ->json_is( '/branchreplyto'    => $library->{branchreplyto} )
206
      ->json_is( '/branchreturnpath' => $library->{branchreturnpath} )
207
      ->json_is( '/branchurl'        => $library->{branchurl} )
208
      ->json_is( '/branchip'        => $library->{branchip} )
209
      ->json_is( '/branchnotes'      => $library->{branchnotes} )
210
      ->json_is( '/opac_info'        => $library->{opac_info} )
211
      ->header_is(Location => "/api/v1/libraries/$library->{branchcode}")
212
      ->tx->res->json->{branchcode};
213
214
    # Authorized attempt to create with null id
215
    $library->{branchcode} = undef;
216
    $tx = $t->ua->build_tx(
217
        POST => "/api/v1/libraries" => json => $library );
218
    $tx->req->cookies(
219
        { name => 'CGISESSID', value => $authorized_session_id } );
220
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
221
    $t->request_ok($tx)
222
      ->status_is(400)
223
      ->json_has('/errors');
224
225
    # Authorized attempt to create with existing id
226
    $library->{branchcode} = $branchcode;
227
    $tx = $t->ua->build_tx(
228
        POST => "/api/v1/libraries" => json => $library );
229
    $tx->req->cookies(
230
        { name => 'CGISESSID', value => $authorized_session_id } );
231
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
232
    $t->request_ok($tx)
233
      ->status_is(400)
234
      ->json_is('/error' => 'Library already exists');
235
236
    $schema->storage->txn_rollback;
237
};
238
239
subtest 'update() tests' => sub {
240
    plan tests => 13;
241
242
    $schema->storage->txn_begin;
243
244
    my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
245
      create_user_and_session( { authorized => 0 } );
246
    my ( $authorized_borrowernumber, $authorized_session_id ) =
247
      create_user_and_session( { authorized => 1 } );
248
249
    my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
250
251
    # Unauthorized attempt to update
252
    my $tx = $t->ua->build_tx( PUT => "/api/v1/libraries/$branchcode"
253
        => json => { branchname => 'New unauthorized name change' } );
254
    $tx->req->cookies(
255
        { name => 'CGISESSID', value => $unauthorized_session_id } );
256
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
257
    $t->request_ok($tx)
258
      ->status_is(403);
259
260
    # Attempt partial update on a PUT
261
    my $library_with_missing_field = {
262
        branchaddress1 => "New library address",
263
    };
264
265
    $tx = $t->ua->build_tx( PUT => "/api/v1/libraries/$branchcode" =>
266
                            json => $library_with_missing_field );
267
    $tx->req->cookies(
268
        { name => 'CGISESSID', value => $authorized_session_id } );
269
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
270
    $t->request_ok($tx)
271
      ->status_is(400)
272
      ->json_has( "/errors" =>
273
          [ { message => "Missing property.", path => "/body/branchaddress2" } ]
274
      );
275
276
    # Full object update on PUT
277
    my $library_with_updated_field = {
278
        branchcode       => "LIBRARYBR2",
279
        branchname       => "Library Name",
280
        branchaddress1   => "Library Address1",
281
        branchaddress2   => "Library Address2",
282
        branchaddress3   => "Library Address3",
283
        branchzip        => "Library Zipcode",
284
        branchcity       => "Library City",
285
        branchstate      => "Library State",
286
        branchcountry    => "Library Country",
287
        branchphone      => "Library Phone",
288
        branchfax        => "Library Fax",
289
        branchemail      => "Library Email",
290
        branchreplyto    => "Library Reply-To",
291
        branchreturnpath => "Library Return-Path",
292
        branchurl        => "http://library.url",
293
        issuing          => undef,                  # unused in Koha
294
        branchip         => "127.0.0.1",
295
        branchprinter    => "Library Printer",      # unused in Koha
296
        branchnotes      => "Library Notes",
297
        opac_info        => "<p>Library OPAC info</p>",
298
    };
299
300
    $tx = $t->ua->build_tx(
301
        PUT => "/api/v1/libraries/$branchcode" => json => $library_with_updated_field );
302
    $tx->req->cookies(
303
        { name => 'CGISESSID', value => $authorized_session_id } );
304
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
305
    $t->request_ok($tx)
306
      ->status_is(200)
307
      ->json_is( '/branchname' => 'Library Name' );
308
309
    # Authorized attempt to write invalid data
310
    my $library_with_invalid_field = { %$library_with_updated_field };
311
    $library_with_invalid_field->{'branchinvalid'} = 'Library invalid';
312
313
    $tx = $t->ua->build_tx(
314
        PUT => "/api/v1/libraries/$branchcode" => json => $library_with_invalid_field );
315
    $tx->req->cookies(
316
        { name => 'CGISESSID', value => $authorized_session_id } );
317
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
318
    $t->request_ok($tx)
319
      ->status_is(400)
320
      ->json_is(
321
        "/errors" => [
322
            {
323
                message => "Properties not allowed: branchinvalid.",
324
                path    => "/body"
325
            }
326
        ]
327
    );
328
329
    my $non_existent_code = 'nope'.int(rand(10000));
330
    $tx =
331
      $t->ua->build_tx( PUT => "/api/v1/libraries/$non_existent_code" => json =>
332
          $library_with_updated_field );
333
    $tx->req->cookies(
334
        { name => 'CGISESSID', value => $authorized_session_id } );
335
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
336
    $t->request_ok($tx)
337
      ->status_is(404);
338
339
    $schema->storage->txn_rollback;
340
};
341
342
subtest 'delete() tests' => sub {
343
    plan tests => 7;
344
345
    $schema->storage->txn_begin;
346
347
    my ( $unauthorized_borrowernumber, $unauthorized_session_id ) =
348
      create_user_and_session( { authorized => 0 } );
349
    my ( $authorized_borrowernumber, $authorized_session_id ) =
350
      create_user_and_session( { authorized => 1 } );
351
352
    my $branchcode = $builder->build( { source => 'Branch' } )->{branchcode};
353
354
    # Unauthorized attempt to delete
355
    my $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" );
356
    $tx->req->cookies(
357
        { name => 'CGISESSID', value => $unauthorized_session_id } );
358
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
359
    $t->request_ok($tx)
360
      ->status_is(403);
361
362
    $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" );
363
    $tx->req->cookies(
364
        { name => 'CGISESSID', value => $authorized_session_id } );
365
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
366
    $t->request_ok($tx)
367
      ->status_is(204)
368
      ->content_is('');
369
370
    $tx = $t->ua->build_tx( DELETE => "/api/v1/libraries/$branchcode" );
371
    $tx->req->cookies(
372
        { name => 'CGISESSID', value => $authorized_session_id } );
373
    $tx->req->env( { REMOTE_ADDR => $remote_address } );
374
    $t->request_ok($tx)
375
      ->status_is(404);
376
377
    $schema->storage->txn_rollback;
378
};
379
380
sub create_user_and_session {
381
382
    my $args  = shift;
383
    my $flags = ( $args->{authorized} ) ? $args->{authorized} : 0;
384
    my $dbh   = C4::Context->dbh;
385
386
    my $user = $builder->build(
387
        {
388
            source => 'Borrower',
389
            value  => {
390
                flags => $flags
391
            }
392
        }
393
    );
394
395
    # Create a session for the authorized user
396
    my $session = C4::Auth::get_session('');
397
    $session->param( 'number',   $user->{borrowernumber} );
398
    $session->param( 'id',       $user->{userid} );
399
    $session->param( 'ip',       '127.0.0.1' );
400
    $session->param( 'lasttime', time() );
401
    $session->flush;
402
403
    if ( $args->{authorized} ) {
404
        $dbh->do( "
405
            INSERT INTO user_permissions (borrowernumber,module_bit,code)
406
            VALUES (?,3,'parameters_remaining_permissions')", undef,
407
            $user->{borrowernumber} );
408
    }
409
410
    return ( $user->{borrowernumber}, $session->id );
411
}
412
413
1;

Return to bug 16497