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

(-)a/Koha/REST/V1/Tickets.pm (+157 lines)
Line 0 Link Here
1
package Koha::REST::V1::Tickets;
2
3
# This file is part of Koha.
4
#
5
# Koha is free software; you can redistribute it and/or modify it
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
17
18
use Modern::Perl;
19
20
use Mojo::Base 'Mojolicious::Controller';
21
22
use Koha::Ticket;
23
use Koha::Tickets;
24
use Koha::Ticket::Update;
25
use Koha::Ticket::Updates;
26
27
use Try::Tiny qw( catch try );
28
29
=head1 API
30
31
=head2 Methods
32
33
=head3 list
34
35
=cut
36
37
sub list {
38
    my $c = shift->openapi->valid_input or return;
39
40
    return try {
41
        my $tickets_set = Koha::Tickets->new;
42
        my $tickets     = $c->objects->search($tickets_set);
43
        return $c->render( status => 200, openapi => $tickets );
44
    }
45
    catch {
46
        $c->unhandled_exception($_);
47
    };
48
49
}
50
51
=head3 get
52
53
=cut
54
55
sub get {
56
    my $c = shift->openapi->valid_input or return;
57
58
    return try {
59
        my $ticket = Koha::Tickets->find( $c->validation->param('ticket_id') );
60
        unless ($ticket) {
61
            return $c->render(
62
                status  => 404,
63
                openapi => { error => "Ticket not found" }
64
            );
65
        }
66
67
        return $c->render( status => 200, openapi => $ticket->to_api );
68
    }
69
    catch {
70
        $c->unhandled_exception($_);
71
    }
72
}
73
74
=head3 add
75
76
=cut
77
78
sub add {
79
    my $c = shift->openapi->valid_input or return;
80
    my $patron = $c->stash('koha.user');
81
82
    return try {
83
        my $body   = $c->validation->param('body');
84
85
        # Set reporter from session
86
        $body->{reporter_id} = $patron->id;
87
        # FIXME: We should allow impersonation at a later date to
88
        # allow an API user to submit on behalf of a user
89
90
        my $ticket = Koha::Ticket->new_from_api($body)->store;
91
        $ticket->discard_changes;
92
        $c->res->headers->location(
93
            $c->req->url->to_string . '/' . $ticket->id );
94
        return $c->render(
95
            status  => 201,
96
            openapi => $ticket->to_api
97
        );
98
    }
99
    catch {
100
        $c->unhandled_exception($_);
101
    };
102
}
103
104
=head3 update
105
106
=cut
107
108
sub update {
109
    my $c = shift->openapi->valid_input or return;
110
111
    my $ticket = Koha::Tickets->find( $c->validation->param('ticket_id') );
112
113
    if ( not defined $ticket ) {
114
        return $c->render(
115
            status  => 404,
116
            openapi => { error => "Object not found" }
117
        );
118
    }
119
120
    return try {
121
        $ticket->set_from_api( $c->validation->param('body') );
122
        $ticket->store();
123
        return $c->render( status => 200, openapi => $ticket->to_api );
124
    }
125
    catch {
126
        $c->unhandled_exception($_);
127
    };
128
}
129
130
=head3 delete
131
132
=cut
133
134
sub delete {
135
    my $c = shift->openapi->valid_input or return;
136
137
    my $ticket = Koha::Tickets->find( $c->validation->param('ticket_id') );
138
    if ( not defined $ticket ) {
139
        return $c->render(
140
            status  => 404,
141
            openapi => { error => "Object not found" }
142
        );
143
    }
144
145
    return try {
146
        $ticket->delete;
147
        return $c->render(
148
            status  => 204,
149
            openapi => q{}
150
        );
151
    }
152
    catch {
153
        $c->unhandled_exception($_);
154
    };
155
}
156
157
1;
(-)a/Koha/Ticket.pm (+13 lines)
Lines 99-104 sub add_update { Link Here
99
99
100
=head2 Internal methods
100
=head2 Internal methods
101
101
102
=cut
103
104
=head3 to_api_mapping
105
106
This method returns the mapping for representing a Koha::Ticket object
107
on the API.
108
109
=cut
110
111
sub to_api_mapping {
112
    return { id => 'ticket_id', };
113
}
114
102
=head3 _type
115
=head3 _type
103
116
104
=cut
117
=cut
(-)a/api/v1/swagger/definitions/ticket.yaml (+59 lines)
Line 0 Link Here
1
---
2
type: object
3
properties:
4
  ticket_id:
5
    type: integer
6
    description: Internal ticket identifier
7
    readOnly: true
8
  reported_date:
9
    type:
10
      - string
11
      - "null"
12
    format: date-time
13
    description: Date the ticket was reported
14
    readOnly: true
15
  biblio:
16
    type:
17
      - object
18
      - "null"
19
    description: The object representing the biblio the ticket is related to
20
    readOnly: true
21
  biblio_id:
22
    type: integer
23
    description: Internal identifier for the biblio the ticket is related to
24
  title:
25
    type: string
26
    description: Ticket title
27
  body:
28
    type: string
29
    description: Ticket details
30
  reporter:
31
    type:
32
      - object
33
      - "null"
34
    description: The object representing the patron who reported the ticket
35
    readOnly: true
36
  reporter_id:
37
    type: integer
38
    description: Internal identifier for the patron who reported the ticket
39
  resolver:
40
    type:
41
      - object
42
      - "null"
43
    description: The object representing the user who resolved the ticket
44
    readOnly: true
45
  resolver_id:
46
    type:
47
      - integer
48
      - "null"
49
    description: Internal identifier for the user who resolved the ticket
50
  resolved_date:
51
    type:
52
      - string
53
      - "null"
54
    format: date-time
55
    description: Date the ticket was resolved_date
56
additionalProperties: false
57
required:
58
  - title
59
  - body
(-)a/api/v1/swagger/paths/tickets.yaml (+252 lines)
Line 0 Link Here
1
---
2
/tickets:
3
  get:
4
    x-mojo-to: Tickets#list
5
    operationId: listTickets
6
    tags:
7
      - tickets
8
    summary: List tickets
9
    produces:
10
      - application/json
11
    parameters:
12
      - $ref: "../swagger.yaml#/parameters/match"
13
      - $ref: "../swagger.yaml#/parameters/order_by"
14
      - $ref: "../swagger.yaml#/parameters/page"
15
      - $ref: "../swagger.yaml#/parameters/per_page"
16
      - $ref: "../swagger.yaml#/parameters/q_param"
17
      - $ref: "../swagger.yaml#/parameters/q_body"
18
      - $ref: "../swagger.yaml#/parameters/q_header"
19
      - $ref: "../swagger.yaml#/parameters/request_id_header"
20
      - name: x-koha-embed
21
        in: header
22
        required: false
23
        description: Embed list sent as a request header
24
        type: array
25
        items:
26
          type: string
27
          enum:
28
            - reporter
29
            - resolver
30
            - biblio
31
        collectionFormat: csv
32
    responses:
33
      "200":
34
        description: A list of tickets
35
        schema:
36
          type: array
37
          items:
38
            $ref: "../swagger.yaml#/definitions/ticket"
39
      "403":
40
        description: Access forbidden
41
        schema:
42
          $ref: "../swagger.yaml#/definitions/error"
43
      "500":
44
        description: |
45
          Internal server error. Possible `error_code` attribute values:
46
47
          * `internal_server_error`
48
        schema:
49
          $ref: "../swagger.yaml#/definitions/error"
50
      "503":
51
        description: Under maintenance
52
        schema:
53
          $ref: "../swagger.yaml#/definitions/error"
54
    x-koha-authorization:
55
      permissions:
56
        catalogue: "1"
57
  post:
58
    x-mojo-to: Tickets#add
59
    operationId: addTicket
60
    tags:
61
      - tickets
62
    summary: Add ticket
63
    parameters:
64
      - name: body
65
        in: body
66
        description: A JSON object containing informations about the new ticket
67
        required: true
68
        schema:
69
          $ref: "../swagger.yaml#/definitions/ticket"
70
    produces:
71
      - application/json
72
    responses:
73
      "201":
74
        description: Ticket added
75
        schema:
76
          $ref: "../swagger.yaml#/definitions/ticket"
77
      "401":
78
        description: Authentication required
79
        schema:
80
          $ref: "../swagger.yaml#/definitions/error"
81
      "403":
82
        description: Access forbidden
83
        schema:
84
          $ref: "../swagger.yaml#/definitions/error"
85
      "500":
86
        description: |
87
          Internal server error. Possible `error_code` attribute values:
88
89
          * `internal_server_error`
90
        schema:
91
          $ref: "../swagger.yaml#/definitions/error"
92
      "503":
93
        description: Under maintenance
94
        schema:
95
          $ref: "../swagger.yaml#/definitions/error"
96
    x-koha-authorization:
97
      permissions:
98
        catalogue: "1"
99
"/tickets/{ticket_id}":
100
  get:
101
    x-mojo-to: Tickets#get
102
    operationId: getTicket
103
    tags:
104
      - tickets
105
    summary: Get ticket
106
    parameters:
107
      - $ref: "../swagger.yaml#/parameters/ticket_id_pp"
108
    produces:
109
      - application/json
110
    responses:
111
      "200":
112
        description: A ticket
113
        schema:
114
          $ref: "../swagger.yaml#/definitions/ticket"
115
      "404":
116
        description: Ticket not found
117
        schema:
118
          $ref: "../swagger.yaml#/definitions/error"
119
      "500":
120
        description: |
121
          Internal server error. Possible `error_code` attribute values:
122
123
          * `internal_server_error`
124
        schema:
125
          $ref: "../swagger.yaml#/definitions/error"
126
      "503":
127
        description: Under maintenance
128
        schema:
129
          $ref: "../swagger.yaml#/definitions/error"
130
    x-koha-authorization:
131
      permissions:
132
        catalogue: "1"
133
  put:
134
    x-mojo-to: Tickets#update
135
    operationId: updateTicket
136
    tags:
137
      - tickets
138
    summary: Update ticket
139
    parameters:
140
      - $ref: "../swagger.yaml#/parameters/ticket_id_pp"
141
      - name: body
142
        in: body
143
        description: A ticket object
144
        required: true
145
        schema:
146
          $ref: "../swagger.yaml#/definitions/ticket"
147
    produces:
148
      - application/json
149
    responses:
150
      "200":
151
        description: A ticket
152
        schema:
153
          $ref: "../swagger.yaml#/definitions/ticket"
154
      "401":
155
        description: Authentication required
156
        schema:
157
          $ref: "../swagger.yaml#/definitions/error"
158
      "403":
159
        description: Access forbidden
160
        schema:
161
          $ref: "../swagger.yaml#/definitions/error"
162
      "404":
163
        description: Ticket not found
164
        schema:
165
          $ref: "../swagger.yaml#/definitions/error"
166
      "500":
167
        description: Internal error
168
        schema:
169
          $ref: "../swagger.yaml#/definitions/error"
170
      "503":
171
        description: Under maintenance
172
        schema:
173
          $ref: "../swagger.yaml#/definitions/error"
174
    x-koha-authorization:
175
      permissions:
176
        editcatalogue: edit_catalogue
177
  delete:
178
    x-mojo-to: Tickets#delete
179
    operationId: deleteTicket
180
    tags:
181
      - tickets
182
    summary: Delete ticket
183
    parameters:
184
      - $ref: "../swagger.yaml#/parameters/ticket_id_pp"
185
    produces:
186
      - application/json
187
    responses:
188
      "204":
189
        description: Ticket deleted
190
      "401":
191
        description: Authentication required
192
        schema:
193
          $ref: "../swagger.yaml#/definitions/error"
194
      "403":
195
        description: Access forbidden
196
        schema:
197
          $ref: "../swagger.yaml#/definitions/error"
198
      "404":
199
        description: Ticket not found
200
        schema:
201
          $ref: "../swagger.yaml#/definitions/error"
202
      "500":
203
        description: Internal error
204
        schema:
205
          $ref: "../swagger.yaml#/definitions/error"
206
      "503":
207
        description: Under maintenance
208
        schema:
209
          $ref: "../swagger.yaml#/definitions/error"
210
    x-koha-authorization:
211
      permissions:
212
        editcatalogue: edit_catalogue
213
/public/tickets:
214
  post:
215
    x-mojo-to: Tickets#add
216
    operationId: addTicketPublic
217
    tags:
218
      - tickets
219
    summary: Add ticket
220
    parameters:
221
      - name: body
222
        in: body
223
        description: A JSON object containing informations about the new ticket
224
        required: true
225
        schema:
226
          $ref: "../swagger.yaml#/definitions/ticket"
227
    produces:
228
      - application/json
229
    responses:
230
      "201":
231
        description: Ticket added
232
        schema:
233
          $ref: "../swagger.yaml#/definitions/ticket"
234
      "401":
235
        description: Authentication required
236
        schema:
237
          $ref: "../swagger.yaml#/definitions/error"
238
      "403":
239
        description: Access forbidden
240
        schema:
241
          $ref: "../swagger.yaml#/definitions/error"
242
      "500":
243
        description: |
244
          Internal server error. Possible `error_code` attribute values:
245
246
          * `internal_server_error`
247
        schema:
248
          $ref: "../swagger.yaml#/definitions/error"
249
      "503":
250
        description: Under maintenance
251
        schema:
252
          $ref: "../swagger.yaml#/definitions/error"
(-)a/api/v1/swagger/swagger.yaml (+14 lines)
Lines 88-93 definitions: Link Here
88
    $ref: ./definitions/smtp_server.yaml
88
    $ref: ./definitions/smtp_server.yaml
89
  suggestion:
89
  suggestion:
90
    $ref: ./definitions/suggestion.yaml
90
    $ref: ./definitions/suggestion.yaml
91
  ticket:
92
    $ref: ./definitions/ticket.yaml
91
  transfer_limit:
93
  transfer_limit:
92
    $ref: ./definitions/transfer_limit.yaml
94
    $ref: ./definitions/transfer_limit.yaml
93
  vendor:
95
  vendor:
Lines 293-298 paths: Link Here
293
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
295
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1guarantors~1can_see_checkouts"
294
  "/public/patrons/{patron_id}/password":
296
  "/public/patrons/{patron_id}/password":
295
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1password"
297
    $ref: "./paths/public_patrons.yaml#/~1public~1patrons~1{patron_id}~1password"
298
  "/public/tickets":
299
    $ref: "./paths/tickets.yaml#/~1public~1tickets"
296
  /quotes:
300
  /quotes:
297
    $ref: ./paths/quotes.yaml#/~1quotes
301
    $ref: ./paths/quotes.yaml#/~1quotes
298
  "/quotes/{quote_id}":
302
  "/quotes/{quote_id}":
Lines 313-318 paths: Link Here
313
    $ref: "./paths/suggestions.yaml#/~1suggestions~1{suggestion_id}"
317
    $ref: "./paths/suggestions.yaml#/~1suggestions~1{suggestion_id}"
314
  /suggestions/managers:
318
  /suggestions/managers:
315
    $ref: paths/suggestions.yaml#/~1suggestions~1managers
319
    $ref: paths/suggestions.yaml#/~1suggestions~1managers
320
  "/tickets":
321
    $ref: "./paths/tickets.yaml#/~1tickets"
322
  "/tickets/{ticket_id}":
323
    $ref: "./paths/tickets.yaml#/~1tickets~1{ticket_id}"
316
  /transfer_limits:
324
  /transfer_limits:
317
    $ref: ./paths/transfer_limits.yaml#/~1transfer_limits
325
    $ref: ./paths/transfer_limits.yaml#/~1transfer_limits
318
  /transfer_limits/batch:
326
  /transfer_limits/batch:
Lines 565-570 parameters: Link Here
565
    name: suggestion_id
573
    name: suggestion_id
566
    required: true
574
    required: true
567
    type: integer
575
    type: integer
576
  ticket_id_pp:
577
    description: Internal ticket identifier
578
    in: path
579
    name: ticket_id
580
    required: true
581
    type: integer
568
  transfer_limit_id_pp:
582
  transfer_limit_id_pp:
569
    description: Internal transfer limit identifier
583
    description: Internal transfer limit identifier
570
    in: path
584
    in: path
(-)a/t/db_dependent/api/v1/tickets.t (-1 / +377 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
6
# under the terms of the GNU General Public License as published by
7
# the Free Software Foundation; either version 3 of the License, or
8
# (at your option) any later version.
9
#
10
# Koha is distributed in the hope that it will be useful, but
11
# WITHOUT ANY WARRANTY; without even the implied warranty of
12
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
# GNU General Public License for more details.
14
#
15
# You should have received a copy of the GNU General Public License
16
# along with Koha; if not, see <http://www.gnu.org/licenses>.
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::Tickets;
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 => 14;
38
39
    $schema->storage->txn_begin;
40
41
    Koha::Tickets->search->delete;
42
43
    my $librarian = $builder->build_object(
44
        {
45
            class => 'Koha::Patrons',
46
            value => { flags => 2**2 }    # catalogue flag = 2
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 tickets, so empty array should be returned
65
    $t->get_ok("//$userid:$password@/api/v1/tickets")->status_is(200)
66
      ->json_is( [] );
67
68
    my $ticket = $builder->build_object( { class => 'Koha::Tickets' } );
69
70
    # One ticket created, should get returned
71
    $t->get_ok("//$userid:$password@/api/v1/tickets")->status_is(200)
72
      ->json_is( [ $ticket->to_api ] );
73
74
    my $another_ticket = $builder->build_object( { class => 'Koha::Tickets' } );
75
    my $and_another_ticket =
76
      $builder->build_object( { class => 'Koha::Tickets' } );
77
78
    # Two tickets created, they should both be returned
79
    $t->get_ok("//$userid:$password@/api/v1/tickets")->status_is(200)->json_is(
80
        [
81
            $ticket->to_api, $another_ticket->to_api,
82
            $and_another_ticket->to_api
83
        ]
84
    );
85
86
    # Warn on unsupported query parameter
87
    $t->get_ok("//$userid:$password@/api/v1/tickets?ticket_blah=blah")
88
      ->status_is(400)->json_is(
89
        [
90
            {
91
                path    => '/query/ticket_blah',
92
                message => 'Malformed query string'
93
            }
94
        ]
95
      );
96
97
    # Unauthorized access
98
    $t->get_ok("//$unauth_userid:$password@/api/v1/tickets")->status_is(403);
99
100
    $schema->storage->txn_rollback;
101
};
102
103
subtest 'get() tests' => sub {
104
105
    plan tests => 8;
106
107
    $schema->storage->txn_begin;
108
109
    my $ticket    = $builder->build_object( { class => 'Koha::Tickets' } );
110
    my $librarian = $builder->build_object(
111
        {
112
            class => 'Koha::Patrons',
113
            value => { flags => 2**2 }    # catalogue flag = 2
114
        }
115
    );
116
    my $password = 'thePassword123';
117
    $librarian->set_password( { password => $password, skip_validation => 1 } );
118
    my $userid = $librarian->userid;
119
120
    my $patron = $builder->build_object(
121
        {
122
            class => 'Koha::Patrons',
123
            value => { flags => 0 }
124
        }
125
    );
126
127
    $patron->set_password( { password => $password, skip_validation => 1 } );
128
    my $unauth_userid = $patron->userid;
129
130
    $t->get_ok( "//$userid:$password@/api/v1/tickets/" . $ticket->id )
131
      ->status_is(200)->json_is( $ticket->to_api );
132
133
    $t->get_ok( "//$unauth_userid:$password@/api/v1/tickets/" . $ticket->id )
134
      ->status_is(403);
135
136
    my $ticket_to_delete =
137
      $builder->build_object( { class => 'Koha::Tickets' } );
138
    my $non_existent_id = $ticket_to_delete->id;
139
    $ticket_to_delete->delete;
140
141
    $t->get_ok("//$userid:$password@/api/v1/tickets/$non_existent_id")
142
      ->status_is(404)->json_is( '/error' => 'Ticket not found' );
143
144
    $schema->storage->txn_rollback;
145
};
146
147
subtest 'add() tests' => sub {
148
149
    plan tests => 21;
150
151
    $schema->storage->txn_begin;
152
153
    my $librarian = $builder->build_object(
154
        {
155
            class => 'Koha::Patrons',
156
            value => { flags => 2**2 }    # catalogue flag = 2
157
        }
158
    );
159
    my $password = 'thePassword123';
160
    $librarian->set_password( { password => $password, skip_validation => 1 } );
161
    my $userid = $librarian->userid;
162
163
    my $patron = $builder->build_object(
164
        {
165
            class => 'Koha::Patrons',
166
            value => { flags => 0 }
167
        }
168
    );
169
170
    $patron->set_password( { password => $password, skip_validation => 1 } );
171
    my $unauth_userid = $patron->userid;
172
173
    my $biblio = $builder->build_sample_biblio();
174
    my $ticket = {
175
        biblio_id => $biblio->id,
176
        title     => "Test ticket",
177
        body      => "Test ticket details",
178
    };
179
180
    # Unauthorized attempt to write
181
    $t->post_ok(
182
        "//$unauth_userid:$password@/api/v1/tickets" => json => $ticket )
183
      ->status_is(403);
184
185
    # Authorized attempt to write invalid data
186
    my $ticket_with_invalid_field = {
187
        blah      => "Something wrong",
188
        biblio_id => $biblio->id,
189
        title     => "Test ticket",
190
        body      => "Test ticket details",
191
    };
192
193
    $t->post_ok( "//$userid:$password@/api/v1/tickets" => json =>
194
          $ticket_with_invalid_field )->status_is(400)->json_is(
195
        "/errors" => [
196
            {
197
                message => "Properties not allowed: blah.",
198
                path    => "/body"
199
            }
200
        ]
201
          );
202
203
    # Authorized attempt to write
204
    my $ticket_id =
205
      $t->post_ok( "//$userid:$password@/api/v1/tickets" => json => $ticket )
206
      ->status_is( 201, 'SWAGGER3.2.1' )->header_like(
207
        Location => qr|^\/api\/v1\/tickets/\d*|,
208
        'SWAGGER3.4.1'
209
    )->json_is( '/biblio_id' => $ticket->{biblio_id} )
210
      ->json_is( '/title'       => $ticket->{title} )
211
      ->json_is( '/body'        => $ticket->{body} )
212
      ->json_is( '/reporter_id' => $librarian->id )->tx->res->json->{ticket_id};
213
214
    # Authorized attempt to create with null id
215
    $ticket->{ticket_id} = undef;
216
    $t->post_ok( "//$userid:$password@/api/v1/tickets" => json => $ticket )
217
      ->status_is(400)->json_has('/errors');
218
219
    # Authorized attempt to create with existing id
220
    $ticket->{ticket_id} = $ticket_id;
221
    $t->post_ok( "//$userid:$password@/api/v1/tickets" => json => $ticket )
222
      ->status_is(400)->json_is(
223
        "/errors" => [
224
            {
225
                message => "Read-only.",
226
                path    => "/body/ticket_id"
227
            }
228
        ]
229
      );
230
231
    # Authorized attempt to write missing data
232
    my $ticket_with_missing_field = {
233
        biblio_id => $biblio->id,
234
        body      => "Test ticket details",
235
    };
236
237
    $t->post_ok( "//$userid:$password@/api/v1/tickets" => json =>
238
          $ticket_with_missing_field )->status_is(400)->json_is(
239
        "/errors" => [
240
            {
241
                message => "Missing property.",
242
                path    => "/body/title"
243
            }
244
        ]
245
    );
246
247
    $schema->storage->txn_rollback;
248
};
249
250
subtest 'update() tests' => sub {
251
252
    plan tests => 15;
253
254
    $schema->storage->txn_begin;
255
256
    my $librarian = $builder->build_object(
257
        {
258
            class => 'Koha::Patrons',
259
            value => { flags => 2**9 }    # editcatalogue flag = 9
260
        }
261
    );
262
    my $password = 'thePassword123';
263
    $librarian->set_password( { password => $password, skip_validation => 1 } );
264
    my $userid = $librarian->userid;
265
266
    my $patron = $builder->build_object(
267
        {
268
            class => 'Koha::Patrons',
269
            value => { flags => 0 }
270
        }
271
    );
272
273
    $patron->set_password( { password => $password, skip_validation => 1 } );
274
    my $unauth_userid = $patron->userid;
275
276
    my $ticket_id = $builder->build_object( { class => 'Koha::Tickets' } )->id;
277
278
    # Unauthorized attempt to update
279
    $t->put_ok(
280
        "//$unauth_userid:$password@/api/v1/tickets/$ticket_id" => json =>
281
          { name => 'New unauthorized name change' } )->status_is(403);
282
283
    # Attempt partial update on a PUT
284
    my $ticket_with_missing_field = {
285
        body      => "Test ticket details",
286
    };
287
288
    $t->put_ok( "//$userid:$password@/api/v1/tickets/$ticket_id" => json =>
289
          $ticket_with_missing_field )->status_is(400)
290
      ->json_is( "/errors" =>
291
          [ { message => "Missing property.", path => "/body/title" } ] );
292
293
    # Full object update on PUT
294
    my $ticket_with_updated_field = {
295
        title     => "Test ticket update",
296
        body      => "Test ticket update details",
297
    };
298
299
    $t->put_ok( "//$userid:$password@/api/v1/tickets/$ticket_id" => json =>
300
          $ticket_with_updated_field )->status_is(200)
301
      ->json_is( '/title' => 'Test ticket update' );
302
303
    # Authorized attempt to write invalid data
304
    my $ticket_with_invalid_field = {
305
        blah        => "Ticket Blah",
306
        title     => "Test ticket update",
307
        body      => "Test ticket update details",
308
    };
309
310
    $t->put_ok( "//$userid:$password@/api/v1/tickets/$ticket_id" => json =>
311
          $ticket_with_invalid_field )->status_is(400)->json_is(
312
        "/errors" => [
313
            {
314
                message => "Properties not allowed: blah.",
315
                path    => "/body"
316
            }
317
        ]
318
          );
319
320
    my $ticket_to_delete =
321
      $builder->build_object( { class => 'Koha::Tickets' } );
322
    my $non_existent_id = $ticket_to_delete->id;
323
    $ticket_to_delete->delete;
324
325
    $t->put_ok(
326
        "//$userid:$password@/api/v1/tickets/$non_existent_id" => json =>
327
          $ticket_with_updated_field )->status_is(404);
328
329
    # Wrong method (POST)
330
    $ticket_with_updated_field->{ticket_id} = 2;
331
332
    $t->post_ok( "//$userid:$password@/api/v1/tickets/$ticket_id" => json =>
333
          $ticket_with_updated_field )->status_is(404);
334
335
    $schema->storage->txn_rollback;
336
};
337
338
subtest 'delete() tests' => sub {
339
340
    plan tests => 7;
341
342
    $schema->storage->txn_begin;
343
344
    my $librarian = $builder->build_object(
345
        {
346
            class => 'Koha::Patrons',
347
            value => { flags => 2**9 }    # editcatalogue flag = 9
348
        }
349
    );
350
    my $password = 'thePassword123';
351
    $librarian->set_password( { password => $password, skip_validation => 1 } );
352
    my $userid = $librarian->userid;
353
354
    my $patron = $builder->build_object(
355
        {
356
            class => 'Koha::Patrons',
357
            value => { flags => 0 }
358
        }
359
    );
360
361
    $patron->set_password( { password => $password, skip_validation => 1 } );
362
    my $unauth_userid = $patron->userid;
363
364
    my $ticket_id = $builder->build_object( { class => 'Koha::Tickets' } )->id;
365
366
    # Unauthorized attempt to delete
367
    $t->delete_ok("//$unauth_userid:$password@/api/v1/tickets/$ticket_id")
368
      ->status_is(403);
369
370
    $t->delete_ok("//$userid:$password@/api/v1/tickets/$ticket_id")
371
      ->status_is( 204, 'SWAGGER3.2.4' )->content_is( '', 'SWAGGER3.3.4' );
372
373
    $t->delete_ok("//$userid:$password@/api/v1/tickets/$ticket_id")
374
      ->status_is(404);
375
376
    $schema->storage->txn_rollback;
377
};

Return to bug 31028