Bugzilla – Attachment 95305 Details for
Bug 23998
Messages REST API
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
Bug 23998: REST API for messages - Add /api/v1/messages endpoint
Bug-23998-REST-API-for-messages---Add-apiv1message.patch (text/plain), 34.86 KB, created by
Lari Taskula
on 2019-11-12 12:46:19 UTC
(
hide
)
Description:
Bug 23998: REST API for messages - Add /api/v1/messages endpoint
Filename:
MIME Type:
Creator:
Lari Taskula
Created:
2019-11-12 12:46:19 UTC
Size:
34.86 KB
patch
obsolete
>From a0a5092c92945786cebf603a9fdeb010f5dad1f8 Mon Sep 17 00:00:00 2001 >From: Lari Taskula <lari.taskula@hypernova.fi> >Date: Fri, 8 Nov 2019 14:20:37 +0000 >Subject: [PATCH] Bug 23998: REST API for messages - Add /api/v1/messages > endpoint > >Exposes messages database table via REST API. > >GET /api/v1/messages >POST /api/v1/messages >PUT /api/v1/messages >DELETE /api/v1/messages > >To test: >1. prove t/db_dependent/api/v1/messages.t > >Sponsored-by: Koha-Suomi Oy >--- > Koha/Patron/Message.pm | 19 ++ > Koha/REST/V1/Messages.pm | 255 +++++++++++++++ > api/v1/swagger/definitions.json | 3 + > api/v1/swagger/definitions/message.json | 37 +++ > api/v1/swagger/parameters.json | 3 + > api/v1/swagger/parameters/message.json | 9 + > api/v1/swagger/paths.json | 6 + > api/v1/swagger/paths/messages.json | 327 +++++++++++++++++++ > api/v1/swagger/x-primitives.json | 5 + > t/db_dependent/api/v1/messages.t | 403 ++++++++++++++++++++++++ > 10 files changed, 1067 insertions(+) > create mode 100644 Koha/REST/V1/Messages.pm > create mode 100644 api/v1/swagger/definitions/message.json > create mode 100644 api/v1/swagger/parameters/message.json > create mode 100644 api/v1/swagger/paths/messages.json > create mode 100644 t/db_dependent/api/v1/messages.t > >diff --git a/Koha/Patron/Message.pm b/Koha/Patron/Message.pm >index 838378011b..4a500d134f 100644 >--- a/Koha/Patron/Message.pm >+++ b/Koha/Patron/Message.pm >@@ -73,6 +73,25 @@ sub delete { > return $self->SUPER::delete($self); > } > >+=head3 to_api_mapping >+ >+This method returns the mapping for representing a Koha::Patron::Message object >+on the API. >+ >+=cut >+ >+sub to_api_mapping { >+ return { >+ message_id => 'message_id', >+ borrowernumber => 'patron_id', >+ branchcode => 'library_id', >+ message_type => 'message_type', >+ message => 'message', >+ message_date => 'message_date', >+ manager_id => 'manager_id', >+ }; >+} >+ > =head3 _type > > =cut >diff --git a/Koha/REST/V1/Messages.pm b/Koha/REST/V1/Messages.pm >new file mode 100644 >index 0000000000..5ea52b1e8e >--- /dev/null >+++ b/Koha/REST/V1/Messages.pm >@@ -0,0 +1,255 @@ >+package Koha::REST::V1::Messages; >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 3 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Mojo::Base 'Mojolicious::Controller'; >+ >+use Koha::Patron::Messages; >+ >+use Try::Tiny; >+ >+=head1 API >+ >+=head2 Class Methods >+ >+=head3 list >+ >+=cut >+ >+sub list { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $messages_set = Koha::Patron::Messages->new; >+ my $messages = $c->objects->search( $messages_set, \&_to_model, \&_to_api ); >+ return $c->render( status => 200, openapi => $messages ); >+ } >+ catch { >+ if ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->{msg} } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+ >+} >+ >+=head3 get >+ >+=cut >+ >+sub get { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $message = Koha::Patron::Messages->find( $c->validation->param('message_id') ); >+ unless ($message) { >+ return $c->render( status => 404, >+ openapi => { error => "Message not found" } ); >+ } >+ >+ return $c->render( status => 200, openapi => $message->to_api ); >+} >+ >+=head3 add >+ >+=cut >+ >+sub add { >+ my $c = shift->openapi->valid_input or return; >+ >+ return try { >+ my $message = Koha::Patron::Message->new( _to_model( $c->validation->param('body') ) ); >+ my $user = $c->stash('koha.user'); >+ $message->set({ manager_id => $user->borrowernumber }) unless defined $message->manager_id; >+ $message->store; >+ $c->res->headers->location( $c->req->url->to_string . '/' . $message->message_id ); >+ return $c->render( >+ status => 201, >+ openapi => $message->to_api >+ ); >+ } >+ catch { >+ if ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( >+ status => 500, >+ openapi => { error => $_->{msg} } >+ ); >+ } >+ else { >+ return $c->render( >+ status => 500, >+ openapi => { error => "Something went wrong, check the logs." } >+ ); >+ } >+ }; >+} >+ >+=head3 update >+ >+=cut >+ >+sub update { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $message = Koha::Patron::Messages->find( $c->validation->param('message_id') ); >+ >+ if ( not defined $message ) { >+ return $c->render( status => 404, >+ openapi => { error => "Object not found" } ); >+ } >+ >+ return try { >+ my $params = $c->req->json; >+ $message->set( _to_model($params) ); >+ $message->store(); >+ return $c->render( status => 200, openapi => $message->to_api ); >+ } >+ catch { >+ if ( $_->isa('Koha::Exceptions::Object') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->message } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+} >+ >+=head3 delete >+ >+=cut >+ >+sub delete { >+ my $c = shift->openapi->valid_input or return; >+ >+ my $message = Koha::Patron::Messages->find( $c->validation->param('message_id') ); >+ if ( not defined $message ) { >+ return $c->render( status => 404, >+ openapi => { error => "Object not found" } ); >+ } >+ >+ return try { >+ $message->delete; >+ return $c->render( status => 200, openapi => "" ); >+ } >+ catch { >+ if ( $_->isa('DBIx::Class::Exception') ) { >+ return $c->render( status => 500, >+ openapi => { error => $_->{msg} } ); >+ } >+ else { >+ return $c->render( status => 500, >+ openapi => { error => "Something went wrong, check the logs."} ); >+ } >+ }; >+} >+ >+=head3 _to_api >+ >+Helper function that maps a hashref of Koha::Patron::Message attributes into REST api >+attribute names. >+ >+=cut >+ >+sub _to_api { >+ my $message = shift; >+ >+ # Rename attributes >+ foreach my $column ( keys %{ $Koha::REST::V1::Messages::to_api_mapping } ) { >+ my $mapped_column = $Koha::REST::V1::Messages::to_api_mapping->{$column}; >+ if ( exists $message->{ $column } >+ && defined $mapped_column ) >+ { >+ # key /= undef >+ $message->{ $mapped_column } = delete $message->{ $column }; >+ } >+ elsif ( exists $message->{ $column } >+ && !defined $mapped_column ) >+ { >+ # key == undef => to be deleted >+ delete $message->{ $column }; >+ } >+ } >+ >+ return $message; >+} >+ >+=head3 _to_model >+ >+Helper function that maps REST api objects into Koha::Patron::Messages >+attribute names. >+ >+=cut >+ >+sub _to_model { >+ my $message = shift; >+ >+ foreach my $attribute ( keys %{ $Koha::REST::V1::Messages::to_model_mapping } ) { >+ my $mapped_attribute = $Koha::REST::V1::Messages::to_model_mapping->{$attribute}; >+ if ( exists $message->{ $attribute } >+ && defined $mapped_attribute ) >+ { >+ # key /= undef >+ $message->{ $mapped_attribute } = delete $message->{ $attribute }; >+ } >+ elsif ( exists $message->{ $attribute } >+ && !defined $mapped_attribute ) >+ { >+ # key == undef => to be deleted >+ delete $message->{ $attribute }; >+ } >+ } >+ >+ return $message; >+} >+ >+=head2 Global variables >+ >+=head3 $to_api_mapping >+ >+=cut >+ >+our $to_api_mapping = { >+ message_id => 'message_id', >+ borrowernumber => 'patron_id', >+ branchcode => 'library_id', >+ message_type => 'message_type', >+ message => 'message', >+ message_date => 'message_date', >+ manager_id => 'manager_id', >+}; >+ >+=head3 $to_model_mapping >+ >+=cut >+ >+our $to_model_mapping = { >+ message_id => 'message_id', >+ patron_id => 'borrowernumber', >+ library_id => 'branchcode', >+ message_type => 'message_type', >+ message => 'message', >+ message_date => 'message_date', >+ manager_id => 'manager_id', >+}; >+ >+1; >diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json >index 90374145a7..1542eabe44 100644 >--- a/api/v1/swagger/definitions.json >+++ b/api/v1/swagger/definitions.json >@@ -23,6 +23,9 @@ > "library": { > "$ref": "definitions/library.json" > }, >+ "message": { >+ "$ref": "definitions/message.json" >+ }, > "item": { > "$ref": "definitions/item.json" > }, >diff --git a/api/v1/swagger/definitions/message.json b/api/v1/swagger/definitions/message.json >new file mode 100644 >index 0000000000..8677280c6a >--- /dev/null >+++ b/api/v1/swagger/definitions/message.json >@@ -0,0 +1,37 @@ >+{ >+ "type": "object", >+ "properties": { >+ "message_id": { >+ "$ref": "../x-primitives.json#/message_id" >+ }, >+ "patron_id": { >+ "$ref": "../x-primitives.json#/patron_id" >+ }, >+ "library_id": { >+ "type": ["string", "null"], >+ "description": "Internally assigned library identifier", >+ "maxLength": 10, >+ "minLength": 1 >+ }, >+ "message_type": { >+ "description": "One of following values: L = For Librarians, B = For Patrons", >+ "type": "string", >+ "maxLength": 1 >+ }, >+ "message": { >+ "description": "Message content", >+ "type": "string" >+ }, >+ "message_date": { >+ "description": "Message content", >+ "format": "date-time", >+ "type": "string" >+ }, >+ "manager_id": { >+ "type": ["integer", "null"], >+ "description": "Internal patron identifier for message manager" >+ } >+ }, >+ "additionalProperties": false, >+ "required": ["patron_id", "message_type", "message"] >+} >diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json >index 932d251d42..b6f528fb15 100644 >--- a/api/v1/swagger/parameters.json >+++ b/api/v1/swagger/parameters.json >@@ -20,6 +20,9 @@ > "library_id_pp": { > "$ref": "parameters/library.json#/library_id_pp" > }, >+ "message_id_pp": { >+ "$ref": "parameters/message.json#/message_id_pp" >+ }, > "item_id_pp": { > "$ref": "parameters/item.json#/item_id_pp" > }, >diff --git a/api/v1/swagger/parameters/message.json b/api/v1/swagger/parameters/message.json >new file mode 100644 >index 0000000000..63468da2e9 >--- /dev/null >+++ b/api/v1/swagger/parameters/message.json >@@ -0,0 +1,9 @@ >+{ >+ "message_id_pp": { >+ "name": "message_id", >+ "in": "path", >+ "description": "Message internal identifier", >+ "required": true, >+ "type": "integer" >+ } >+} >diff --git a/api/v1/swagger/paths.json b/api/v1/swagger/paths.json >index 95278ec23a..c152e072b2 100644 >--- a/api/v1/swagger/paths.json >+++ b/api/v1/swagger/paths.json >@@ -56,6 +56,12 @@ > "/libraries/{library_id}": { > "$ref": "paths/libraries.json#/~1libraries~1{library_id}" > }, >+ "/messages": { >+ "$ref": "paths/messages.json#/~1messages" >+ }, >+ "/messages/{message_id}": { >+ "$ref": "paths/messages.json#/~1messages~1{message_id}" >+ }, > "/checkouts/{checkout_id}/allows_renewal": { > "$ref": "paths/checkouts.json#/~1checkouts~1{checkout_id}~1allows_renewal" > }, >diff --git a/api/v1/swagger/paths/messages.json b/api/v1/swagger/paths/messages.json >new file mode 100644 >index 0000000000..f158441ab7 >--- /dev/null >+++ b/api/v1/swagger/paths/messages.json >@@ -0,0 +1,327 @@ >+{ >+ "/messages": { >+ "get": { >+ "x-mojo-to": "Messages#list", >+ "operationId": "listmessages", >+ "tags": ["messages"], >+ "produces": [ >+ "application/json" >+ ], >+ "parameters": [{ >+ "name": "patron_id", >+ "in": "query", >+ "description": "Search on patron id", >+ "required": false, >+ "type": "integer" >+ }, { >+ "name": "library_id", >+ "in": "query", >+ "description": "Case insensitive search on library id", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "message_type", >+ "in": "query", >+ "description": "Case insensitive search on message type", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "message", >+ "in": "query", >+ "description": "Case Insensitive search on message content", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "message_date", >+ "in": "query", >+ "description": "Case Insensitive search on message date", >+ "required": false, >+ "type": "string" >+ }, { >+ "name": "manager_id", >+ "in": "query", >+ "description": "Case Insensitive search on manager patron id", >+ "required": false, >+ "type": "integer" >+ }], >+ "responses": { >+ "200": { >+ "description": "A list of messages", >+ "schema": { >+ "type": "array", >+ "items": { >+ "$ref": "../definitions.json#/message" >+ } >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "borrowers": "1" >+ } >+ } >+ }, >+ "post": { >+ "x-mojo-to": "Messages#add", >+ "operationId": "addmessage", >+ "tags": ["messages"], >+ "parameters": [{ >+ "name": "body", >+ "in": "body", >+ "description": "A JSON object containing informations about the new hold", >+ "required": true, >+ "schema": { >+ "$ref": "../definitions.json#/message" >+ } >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "201": { >+ "description": "message added", >+ "schema": { >+ "$ref": "../definitions.json#/message" >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "borrowers": "edit_borrowers" >+ } >+ } >+ } >+ }, >+ "/messages/{message_id}": { >+ "get": { >+ "x-mojo-to": "Messages#get", >+ "operationId": "getmessage", >+ "tags": ["messages"], >+ "parameters": [{ >+ "$ref": "../parameters.json#/message_id_pp" >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A message", >+ "schema": { >+ "$ref": "../definitions.json#/message" >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "message not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "borrowers": "1" >+ } >+ } >+ }, >+ "put": { >+ "x-mojo-to": "Messages#update", >+ "operationId": "updatemessage", >+ "tags": ["messages"], >+ "parameters": [{ >+ "$ref": "../parameters.json#/message_id_pp" >+ }, { >+ "name": "body", >+ "in": "body", >+ "description": "A message object", >+ "required": true, >+ "schema": { >+ "$ref": "../definitions.json#/message" >+ } >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "A message", >+ "schema": { >+ "$ref": "../definitions.json#/message" >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "message not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "borrowers": "edit_borrowers" >+ } >+ } >+ }, >+ "delete": { >+ "x-mojo-to": "Messages#delete", >+ "operationId": "deletemessage", >+ "tags": ["messages"], >+ "parameters": [{ >+ "$ref": "../parameters.json#/message_id_pp" >+ }], >+ "produces": [ >+ "application/json" >+ ], >+ "responses": { >+ "200": { >+ "description": "message deleted", >+ "schema": { >+ "type": "string" >+ } >+ }, >+ "400": { >+ "description": "Bad request", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "401": { >+ "description": "Authentication required", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "403": { >+ "description": "Access forbidden", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "404": { >+ "description": "message not found", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "500": { >+ "description": "Internal error", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ }, >+ "503": { >+ "description": "Under maintenance", >+ "schema": { >+ "$ref": "../definitions.json#/error" >+ } >+ } >+ }, >+ "x-koha-authorization": { >+ "permissions": { >+ "borrowers": "edit_borrowers" >+ } >+ } >+ } >+ } >+} >diff --git a/api/v1/swagger/x-primitives.json b/api/v1/swagger/x-primitives.json >index ee15fa6aa1..7ee33f11fa 100644 >--- a/api/v1/swagger/x-primitives.json >+++ b/api/v1/swagger/x-primitives.json >@@ -26,6 +26,11 @@ > "type": ["string", "null"], > "description": "primary email address for patron's primary address" > }, >+ "message_id": { >+ "type": "integer", >+ "description": "internally assigned message identifier", >+ "readOnly": true >+ }, > "firstname": { > "type": ["string", "null"], > "description": "patron's first name" >diff --git a/t/db_dependent/api/v1/messages.t b/t/db_dependent/api/v1/messages.t >new file mode 100644 >index 0000000000..70f746c745 >--- /dev/null >+++ b/t/db_dependent/api/v1/messages.t >@@ -0,0 +1,403 @@ >+#!/usr/bin/env perl >+ >+# This file is part of Koha. >+# >+# Koha is free software; you can redistribute it and/or modify it under the >+# terms of the GNU General Public License as published by the Free Software >+# Foundation; either version 3 of the License, or (at your option) any later >+# version. >+# >+# Koha is distributed in the hope that it will be useful, but WITHOUT ANY >+# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR >+# A PARTICULAR PURPOSE. See the GNU General Public License for more details. >+# >+# You should have received a copy of the GNU General Public License along >+# with Koha; if not, write to the Free Software Foundation, Inc., >+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. >+ >+use Modern::Perl; >+ >+use Test::More tests => 5; >+use Test::Mojo; >+ >+use t::lib::TestBuilder; >+use t::lib::Mocks; >+ >+use Koha::Patron::Messages; >+use Koha::Database; >+ >+my $schema = Koha::Database->new->schema; >+my $builder = t::lib::TestBuilder->new; >+ >+my $t = Test::Mojo->new('Koha::REST::V1'); >+t::lib::Mocks::mock_preference( 'RESTBasicAuth', 1 ); >+ >+subtest 'list() tests' => sub { >+ >+ plan tests => 20; >+ >+ $schema->storage->txn_begin; >+ >+ Koha::Patron::Messages->search->delete; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 4 ** 2 } # borrowers flag = 4 >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ ## Authorized user tests >+ # No messages, so empty array should be returned >+ $t->get_ok("//$userid:$password@/api/v1/messages") >+ ->status_is(200) >+ ->json_is( [] ); >+ >+ my $message = $builder->build_object({ class => 'Koha::Patron::Messages' }); >+ >+ # One message created, should get returned >+ $t->get_ok("//$userid:$password@/api/v1/messages") >+ ->status_is(200) >+ ->json_is( [Koha::REST::V1::Messages::_to_api( $message->TO_JSON )] ); >+ >+ my $another_message = $builder->build_object( >+ { class => 'Koha::Patron::Messages', value => { message_type => $message->message_type } } ); >+ my $message_with_another_message_type = $builder->build_object({ class => 'Koha::Patron::Messages' }); >+ >+ # Two messages created, they should both be returned >+ $t->get_ok("//$userid:$password@/api/v1/messages") >+ ->status_is(200) >+ ->json_is([Koha::REST::V1::Messages::_to_api($message->TO_JSON), >+ Koha::REST::V1::Messages::_to_api($another_message->TO_JSON), >+ Koha::REST::V1::Messages::_to_api($message_with_another_message_type->TO_JSON) >+ ] ); >+ >+ # Filtering works, two messages sharing message_type >+ $t->get_ok("//$userid:$password@/api/v1/messages?message_type=" . $message->message_type ) >+ ->status_is(200) >+ ->json_is([ Koha::REST::V1::Messages::_to_api($message->TO_JSON), >+ Koha::REST::V1::Messages::_to_api($another_message->TO_JSON) >+ ]); >+ >+ $t->get_ok("//$userid:$password@/api/v1/messages?message=" . $message->message ) >+ ->status_is(200) >+ ->json_is( [Koha::REST::V1::Messages::_to_api($message->TO_JSON)] ); >+ >+ # Warn on unsupported query parameter >+ $t->get_ok("//$userid:$password@/api/v1/messages?message_blah=blah" ) >+ ->status_is(400) >+ ->json_is( [{ path => '/query/message_blah', message => 'Malformed query string'}] ); >+ >+ # Unauthorized access >+ $t->get_ok("//$unauth_userid:$password@/api/v1/messages") >+ ->status_is(403); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'get() tests' => sub { >+ >+ plan tests => 8; >+ >+ $schema->storage->txn_begin; >+ >+ my $message = $builder->build_object({ class => 'Koha::Patron::Messages' }); >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 4**2 } # borrowers flag = 4 >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ $t->get_ok( "//$userid:$password@/api/v1/messages/" . $message->message_id ) >+ ->status_is(200) >+ ->json_is(Koha::REST::V1::Messages::_to_api($message->TO_JSON)); >+ >+ $t->get_ok( "//$unauth_userid:$password@/api/v1/messages/" . $message->message_id ) >+ ->status_is(403); >+ >+ my $message_to_delete = $builder->build_object({ class => 'Koha::Patron::Messages' }); >+ my $non_existent_id = $message_to_delete->id; >+ $message_to_delete->delete; >+ >+ $t->get_ok( "//$userid:$password@/api/v1/messages/$non_existent_id" ) >+ ->status_is(404) >+ ->json_is( '/error' => 'Message not found' ); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'add() tests' => sub { >+ >+ plan tests => 27; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 4**2 } # borrowers flag = 4 >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ my $message = { >+ patron_id => $patron->borrowernumber, >+ library_id => $patron->branchcode, >+ message_type => "B", >+ message => "Old Fox jumped over Cheeseboy" >+ }; >+ >+ # Unauthorized attempt to write >+ $t->post_ok("//$unauth_userid:$password@/api/v1/messages" => json => $message) >+ ->status_is(403); >+ >+ # Authorized attempt to write invalid data >+ my $message_with_invalid_field = { >+ blah => "message Blah", >+ patron_id => $patron->borrowernumber, >+ library_id => $patron->branchcode, >+ message_type => "B", >+ message => "Old Fox jumped over Cheeseboy", >+ manager_id => $librarian->borrowernumber >+ }; >+ >+ $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message_with_invalid_field ) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Properties not allowed: blah.", >+ path => "/body" >+ } >+ ] >+ ); >+ >+ # Authorized attempt to write >+ my $message_id = >+ $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message ) >+ ->status_is( 201, 'SWAGGER3.2.1' ) >+ ->header_like( >+ Location => qr|^\/api\/v1\/messages/\d*|, >+ 'SWAGGER3.4.1' >+ ) >+ ->json_is( '/patron_id' => $message->{patron_id} ) >+ ->json_is( '/library_id' => $message->{library_id} ) >+ ->json_is( '/message_type' => $message->{message_type} ) >+ ->json_is( '/message' => $message->{message} ) >+ ->json_is( '/manager_id' => $librarian->borrowernumber ) >+ ->tx->res->json->{message_id}; >+ >+ # Authorized attempt to write with manager_id defined >+ $message->{manager_id} = $message->{patron_id}; >+ $message_id = >+ $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message ) >+ ->status_is( 201, 'SWAGGER3.2.1' ) >+ ->header_like( >+ Location => qr|^\/api\/v1\/messages/\d*|, >+ 'SWAGGER3.4.1' >+ ) >+ ->json_is( '/patron_id' => $message->{patron_id} ) >+ ->json_is( '/library_id' => $message->{library_id} ) >+ ->json_is( '/message_type' => $message->{message_type} ) >+ ->json_is( '/message' => $message->{message} ) >+ ->json_is( '/manager_id' => $message->{patron_id} ) >+ ->tx->res->json->{message_id}; >+ >+ # Authorized attempt to create with null id >+ $message->{message_id} = undef; >+ $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message ) >+ ->status_is(400) >+ ->json_has('/errors'); >+ >+ # Authorized attempt to create with existing id >+ $message->{message_id} = $message_id; >+ $t->post_ok( "//$userid:$password@/api/v1/messages" => json => $message ) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Read-only.", >+ path => "/body/message_id" >+ } >+ ] >+ ); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'update() tests' => sub { >+ >+ plan tests => 15; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 4**2 } # borrowers flag = 4 >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ my $message_id = $builder->build_object({ class => 'Koha::Patron::Messages' } )->id; >+ >+ # Unauthorized attempt to update >+ $t->put_ok( "//$unauth_userid:$password@/api/v1/messages/$message_id" => json => { name => 'New unauthorized name change' } ) >+ ->status_is(403); >+ >+ # Attempt partial update on a PUT >+ my $message_with_missing_field = { >+ patron_id => $patron->borrowernumber, >+ library_id => $patron->branchcode, >+ message => "Old Fox jumped over Cheeseboy", >+ manager_id => $librarian->borrowernumber >+ }; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_missing_field ) >+ ->status_is(400) >+ ->json_is( "/errors" => >+ [ { message => "Missing property.", path => "/body/message_type" } ] >+ ); >+ >+ # Full object update on PUT >+ my $message_with_updated_field = { >+ patron_id => $patron->borrowernumber, >+ library_id => $patron->branchcode, >+ message_type => "B", >+ message => "Old Fox jumped over Cheeseboy", >+ manager_id => $librarian->borrowernumber >+ }; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_updated_field ) >+ ->status_is(200) >+ ->json_is( '/message' => 'Old Fox jumped over Cheeseboy' ); >+ >+ # Authorized attempt to write invalid data >+ my $message_with_invalid_field = { >+ blah => "message Blah", >+ patron_id => $patron->borrowernumber, >+ library_id => $patron->branchcode, >+ message_type => "B", >+ message => "Old Fox jumped over Cheeseboy", >+ manager_id => $librarian->borrowernumber >+ }; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_invalid_field ) >+ ->status_is(400) >+ ->json_is( >+ "/errors" => [ >+ { >+ message => "Properties not allowed: blah.", >+ path => "/body" >+ } >+ ] >+ ); >+ >+ my $message_to_delete = $builder->build_object({ class => 'Koha::Patron::Messages' }); >+ my $non_existent_id = $message_to_delete->id; >+ $message_to_delete->delete; >+ >+ $t->put_ok( "//$userid:$password@/api/v1/messages/$non_existent_id" => json => $message_with_updated_field ) >+ ->status_is(404); >+ >+ # Wrong method (POST) >+ $message_with_updated_field->{message_id} = 2; >+ >+ $t->post_ok( "//$userid:$password@/api/v1/messages/$message_id" => json => $message_with_updated_field ) >+ ->status_is(404); >+ >+ $schema->storage->txn_rollback; >+}; >+ >+subtest 'delete() tests' => sub { >+ >+ plan tests => 7; >+ >+ $schema->storage->txn_begin; >+ >+ my $librarian = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 4**2 } # borrowers flag = 4 >+ } >+ ); >+ my $password = 'thePassword123'; >+ $librarian->set_password( { password => $password, skip_validation => 1 } ); >+ my $userid = $librarian->userid; >+ >+ my $patron = $builder->build_object( >+ { >+ class => 'Koha::Patrons', >+ value => { flags => 0 } >+ } >+ ); >+ >+ $patron->set_password( { password => $password, skip_validation => 1 } ); >+ my $unauth_userid = $patron->userid; >+ >+ my $message_id = $builder->build_object({ class => 'Koha::Patron::Messages' })->id; >+ >+ # Unauthorized attempt to delete >+ $t->delete_ok( "//$unauth_userid:$password@/api/v1/messages/$message_id" ) >+ ->status_is(403); >+ >+ $t->delete_ok("//$userid:$password@/api/v1/messages/$message_id") >+ ->status_is(200) >+ ->content_is('""'); >+ >+ $t->delete_ok("//$userid:$password@/api/v1/messages/$message_id") >+ ->status_is(404); >+ >+ $schema->storage->txn_rollback; >+}; >-- >2.17.1
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
|
Splinter Review
Attachments on
bug 23998
:
95304
|
95305
|
95310