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

(-)a/Koha/REST/V1/Library.pm (+141 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 = shift->openapi->valid_input or return;
29
30
    my $libraries;
31
    my $filter;
32
    my $args = $c->req->params->to_hash;
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->render( status => 200, openapi => $libraries );
41
    }
42
    catch {
43
        if ( $_->isa('DBIx::Class::Exception') ) {
44
            return $c->render( status  => 500,
45
                               openapi => { error => $_->{msg} } );
46
        }
47
        else {
48
            return $c->render( status => 500,
49
                openapi => { error => "Something went wrong, check the logs."} );
50
        }
51
    };
52
}
53
54
sub get {
55
    my $c = shift->openapi->valid_input or return;
56
57
    my $branchcode = $c->validation->param('branchcode');
58
    my $library = Koha::Libraries->find({ branchcode => $branchcode });
59
    unless ($library) {
60
        return $c->render( status  => 404,
61
                           openapi => { error => "Library not found" } );
62
    }
63
64
    return $c->render( status => 200, openapi => $library );
65
}
66
67
sub add {
68
    my $c = shift->openapi->valid_input or return;
69
70
    return try {
71
        if (Koha::Libraries->find($c->req->json->{branchcode})) {
72
            return $c->render( status => 400,
73
                openapi => { error => 'Library already exists' } );
74
        }
75
        my $library = Koha::Library->new($c->validation->param('body'))->store;
76
        my $branchcode = $library->branchcode;
77
        $c->res->headers->location($c->req->url->to_string.'/'.$branchcode);
78
        return $c->render( status => 201, openapi => $library);
79
    }
80
    catch {
81
        if ( $_->isa('DBIx::Class::Exception') ) {
82
            return $c->render( status  => 500,
83
                               openapi => { error => $_->{msg} } );
84
        }
85
        else {
86
            return $c->render( status => 500,
87
                openapi => { error => "Something went wrong, check the logs."} );
88
        }
89
    };
90
}
91
92
sub update {
93
    my $c = shift->openapi->valid_input or return;
94
95
    my $library;
96
    return try {
97
        $library = Koha::Libraries->find($c->validation->param('branchcode'));
98
        $library->set($c->validation->param('body'))->store;
99
        return $c->render( status => 200, openapi => $library );
100
    }
101
    catch {
102
        if ( not defined $library ) {
103
            return $c->render( status => 404,
104
                               openapi => { error => "Object not found" });
105
        }
106
        elsif ( $_->isa('DBIx::Class::Exception') ) {
107
            return $c->render( status  => 500,
108
                               openapi => { error => $_->{msg} } );
109
        }
110
        else {
111
            return $c->render( status => 500,
112
                openapi => { error => "Something went wrong, check the logs."} );
113
        }
114
    };
115
}
116
117
sub delete {
118
    my $c = shift->openapi->valid_input or return;
119
120
    my $library;
121
    return try {
122
        $library = Koha::Libraries->find($c->validation->param('branchcode'));
123
        $library->delete;
124
        return $c->render( status => 204, openapi => '');
125
    }
126
    catch {
127
        if ( not defined $library ) {
128
            return $c->render( status => 404, openapi => { error => "Object not found" } );
129
        }
130
        elsif ( $_->isa('DBIx::Class::Exception') ) {
131
            return $c->render( status  => 500,
132
                               openapi => { error => $_->{msg} } );
133
        }
134
        else {
135
            return $c->render( status => 500,
136
                openapi => { error => "Something went wrong, check the logs."} );
137
        }
138
    };
139
}
140
141
1;
(-)a/api/v1/swagger/definitions.json (+3 lines)
Lines 11-16 Link Here
11
  "holds": {
11
  "holds": {
12
    "$ref": "definitions/holds.json"
12
    "$ref": "definitions/holds.json"
13
  },
13
  },
14
  "library": {
15
    "$ref": "definitions/library.json"
16
  },
14
  "patron": {
17
  "patron": {
15
    "$ref": "definitions/patron.json"
18
    "$ref": "definitions/patron.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 17-22 Link Here
17
  "/holds/{reserve_id}": {
17
  "/holds/{reserve_id}": {
18
    "$ref": "paths/holds.json#/~1holds~1{reserve_id}"
18
    "$ref": "paths/holds.json#/~1holds~1{reserve_id}"
19
  },
19
  },
20
  "/libraries": {
21
    "$ref": "paths/libraries.json#/~1libraries"
22
  },
23
  "/libraries/{branchcode}": {
24
    "$ref": "paths/libraries.json#/~1libraries~1{branchcode}"
25
  },
20
  "/patrons": {
26
  "/patrons": {
21
    "$ref": "paths/patrons.json#/~1patrons"
27
    "$ref": "paths/patrons.json#/~1patrons"
22
  },
28
  },
(-)a/api/v1/swagger/paths/libraries.json (+362 lines)
Line 0 Link Here
1
{
2
  "/libraries": {
3
    "get": {
4
      "x-mojo-to": "Library#list",
5
      "operationId": "listLibrary",
6
      "tags": ["library"],
7
      "parameters": [{
8
        "name": "branchname",
9
        "in": "query",
10
        "description": "Case insensitive 'starts-with' search on name",
11
        "required": false,
12
        "type": "string"
13
      }, {
14
        "name": "branchaddress1",
15
        "in": "query",
16
        "description": "Case insensitive 'starts-with' search on address1",
17
        "required": false,
18
        "type": "string"
19
      }, {
20
        "name": "branchaddress2",
21
        "in": "query",
22
        "description": "Case insensitive 'starts-with' search on address2",
23
        "required": false,
24
        "type": "string"
25
      }, {
26
        "name": "branchaddress3",
27
        "in": "query",
28
        "description": "Case insensitive 'starts-with' search on address3",
29
        "required": false,
30
        "type": "string"
31
      }, {
32
        "name": "branchzip",
33
        "in": "query",
34
        "description": "Case insensitive 'starts-with' search on zipcode",
35
        "required": false,
36
        "type": "string"
37
      }, {
38
        "name": "branchcity",
39
        "in": "query",
40
        "description": "Case insensitive 'starts-with' search on city",
41
        "required": false,
42
        "type": "string"
43
      }, {
44
        "name": "branchstate",
45
        "in": "query",
46
        "description": "Case insensitive 'starts-with' search on state",
47
        "required": false,
48
        "type": "string"
49
      }, {
50
        "name": "branchcountry",
51
        "in": "query",
52
        "description": "Case insensitive 'starts_with' search on country",
53
        "required": false,
54
        "type": "string"
55
      }, {
56
        "name": "branchphone",
57
        "in": "query",
58
        "description": "Case insensitive 'starts_with' search on phone number",
59
        "required": false,
60
        "type": "string"
61
      }, {
62
        "name": "branchfax",
63
        "in": "query",
64
        "description": "Case insensitive 'starts_with' search on fax number",
65
        "required": false,
66
        "type": "string"
67
      }, {
68
        "name": "branchemail",
69
        "in": "query",
70
        "description": "Case insensitive 'starts_with' search on email address",
71
        "required": false,
72
        "type": "string"
73
      }, {
74
        "name": "branchreplyto",
75
        "in": "query",
76
        "description": "Case insensitive 'starts_with' search on Reply-To email address",
77
        "required": false,
78
        "type": "string"
79
      }, {
80
        "name": "branchreturnpath",
81
        "in": "query",
82
        "description": "Case insensitive 'starts_with' search on Return-Path email address",
83
        "required": false,
84
        "type": "string"
85
      }, {
86
        "name": "branchurl",
87
        "in": "query",
88
        "description": "Case insensitive 'starts_with' search on website URL",
89
        "required": false,
90
        "type": "string"
91
      }, {
92
        "name": "issuing",
93
        "in": "query",
94
        "description": "Unused in Koha",
95
        "required": false,
96
        "type": "integer"
97
      }, {
98
        "name": "branchip",
99
        "in": "query",
100
        "description": "Case insensitive 'starts_with' search on IP address",
101
        "required": false,
102
        "type": "string"
103
      }, {
104
        "name": "branchprinter",
105
        "in": "query",
106
        "description": "Unused in Koha",
107
        "required": false,
108
        "type": "string"
109
      }, {
110
        "name": "branchnotes",
111
        "in": "query",
112
        "description": "Case insensitive 'starts_with' search on notes",
113
        "required": false,
114
        "type": "string"
115
      }, {
116
        "name": "opac_info",
117
        "in": "query",
118
        "description": "Case insensitive 'starts-with' search on OPAC info",
119
        "required": false,
120
        "type": "string"
121
      }],
122
      "produces": [
123
        "application/json"
124
      ],
125
      "responses": {
126
        "200": {
127
          "description": "A list of libraries",
128
          "schema": {
129
            "type": "array",
130
            "items": {
131
              "$ref": "../definitions.json#/library"
132
            }
133
          }
134
        },
135
        "500": {
136
          "description": "Internal error",
137
          "schema": {
138
            "$ref": "../definitions.json#/error"
139
          }
140
        },
141
        "503": {
142
          "description": "Under maintenance",
143
          "schema": {
144
            "$ref": "../definitions.json#/error"
145
          }
146
        }
147
      }
148
    },
149
    "post": {
150
      "x-mojo-to": "Library#add",
151
      "operationId": "addLibrary",
152
      "tags": ["library"],
153
      "parameters": [{
154
        "name": "body",
155
        "in": "body",
156
        "description": "A JSON object containing informations about the new library",
157
        "required": true,
158
        "schema": {
159
          "$ref": "../definitions.json#/library"
160
        }
161
      }],
162
      "produces": [
163
        "application/json"
164
      ],
165
      "responses": {
166
        "201": {
167
          "description": "Library added",
168
          "schema": {
169
            "$ref": "../definitions.json#/library"
170
          }
171
        },
172
        "400": {
173
          "description": "Bad request",
174
          "schema": {
175
            "$ref": "../definitions.json#/error"
176
          }
177
        },
178
        "401": {
179
          "description": "Authentication required",
180
          "schema": {
181
            "$ref": "../definitions.json#/error"
182
          }
183
        },
184
        "403": {
185
          "description": "Access forbidden",
186
          "schema": {
187
            "$ref": "../definitions.json#/error"
188
          }
189
        },
190
        "500": {
191
          "description": "Internal error",
192
          "schema": {
193
            "$ref": "../definitions.json#/error"
194
          }
195
        },
196
        "503": {
197
          "description": "Under maintenance",
198
          "schema": {
199
            "$ref": "../definitions.json#/error"
200
          }
201
        }
202
      },
203
      "x-koha-authorization": {
204
        "permissions": {
205
          "parameters": "parameters_remaining_permissions"
206
        }
207
      }
208
    }
209
  },
210
  "/libraries/{branchcode}": {
211
    "get": {
212
      "x-mojo-to": "Library#get",
213
      "operationId": "getLibrary",
214
      "tags": ["library"],
215
      "parameters": [
216
        {
217
          "$ref": "../parameters.json#/branchcodePathParam"
218
        }
219
      ],
220
      "produces": [
221
        "application/json"
222
      ],
223
      "responses": {
224
        "200": {
225
          "description": "A library",
226
          "schema": {
227
            "$ref": "../definitions.json#/library"
228
          }
229
        },
230
        "404": {
231
          "description": "Library not found",
232
          "schema": {
233
            "$ref": "../definitions.json#/error"
234
          }
235
        }
236
      }
237
    },
238
    "put": {
239
      "x-mojo-to": "Library#update",
240
      "operationId": "updateLibrary",
241
      "tags": ["library"],
242
      "parameters": [{
243
        "$ref": "../parameters.json#/branchcodePathParam"
244
      }, {
245
        "name": "body",
246
        "in": "body",
247
        "description": "A JSON object containing information on the library",
248
        "required": true,
249
        "schema": {
250
          "$ref": "../definitions.json#/library"
251
        }
252
      }],
253
      "consumes": [
254
        "application/json"
255
      ],
256
      "produces": [
257
        "application/json"
258
      ],
259
      "responses": {
260
        "200": {
261
          "description": "A library",
262
          "schema": {
263
            "$ref": "../definitions.json#/library"
264
          }
265
        },
266
        "400": {
267
          "description": "Bad request",
268
          "schema": {
269
            "$ref": "../definitions.json#/error"
270
          }
271
        },
272
        "401": {
273
          "description": "Authentication required",
274
          "schema": {
275
            "$ref": "../definitions.json#/error"
276
          }
277
        },
278
        "403": {
279
          "description": "Access forbidden",
280
          "schema": {
281
            "$ref": "../definitions.json#/error"
282
          }
283
        },
284
        "404": {
285
          "description": "Library not found",
286
          "schema": {
287
            "$ref": "../definitions.json#/error"
288
          }
289
        },
290
        "500": {
291
          "description": "Internal error",
292
          "schema": {
293
            "$ref": "../definitions.json#/error"
294
          }
295
        },
296
        "503": {
297
          "description": "Under maintenance",
298
          "schema": {
299
            "$ref": "../definitions.json#/error"
300
          }
301
        }
302
      },
303
      "x-koha-authorization": {
304
        "permissions": {
305
          "parameters": "parameters_remaining_permissions"
306
        }
307
      }
308
    },
309
    "delete": {
310
      "x-mojo-to": "Library#delete",
311
      "operationId": "deleteLibrary",
312
      "tags": ["library"],
313
      "parameters": [{
314
        "$ref": "../parameters.json#/branchcodePathParam"
315
      }],
316
      "produces": [
317
        "application/json"
318
      ],
319
      "responses": {
320
        "204": {
321
          "description": "Library deleted",
322
          "schema": { "type": "string" }
323
        },
324
        "401": {
325
          "description": "Authentication required",
326
          "schema": {
327
            "$ref": "../definitions.json#/error"
328
          }
329
        },
330
        "403": {
331
          "description": "Access forbidden",
332
          "schema": {
333
            "$ref": "../definitions.json#/error"
334
          }
335
        },
336
        "404": {
337
          "description": "Library not found",
338
          "schema": {
339
            "$ref": "../definitions.json#/error"
340
          }
341
        },
342
        "500": {
343
          "description": "Internal error",
344
          "schema": {
345
            "$ref": "../definitions.json#/error"
346
          }
347
        },
348
        "503": {
349
          "description": "Under maintenance",
350
          "schema": {
351
            "$ref": "../definitions.json#/error"
352
          }
353
        }
354
      },
355
      "x-koha-authorization": {
356
        "permissions": {
357
          "parameters": "parameters_remaining_permissions"
358
        }
359
      }
360
    }
361
  }
362
}
(-)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