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

(-)a/Koha/Patron/Message.pm (+19 lines)
Lines 73-78 sub delete { Link Here
73
    return $self->SUPER::delete($self);
73
    return $self->SUPER::delete($self);
74
}
74
}
75
75
76
=head3 to_api_mapping
77
78
This method returns the mapping for representing a Koha::Patron::Message object
79
on the API.
80
81
=cut
82
83
sub to_api_mapping {
84
    return {
85
        message_id      => 'message_id',
86
        borrowernumber  => 'patron_id',
87
        branchcode      => 'library_id',
88
        message_type    => 'message_type',
89
        message         => 'message',
90
        message_date    => 'message_date',
91
        manager_id      => 'manager_id',
92
    };
93
}
94
76
=head3 _type
95
=head3 _type
77
96
78
=cut
97
=cut
(-)a/Koha/REST/V1/Messages.pm (+255 lines)
Line 0 Link Here
1
package Koha::REST::V1::Messages;
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
22
use Koha::Patron::Messages;
23
24
use Try::Tiny;
25
26
=head1 API
27
28
=head2 Class Methods
29
30
=head3 list
31
32
=cut
33
34
sub list {
35
    my $c = shift->openapi->valid_input or return;
36
37
    return try {
38
        my $messages_set = Koha::Patron::Messages->new;
39
        my $messages = $c->objects->search( $messages_set, \&_to_model, \&_to_api );
40
        return $c->render( status => 200, openapi => $messages );
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
55
=head3 get
56
57
=cut
58
59
sub get {
60
    my $c = shift->openapi->valid_input or return;
61
62
    my $message = Koha::Patron::Messages->find( $c->validation->param('message_id') );
63
    unless ($message) {
64
        return $c->render( status  => 404,
65
                           openapi => { error => "Message not found" } );
66
    }
67
68
    return $c->render( status => 200, openapi => $message->to_api );
69
}
70
71
=head3 add
72
73
=cut
74
75
sub add {
76
    my $c = shift->openapi->valid_input or return;
77
78
    return try {
79
        my $message = Koha::Patron::Message->new( _to_model( $c->validation->param('body') ) );
80
        my $user = $c->stash('koha.user');
81
        $message->set({ manager_id => $user->borrowernumber }) unless defined $message->manager_id;
82
        $message->store;
83
        $c->res->headers->location( $c->req->url->to_string . '/' . $message->message_id );
84
        return $c->render(
85
            status  => 201,
86
            openapi => $message->to_api
87
        );
88
    }
89
    catch {
90
        if ( $_->isa('DBIx::Class::Exception') ) {
91
            return $c->render(
92
                status  => 500,
93
                openapi => { error => $_->{msg} }
94
            );
95
        }
96
        else {
97
            return $c->render(
98
                status  => 500,
99
                openapi => { error => "Something went wrong, check the logs." }
100
            );
101
        }
102
    };
103
}
104
105
=head3 update
106
107
=cut
108
109
sub update {
110
    my $c = shift->openapi->valid_input or return;
111
112
    my $message = Koha::Patron::Messages->find( $c->validation->param('message_id') );
113
114
    if ( not defined $message ) {
115
        return $c->render( status  => 404,
116
                           openapi => { error => "Object not found" } );
117
    }
118
119
    return try {
120
        my $params = $c->req->json;
121
        $message->set( _to_model($params) );
122
        $message->store();
123
        return $c->render( status => 200, openapi => $message->to_api );
124
    }
125
    catch {
126
        if ( $_->isa('Koha::Exceptions::Object') ) {
127
            return $c->render( status  => 500,
128
                               openapi => { error => $_->message } );
129
        }
130
        else {
131
            return $c->render( status => 500,
132
                openapi => { error => "Something went wrong, check the logs."} );
133
        }
134
    };
135
}
136
137
=head3 delete
138
139
=cut
140
141
sub delete {
142
    my $c = shift->openapi->valid_input or return;
143
144
    my $message = Koha::Patron::Messages->find( $c->validation->param('message_id') );
145
    if ( not defined $message ) {
146
        return $c->render( status  => 404,
147
                           openapi => { error => "Object not found" } );
148
    }
149
150
    return try {
151
        $message->delete;
152
        return $c->render( status => 200, openapi => "" );
153
    }
154
    catch {
155
        if ( $_->isa('DBIx::Class::Exception') ) {
156
            return $c->render( status  => 500,
157
                               openapi => { error => $_->{msg} } );
158
        }
159
        else {
160
            return $c->render( status => 500,
161
                openapi => { error => "Something went wrong, check the logs."} );
162
        }
163
    };
164
}
165
166
=head3 _to_api
167
168
Helper function that maps a hashref of Koha::Patron::Message attributes into REST api
169
attribute names.
170
171
=cut
172
173
sub _to_api {
174
    my $message    = shift;
175
176
    # Rename attributes
177
    foreach my $column ( keys %{ $Koha::REST::V1::Messages::to_api_mapping } ) {
178
        my $mapped_column = $Koha::REST::V1::Messages::to_api_mapping->{$column};
179
        if (    exists $message->{ $column }
180
             && defined $mapped_column )
181
        {
182
            # key /= undef
183
            $message->{ $mapped_column } = delete $message->{ $column };
184
        }
185
        elsif (    exists $message->{ $column }
186
                && !defined $mapped_column )
187
        {
188
            # key == undef => to be deleted
189
            delete $message->{ $column };
190
        }
191
    }
192
193
    return $message;
194
}
195
196
=head3 _to_model
197
198
Helper function that maps REST api objects into Koha::Patron::Messages
199
attribute names.
200
201
=cut
202
203
sub _to_model {
204
    my $message = shift;
205
206
    foreach my $attribute ( keys %{ $Koha::REST::V1::Messages::to_model_mapping } ) {
207
        my $mapped_attribute = $Koha::REST::V1::Messages::to_model_mapping->{$attribute};
208
        if (    exists $message->{ $attribute }
209
             && defined $mapped_attribute )
210
        {
211
            # key /= undef
212
            $message->{ $mapped_attribute } = delete $message->{ $attribute };
213
        }
214
        elsif (    exists $message->{ $attribute }
215
                && !defined $mapped_attribute )
216
        {
217
            # key == undef => to be deleted
218
            delete $message->{ $attribute };
219
        }
220
    }
221
222
    return $message;
223
}
224
225
=head2 Global variables
226
227
=head3 $to_api_mapping
228
229
=cut
230
231
our $to_api_mapping = {
232
    message_id      => 'message_id',
233
    borrowernumber  => 'patron_id',
234
    branchcode      => 'library_id',
235
    message_type    => 'message_type',
236
    message         => 'message',
237
    message_date    => 'message_date',
238
    manager_id      => 'manager_id',
239
};
240
241
=head3 $to_model_mapping
242
243
=cut
244
245
our $to_model_mapping = {
246
    message_id      => 'message_id',
247
    patron_id       => 'borrowernumber',
248
    library_id      => 'branchcode',
249
    message_type    => 'message_type',
250
    message         => 'message',
251
    message_date    => 'message_date',
252
    manager_id      => 'manager_id',
253
};
254
255
1;
(-)a/api/v1/swagger/definitions.json (+3 lines)
Lines 23-28 Link Here
23
  "library": {
23
  "library": {
24
    "$ref": "definitions/library.json"
24
    "$ref": "definitions/library.json"
25
  },
25
  },
26
  "message": {
27
    "$ref": "definitions/message.json"
28
  },
26
  "item": {
29
  "item": {
27
    "$ref": "definitions/item.json"
30
    "$ref": "definitions/item.json"
28
  },
31
  },
(-)a/api/v1/swagger/definitions/message.json (+37 lines)
Line 0 Link Here
1
{
2
  "type": "object",
3
  "properties": {
4
    "message_id": {
5
      "$ref": "../x-primitives.json#/message_id"
6
    },
7
    "patron_id": {
8
      "$ref": "../x-primitives.json#/patron_id"
9
    },
10
    "library_id": {
11
      "type": ["string", "null"],
12
      "description": "Internally assigned library identifier",
13
      "maxLength": 10,
14
      "minLength": 1
15
    },
16
    "message_type": {
17
      "description": "One of following values: L = For Librarians, B = For Patrons",
18
      "type": "string",
19
      "maxLength": 1
20
    },
21
    "message": {
22
      "description": "Message content",
23
      "type": "string"
24
    },
25
    "message_date": {
26
      "description": "Message content",
27
      "format": "date-time",
28
      "type": "string"
29
    },
30
    "manager_id": {
31
      "type": ["integer", "null"],
32
      "description": "Internal patron identifier for message manager"
33
    }
34
  },
35
  "additionalProperties": false,
36
  "required": ["patron_id", "message_type", "message"]
37
}
(-)a/api/v1/swagger/parameters.json (+3 lines)
Lines 20-25 Link Here
20
  "library_id_pp": {
20
  "library_id_pp": {
21
    "$ref": "parameters/library.json#/library_id_pp"
21
    "$ref": "parameters/library.json#/library_id_pp"
22
  },
22
  },
23
  "message_id_pp": {
24
    "$ref": "parameters/message.json#/message_id_pp"
25
  },
23
  "item_id_pp": {
26
  "item_id_pp": {
24
    "$ref": "parameters/item.json#/item_id_pp"
27
    "$ref": "parameters/item.json#/item_id_pp"
25
  },
28
  },
(-)a/api/v1/swagger/parameters/message.json (+9 lines)
Line 0 Link Here
1
{
2
    "message_id_pp": {
3
      "name": "message_id",
4
      "in": "path",
5
      "description": "Message internal identifier",
6
      "required": true,
7
      "type": "integer"
8
    }
9
}
(-)a/api/v1/swagger/paths.json (+6 lines)
Lines 56-61 Link Here
56
  "/libraries/{library_id}": {
56
  "/libraries/{library_id}": {
57
    "$ref": "paths/libraries.json#/~1libraries~1{library_id}"
57
    "$ref": "paths/libraries.json#/~1libraries~1{library_id}"
58
  },
58
  },
59
  "/messages": {
60
    "$ref": "paths/messages.json#/~1messages"
61
  },
62
  "/messages/{message_id}": {
63
    "$ref": "paths/messages.json#/~1messages~1{message_id}"
64
  },
59
  "/checkouts/{checkout_id}/allows_renewal": {
65
  "/checkouts/{checkout_id}/allows_renewal": {
60
    "$ref": "paths/checkouts.json#/~1checkouts~1{checkout_id}~1allows_renewal"
66
    "$ref": "paths/checkouts.json#/~1checkouts~1{checkout_id}~1allows_renewal"
61
  },
67
  },
(-)a/api/v1/swagger/paths/messages.json (+327 lines)
Line 0 Link Here
1
{
2
  "/messages": {
3
    "get": {
4
      "x-mojo-to": "Messages#list",
5
      "operationId": "listmessages",
6
      "tags": ["messages"],
7
      "produces": [
8
        "application/json"
9
      ],
10
      "parameters": [{
11
        "name": "patron_id",
12
        "in": "query",
13
        "description": "Search on patron id",
14
        "required": false,
15
        "type": "integer"
16
      }, {
17
        "name": "library_id",
18
        "in": "query",
19
        "description": "Case insensitive search on library id",
20
        "required": false,
21
        "type": "string"
22
      }, {
23
        "name": "message_type",
24
        "in": "query",
25
        "description": "Case insensitive search on message type",
26
        "required": false,
27
        "type": "string"
28
      }, {
29
        "name": "message",
30
        "in": "query",
31
        "description": "Case Insensitive search on message content",
32
        "required": false,
33
        "type": "string"
34
      }, {
35
        "name": "message_date",
36
        "in": "query",
37
        "description": "Case Insensitive search on message date",
38
        "required": false,
39
        "type": "string"
40
      }, {
41
        "name": "manager_id",
42
        "in": "query",
43
        "description": "Case Insensitive search on manager patron id",
44
        "required": false,
45
        "type": "integer"
46
      }],
47
      "responses": {
48
        "200": {
49
          "description": "A list of messages",
50
          "schema": {
51
            "type": "array",
52
            "items": {
53
              "$ref": "../definitions.json#/message"
54
            }
55
          }
56
        },
57
        "400": {
58
          "description": "Bad request",
59
          "schema": {
60
            "$ref": "../definitions.json#/error"
61
          }
62
        },
63
        "403": {
64
          "description": "Access forbidden",
65
          "schema": {
66
            "$ref": "../definitions.json#/error"
67
          }
68
        },
69
        "500": {
70
          "description": "Internal error",
71
          "schema": {
72
            "$ref": "../definitions.json#/error"
73
          }
74
        },
75
        "503": {
76
          "description": "Under maintenance",
77
          "schema": {
78
            "$ref": "../definitions.json#/error"
79
          }
80
        }
81
      },
82
      "x-koha-authorization": {
83
        "permissions": {
84
            "borrowers": "1"
85
        }
86
      }
87
    },
88
    "post": {
89
      "x-mojo-to": "Messages#add",
90
      "operationId": "addmessage",
91
      "tags": ["messages"],
92
      "parameters": [{
93
        "name": "body",
94
        "in": "body",
95
        "description": "A JSON object containing informations about the new hold",
96
        "required": true,
97
        "schema": {
98
          "$ref": "../definitions.json#/message"
99
        }
100
      }],
101
      "produces": [
102
        "application/json"
103
      ],
104
      "responses": {
105
        "201": {
106
          "description": "message added",
107
          "schema": {
108
            "$ref": "../definitions.json#/message"
109
          }
110
        },
111
        "400": {
112
          "description": "Bad request",
113
          "schema": {
114
            "$ref": "../definitions.json#/error"
115
          }
116
        },
117
        "401": {
118
          "description": "Authentication required",
119
          "schema": {
120
            "$ref": "../definitions.json#/error"
121
          }
122
        },
123
        "403": {
124
          "description": "Access forbidden",
125
          "schema": {
126
            "$ref": "../definitions.json#/error"
127
          }
128
        },
129
        "500": {
130
          "description": "Internal error",
131
          "schema": {
132
            "$ref": "../definitions.json#/error"
133
          }
134
        },
135
        "503": {
136
          "description": "Under maintenance",
137
          "schema": {
138
            "$ref": "../definitions.json#/error"
139
          }
140
        }
141
      },
142
      "x-koha-authorization": {
143
        "permissions": {
144
          "borrowers": "edit_borrowers"
145
        }
146
      }
147
    }
148
  },
149
  "/messages/{message_id}": {
150
    "get": {
151
      "x-mojo-to": "Messages#get",
152
      "operationId": "getmessage",
153
      "tags": ["messages"],
154
      "parameters": [{
155
        "$ref": "../parameters.json#/message_id_pp"
156
      }],
157
      "produces": [
158
        "application/json"
159
      ],
160
      "responses": {
161
        "200": {
162
          "description": "A message",
163
          "schema": {
164
            "$ref": "../definitions.json#/message"
165
          }
166
        },
167
        "400": {
168
          "description": "Bad request",
169
          "schema": {
170
            "$ref": "../definitions.json#/error"
171
          }
172
        },
173
        "404": {
174
          "description": "message not found",
175
          "schema": {
176
            "$ref": "../definitions.json#/error"
177
          }
178
        },
179
        "500": {
180
          "description": "Internal error",
181
          "schema": {
182
            "$ref": "../definitions.json#/error"
183
          }
184
        },
185
        "503": {
186
          "description": "Under maintenance",
187
          "schema": {
188
            "$ref": "../definitions.json#/error"
189
          }
190
        }
191
      },
192
      "x-koha-authorization": {
193
        "permissions": {
194
            "borrowers": "1"
195
        }
196
      }
197
    },
198
    "put": {
199
      "x-mojo-to": "Messages#update",
200
      "operationId": "updatemessage",
201
      "tags": ["messages"],
202
      "parameters": [{
203
        "$ref": "../parameters.json#/message_id_pp"
204
      }, {
205
        "name": "body",
206
        "in": "body",
207
        "description": "A message object",
208
        "required": true,
209
        "schema": {
210
          "$ref": "../definitions.json#/message"
211
        }
212
      }],
213
      "produces": [
214
        "application/json"
215
      ],
216
      "responses": {
217
        "200": {
218
          "description": "A message",
219
          "schema": {
220
            "$ref": "../definitions.json#/message"
221
          }
222
        },
223
        "400": {
224
          "description": "Bad request",
225
          "schema": {
226
            "$ref": "../definitions.json#/error"
227
          }
228
        },
229
        "401": {
230
          "description": "Authentication required",
231
          "schema": {
232
            "$ref": "../definitions.json#/error"
233
          }
234
        },
235
        "403": {
236
          "description": "Access forbidden",
237
          "schema": {
238
            "$ref": "../definitions.json#/error"
239
          }
240
        },
241
        "404": {
242
          "description": "message not found",
243
          "schema": {
244
            "$ref": "../definitions.json#/error"
245
          }
246
        },
247
        "500": {
248
          "description": "Internal error",
249
          "schema": {
250
            "$ref": "../definitions.json#/error"
251
          }
252
        },
253
        "503": {
254
          "description": "Under maintenance",
255
          "schema": {
256
            "$ref": "../definitions.json#/error"
257
          }
258
        }
259
      },
260
      "x-koha-authorization": {
261
        "permissions": {
262
          "borrowers": "edit_borrowers"
263
        }
264
      }
265
    },
266
    "delete": {
267
      "x-mojo-to": "Messages#delete",
268
      "operationId": "deletemessage",
269
      "tags": ["messages"],
270
      "parameters": [{
271
        "$ref": "../parameters.json#/message_id_pp"
272
      }],
273
      "produces": [
274
        "application/json"
275
      ],
276
      "responses": {
277
        "200": {
278
          "description": "message deleted",
279
          "schema": {
280
            "type": "string"
281
          }
282
        },
283
        "400": {
284
          "description": "Bad request",
285
          "schema": {
286
            "$ref": "../definitions.json#/error"
287
          }
288
        },
289
        "401": {
290
          "description": "Authentication required",
291
          "schema": {
292
            "$ref": "../definitions.json#/error"
293
          }
294
        },
295
        "403": {
296
          "description": "Access forbidden",
297
          "schema": {
298
            "$ref": "../definitions.json#/error"
299
          }
300
        },
301
        "404": {
302
          "description": "message not found",
303
          "schema": {
304
            "$ref": "../definitions.json#/error"
305
          }
306
        },
307
        "500": {
308
          "description": "Internal error",
309
          "schema": {
310
            "$ref": "../definitions.json#/error"
311
          }
312
        },
313
        "503": {
314
          "description": "Under maintenance",
315
          "schema": {
316
            "$ref": "../definitions.json#/error"
317
          }
318
        }
319
      },
320
      "x-koha-authorization": {
321
        "permissions": {
322
          "borrowers": "edit_borrowers"
323
        }
324
      }
325
    }
326
  }
327
}
(-)a/api/v1/swagger/x-primitives.json (+5 lines)
Lines 26-31 Link Here
26
    "type": ["string", "null"],
26
    "type": ["string", "null"],
27
    "description": "primary email address for patron's primary address"
27
    "description": "primary email address for patron's primary address"
28
  },
28
  },
29
  "message_id": {
30
    "type": "integer",
31
    "description": "internally assigned message identifier",
32
    "readOnly": true
33
  },
29
  "firstname": {
34
  "firstname": {
30
    "type": ["string", "null"],
35
    "type": ["string", "null"],
31
    "description": "patron's first name"
36
    "description": "patron's first name"
(-)a/t/db_dependent/api/v1/messages.t (-1 / +403 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
23
use t::lib::TestBuilder;
24
use t::lib::Mocks;
25
26
use Koha::Patron::Messages;
27
use Koha::Database;
28
29
my $schema  = Koha::Database->new->schema;
30
my $builder = t::lib::TestBuilder->new;
31
32
my $t = Test::Mojo->new('Koha::REST::V1');
33
t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 );
34
35
subtest 'list() tests' => sub {
36
37
    plan tests => 20;
38
39
    $schema->storage->txn_begin;
40
41
    Koha::Patron::Messages->search->delete;
42
43
    my $librarian = $builder->build_object(
44
        {
45
            class => 'Koha::Patrons',
46
            value => { flags => 4 ** 2 } # borrowers flag = 4
47
        }
48
    );
49
    my $password = 'thePassword123';
50
    $librarian->set_password( { password => $password, skip_validation => 1 } );
51
    my $userid = $librarian->userid;
52
53
    my $patron = $builder->build_object(
54
        {
55
            class => 'Koha::Patrons',
56
            value => { flags => 0 }
57
        }
58
    );
59
60
    $patron->set_password( { password => $password, skip_validation => 1 } );
61
    my $unauth_userid = $patron->userid;
62
63
    ## Authorized user tests
64
    # No messages, so empty array should be returned
65
    $t->get_ok("//$userid:$password@/api/v1/messages")
66
      ->status_is(200)
67
      ->json_is( [] );
68
69
    my $message = $builder->build_object({ class => 'Koha::Patron::Messages' });
70
71
    # One message created, should get returned
72
    $t->get_ok("//$userid:$password@/api/v1/messages")
73
      ->status_is(200)
74
      ->json_is( [Koha::REST::V1::Messages::_to_api( $message->TO_JSON )] );
75
76
    my $another_message = $builder->build_object(
77
        { class => 'Koha::Patron::Messages', value => { message_type => $message->message_type } } );
78
    my $message_with_another_message_type = $builder->build_object({ class => 'Koha::Patron::Messages' });
79
80
    # Two messages created, they should both be returned
81
    $t->get_ok("//$userid:$password@/api/v1/messages")
82
      ->status_is(200)
83
      ->json_is([Koha::REST::V1::Messages::_to_api($message->TO_JSON),
84
                 Koha::REST::V1::Messages::_to_api($another_message->TO_JSON),
85
                 Koha::REST::V1::Messages::_to_api($message_with_another_message_type->TO_JSON)
86
                 ] );
87
88
    # Filtering works, two messages sharing message_type
89
    $t->get_ok("//$userid:$password@/api/v1/messages?message_type=" . $message->message_type )
90
      ->status_is(200)
91
      ->json_is([ Koha::REST::V1::Messages::_to_api($message->TO_JSON),
92
                  Koha::REST::V1::Messages::_to_api($another_message->TO_JSON)
93
                  ]);
94
95
    $t->get_ok("//$userid:$password@/api/v1/messages?message=" . $message->message )
96
      ->status_is(200)
97
      ->json_is( [Koha::REST::V1::Messages::_to_api($message->TO_JSON)] );
98
99
    # Warn on unsupported query parameter
100
    $t->get_ok("//$userid:$password@/api/v1/messages?message_blah=blah" )
101
      ->status_is(400)
102
      ->json_is( [{ path => '/query/message_blah', message => 'Malformed query string'}] );
103
104
    # Unauthorized access
105
    $t->get_ok("//$unauth_userid:$password@/api/v1/messages")
106
      ->status_is(403);
107
108
    $schema->storage->txn_rollback;
109
};
110
111
subtest 'get() tests' => sub {
112
113
    plan tests => 8;
114
115
    $schema->storage->txn_begin;
116
117
    my $message = $builder->build_object({ class => 'Koha::Patron::Messages' });
118
    my $librarian = $builder->build_object(
119
        {
120
            class => 'Koha::Patrons',
121
            value => { flags => 4**2 }    # borrowers flag = 4
122
        }
123
    );
124
    my $password = 'thePassword123';
125
    $librarian->set_password( { password => $password, skip_validation => 1 } );
126
    my $userid = $librarian->userid;
127
128
    my $patron = $builder->build_object(
129
        {
130
            class => 'Koha::Patrons',
131
            value => { flags => 0 }
132
        }
133
    );
134
135
    $patron->set_password( { password => $password, skip_validation => 1 } );
136
    my $unauth_userid = $patron->userid;
137
138
    $t->get_ok( "//$userid:$password@/api/v1/messages/" . $message->message_id )
139
      ->status_is(200)
140
      ->json_is(Koha::REST::V1::Messages::_to_api($message->TO_JSON));
141
142
    $t->get_ok( "//$unauth_userid:$password@/api/v1/messages/" . $message->message_id )
143
      ->status_is(403);
144
145
    my $message_to_delete = $builder->build_object({ class => 'Koha::Patron::Messages' });
146
    my $non_existent_id = $message_to_delete->id;
147
    $message_to_delete->delete;
148
149
    $t->get_ok( "//$userid:$password@/api/v1/messages/$non_existent_id" )
150
      ->status_is(404)
151
      ->json_is( '/error' => 'Message not found' );
152
153
    $schema->storage->txn_rollback;
154
};
155
156
subtest 'add() tests' => sub {
157
158
    plan tests => 27;
159
160
    $schema->storage->txn_begin;
161
162
    my $librarian = $builder->build_object(
163
        {
164
            class => 'Koha::Patrons',
165
            value => { flags => 4**2 }    # borrowers flag = 4
166
        }
167
    );
168
    my $password = 'thePassword123';
169
    $librarian->set_password( { password => $password, skip_validation => 1 } );
170
    my $userid = $librarian->userid;
171
172
    my $patron = $builder->build_object(
173
        {
174
            class => 'Koha::Patrons',
175
            value => { flags => 0 }
176
        }
177
    );
178
179
    $patron->set_password( { password => $password, skip_validation => 1 } );
180
    my $unauth_userid = $patron->userid;
181
182
    my $message = {
183
        patron_id       => $patron->borrowernumber,
184
        library_id      => $patron->branchcode,
185
        message_type    => "B",
186
        message         => "Old Fox jumped over Cheeseboy"
187
    };
188
189
    # Unauthorized attempt to write
190
    $t->post_ok("//$unauth_userid:$password@/api/v1/messages" => json => $message)
191
      ->status_is(403);
192
193
    # Authorized attempt to write invalid data
194
    my $message_with_invalid_field = {
195
        blah            => "message Blah",
196
        patron_id       => $patron->borrowernumber,
197
        library_id      => $patron->branchcode,
198
        message_type    => "B",
199
        message         => "Old Fox jumped over Cheeseboy",
200
        manager_id      => $librarian->borrowernumber
201
    };
202
203
    $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message_with_invalid_field )
204
      ->status_is(400)
205
      ->json_is(
206
        "/errors" => [
207
            {
208
                message => "Properties not allowed: blah.",
209
                path    => "/body"
210
            }
211
        ]
212
      );
213
214
    # Authorized attempt to write
215
    my $message_id =
216
       $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message )
217
        ->status_is( 201, 'SWAGGER3.2.1' )
218
        ->header_like(
219
            Location => qr|^\/api\/v1\/messages/\d*|,
220
            'SWAGGER3.4.1'
221
            )
222
        ->json_is( '/patron_id'     => $message->{patron_id} )
223
        ->json_is( '/library_id'    => $message->{library_id} )
224
        ->json_is( '/message_type'  => $message->{message_type} )
225
        ->json_is( '/message'       => $message->{message} )
226
        ->json_is( '/manager_id'    => $librarian->borrowernumber )
227
        ->tx->res->json->{message_id};
228
229
    # Authorized attempt to write with manager_id defined
230
    $message->{manager_id} = $message->{patron_id};
231
    $message_id =
232
       $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message )
233
        ->status_is( 201, 'SWAGGER3.2.1' )
234
        ->header_like(
235
            Location => qr|^\/api\/v1\/messages/\d*|,
236
            'SWAGGER3.4.1'
237
            )
238
        ->json_is( '/patron_id'     => $message->{patron_id} )
239
        ->json_is( '/library_id'    => $message->{library_id} )
240
        ->json_is( '/message_type'  => $message->{message_type} )
241
        ->json_is( '/message'       => $message->{message} )
242
        ->json_is( '/manager_id'    => $message->{patron_id} )
243
        ->tx->res->json->{message_id};
244
245
    # Authorized attempt to create with null id
246
    $message->{message_id} = undef;
247
    $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message )
248
      ->status_is(400)
249
      ->json_has('/errors');
250
251
    # Authorized attempt to create with existing id
252
    $message->{message_id} = $message_id;
253
    $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message )
254
      ->status_is(400)
255
      ->json_is(
256
        "/errors" => [
257
            {
258
                message => "Read-only.",
259
                path    => "/body/message_id"
260
            }
261
        ]
262
    );
263
264
    $schema->storage->txn_rollback;
265
};
266
267
subtest 'update() tests' => sub {
268
269
    plan tests => 15;
270
271
    $schema->storage->txn_begin;
272
273
    my $librarian = $builder->build_object(
274
        {
275
            class => 'Koha::Patrons',
276
            value => { flags => 4**2 }    # borrowers flag = 4
277
        }
278
    );
279
    my $password = 'thePassword123';
280
    $librarian->set_password( { password => $password, skip_validation => 1 } );
281
    my $userid = $librarian->userid;
282
283
    my $patron = $builder->build_object(
284
        {
285
            class => 'Koha::Patrons',
286
            value => { flags => 0 }
287
        }
288
    );
289
290
    $patron->set_password( { password => $password, skip_validation => 1 } );
291
    my $unauth_userid = $patron->userid;
292
293
    my $message_id = $builder->build_object({ class => 'Koha::Patron::Messages' } )->id;
294
295
    # Unauthorized attempt to update
296
    $t->put_ok( "//$unauth_userid:$password@/api/v1/messages/$message_id" => json => { name => 'New unauthorized name change' } )
297
      ->status_is(403);
298
299
    # Attempt partial update on a PUT
300
    my $message_with_missing_field = {
301
        patron_id       => $patron->borrowernumber,
302
        library_id      => $patron->branchcode,
303
        message         => "Old Fox jumped over Cheeseboy",
304
        manager_id      => $librarian->borrowernumber
305
    };
306
307
    $t->put_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_missing_field )
308
      ->status_is(400)
309
      ->json_is( "/errors" =>
310
          [ { message => "Missing property.", path => "/body/message_type" } ]
311
      );
312
313
    # Full object update on PUT
314
    my $message_with_updated_field = {
315
        patron_id       => $patron->borrowernumber,
316
        library_id      => $patron->branchcode,
317
        message_type    => "B",
318
        message         => "Old Fox jumped over Cheeseboy",
319
        manager_id      => $librarian->borrowernumber
320
    };
321
322
    $t->put_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_updated_field )
323
      ->status_is(200)
324
      ->json_is( '/message' => 'Old Fox jumped over Cheeseboy' );
325
326
    # Authorized attempt to write invalid data
327
    my $message_with_invalid_field = {
328
        blah            => "message Blah",
329
        patron_id       => $patron->borrowernumber,
330
        library_id      => $patron->branchcode,
331
        message_type    => "B",
332
        message         => "Old Fox jumped over Cheeseboy",
333
        manager_id      => $librarian->borrowernumber
334
    };
335
336
    $t->put_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_invalid_field )
337
      ->status_is(400)
338
      ->json_is(
339
        "/errors" => [
340
            {
341
                message => "Properties not allowed: blah.",
342
                path    => "/body"
343
            }
344
        ]
345
    );
346
347
    my $message_to_delete = $builder->build_object({ class => 'Koha::Patron::Messages' });
348
    my $non_existent_id = $message_to_delete->id;
349
    $message_to_delete->delete;
350
351
    $t->put_ok( "//$userid:$password@/api/v1/messages/$non_existent_id" => json => $message_with_updated_field )
352
      ->status_is(404);
353
354
    # Wrong method (POST)
355
    $message_with_updated_field->{message_id} = 2;
356
357
    $t->post_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_updated_field )
358
      ->status_is(404);
359
360
    $schema->storage->txn_rollback;
361
};
362
363
subtest 'delete() tests' => sub {
364
365
    plan tests => 7;
366
367
    $schema->storage->txn_begin;
368
369
    my $librarian = $builder->build_object(
370
        {
371
            class => 'Koha::Patrons',
372
            value => { flags => 4**2 }    # borrowers flag = 4
373
        }
374
    );
375
    my $password = 'thePassword123';
376
    $librarian->set_password( { password => $password, skip_validation => 1 } );
377
    my $userid = $librarian->userid;
378
379
    my $patron = $builder->build_object(
380
        {
381
            class => 'Koha::Patrons',
382
            value => { flags => 0 }
383
        }
384
    );
385
386
    $patron->set_password( { password => $password, skip_validation => 1 } );
387
    my $unauth_userid = $patron->userid;
388
389
    my $message_id = $builder->build_object({ class => 'Koha::Patron::Messages' })->id;
390
391
    # Unauthorized attempt to delete
392
    $t->delete_ok( "//$unauth_userid:$password@/api/v1/messages/$message_id" )
393
      ->status_is(403);
394
395
    $t->delete_ok("//$userid:$password@/api/v1/messages/$message_id")
396
      ->status_is(200)
397
      ->content_is('""');
398
399
    $t->delete_ok("//$userid:$password@/api/v1/messages/$message_id")
400
      ->status_is(404);
401
402
    $schema->storage->txn_rollback;
403
};

Return to bug 23998