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

(-)a/Koha/REST/V1/Patron.pm (-92 / +179 lines)
Lines 20-58 use Modern::Perl; Link Here
20
use Mojo::Base 'Mojolicious::Controller';
20
use Mojo::Base 'Mojolicious::Controller';
21
21
22
use C4::Members qw( AddMember ModMember );
22
use C4::Members qw( AddMember ModMember );
23
use Koha::AuthUtils qw(hash_password);
24
use Koha::Patrons;
23
use Koha::Patrons;
25
use Koha::Patron::Categories;
26
use Koha::Patron::Modifications;
27
use Koha::Libraries;
28
24
29
use Scalar::Util qw(blessed);
25
use Scalar::Util qw(blessed);
30
use Try::Tiny;
26
use Try::Tiny;
31
27
32
sub list {
28
=head1 NAME
33
    my $c = shift->openapi->valid_input or return;
34
29
30
Koha::REST::V1::Patron
35
31
36
    my $args   = $c->req->params->to_hash;
32
=head1 API
37
    my $filter = {};
33
38
    for my $filter_param ( keys %$args ) {
34
=head2 Methods
39
        $filter->{$filter_param} = { LIKE => $args->{$filter_param} . "%" };
35
40
    }
36
=head3 list
37
38
Controller function that handles listing Koha::Patron objects
39
40
=cut
41
42
sub list {
43
    my $c = shift->openapi->valid_input or return;
41
44
42
    return try {
45
    return try {
43
        my $patrons = Koha::Patrons->search_limited($filter);
46
        my $patrons_set = Koha::Patrons->new;
44
        return $c->render(status => 200, openapi => $patrons);
47
        my @patrons = $c->objects->search( $patrons_set )->as_list;
48
        return $c->render( status => 200, openapi => \@patrons );
45
    }
49
    }
46
    catch {
50
    catch {
47
        if ( $_->isa('DBIx::Class::Exception') ) {
51
        if ( $_->isa('DBIx::Class::Exception') ) {
48
            return $c->render( status => 500, openapi => { error => $_->{msg} } );
52
            return $c->render( status => 500,
53
                openapi => { error => $_->{msg} } );
49
        }
54
        }
50
        else {
55
        else {
51
            return $c->render( status => 500, openapi => { error => "Something went wrong, check the logs." } );
56
            return $c->render(
57
                status  => 500,
58
                openapi => { error => "Something went wrong, check the logs." }
59
            );
52
        }
60
        }
53
    };
61
    };
54
}
62
}
55
63
64
=head3 get
65
66
Controller function that handles retrieving a single Koha::Patron object
67
68
=cut
69
56
sub get {
70
sub get {
57
    my $c = shift->openapi->valid_input or return;
71
    my $c = shift->openapi->valid_input or return;
58
72
Lines 66-205 sub get { Link Here
66
    return $c->render(status => 200, openapi => $patron);
80
    return $c->render(status => 200, openapi => $patron);
67
}
81
}
68
82
83
=head3 add
84
85
Controller function that handles adding a new Koha::Patron object
86
87
=cut
88
69
sub add {
89
sub add {
70
    my ($c, $args, $cb) = @_;
90
    my $c = shift->openapi->valid_input or return;
71
91
72
    return try {
92
    return try {
73
        my $body = $c->req->json;
93
        my $body = $c->validation->param('body');
74
94
75
        Koha::Patron->new($body)->_validate;
95
        Koha::Patron->new($body)->_validate;
96
76
        # TODO: Use AddMember until it has been moved to Koha-namespace
97
        # TODO: Use AddMember until it has been moved to Koha-namespace
77
        my $borrowernumber = AddMember(%$body);
98
        my $borrowernumber = AddMember(%$body);
78
        my $patron = Koha::Patrons->find($borrowernumber);
99
        my $patron         = Koha::Patrons->find($borrowernumber);
79
100
80
        return $c->$cb($patron, 201);
101
        return $c->render( status => 201, openapi => $patron );
81
    }
102
    }
82
    catch {
103
    catch {
83
        unless (blessed $_ && $_->can('rethrow')) {
104
        unless ( blessed $_ && $_->can('rethrow') ) {
84
            return $c->$cb({ error =>
105
            return $c->render(
85
                "Something went wrong, check Koha logs for details."}, 500);
106
                status  => 500,
107
                openapi => {
108
                    error => "Something went wrong, check Koha logs for details."
109
                }
110
            );
86
        }
111
        }
87
        if ($_->isa('Koha::Exceptions::Patron::DuplicateObject')) {
112
        if ( $_->isa('Koha::Exceptions::Patron::DuplicateObject') ) {
88
            return $c->$cb({ error => $_->error, conflict => $_->conflict }, 409);
113
            return $c->render(
114
                status  => 409,
115
                openapi => { error => $_->error, conflict => $_->conflict }
116
            );
89
        }
117
        }
90
        elsif ($_->isa('Koha::Exceptions::Library::BranchcodeNotFound')) {
118
        elsif ( $_->isa('Koha::Exceptions::Library::BranchcodeNotFound') ) {
91
            return $c->$cb({ error => "Given branchcode does not exist" }, 400);
119
            return $c->render(
120
                status  => 400,
121
                openapi => { error => "Given branchcode does not exist" }
122
            );
92
        }
123
        }
93
        elsif ($_->isa('Koha::Exceptions::Category::CategorycodeNotFound')) {
124
        elsif ( $_->isa('Koha::Exceptions::Category::CategorycodeNotFound') ) {
94
            return $c->$cb({ error => "Given categorycode does not exist"}, 400);
125
            return $c->render(
126
                status  => 400,
127
                openapi => { error => "Given categorycode does not exist" }
128
            );
95
        }
129
        }
96
        else {
130
        else {
97
            return $c->$cb({ error =>
131
            return $c->render(
98
                "Something went wrong, check Koha logs for details."}, 500);
132
                status  => 500,
133
                openapi => {
134
                    error => "Something went wrong, check Koha logs for details."
135
                }
136
            );
99
        }
137
        }
100
    };
138
    };
101
}
139
}
102
140
103
sub edit {
141
=head3 update
104
    my ($c, $args, $cb) = @_;
142
143
Controller function that handles updating a Koha::Patron object
144
145
=cut
146
147
sub update {
148
    my $c = shift->openapi->valid_input or return;
149
150
    my $patron = Koha::Patrons->find( $c->validation->param('borrowernumber') );
105
151
106
    my $patron;
107
    return try {
152
    return try {
108
        my $user = $c->stash('koha.user');
153
        my $body = $c->validation->param('body');
109
        $patron = Koha::Patrons->find($args->{borrowernumber});
154
110
        my $body = $c->req->json;
155
        $patron->set( _to_model($body) )->_validate;
111
156
112
        $body->{borrowernumber} = $args->{borrowernumber};
157
        # TODO: Use ModMember until it has been moved to Koha-namespace
113
158
        if ( ModMember(%$body) ) {
114
        if (!C4::Auth::haspermission($user->userid, { borrowers => 1 }) &&
159
            return $c->render( status => 200, openapi => $patron );
115
            $user->borrowernumber == $patron->borrowernumber){
116
            if (C4::Context->preference('OPACPatronDetails')) {
117
                $body = _delete_unmodifiable_parameters($body);
118
                die unless $patron->set($body)->_validate;
119
                my $m = Koha::Patron::Modification->new($body)->store();
120
                return $c->$cb({}, 202);
121
            } else {
122
                return $c->$cb({ error => "You need a permission to change"
123
                                ." Your personal details"}, 403);
124
            }
125
        }
160
        }
126
        else {
161
        else {
127
            delete $body->{borrowernumber};
162
            return $c->render(
128
            die unless $patron->set($body)->_validate;
163
                status  => 500,
129
            # TODO: Use ModMember until it has been moved to Koha-namespace
164
                openapi => {
130
            $body->{borrowernumber} = $args->{borrowernumber};
165
                    error => 'Something went wrong, check Koha logs for details.'
131
            die unless ModMember(%$body);
166
                }
132
            return $c->$cb($patron, 200);
167
            );
133
        }
168
        }
134
    }
169
    }
135
    catch {
170
    catch {
136
        unless ($patron) {
171
        unless ($patron) {
137
            return $c->$cb({error => "Patron not found"}, 404);
172
            return $c->render(
173
                status  => 404,
174
                openapi => { error => "Patron not found" }
175
            );
138
        }
176
        }
139
        unless (blessed $_ && $_->can('rethrow')) {
177
        unless ( blessed $_ && $_->can('rethrow') ) {
140
            return $c->$cb({ error =>
178
            return $c->render(
141
                "Something went wrong, check Koha logs for details."}, 500);
179
                status  => 500,
180
                openapi => {
181
                    error => "Something went wrong, check Koha logs for details."
182
                }
183
            );
142
        }
184
        }
143
        if ($_->isa('Koha::Exceptions::Patron::DuplicateObject')) {
185
        if ( $_->isa('Koha::Exceptions::Patron::DuplicateObject') ) {
144
            return $c->$cb({ error => $_->error, conflict => $_->conflict }, 409);
186
            return $c->render(
187
                status  => 409,
188
                openapi => { error => $_->error, conflict => $_->conflict }
189
            );
145
        }
190
        }
146
        elsif ($_->isa('Koha::Exceptions::Library::BranchcodeNotFound')) {
191
        elsif ( $_->isa('Koha::Exceptions::Library::BranchcodeNotFound') ) {
147
            return $c->$cb({ error => "Given branchcode does not exist" }, 400);
192
            return $c->render(
193
                status  => 400,
194
                openapi => { error => "Given branchcode does not exist" }
195
            );
148
        }
196
        }
149
        elsif ($_->isa('Koha::Exceptions::Category::CategorycodeNotFound')) {
197
        elsif ( $_->isa('Koha::Exceptions::Category::CategorycodeNotFound') ) {
150
            return $c->$cb({ error => "Given categorycode does not exist"}, 400);
198
            return $c->render(
199
                status  => 400,
200
                openapi => { error => "Given categorycode does not exist" }
201
            );
151
        }
202
        }
152
        elsif ($_->isa('Koha::Exceptions::MissingParameter')) {
203
        elsif ( $_->isa('Koha::Exceptions::MissingParameter') ) {
153
            return $c->$cb({error => "Missing mandatory parameter(s)",
204
            return $c->render(
154
                            parameters => $_->parameter }, 400);
205
                status  => 400,
206
                openapi => {
207
                    error      => "Missing mandatory parameter(s)",
208
                    parameters => $_->parameter
209
                }
210
            );
155
        }
211
        }
156
        elsif ($_->isa('Koha::Exceptions::BadParameter')) {
212
        elsif ( $_->isa('Koha::Exceptions::BadParameter') ) {
157
            return $c->$cb({error => "Invalid parameter(s)",
213
            return $c->render(
158
                            parameters => $_->parameter }, 400);
214
                status  => 400,
215
                openapi => {
216
                    error      => "Invalid parameter(s)",
217
                    parameters => $_->parameter
218
                }
219
            );
159
        }
220
        }
160
        elsif ($_->isa('Koha::Exceptions::NoChanges')) {
221
        elsif ( $_->isa('Koha::Exceptions::NoChanges') ) {
161
            return $c->$cb({error => "No changes have been made"}, 204);
222
            return $c->render(
223
                status  => 204,
224
                openapi => { error => "No changes have been made" }
225
            );
162
        }
226
        }
163
        else {
227
        else {
164
            return $c->$cb({ error =>
228
            return $c->render(
165
                "Something went wrong, check Koha logs for details."}, 500);
229
                status  => 500,
230
                openapi => {
231
                    error =>
232
                      "Something went wrong, check Koha logs for details."
233
                }
234
            );
166
        }
235
        }
167
    };
236
    };
168
}
237
}
169
238
239
=head3 delete
240
241
Controller function that handles deleting a Koha::Patron object
242
243
=cut
244
170
sub delete {
245
sub delete {
171
    my ($c, $args, $cb) = @_;
246
    my $c = shift->openapi->valid_input or return;
172
247
173
    my $patron;
248
    my $patron;
174
249
175
    return try {
250
    return try {
176
        $patron = Koha::Patrons->find($args->{borrowernumber});
251
        $patron = Koha::Patrons->find( $c->validation->param('borrowernumber') );
252
177
        # check if loans, reservations, debarrment, etc. before deletion!
253
        # check if loans, reservations, debarrment, etc. before deletion!
178
        my $res = $patron->delete;
254
        my $res = $patron->delete;
179
255
        return $c->render( status => 200, openapi => {} );
180
        return $c->$cb({}, 200);
181
    }
256
    }
182
    catch {
257
    catch {
183
        unless ($patron) {
258
        unless ($patron) {
184
            return $c->$cb({error => "Patron not found"}, 404);
259
            return $c->render(
260
                status  => 404,
261
                openapi => { error => "Patron not found" }
262
            );
185
        }
263
        }
186
        else {
264
        else {
187
            return $c->$cb({ error =>
265
            return $c->render(
188
                "Something went wrong, check Koha logs for details."}, 500);
266
                status  => 500,
267
                openapi => {
268
                    error =>
269
                      "Something went wrong, check Koha logs for details."
270
                }
271
            );
189
        }
272
        }
190
    };
273
    };
191
}
274
}
192
275
193
sub _delete_unmodifiable_parameters {
276
=head3 _to_model
194
    my ($body) = @_;
195
277
196
    my %columns = map { $_ => 1 } Koha::Patron::Modifications->columns;
278
Helper function that maps REST api objects into Koha::Patron
197
    foreach my $param (keys %$body) {
279
attribute names.
198
        unless (exists $columns{$param}) {
280
199
            delete $body->{$param};
281
=cut
200
        }
282
201
    }
283
sub _to_model {
202
    return $body;
284
    my $params = shift;
285
286
    $params->{lost} = ($params->{lost}) ? 1 : 0;
287
    $params->{gonenoaddress} = ($params->{gonenoaddress}) ? 1 : 0;
288
289
    return $params;
203
}
290
}
204
291
205
1;
292
1;
(-)a/api/v1/swagger/paths/patrons.json (-226 / +163 lines)
Lines 10-522 Link Here
10
      "parameters": [{
10
      "parameters": [{
11
        "name": "borrowernumber",
11
        "name": "borrowernumber",
12
        "in": "query",
12
        "in": "query",
13
        "description": "Case insensetive 'starts_with' search on borrowernumber",
13
        "description": "Case insensitive search on borrowernumber",
14
        "required": false,
14
        "required": false,
15
        "type": "string"
15
        "type": "string"
16
      },
16
      }, {
17
      {
18
        "name": "cardnumber",
17
        "name": "cardnumber",
19
        "in": "query",
18
        "in": "query",
20
        "description": "Case insensetive 'starts_with' search on cardnumber",
19
        "description": "Case insensitive search on cardnumber",
21
        "required": false,
20
        "required": false,
22
        "type": "string"
21
        "type": "string"
23
      },
22
      }, {
24
      {
25
        "name": "surname",
23
        "name": "surname",
26
        "in": "query",
24
        "in": "query",
27
        "description": "Case insensetive 'starts_with' search on surname",
25
        "description": "Case insensitive search on surname",
28
        "required": false,
26
        "required": false,
29
        "type": "string"
27
        "type": "string"
30
      },
28
      }, {
31
      {
32
        "name": "firstname",
29
        "name": "firstname",
33
        "in": "query",
30
        "in": "query",
34
        "description": "Case insensetive 'starts_with' search on firstname",
31
        "description": "Case insensitive search on firstname",
35
        "required": false,
32
        "required": false,
36
        "type": "string"
33
        "type": "string"
37
      },
34
      }, {
38
      {
39
        "name": "title",
35
        "name": "title",
40
        "in": "query",
36
        "in": "query",
41
        "description": "Case insensetive 'starts_with' search on title",
37
        "description": "Case insensitive search on title",
42
        "required": false,
38
        "required": false,
43
        "type": "string"
39
        "type": "string"
44
      },
40
      }, {
45
      {
46
        "name": "othernames",
41
        "name": "othernames",
47
        "in": "query",
42
        "in": "query",
48
        "description": "Case insensetive 'starts_with' search on othernames",
43
        "description": "Case insensitive search on othernames",
49
        "required": false,
44
        "required": false,
50
        "type": "string"
45
        "type": "string"
51
      },
46
      }, {
52
      {
53
        "name": "initials",
47
        "name": "initials",
54
        "in": "query",
48
        "in": "query",
55
        "description": "Case insensetive 'starts_with' search on initials",
49
        "description": "Case insensitive search on initials",
56
        "required": false,
50
        "required": false,
57
        "type": "string"
51
        "type": "string"
58
      },
52
      }, {
59
      {
60
        "name": "streetnumber",
53
        "name": "streetnumber",
61
        "in": "query",
54
        "in": "query",
62
        "description": "Case insensetive 'starts_with' search on streetnumber",
55
        "description": "Case insensitive search on streetnumber",
63
        "required": false,
56
        "required": false,
64
        "type": "string"
57
        "type": "string"
65
      },
58
      }, {
66
      {
67
        "name": "streettype",
59
        "name": "streettype",
68
        "in": "query",
60
        "in": "query",
69
        "description": "Case insensetive 'starts_with' search on streettype",
61
        "description": "Case insensitive search on streettype",
70
        "required": false,
62
        "required": false,
71
        "type": "string"
63
        "type": "string"
72
      },
64
      }, {
73
      {
74
        "name": "address",
65
        "name": "address",
75
        "in": "query",
66
        "in": "query",
76
        "description": "Case insensetive 'starts_with' search on address",
67
        "description": "Case insensitive search on address",
77
        "required": false,
68
        "required": false,
78
        "type": "string"
69
        "type": "string"
79
      },
70
      }, {
80
      {
81
        "name": "address2",
71
        "name": "address2",
82
        "in": "query",
72
        "in": "query",
83
        "description": "Case insensetive 'starts_with' search on address2",
73
        "description": "Case insensitive search on address2",
84
        "required": false,
74
        "required": false,
85
        "type": "string"
75
        "type": "string"
86
      },
76
      }, {
87
      {
88
        "name": "city",
77
        "name": "city",
89
        "in": "query",
78
        "in": "query",
90
        "description": "Case insensetive 'starts_with' search on city",
79
        "description": "Case insensitive search on city",
91
        "required": false,
80
        "required": false,
92
        "type": "string"
81
        "type": "string"
93
      },
82
      }, {
94
      {
95
        "name": "state",
83
        "name": "state",
96
        "in": "query",
84
        "in": "query",
97
        "description": "Case insensetive 'starts_with' search on state",
85
        "description": "Case insensitive search on state",
98
        "required": false,
86
        "required": false,
99
        "type": "string"
87
        "type": "string"
100
      },
88
      }, {
101
      {
102
        "name": "zipcode",
89
        "name": "zipcode",
103
        "in": "query",
90
        "in": "query",
104
        "description": "Case insensetive 'starts_with' search on zipcode",
91
        "description": "Case insensitive search on zipcode",
105
        "required": false,
92
        "required": false,
106
        "type": "string"
93
        "type": "string"
107
      },
94
      }, {
108
      {
109
        "name": "country",
95
        "name": "country",
110
        "in": "query",
96
        "in": "query",
111
        "description": "Case insensetive 'starts_with' search on country",
97
        "description": "Case insensitive search on country",
112
        "required": false,
98
        "required": false,
113
        "type": "string"
99
        "type": "string"
114
      },
100
      }, {
115
      {
116
        "name": "email",
101
        "name": "email",
117
        "in": "query",
102
        "in": "query",
118
        "description": "Case insensetive 'starts_with' search on email",
103
        "description": "Case insensitive search on email",
119
        "required": false,
104
        "required": false,
120
        "type": "string"
105
        "type": "string"
121
      },
106
      }, {
122
      {
123
        "name": "phone",
107
        "name": "phone",
124
        "in": "query",
108
        "in": "query",
125
        "description": "Case insensetive 'starts_with' search on phone",
109
        "description": "Case insensitive search on phone",
126
        "required": false,
110
        "required": false,
127
        "type": "string"
111
        "type": "string"
128
      },
112
      }, {
129
      {
130
        "name": "mobile",
113
        "name": "mobile",
131
        "in": "query",
114
        "in": "query",
132
        "description": "Case insensetive 'starts_with' search on mobile",
115
        "description": "Case insensitive search on mobile",
133
        "required": false,
116
        "required": false,
134
        "type": "string"
117
        "type": "string"
135
      },
118
      }, {
136
      {
137
        "name": "fax",
119
        "name": "fax",
138
        "in": "query",
120
        "in": "query",
139
        "description": "Case insensetive 'starts_with' search on fax",
121
        "description": "Case insensitive search on fax",
140
        "required": false,
122
        "required": false,
141
        "type": "string"
123
        "type": "string"
142
      },
124
      }, {
143
      {
144
        "name": "emailpro",
125
        "name": "emailpro",
145
        "in": "query",
126
        "in": "query",
146
        "description": "Case insensetive 'starts_with' search on emailpro",
127
        "description": "Case insensitive search on emailpro",
147
        "required": false,
128
        "required": false,
148
        "type": "string"
129
        "type": "string"
149
      },
130
      }, {
150
      {
151
        "name": "phonepro",
131
        "name": "phonepro",
152
        "in": "query",
132
        "in": "query",
153
        "description": "Case insensetive 'starts_with' search on phonepro",
133
        "description": "Case insensitive search on phonepro",
154
        "required": false,
134
        "required": false,
155
        "type": "string"
135
        "type": "string"
156
      },
136
      }, {
157
      {
158
        "name": "B_streetnumber",
137
        "name": "B_streetnumber",
159
        "in": "query",
138
        "in": "query",
160
        "description": "Case insensetive 'starts_with' search on B_streetnumber",
139
        "description": "Case insensitive search on B_streetnumber",
161
        "required": false,
140
        "required": false,
162
        "type": "string"
141
        "type": "string"
163
      },
142
      }, {
164
      {
165
        "name": "B_streettype",
143
        "name": "B_streettype",
166
        "in": "query",
144
        "in": "query",
167
        "description": "Case insensetive 'starts_with' search on B_streettype",
145
        "description": "Case insensitive search on B_streettype",
168
        "required": false,
146
        "required": false,
169
        "type": "string"
147
        "type": "string"
170
      },
148
      }, {
171
      {
172
        "name": "B_address",
149
        "name": "B_address",
173
        "in": "query",
150
        "in": "query",
174
        "description": "Case insensetive 'starts_with' search on B_address",
151
        "description": "Case insensitive search on B_address",
175
        "required": false,
152
        "required": false,
176
        "type": "string"
153
        "type": "string"
177
      },
154
      }, {
178
      {
179
        "name": "B_address2",
155
        "name": "B_address2",
180
        "in": "query",
156
        "in": "query",
181
        "description": "Case insensetive 'starts_with' search on B_address2",
157
        "description": "Case insensitive search on B_address2",
182
        "required": false,
158
        "required": false,
183
        "type": "string"
159
        "type": "string"
184
      },
160
      }, {
185
      {
186
        "name": "B_city",
161
        "name": "B_city",
187
        "in": "query",
162
        "in": "query",
188
        "description": "Case insensetive 'starts_with' search on B_city",
163
        "description": "Case insensitive search on B_city",
189
        "required": false,
164
        "required": false,
190
        "type": "string"
165
        "type": "string"
191
      },
166
      }, {
192
      {
193
        "name": "B_state",
167
        "name": "B_state",
194
        "in": "query",
168
        "in": "query",
195
        "description": "Case insensetive 'starts_with' search on B_state",
169
        "description": "Case insensitive search on B_state",
196
        "required": false,
170
        "required": false,
197
        "type": "string"
171
        "type": "string"
198
      },
172
      }, {
199
      {
200
        "name": "B_zipcode",
173
        "name": "B_zipcode",
201
        "in": "query",
174
        "in": "query",
202
        "description": "Case insensetive 'starts_with' search on B_zipcode",
175
        "description": "Case insensitive search on B_zipcode",
203
        "required": false,
176
        "required": false,
204
        "type": "string"
177
        "type": "string"
205
      },
178
      }, {
206
      {
207
        "name": "B_country",
179
        "name": "B_country",
208
        "in": "query",
180
        "in": "query",
209
        "description": "Case insensetive 'starts_with' search on B_country",
181
        "description": "Case insensitive search on B_country",
210
        "required": false,
182
        "required": false,
211
        "type": "string"
183
        "type": "string"
212
      },
184
      }, {
213
      {
214
        "name": "B_email",
185
        "name": "B_email",
215
        "in": "query",
186
        "in": "query",
216
        "description": "Case insensetive 'starts_with' search on B_email",
187
        "description": "Case insensitive search on B_email",
217
        "required": false,
188
        "required": false,
218
        "type": "string"
189
        "type": "string"
219
      },
190
      }, {
220
      {
221
        "name": "B_phone",
191
        "name": "B_phone",
222
        "in": "query",
192
        "in": "query",
223
        "description": "Case insensetive 'starts_with' search on B_phone",
193
        "description": "Case insensitive search on B_phone",
224
        "required": false,
194
        "required": false,
225
        "type": "string"
195
        "type": "string"
226
      },
196
      }, {
227
      {
228
        "name": "dateofbirth",
197
        "name": "dateofbirth",
229
        "in": "query",
198
        "in": "query",
230
        "description": "Case insensetive 'starts_with' search on dateofbirth",
199
        "description": "Case insensitive search on dateofbirth",
231
        "required": false,
200
        "required": false,
232
        "type": "string"
201
        "type": "string"
233
      },
202
      }, {
234
      {
235
        "name": "branchcode",
203
        "name": "branchcode",
236
        "in": "query",
204
        "in": "query",
237
        "description": "Case insensetive 'starts_with' search on branchcode",
205
        "description": "Case insensitive search on branchcode",
238
        "required": false,
206
        "required": false,
239
        "type": "string"
207
        "type": "string"
240
      },
208
      }, {
241
      {
242
        "name": "categorycode",
209
        "name": "categorycode",
243
        "in": "query",
210
        "in": "query",
244
        "description": "Case insensetive 'starts_with' search on categorycode",
211
        "description": "Case insensitive search on categorycode",
245
        "required": false,
212
        "required": false,
246
        "type": "string"
213
        "type": "string"
247
      },
214
      }, {
248
      {
249
        "name": "dateenrolled",
215
        "name": "dateenrolled",
250
        "in": "query",
216
        "in": "query",
251
        "description": "Case insensetive 'starts_with' search on dateenrolled",
217
        "description": "Case insensitive search on dateenrolled",
252
        "required": false,
218
        "required": false,
253
        "type": "string"
219
        "type": "string"
254
      },
220
      }, {
255
      {
256
        "name": "dateexpiry",
221
        "name": "dateexpiry",
257
        "in": "query",
222
        "in": "query",
258
        "description": "Case insensetive 'starts_with' search on dateexpiry",
223
        "description": "Case insensitive search on dateexpiry",
259
        "required": false,
224
        "required": false,
260
        "type": "string"
225
        "type": "string"
261
      },
226
      }, {
262
      {
263
        "name": "gonenoaddress",
227
        "name": "gonenoaddress",
264
        "in": "query",
228
        "in": "query",
265
        "description": "Case insensetive 'starts_with' search on gonenoaddress",
229
        "description": "Search on gonenoaddress",
266
        "required": false,
230
        "required": false,
267
        "type": "string"
231
        "type": "boolean"
268
      },
232
      }, {
269
      {
270
        "name": "lost",
233
        "name": "lost",
271
        "in": "query",
234
        "in": "query",
272
        "description": "Case insensetive 'starts_with' search on lost",
235
        "description": "Search on lost",
273
        "required": false,
236
        "required": false,
274
        "type": "string"
237
        "type": "boolean"
275
      },
238
      }, {
276
      {
277
        "name": "debarred",
239
        "name": "debarred",
278
        "in": "query",
240
        "in": "query",
279
        "description": "Case insensetive 'starts_with' search on debarred",
241
        "description": "Case insensitive search on debarred",
280
        "required": false,
242
        "required": false,
281
        "type": "string"
243
        "type": "string"
282
      },
244
      }, {
283
      {
284
        "name": "debarredcomment",
245
        "name": "debarredcomment",
285
        "in": "query",
246
        "in": "query",
286
        "description": "Case insensetive 'starts_with' search on debarredcomment",
247
        "description": "Case insensitive search on debarredcomment",
287
        "required": false,
248
        "required": false,
288
        "type": "string"
249
        "type": "string"
289
      },
250
      }, {
290
      {
291
        "name": "contactname",
251
        "name": "contactname",
292
        "in": "query",
252
        "in": "query",
293
        "description": "Case insensetive 'starts_with' search on contactname",
253
        "description": "Case insensitive search on contactname",
294
        "required": false,
254
        "required": false,
295
        "type": "string"
255
        "type": "string"
296
      },
256
      }, {
297
      {
298
        "name": "contactfirstname",
257
        "name": "contactfirstname",
299
        "in": "query",
258
        "in": "query",
300
        "description": "Case insensetive 'starts_with' search on contactfirstname",
259
        "description": "Case insensitive search on contactfirstname",
301
        "required": false,
260
        "required": false,
302
        "type": "string"
261
        "type": "string"
303
      },
262
      }, {
304
      {
305
        "name": "contacttitle",
263
        "name": "contacttitle",
306
        "in": "query",
264
        "in": "query",
307
        "description": "Case insensetive 'starts_with' search on contacttitle",
265
        "description": "Case insensitive search on contacttitle",
308
        "required": false,
266
        "required": false,
309
        "type": "string"
267
        "type": "string"
310
      },
268
      }, {
311
      {
312
        "name": "guarantorid",
269
        "name": "guarantorid",
313
        "in": "query",
270
        "in": "query",
314
        "description": "Case insensetive 'starts_with' search on guarantorid",
271
        "description": "Case insensitive search on guarantorid",
315
        "required": false,
272
        "required": false,
316
        "type": "string"
273
        "type": "string"
317
      },
274
      }, {
318
      {
319
        "name": "borrowernotes",
275
        "name": "borrowernotes",
320
        "in": "query",
276
        "in": "query",
321
        "description": "Case insensetive 'starts_with' search on borrowernotes",
277
        "description": "Case insensitive search on borrowernotes",
322
        "required": false,
278
        "required": false,
323
        "type": "string"
279
        "type": "string"
324
      },
280
      }, {
325
      {
326
        "name": "relationship",
281
        "name": "relationship",
327
        "in": "query",
282
        "in": "query",
328
        "description": "Case insensetive 'starts_with' search on relationship",
283
        "description": "Case insensitive search on relationship",
329
        "required": false,
284
        "required": false,
330
        "type": "string"
285
        "type": "string"
331
      },
286
      }, {
332
      {
333
        "name": "sex",
287
        "name": "sex",
334
        "in": "query",
288
        "in": "query",
335
        "description": "Case insensetive 'starts_with' search on sex",
289
        "description": "Case insensitive search on sex",
336
        "required": false,
290
        "required": false,
337
        "type": "string"
291
        "type": "string"
338
      },
292
      }, {
339
      {
340
        "name": "password",
293
        "name": "password",
341
        "in": "query",
294
        "in": "query",
342
        "description": "Case insensetive 'starts_with' search on password",
295
        "description": "Case insensitive search on password",
343
        "required": false,
296
        "required": false,
344
        "type": "string"
297
        "type": "string"
345
      },
298
      }, {
346
      {
347
        "name": "flags",
299
        "name": "flags",
348
        "in": "query",
300
        "in": "query",
349
        "description": "Case insensetive 'starts_with' search on flags",
301
        "description": "Case insensitive search on flags",
350
        "required": false,
302
        "required": false,
351
        "type": "string"
303
        "type": "string"
352
      },
304
      }, {
353
      {
354
        "name": "userid",
305
        "name": "userid",
355
        "in": "query",
306
        "in": "query",
356
        "description": "Case insensetive 'starts_with' search on userid",
307
        "description": "Case insensitive search on userid",
357
        "required": false,
308
        "required": false,
358
        "type": "string"
309
        "type": "string"
359
      },
310
      }, {
360
      {
361
        "name": "opacnote",
311
        "name": "opacnote",
362
        "in": "query",
312
        "in": "query",
363
        "description": "Case insensetive 'starts_with' search on opacnote",
313
        "description": "Case insensitive search on opacnote",
364
        "required": false,
314
        "required": false,
365
        "type": "string"
315
        "type": "string"
366
      },
316
      }, {
367
      {
368
        "name": "contactnote",
317
        "name": "contactnote",
369
        "in": "query",
318
        "in": "query",
370
        "description": "Case insensetive 'starts_with' search on contactnote",
319
        "description": "Case insensitive search on contactnote",
371
        "required": false,
320
        "required": false,
372
        "type": "string"
321
        "type": "string"
373
      },
322
      }, {
374
      {
375
        "name": "sort1",
323
        "name": "sort1",
376
        "in": "query",
324
        "in": "query",
377
        "description": "Case insensetive 'starts_with' search on sort1",
325
        "description": "Case insensitive search on sort1",
378
        "required": false,
326
        "required": false,
379
        "type": "string"
327
        "type": "string"
380
      },
328
      }, {
381
      {
382
        "name": "sort2",
329
        "name": "sort2",
383
        "in": "query",
330
        "in": "query",
384
        "description": "Case insensetive 'starts_with' search on sort2",
331
        "description": "Case insensitive search on sort2",
385
        "required": false,
332
        "required": false,
386
        "type": "string"
333
        "type": "string"
387
      },
334
      }, {
388
      {
389
        "name": "altcontactfirstname",
335
        "name": "altcontactfirstname",
390
        "in": "query",
336
        "in": "query",
391
        "description": "Case insensetive 'starts_with' search on altcontactfirstname",
337
        "description": "Case insensitive search on altcontactfirstname",
392
        "required": false,
338
        "required": false,
393
        "type": "string"
339
        "type": "string"
394
      },
340
      }, {
395
      {
396
        "name": "altcontactsurname",
341
        "name": "altcontactsurname",
397
        "in": "query",
342
        "in": "query",
398
        "description": "Case insensetive 'starts_with' search on altcontactsurname",
343
        "description": "Case insensitive search on altcontactsurname",
399
        "required": false,
344
        "required": false,
400
        "type": "string"
345
        "type": "string"
401
      },
346
      }, {
402
      {
403
        "name": "altcontactaddress1",
347
        "name": "altcontactaddress1",
404
        "in": "query",
348
        "in": "query",
405
        "description": "Case insensetive 'starts_with' search on altcontactaddress1",
349
        "description": "Case insensitive search on altcontactaddress1",
406
        "required": false,
350
        "required": false,
407
        "type": "string"
351
        "type": "string"
408
      },
352
      }, {
409
      {
410
        "name": "altcontactaddress2",
353
        "name": "altcontactaddress2",
411
        "in": "query",
354
        "in": "query",
412
        "description": "Case insensetive 'starts_with' search on altcontactaddress2",
355
        "description": "Case insensitive search on altcontactaddress2",
413
        "required": false,
356
        "required": false,
414
        "type": "string"
357
        "type": "string"
415
      },
358
      }, {
416
      {
417
        "name": "altcontactaddress3",
359
        "name": "altcontactaddress3",
418
        "in": "query",
360
        "in": "query",
419
        "description": "Case insensetive 'starts_with' search on altcontactaddress3",
361
        "description": "Case insensitive search on altcontactaddress3",
420
        "required": false,
362
        "required": false,
421
        "type": "string"
363
        "type": "string"
422
      },
364
      }, {
423
      {
424
        "name": "altcontactstate",
365
        "name": "altcontactstate",
425
        "in": "query",
366
        "in": "query",
426
        "description": "Case insensetive 'starts_with' search on altcontactstate",
367
        "description": "Case insensitive search on altcontactstate",
427
        "required": false,
368
        "required": false,
428
        "type": "string"
369
        "type": "string"
429
      },
370
      }, {
430
      {
431
        "name": "altcontactzipcode",
371
        "name": "altcontactzipcode",
432
        "in": "query",
372
        "in": "query",
433
        "description": "Case insensetive 'starts_with' search on altcontactzipcode",
373
        "description": "Case insensitive search on altcontactzipcode",
434
        "required": false,
374
        "required": false,
435
        "type": "string"
375
        "type": "string"
436
      },
376
      }, {
437
      {
438
        "name": "altcontactcountry",
377
        "name": "altcontactcountry",
439
        "in": "query",
378
        "in": "query",
440
        "description": "Case insensetive 'starts_with' search on altcontactcountry",
379
        "description": "Case insensitive search on altcontactcountry",
441
        "required": false,
380
        "required": false,
442
        "type": "string"
381
        "type": "string"
443
      },
382
      }, {
444
      {
445
        "name": "altcontactphone",
383
        "name": "altcontactphone",
446
        "in": "query",
384
        "in": "query",
447
        "description": "Case insensetive 'starts_with' search on altcontactphone",
385
        "description": "Case insensitive search on altcontactphone",
448
        "required": false,
386
        "required": false,
449
        "type": "string"
387
        "type": "string"
450
      },
388
      }, {
451
      {
452
        "name": "smsalertnumber",
389
        "name": "smsalertnumber",
453
        "in": "query",
390
        "in": "query",
454
        "description": "Case insensetive 'starts_with' search on smsalertnumber",
391
        "description": "Case insensitive search on smsalertnumber",
455
        "required": false,
392
        "required": false,
456
        "type": "string"
393
        "type": "string"
457
      },
394
      }, {
458
      {
459
        "name": "sms_provider_id",
395
        "name": "sms_provider_id",
460
        "in": "query",
396
        "in": "query",
461
        "description": "Case insensetive 'starts_with' search on sms_provider_id",
397
        "description": "Case insensitive search on sms_provider_id",
462
        "required": false,
398
        "required": false,
463
        "type": "string"
399
        "type": "string"
464
      },
400
      }, {
465
      {
466
        "name": "privacy",
401
        "name": "privacy",
467
        "in": "query",
402
        "in": "query",
468
        "description": "Case insensetive 'starts_with' search on privacy",
403
        "description": "Case insensitive search on privacy",
469
        "required": false,
404
        "required": false,
470
        "type": "string"
405
        "type": "string"
471
      },
406
      }, {
472
      {
473
        "name": "privacy_guarantor_checkouts",
407
        "name": "privacy_guarantor_checkouts",
474
        "in": "query",
408
        "in": "query",
475
        "description": "Case insensetive 'starts_with' search on privacy_guarantor_checkouts",
409
        "description": "Case insensitive search on privacy_guarantor_checkouts",
476
        "required": false,
410
        "required": false,
477
        "type": "string"
411
        "type": "string"
478
      },
412
      }, {
479
      {
480
        "name": "checkprevcheckout",
413
        "name": "checkprevcheckout",
481
        "in": "query",
414
        "in": "query",
482
        "description": "Case insensetive 'starts_with' search on checkprevcheckout",
415
        "description": "Case insensitive search on checkprevcheckout",
483
        "required": false,
416
        "required": false,
484
        "type": "string"
417
        "type": "string"
485
      },
418
      }, {
486
      {
487
        "name": "updated_on",
419
        "name": "updated_on",
488
        "in": "query",
420
        "in": "query",
489
        "description": "Case insensetive 'starts_with' search on updated_on",
421
        "description": "Case insensitive search on updated_on",
490
        "required": false,
422
        "required": false,
491
        "type": "string"
423
        "type": "string"
492
      },
424
      }, {
493
      {
494
        "name": "lastseen",
425
        "name": "lastseen",
495
        "in": "query",
426
        "in": "query",
496
        "description": "Case insensetive 'starts_with' search on lastseen",
427
        "description": "Case insensitive search on lastseen",
497
        "required": false,
428
        "required": false,
498
        "type": "string"
429
        "type": "string"
499
      },
430
      }, {
500
      {
501
        "name": "lang",
431
        "name": "lang",
502
        "in": "query",
432
        "in": "query",
503
        "description": "Case insensetive 'starts_with' search on lang",
433
        "description": "Case insensitive search on lang",
504
        "required": false,
434
        "required": false,
505
        "type": "string"
435
        "type": "string"
506
      },
436
      }, {
507
      {
508
        "name": "login_attempts",
437
        "name": "login_attempts",
509
        "in": "query",
438
        "in": "query",
510
        "description": "Case insensetive 'starts_with' search on login_attempts",
439
        "description": "Case insensitive search on login_attempts",
511
        "required": false,
440
        "required": false,
512
        "type": "string"
441
        "type": "string"
513
      },
442
      }, {
514
      {
515
        "name": "overdrive_auth_token",
443
        "name": "overdrive_auth_token",
516
        "in": "query",
444
        "in": "query",
517
        "description": "Case insensetive 'starts_with' search on overdrive_auth_token",
445
        "description": "Case insensitive search on overdrive_auth_token",
518
        "required": false,
446
        "required": false,
519
        "type": "string"
447
        "type": "string"
448
      }, {
449
        "$ref": "../parameters.json#/match"
450
      }, {
451
        "$ref": "../parameters.json#/order_by"
452
      }, {
453
        "$ref": "../parameters.json#/page"
454
      }, {
455
        "$ref": "../parameters.json#/per_page"
520
      }],
456
      }],
521
      "responses": {
457
      "responses": {
522
        "200": {
458
        "200": {
Lines 554-559 Link Here
554
      }
490
      }
555
    },
491
    },
556
    "post": {
492
    "post": {
493
      "x-mojo-to": "Patron#add",
557
      "operationId": "addPatron",
494
      "operationId": "addPatron",
558
      "tags": ["patrons"],
495
      "tags": ["patrons"],
559
      "parameters": [{
496
      "parameters": [{
Lines 606-619 Link Here
606
            "$ref": "../definitions.json#/error"
543
            "$ref": "../definitions.json#/error"
607
          }
544
          }
608
        },
545
        },
609
        "503": {
546
        "500": {
610
          "description": "Under maintenance",
547
          "description": "Internal server error",
611
          "schema": {
548
          "schema": {
612
            "$ref": "../definitions.json#/error"
549
            "$ref": "../definitions.json#/error"
613
          }
550
          }
614
        },
551
        },
615
        "500": {
552
        "503": {
616
          "description": "Internal server error",
553
          "description": "Under maintenance",
617
          "schema": {
554
          "schema": {
618
            "$ref": "../definitions.json#/error"
555
            "$ref": "../definitions.json#/error"
619
          }
556
          }
Lines 684-690 Link Here
684
      }
621
      }
685
    },
622
    },
686
    "put": {
623
    "put": {
687
      "operationId": "editPatron",
624
      "x-mojo-to": "Patron#update",
625
      "operationId": "updatePatron",
688
      "tags": ["patrons"],
626
      "tags": ["patrons"],
689
      "parameters": [
627
      "parameters": [
690
        {
628
        {
Lines 755-768 Link Here
755
        }
693
        }
756
      },
694
      },
757
      "x-koha-authorization": {
695
      "x-koha-authorization": {
758
        "allow-owner": true,
759
        "allow-guarantor": true,
760
        "permissions": {
696
        "permissions": {
761
          "borrowers": "1"
697
          "borrowers": "1"
762
        }
698
        }
763
      }
699
      }
764
    },
700
    },
765
    "delete": {
701
    "delete": {
702
      "x-mojo-to": "Patron#delete",
766
      "operationId": "deletePatron",
703
      "operationId": "deletePatron",
767
      "tags": ["patrons"],
704
      "tags": ["patrons"],
768
      "parameters": [{
705
      "parameters": [{
(-)a/t/db_dependent/api/v1/patrons.t (-77 / +31 lines)
Lines 19-31 use Modern::Perl; Link Here
19
19
20
use Test::More tests => 5;
20
use Test::More tests => 5;
21
use Test::Mojo;
21
use Test::Mojo;
22
use Test::Warn;
23
22
24
use t::lib::TestBuilder;
23
use t::lib::TestBuilder;
25
use t::lib::Mocks;
24
use t::lib::Mocks;
26
25
27
use C4::Auth;
26
use C4::Auth;
28
use Koha::Cities;
29
use Koha::Database;
27
use Koha::Database;
30
28
31
my $schema  = Koha::Database->new->schema;
29
my $schema  = Koha::Database->new->schema;
Lines 168-174 subtest 'add() tests' => sub { Link Here
168
            authorized => 1 });
166
            authorized => 1 });
169
167
170
        $newpatron->{branchcode} = "nonexistent"; # Test invalid branchcode
168
        $newpatron->{branchcode} = "nonexistent"; # Test invalid branchcode
171
        my $tx = $t->ua->build_tx(POST => "/api/v1/patrons" =>json => $newpatron);
169
        my $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron );
172
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
170
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
173
        $t->request_ok($tx)
171
        $t->request_ok($tx)
174
          ->status_is(400)
172
          ->status_is(400)
Lines 216-307 subtest 'add() tests' => sub { Link Here
216
    $schema->storage->txn_rollback;
214
    $schema->storage->txn_rollback;
217
};
215
};
218
216
219
subtest 'edit() tests' => sub {
217
subtest 'update() tests' => sub {
220
    plan tests => 3;
218
    plan tests => 2;
221
219
222
    $schema->storage->txn_begin;
220
    $schema->storage->txn_begin;
223
221
224
    unauthorized_access_tests('PUT', 123, {email => 'nobody@example.com'});
222
    unauthorized_access_tests('PUT', 123, {email => 'nobody@example.com'});
225
223
226
    subtest 'patron modifying own data' => sub {
227
        plan tests => 7;
228
229
        my ($borrowernumber, $sessionid) = create_user_and_session({
230
            authorized => 0 });
231
        my $patron = Koha::Patrons->find($borrowernumber)->TO_JSON;
232
233
        t::lib::Mocks::mock_preference("OPACPatronDetails", 0);
234
        my $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
235
                            $patron->{borrowernumber} => json => $patron);
236
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
237
        $t->request_ok($tx)
238
          ->status_is(403, 'OPACPatronDetails off - modifications not allowed.');
239
240
        t::lib::Mocks::mock_preference("OPACPatronDetails", 1);
241
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
242
                            $patron->{borrowernumber} => json => $patron);
243
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
244
        $t->request_ok($tx)
245
          ->status_is(204, 'Updating myself with my current data');
246
247
        $patron->{'firstname'} = "noob";
248
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
249
                            $patron->{borrowernumber} => json => $patron);
250
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
251
        $t->request_ok($tx)
252
          ->status_is(202, 'Updating myself with my current data');
253
254
        # Approve changes
255
        Koha::Patron::Modifications->find({
256
            borrowernumber => $patron->{borrowernumber},
257
            firstname => "noob"
258
        })->approve;
259
        is(Koha::Patrons->find({
260
            borrowernumber => $patron->{borrowernumber}})->firstname,
261
           "noob", "Changes approved");
262
    };
263
264
    subtest 'librarian access tests' => sub {
224
    subtest 'librarian access tests' => sub {
265
        plan tests => 20;
225
        plan tests => 20;
266
226
267
        t::lib::Mocks::mock_preference('minPasswordLength', 1);
227
        t::lib::Mocks::mock_preference('minPasswordLength', 1);
268
        my ($borrowernumber, $sessionid) = create_user_and_session({
228
        my ($borrowernumber, $sessionid) = create_user_and_session({ authorized => 1 });
269
            authorized => 1 });
229
        my ($borrowernumber2, undef) = create_user_and_session({ authorized => 0 });
270
        my ($borrowernumber2, undef) = create_user_and_session({
230
271
            authorized => 0 });
231
        my $patron_1  = Koha::Patrons->find($borrowernumber);
272
        my $patron    = Koha::Patrons->find($borrowernumber2);
232
        my $patron_2  = Koha::Patrons->find($borrowernumber2);
273
        my $newpatron = Koha::Patrons->find($borrowernumber2)->TO_JSON;
233
        my $newpatron = $patron_2->TO_JSON;
274
234
275
        my $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/-1" =>
235
        my $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/-1" => json => $newpatron );
276
                                  json => $newpatron);
277
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
236
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
278
        $t->request_ok($tx)
237
        $t->request_ok($tx)
279
          ->status_is(404)
238
          ->status_is(404)
280
          ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
239
          ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
281
240
282
        $newpatron->{categorycode} = 'nonexistent';
241
        $newpatron->{categorycode} = 'nonexistent';
283
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
242
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
284
                    $newpatron->{borrowernumber} => json => $newpatron
285
        );
286
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
243
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
287
        $t->request_ok($tx)
244
        $t->request_ok($tx)
288
          ->status_is(400)
245
          ->status_is(400)
289
          ->json_is('/error' => "Given categorycode does not exist");
246
          ->json_is('/error' => "Given categorycode does not exist");
290
        $newpatron->{categorycode} = $patron->categorycode;
247
        $newpatron->{categorycode} = $patron_2->categorycode;
291
248
292
        $newpatron->{branchcode} = 'nonexistent';
249
        $newpatron->{branchcode} = 'nonexistent';
293
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
250
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
294
                    $newpatron->{borrowernumber} => json => $newpatron
295
        );
296
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
251
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
297
        $t->request_ok($tx)
252
        $t->request_ok($tx)
298
          ->status_is(400)
253
          ->status_is(400)
299
          ->json_is('/error' => "Given branchcode does not exist");
254
          ->json_is('/error' => "Given branchcode does not exist");
300
        $newpatron->{branchcode} = $patron->branchcode;
255
        $newpatron->{branchcode} = $patron_2->branchcode;
301
256
302
        $newpatron->{falseproperty} = "Non existent property";
257
        $newpatron->{falseproperty} = "Non existent property";
303
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
258
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
304
                    $newpatron->{borrowernumber} => json => $newpatron);
305
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
259
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
306
        $t->request_ok($tx)
260
        $t->request_ok($tx)
307
          ->status_is(400)
261
          ->status_is(400)
Lines 309-326 subtest 'edit() tests' => sub { Link Here
309
                    'Properties not allowed: falseproperty.');
263
                    'Properties not allowed: falseproperty.');
310
        delete $newpatron->{falseproperty};
264
        delete $newpatron->{falseproperty};
311
265
312
        $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" .
266
        # Set both cardnumber and userid to already existing values
313
                    $borrowernumber => json => $newpatron);
267
        $newpatron->{cardnumber} = $patron_1->cardnumber;
314
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
268
        $newpatron->{userid}     = $patron_1->userid;
315
        $t->request_ok($tx)
269
316
          ->status_is(409)
270
        $tx = $t->ua->build_tx( PUT => "/api/v1/patrons/$borrowernumber2" => json => $newpatron );
317
          ->json_has('/error' => "Fails when trying to update to an existing"
271
        $tx->req->cookies({ name => 'CGISESSID', value => $sessionid });
318
                     ."cardnumber or userid")
272
        $t->request_ok($tx)->status_is(409)
319
          ->json_has('/conflict', {
273
          ->json_has( '/error' => "Fails when trying to update to an existing cardnumber or userid")
320
                cardnumber => $newpatron->{ cardnumber },
274
          ->json_is(  '/conflict',
321
                userid => $newpatron->{ userid }
275
                        {
322
                }
276
                            cardnumber => $newpatron->{cardnumber},
323
            );
277
                            userid     => $newpatron->{userid}
278
                        }
279
          );
324
280
325
        $newpatron->{ cardnumber } = $borrowernumber.$borrowernumber2;
281
        $newpatron->{ cardnumber } = $borrowernumber.$borrowernumber2;
326
        $newpatron->{ userid } = "user".$borrowernumber.$borrowernumber2;
282
        $newpatron->{ userid } = "user".$borrowernumber.$borrowernumber2;
Lines 390-396 sub unauthorized_access_tests { Link Here
390
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
346
        $tx->req->cookies({name => 'CGISESSID', value => $sessionid});
391
        $t->request_ok($tx)
347
        $t->request_ok($tx)
392
          ->status_is(403)
348
          ->status_is(403)
393
          ->json_is('/required_permissions', {"borrowers" => "1"});
349
          ->json_has('/required_permissions');
394
    };
350
    };
395
}
351
}
396
352
Lines 398-404 sub create_user_and_session { Link Here
398
354
399
    my $args  = shift;
355
    my $args  = shift;
400
    my $flags = ( $args->{authorized} ) ? 16 : 0;
356
    my $flags = ( $args->{authorized} ) ? 16 : 0;
401
    my $dbh   = C4::Context->dbh;
402
357
403
    my $user = $builder->build(
358
    my $user = $builder->build(
404
        {
359
        {
Lines 409-415 sub create_user_and_session { Link Here
409
                lost => 0,
364
                lost => 0,
410
                email => 'nobody@example.com',
365
                email => 'nobody@example.com',
411
                emailpro => 'nobody@example.com',
366
                emailpro => 'nobody@example.com',
412
                B_email => 'nobody@example.com',
367
                B_email => 'nobody@example.com'
413
            }
368
            }
414
        }
369
        }
415
    );
370
    );
416
- 

Return to bug 16330