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

(-)a/Koha/Exceptions.pm (+4 lines)
Lines 21-26 use Exception::Class ( Link Here
21
        isa => 'Koha::Exceptions::Exception',
21
        isa => 'Koha::Exceptions::Exception',
22
        description => 'A required parameter is missing'
22
        description => 'A required parameter is missing'
23
    },
23
    },
24
    'Koha::Exceptions::UnblessedReference' => {
25
        isa => 'Koha::Exceptions::Exception',
26
        description => 'Calling unblessed reference'
27
    },
24
    # Virtualshelves exceptions
28
    # Virtualshelves exceptions
25
    'Koha::Exceptions::Virtualshelves::DuplicateObject' => {
29
    'Koha::Exceptions::Virtualshelves::DuplicateObject' => {
26
        isa => 'Koha::Exceptions::DuplicateObject',
30
        isa => 'Koha::Exceptions::DuplicateObject',
(-)a/Koha/Exceptions/Category.pm (+17 lines)
Line 0 Link Here
1
package Koha::Exceptions::Category;
2
3
use Modern::Perl;
4
5
use Exception::Class (
6
7
    'Koha::Exceptions::Category' => {
8
        description => 'Something went wrong!',
9
    },
10
    'Koha::Exceptions::Category::CategorycodeNotFound' => {
11
        isa => 'Koha::Exceptions::Category',
12
        description => "Category does not exist",
13
        fields => ["categorycode"],
14
    },
15
);
16
17
1;
(-)a/Koha/Exceptions/Library.pm (+17 lines)
Line 0 Link Here
1
package Koha::Exceptions::Library;
2
3
use Modern::Perl;
4
5
use Exception::Class (
6
7
    'Koha::Exceptions::Library' => {
8
        description => 'Something went wrong!',
9
    },
10
    'Koha::Exceptions::Library::BranchcodeNotFound' => {
11
        isa => 'Koha::Exceptions::Library',
12
        description => "Library does not exist",
13
        fields => ["branchcode"],
14
    },
15
);
16
17
1;
(-)a/Koha/Exceptions/Patron.pm (+17 lines)
Line 0 Link Here
1
package Koha::Exceptions::Patron;
2
3
use Modern::Perl;
4
5
use Exception::Class (
6
7
    'Koha::Exceptions::Patron' => {
8
        description => 'Something went wrong!',
9
    },
10
    'Koha::Exceptions::Patron::DuplicateObject' => {
11
        isa => 'Koha::Exceptions::Patron',
12
        description => "Patron cardnumber and userid must be unique",
13
        fields => ["conflict"],
14
    },
15
);
16
17
1;
(-)a/Koha/Patron.pm (+59 lines)
Lines 2-7 package Koha::Patron; Link Here
2
2
3
# Copyright ByWater Solutions 2014
3
# Copyright ByWater Solutions 2014
4
# Copyright PTFS Europe 2016
4
# Copyright PTFS Europe 2016
5
# Copyright Koha-Suomi Oy 2016
5
#
6
#
6
# This file is part of Koha.
7
# This file is part of Koha.
7
#
8
#
Lines 26-32 use C4::Context; Link Here
26
use C4::Log;
27
use C4::Log;
27
use Koha::Database;
28
use Koha::Database;
28
use Koha::DateUtils;
29
use Koha::DateUtils;
30
use Koha::Exceptions;
31
use Koha::Exceptions::Category;
32
use Koha::Exceptions::Library;
33
use Koha::Exceptions::Patron;
29
use Koha::Issues;
34
use Koha::Issues;
35
use Koha::Libraries;
30
use Koha::OldIssues;
36
use Koha::OldIssues;
31
use Koha::Patron::Categories;
37
use Koha::Patron::Categories;
32
use Koha::Patron::Images;
38
use Koha::Patron::Images;
Lines 267-272 sub track_login { Link Here
267
    $self->lastseen( dt_from_string() )->store;
273
    $self->lastseen( dt_from_string() )->store;
268
}
274
}
269
275
276
=head3 validate
277
278
my $patron = $patron->new($body)->validate->store;
279
   $patron = $patron->set($body)->validate->store;
280
281
Validates Koha::Patron object and throws Koha::Exceptions if validation issues
282
are found.
283
284
Throws Koha::Exceptions::UnblessedReference if validate() is called
285
       on an unblessed reference.
286
Throws Koha::Exceptions::Patron::DuplicateObject if trying to add a duplicate.
287
Throws Koha::Exceptions::Library::BranchcodeNotFound if branchcode is not found.
288
Throws Koha::Exceptions::Category::CategorycodeNotFound if categorycode is not
289
       found.
290
291
=cut
292
293
sub validate {
294
    my ($self) = @_;
295
296
    Koha::Exceptions::UnblessedReference->throw(
297
        error => 'validate() must be called on a blessed Koha::Patron object'
298
    ) unless $self && ref($self) eq "Koha::Patron";
299
300
    # patron cardnumber and/or userid unique?
301
    if ($self->cardnumber || $self->userid) {
302
        my $patron = Koha::Patrons->find({cardnumber => $self->cardnumber, userid => $self->userid});
303
        if ($patron && (!$self->in_storage || $self->in_storage
304
            && $self->borrowernumber ne $patron->borrowernumber)) {
305
            Koha::Exceptions::Patron::DuplicateObject->throw(
306
                error => "Patron cardnumber and userid must be unique",
307
                conflict => { cardnumber => $patron->cardnumber, userid => $patron->userid }
308
            );
309
        }
310
    }
311
312
    my $branch = Koha::Libraries->find({branchcode => $self->branchcode });
313
    unless ($branch) {
314
        Koha::Exceptions::Library::BranchcodeNotFound->throw(
315
            error => "Library does not exist",
316
            branchcode => $self->branchcode,
317
        );
318
    }
319
    my $category = Koha::Patron::Categories->find({ categorycode => $self->categorycode });
320
    unless ($category) {
321
        Koha::Exceptions::Category::CategorycodeNotFound->throw(
322
            error => "Patron category does not exist",
323
            categorycode => $self->categorycode,
324
        );
325
    }
326
    return $self;
327
}
328
270
=head3 type
329
=head3 type
271
330
272
=cut
331
=cut
(-)a/Koha/REST/V1/Patron.pm (-84 / +52 lines)
Lines 23-28 use Koha::Patrons; Link Here
23
use Koha::Patron::Categories;
23
use Koha::Patron::Categories;
24
use Koha::Libraries;
24
use Koha::Libraries;
25
25
26
use Scalar::Util qw(blessed);
27
use Try::Tiny;
28
26
sub list {
29
sub list {
27
    my ($c, $args, $cb) = @_;
30
    my ($c, $args, $cb) = @_;
28
31
Lines 55-158 sub get { Link Here
55
sub add {
58
sub add {
56
    my ($c, $args, $cb) = @_;
59
    my ($c, $args, $cb) = @_;
57
60
58
    my $body = $c->req->json;
61
    try {
62
        my $body = $c->req->json;
59
63
60
    # patron cardnumber and/or userid unique?
64
        if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
61
    if ($body->{cardnumber} || $body->{userid}) {
62
        my $patron = Koha::Patrons->find({cardnumber => $body->{cardnumber}, userid => $body->{userid} });
63
        if ($patron) {
64
            return $c->$cb({
65
                error => "Patron cardnumber and userid must be unique",
66
                conflict => { cardnumber => $patron->cardnumber, userid => $patron->userid }
67
            }, 409);
68
        }
69
    }
70
65
71
    my $branch = Koha::Libraries->find({branchcode => $body->{branchcode} });
66
        my $patron = Koha::Patron->new($body)->validate->store;
72
    unless ($branch) {
67
        return $c->$cb($patron->unblessed, 201);
73
        return $c->$cb({error => "Library with branchcode \"" . $body->{branchcode} . "\" does not exist"}, 404);
74
    }
68
    }
75
    my $category = Koha::Patron::Categories->find({ categorycode => $body->{categorycode} });
69
    catch {
76
    unless ($category) {
70
        unless (blessed $_ && $_->can('rethrow')) {
77
        return $c->$cb({error => "Patron category \"" . $body->{categorycode} . "\" does not exist"}, 404);
71
            return $c->$cb({error => "Something went wrong, check Koha logs for details."}, 500);
78
    }
72
        }
79
    # All OK - save new patron
73
        if ($_->isa('Koha::Exceptions::Patron::DuplicateObject')) {
80
74
            return $c->$cb({ error => $_->error, conflict => $_->conflict }, 409);
81
    if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
75
        }
82
76
        elsif ($_->isa('Koha::Exceptions::Library::BranchcodeNotFound')) {
83
    my $patron = eval {
77
            return $c->$cb({ error => "Library with branchcode \"".$_->branchcode."\" does not exist" }, 404);
84
        Koha::Patron->new($body)->store;
78
        }
79
        elsif ($_->isa('Koha::Exceptions::Category::CategorycodeNotFound')) {
80
            return $c->$cb({error => "Patron category \"".$_->categorycode."\" does not exist"}, 404);
81
        }
82
        else {
83
            return $c->$cb({error => "Something went wrong, check Koha logs for details."}, 500);
84
        }
85
    };
85
    };
86
87
    unless ($patron) {
88
        return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
89
    }
90
91
    return $c->$cb($patron->unblessed, 201);
92
}
86
}
93
87
94
sub edit {
88
sub edit {
95
    my ($c, $args, $cb) = @_;
89
    my ($c, $args, $cb) = @_;
96
90
97
    my $patron = Koha::Patrons->find($args->{borrowernumber});
91
    my $patron;
98
    unless ($patron) {
92
    try {
99
        return $c->$cb({error => "Patron not found"}, 404);
93
        $patron = Koha::Patrons->find($args->{borrowernumber});
100
    }
94
        my $body = $c->req->json;
101
95
102
    my $body = $c->req->json;
96
        if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
103
104
    # Can we change userid and/or cardnumber? in that case check that they are altered first
105
    if ($body->{cardnumber} || $body->{userid}) {
106
        if ( ($body->{cardnumber} && $body->{cardnumber} ne $patron->cardnumber) || ($body->{userid} && $body->{userid} ne $patron->userid) ) {
107
            my $conflictingPatron = Koha::Patrons->find({cardnumber => $body->{cardnumber}, userid => $body->{userid} });
108
            if ($conflictingPatron) {
109
                return $c->$cb({
110
                    error => "Patron cardnumber and userid must be unique",
111
                    conflict => { cardnumber => $conflictingPatron->cardnumber, userid => $conflictingPatron->userid }
112
                }, 409);
113
            }
114
        }
115
    }
116
97
117
    if ($body->{branchcode}) {
98
        die unless $patron->set($body)->validate;
118
        my $branch = Koha::Libraries->find({branchcode => $body->{branchcode} });
119
        unless ($branch) {
120
            return $c->$cb({error => "Library with branchcode \"" . $body->{branchcode} . "\" does not exist"}, 404);
121
        }
122
    }
123
99
124
    if ($body->{categorycode}) {
100
        return $c->$cb({}, 204) unless $patron->is_changed; # No Content = No changes made
125
        my $category = Koha::Patron::Categories->find({ categorycode => $body->{categorycode} });
101
        $patron->store;
126
        unless ($category) {
102
        return $c->$cb($patron->unblessed, 200);
127
            return $c->$cb({error => "Patron category \"" . $body->{categorycode} . "\" does not exist"}, 404);
128
        }
129
    }
103
    }
130
    # ALL OK - Update patron
104
    catch {
131
    # Perhaps limit/validate what should be updated here? flags, et.al.
105
        unless ($patron) {
132
    if ($body->{password}) { $body->{password} = hash_password($body->{password}) }; # bcrypt password if given
106
            return $c->$cb({error => "Patron not found"}, 404);
133
134
    my $updatedpatron = eval {
135
        $patron->set($body);
136
    };
137
138
    if ($updatedpatron) {
139
        if ($updatedpatron->is_changed) {
140
141
            my $res = eval {
142
                $updatedpatron->store;
143
            };
144
145
            unless ($res) {
146
                return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
147
            }
148
            return $c->$cb($res->unblessed, 200);
149
150
        } else {
151
            return $c->$cb({}, 204); # No Content = No changes made
152
        }
107
        }
153
    } else {
108
        unless (blessed $_ && $_->can('rethrow')) {
154
        return $c->$cb({error => "Something went wrong, check Koha logs for details"}, 500);
109
            return $c->$cb({error => "Something went wrong, check Koha logs for details."}, 500);
155
    }
110
        }
111
        if ($_->isa('Koha::Exceptions::Patron::DuplicateObject')) {
112
            return $c->$cb({ error => $_->error, conflict => $_->conflict }, 409);
113
        }
114
        elsif ($_->isa('Koha::Exceptions::Library::BranchcodeNotFound')) {
115
            return $c->$cb({ error => "Library with branchcode \"".$_->branchcode."\" does not exist" }, 404);
116
        }
117
        elsif ($_->isa('Koha::Exceptions::Category::CategorycodeNotFound')) {
118
            return $c->$cb({error => "Patron category \"".$_->categorycode."\" does not exist"}, 404);
119
        }
120
        else {
121
            return $c->$cb({error => "Something went wrong, check Koha logs for details."}, 500);
122
        }
123
    };
156
}
124
}
157
125
158
sub delete {
126
sub delete {
(-)a/t/db_dependent/Patrons.t (-2 / +28 lines)
Lines 17-24 Link Here
17
17
18
use Modern::Perl;
18
use Modern::Perl;
19
19
20
use Test::More tests => 17;
20
use Test::More tests => 22;
21
use Test::Warn;
21
use Test::Warn;
22
use Test::Fatal;
23
use t::lib::TestBuilder;
22
24
23
use C4::Context;
25
use C4::Context;
24
use Koha::Database;
26
use Koha::Database;
Lines 36-41 $dbh->{RaiseError} = 1; Link Here
36
$dbh->do("DELETE FROM issues");
38
$dbh->do("DELETE FROM issues");
37
$dbh->do("DELETE FROM borrowers");
39
$dbh->do("DELETE FROM borrowers");
38
40
41
my $builder = t::lib::TestBuilder->new();
39
my $categorycode =
42
my $categorycode =
40
  Koha::Database->new()->schema()->resultset('Category')->first()
43
  Koha::Database->new()->schema()->resultset('Category')->first()
41
  ->categorycode();
44
  ->categorycode();
Lines 46-52 my $b1 = Koha::Patron->new( Link Here
46
    {
49
    {
47
        surname      => 'Test 1',
50
        surname      => 'Test 1',
48
        branchcode   => $branchcode,
51
        branchcode   => $branchcode,
49
        categorycode => $categorycode
52
        categorycode => $categorycode,
50
    }
53
    }
51
);
54
);
52
$b1->store();
55
$b1->store();
Lines 98-103 is( $b->surname(), 'Test 3', "Next returns third patron" ); Link Here
98
$b = $patrons->next();
101
$b = $patrons->next();
99
is( $b, undef, "Next returns undef" );
102
is( $b, undef, "Next returns undef" );
100
103
104
is($b1->validate, $b1, "Patron b1 validates");
105
isa_ok(exception { $b1->set({ categorycode => "nonexistent" })->validate },
106
   "Koha::Exceptions::Category::CategorycodeNotFound",
107
   "Invalid categorycode");
108
isa_ok(exception { $b1->set({ branchcode => "nonexistent" })->validate },
109
   "Koha::Exceptions::Library::BranchcodeNotFound",
110
   "Invalid branchcode");
111
112
# test validation for duplicate cardnumber & userid
113
my $patron = $builder->build({
114
    source => 'Borrower',
115
    value => {
116
        branchcode   => $branchcode,
117
        categorycode => $categorycode,
118
        flags        => 0,
119
    }
120
});
121
my $duplicate = $patron;
122
isa_ok(exception { Koha::Patron->new($duplicate)->validate },
123
    "Koha::Exceptions::Patron::DuplicateObject",
124
    "Duplicate patron");
125
126
101
# Test Reset and iteration in concert
127
# Test Reset and iteration in concert
102
$patrons->reset();
128
$patrons->reset();
103
foreach my $b ( $patrons->as_list() ) {
129
foreach my $b ( $patrons->as_list() ) {
(-)a/t/db_dependent/api/v1/patrons.t (-4 / +3 lines)
Lines 186-192 $tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron); Link Here
186
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
186
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
187
$t->request_ok($tx)
187
$t->request_ok($tx)
188
  ->status_is(500)
188
  ->status_is(500)
189
  ->json_is('/error' => "Something went wrong, check Koha logs for details");
189
  ->json_is('/error' => "Something went wrong, check Koha logs for details.");
190
190
191
delete $newpatron->{ falseproperty };
191
delete $newpatron->{ falseproperty };
192
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
192
$tx = $t->ua->build_tx(POST => "/api/v1/patrons" => json => $newpatron);
Lines 213-219 $t->request_ok($tx) Link Here
213
  ->status_is(404)
213
  ->status_is(404)
214
  ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
214
  ->json_has('/error', 'Fails when trying to PUT nonexistent patron');
215
215
216
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => {categorycode => "nonexistent"});
216
$tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber } => json => {branchcode => $branchcode, categorycode => "nonexistent"});
217
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
217
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
218
$t->request_ok($tx)
218
$t->request_ok($tx)
219
  ->status_is(404)
219
  ->status_is(404)
Lines 230-236 $tx = $t->ua->build_tx(PUT => "/api/v1/patrons/" . $newpatron->{ borrowernumber Link Here
230
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
230
$tx->req->cookies({name => 'CGISESSID', value => $session->id});
231
$t->request_ok($tx)
231
$t->request_ok($tx)
232
  ->status_is(500)
232
  ->status_is(500)
233
  ->json_is('/error' => "Something went wrong, check Koha logs for details");
233
  ->json_is('/error' => "Something went wrong, check Koha logs for details.");
234
delete $newpatron->{ falseproperty };
234
delete $newpatron->{ falseproperty };
235
235
236
$newpatron->{ cardnumber } = $patron-> { cardnumber };
236
$newpatron->{ cardnumber } = $patron-> { cardnumber };
237
- 

Return to bug 16330