From c7266d8a9c8f9372d8a6cc79f4a8c6de11882912 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Thu, 27 Apr 2017 13:02:11 +0000 Subject: [PATCH] Bug 14843: REST API for message queue - /api/v1/notices GET /api/v1/notices POST /api/v1/notices GET /api/v1/notices/{message_id} PUT /api/v1/notices/{message_id} PATCH /api/v1/notices/{message_id} DELETE /api/v1/notices/{message_id} POST /api/v1/notices/{message_id}/resend New permissions: - Module * messages - Sub-permissions * get_message * create_message * update_message * delete_message * resend_message To test: 1. prove t/db_dependent/api/v1/notices.t --- Koha/REST/V1/Auth.pm | 16 + Koha/REST/V1/Notice.pm | 176 ++++++++ api/v1/swagger/definitions.json | 3 + api/v1/swagger/definitions/notice.json | 59 +++ api/v1/swagger/parameters.json | 3 + api/v1/swagger/parameters/notice.json | 9 + api/v1/swagger/paths.json | 9 + api/v1/swagger/paths/notices.json | 493 +++++++++++++++++++++ ...ermissions_for_message_queue-REST_operations.pl | 35 ++ t/db_dependent/api/v1/notices.t | 411 +++++++++++++++++ 10 files changed, 1214 insertions(+) create mode 100644 Koha/REST/V1/Notice.pm create mode 100644 api/v1/swagger/definitions/notice.json create mode 100644 api/v1/swagger/parameters/notice.json create mode 100644 api/v1/swagger/paths/notices.json create mode 100644 installer/data/mysql/atomicupdate/Bug-14843-Add_Permissions_for_message_queue-REST_operations.pl create mode 100644 t/db_dependent/api/v1/notices.t diff --git a/Koha/REST/V1/Auth.pm b/Koha/REST/V1/Auth.pm index 3b47f77..d094545 100644 --- a/Koha/REST/V1/Auth.pm +++ b/Koha/REST/V1/Auth.pm @@ -28,6 +28,7 @@ use C4::Auth qw( check_cookie_auth get_session haspermission ); use Koha::Account::Lines; use Koha::Checkouts; use Koha::Holds; +use Koha::Notice::Messages; use Koha::Old::Checkouts; use Koha::Patrons; @@ -335,6 +336,7 @@ sub check_object_ownership { borrowernumber => \&_object_ownership_by_borrowernumber, checkout_id => \&_object_ownership_by_checkout_id, reserve_id => \&_object_ownership_by_reserve_id, + message_id => \&_object_ownership_by_message_id, }; foreach my $param ( keys %{ $parameters } ) { @@ -398,6 +400,20 @@ sub _object_ownership_by_checkout_id { && $user->borrowernumber == $issue->borrowernumber; } +=head3 _object_ownership_by_message_id + +Finds a Koha::Notice::Message-object by C<$message_id> and checks if it +belongs to C<$user>. + +=cut + +sub _object_ownership_by_message_id { + my ($c, $user, $message_id) = @_; + + my $message = Koha::Notice::Messages->find($message_id); + return $message && $user->borrowernumber == $message->borrowernumber; +} + =head3 _object_ownership_by_reserve_id Finds a Koha::Hold-object by C<$reserve_id> and checks if it diff --git a/Koha/REST/V1/Notice.pm b/Koha/REST/V1/Notice.pm new file mode 100644 index 0000000..f910e01 --- /dev/null +++ b/Koha/REST/V1/Notice.pm @@ -0,0 +1,176 @@ +package Koha::REST::V1::Notice; + +# 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::Notice::Messages; + +use Try::Tiny; + +sub list { + my $c = shift->openapi->valid_input or return; + + return try { + my $params = $c->req->query_params->to_hash; + $params = _between_time_queued($params); # Construct 'time_queued' + my $notices; + if (keys %$params) { + my @valid_params = Koha::Notice::Messages->columns; + foreach my $key (keys %$params) { + delete $params->{$key} unless grep { $key eq $_ } @valid_params; + } + $notices = Koha::Notice::Messages->search($params); + } else { + $notices = Koha::Notice::Messages->search; + } + + return $c->render(status => 200, openapi => $notices); + } + catch { + Koha::Exceptions::rethrow_exception($_); + }; +} + +sub get { + my $c = shift->openapi->valid_input or return; + + my $message_id = $c->validation->param('message_id'); + my $notice; + return try { + $notice = Koha::Notice::Messages->find($message_id); + + unless ($notice) { + return $c->render( status => 404, + openapi => { error => "Notice not found" } ); + } + + return $c->render(status => 200, openapi => $notice); + } + catch { + Koha::Exceptions::rethrow_exception($_); + }; +} + +sub add { + my $c = shift->openapi->valid_input or return; + + return try { + my $body = $c->req->json; + + my $notice = Koha::Notice::Message->new($body)->store; + $notice = Koha::Notice::Messages->find($notice->message_id); + return $c->render(status => 201, openapi => $notice); + } + catch { + Koha::Exceptions::rethrow_exception($_); + }; +} + +sub edit { + my $c = shift->openapi->valid_input or return; + + my $notice; + return try { + my $message_id = $c->validation->param('message_id'); + $notice = Koha::Notice::Messages->find($message_id); + my $body = $c->req->json; + + $notice->set($body); + return $c->render( status => 204, openapi => {}) unless $notice->is_changed; + $notice->store; + return $c->render( status => 200, openapi => $notice); + } + catch { + unless ($notice) { + return $c->render( status => 404, + openapi => { error => "Notice not found" } ); + } + Koha::Exceptions::rethrow_exception($_); + }; +} + +sub patch { + return edit(@_); +} + +sub delete { + my $c = shift->openapi->valid_input or return; + + my $notice = Koha::Notice::Messages->find($c->validation->param('message_id')); + unless ($notice) { + return $c->render( status => 404, + openapi => { error => "Notice not found" } ); + } + + my $res = $notice->delete; + + if ($res eq '1') { + return $c->render( status => 204, openapi => {}); + } elsif ($res eq '-1') { + return $c->render( status => 404, openapi => {}); + } else { + return $c->render( status => 400, openapi => {}); + } +} + +sub resend { + my $c = shift->openapi->valid_input or return; + + my $notice; + return try { + my $message_id = $c->validation->param('message_id'); + $notice = Koha::Notice::Messages->find($message_id); + $notice->status('pending')->store; + return $c->render( status => 204, openapi => {}); + } + catch { + unless ($notice) { + return $c->render( status => 404, + openapi => { error => "Notice not found" } ); + } + Koha::Exceptions::rethrow_exception($_); + }; +} + +sub _between_time_queued { + my ($params) = @_; + + return $params if $params->{'time_queued'}; + return $params if ( !$params->{'time_queued_start'} + && !$params->{'time_queued_end'} ); + + my $start = $params->{'time_queued_start'}; + my $end = $params->{'time_queued_end'}; + + if ($start && !$end) { + $params->{'time_queued'} = { '>=', $start }; + } + elsif (!$start && $end) { + $params->{'time_queued'} = { '<=', $end }; + } + else { + $params->{'time_queued'} = { '-between', [$start, $end] }; + } + + delete $params->{'time_queued_start'}; + delete $params->{'time_queued_end'}; + return $params; +} + +1; diff --git a/api/v1/swagger/definitions.json b/api/v1/swagger/definitions.json index 4dd6d33..5a5a406 100644 --- a/api/v1/swagger/definitions.json +++ b/api/v1/swagger/definitions.json @@ -50,6 +50,9 @@ "library": { "$ref": "definitions/library.json" }, + "notice": { + "$ref": "definitions/notice.json" + }, "error": { "$ref": "definitions/error.json" }, diff --git a/api/v1/swagger/definitions/notice.json b/api/v1/swagger/definitions/notice.json new file mode 100644 index 0000000..1f02944 --- /dev/null +++ b/api/v1/swagger/definitions/notice.json @@ -0,0 +1,59 @@ +{ + "type": "object", + "properties": { + "message_id": { + "description": "Message internal identifier", + "type": "integer", + "readOnly": true + }, + "borrowernumber": { + "$ref": "../x-primitives.json#/borrowernumber" + }, + "subject": { + "description": "Subject of the message", + "type": ["string", "null"] + }, + "content": { + "description": "Content of the message", + "type": ["string", "null"] + }, + "metadata": { + "description": "", + "type": ["string", "null"] + }, + "letter_code": { + "description": "", + "type": ["string", "null"] + }, + "message_transport_type": { + "description": "Transport method. Values accepted by default are 'email', 'sms', 'phone' and 'print'", + "type": "string" + }, + "status": { + "description": "Delivery status", + "type": "string" + }, + "time_queued": { + "description": "Date and time of when message was placed in queue", + "type": "string", + "format": "date-time" + }, + "to_address": { + "description": "Destination email address", + "type": ["string", "null"] + }, + "from_address": { + "description": "Source address of email", + "type": ["string", "null"] + }, + "content_type": { + "description": "Content type", + "type": ["string", "null"] + }, + "delivery_note": { + "description": "Additional delivery notes", + "type": ["string", "null"] + } + }, + "additionalProperties": false +} diff --git a/api/v1/swagger/parameters.json b/api/v1/swagger/parameters.json index f8fd864..24d1ca0 100644 --- a/api/v1/swagger/parameters.json +++ b/api/v1/swagger/parameters.json @@ -38,6 +38,9 @@ "itemnumbersQueryParam": { "$ref": "parameters/item.json#/itemnumbersQueryParam" }, + "message_idPathParam": { + "$ref": "parameters/notice.json#/message_idPathParam" + }, "passwordPostParam": { "$ref": "parameters/auth.json#/passwordPostParam" }, diff --git a/api/v1/swagger/parameters/notice.json b/api/v1/swagger/parameters/notice.json new file mode 100644 index 0000000..5788419 --- /dev/null +++ b/api/v1/swagger/parameters/notice.json @@ -0,0 +1,9 @@ +{ + "message_idPathParam": { + "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 db50edc..a398805 100644 --- a/api/v1/swagger/paths.json +++ b/api/v1/swagger/paths.json @@ -77,6 +77,15 @@ "/libraries/{branchcode}": { "$ref": "paths/libraries.json#/~1libraries~1{branchcode}" }, + "/notices": { + "$ref": "paths/notices.json#/~1notices" + }, + "/notices/{message_id}": { + "$ref": "paths/notices.json#/~1notices~1{message_id}" + }, + "/notices/{message_id}/resend": { + "$ref": "paths/notices.json#/~1notices~1{message_id}~1resend" + }, "/patrons": { "$ref": "paths/patrons.json#/~1patrons" }, diff --git a/api/v1/swagger/paths/notices.json b/api/v1/swagger/paths/notices.json new file mode 100644 index 0000000..6351f5c --- /dev/null +++ b/api/v1/swagger/paths/notices.json @@ -0,0 +1,493 @@ +{ + "/notices": { + "get": { + "x-mojo-to": "Notice#list", + "operationId": "listNotices", + "x-koha-authorization": { + "permissions": { + "messages": "get_message" + }, + "allow-owner": true, + "allow-guarantor": true + }, + "tags": ["notices"], + "parameters": [{ + "name": "borrowernumber", + "in": "query", + "description": "Patron's borrowernumber", + "required": false, + "type": "integer" + }, { + "name": "subject", + "in": "query", + "description": "Case insensative 'starts-with' search on subject", + "required": false, + "type": "string" + }, { + "name": "content", + "in": "query", + "description": "Case insensative 'starts_with' search on content", + "required": false, + "type": "string" + }, { + "name": "metadata", + "in": "query", + "description": "Case insensative 'starts_with' search on metadata", + "required": false, + "type": "string" + }, { + "name": "message_transport_type", + "in": "query", + "description": "Case insensative 'starts_with' search on message transport type", + "required": false, + "type": "string" + }, { + "name": "time_queued_start", + "in": "query", + "description": "Search notices after given time", + "required": false, + "type": "string", + "format": "date-time" + }, { + "name": "time_queued_end", + "in": "query", + "description": "Search notices before given time", + "required": false, + "type": "string" + }, { + "name": "to_address", + "in": "query", + "description": "Case insensative 'starts_with' search on to address", + "required": false, + "type": "string" + }, { + "name": "from_address", + "in": "query", + "description": "Case insensative 'starts_with' search on from address", + "required": false, + "type": "string" + }, { + "name": "content_type", + "in": "query", + "description": "Case insensative 'starts_with' search on content type", + "required": false, + "type": "string" + }, { + "name": "delivery_note", + "in": "query", + "description": "Case insensative 'starts_with' search on delivery note", + "required": false, + "type": "string" + }], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A list of notices", + "schema": { + "type": "array", + "items": { + "$ref" : "../definitions.json#/notice" + } + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Notice 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" + } + } + } + }, + "post": { + "x-mojo-to": "Notice#add", + "operationId": "addNotice", + "x-koha-authorization": { + "permissions": { + "messages": "create_message" + } + }, + "tags": ["notices"], + "parameters": [ + { + "name": "body", + "in": "body", + "description": "A JSON object containing informations about the new notice", + "required": true, + "schema": { "$ref" : "../definitions.json#/notice" } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "201": { + "description": "A notice", + "schema": { + "$ref" : "../definitions.json#/notice" + } + }, + "400": { + "description": "Missing or wrong parameters", + "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" + } + } + } + } + }, + "/notices/{message_id}": { + "put": { + "x-mojo-to": "Notice#edit", + "operationId": "editNotice", + "x-koha-authorization": { + "permissions": { + "messages": "update_message" + } + }, + "tags": ["notices"], + "parameters": [ + { + "name": "body", + "in": "body", + "description": "A JSON object containing informations about the new notice", + "required": false, + "schema": { "$ref": "../definitions.json#/notice" } + }, + { + "$ref": "../parameters.json#/message_idPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A notice", + "schema": { + "$ref" : "../definitions.json#/notice" + } + }, + "400": { + "description": "Missing or wrong parameters", + "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": "Notice 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" + } + } + } + }, + "patch": { + "x-mojo-to": "Notice#patch", + "operationId": "patchNotice", + "x-koha-authorization": { + "permissions": { + "messages": "update_message" + } + }, + "tags": ["notices"], + "parameters": [ + { + "name": "body", + "in": "body", + "description": "A JSON object containing informations about the new notice", + "schema": { "$ref": "../definitions.json#/notice" } + }, + { + "$ref": "../parameters.json#/message_idPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A notice", + "schema": { + "$ref" : "../definitions.json#/notice" + } + }, + "400": { + "description": "Missing or wrong parameters", + "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": "Notice 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" + } + } + } + }, + "delete": { + "x-mojo-to": "Notice#delete", + "operationId": "deleteNotice", + "x-koha-authorization": { + "permissions": { + "messages": "delete_message" + } + }, + "tags": ["notices"], + "parameters": [ + { + "$ref": "../parameters.json#/message_idPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "204": { + "description": "Deleting the notice succeeded.", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Notice 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" + } + } + } + }, + "get": { + "x-mojo-to": "Notice#get", + "operationId": "getNotice", + "x-koha-authorization": { + "permissions": { + "messages": "get_message" + }, + "allow-owner": true, + "allow-guarantor": true + }, + "tags": ["notices"], + "parameters": [ + { + "$ref": "../parameters.json#/message_idPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A notice", + "schema": { + "$ref" : "../definitions.json#/notice" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Notice 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" + } + } + } + } + }, + "/notices/{message_id}/resend": { + "post": { + "x-mojo-to": "Notice#resend", + "operationId": "resendNotice", + "x-koha-authorization": { + "permissions": { + "messages": "resend_message" + } + }, + "tags": ["notices"], + "parameters": [ + { + "$ref": "../parameters.json#/message_idPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "204": { + "description": "Resending the notice succeeded.", + "schema": { + "type": "object" + } + }, + "401": { + "description": "Authentication required", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "403": { + "description": "Access forbidden", + "schema": { + "$ref": "../definitions.json#/error" + } + }, + "404": { + "description": "Notice 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" + } + } + } + } + } +} diff --git a/installer/data/mysql/atomicupdate/Bug-14843-Add_Permissions_for_message_queue-REST_operations.pl b/installer/data/mysql/atomicupdate/Bug-14843-Add_Permissions_for_message_queue-REST_operations.pl new file mode 100644 index 0000000..4418ce4 --- /dev/null +++ b/installer/data/mysql/atomicupdate/Bug-14843-Add_Permissions_for_message_queue-REST_operations.pl @@ -0,0 +1,35 @@ +#!/usr/bin/perl + +# Copyright Koha-Suomi Oy 2017 +# +# 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 C4::Context; +use Koha::AtomicUpdater; + +my $dbh = C4::Context->dbh(); +my $atomicUpdater = Koha::AtomicUpdater->new(); + +use Koha::Auth::PermissionManager; +my $pm = Koha::Auth::PermissionManager->new(); +$pm->addPermissionModule({module => 'messages', description => 'Permission regarding notifications and messages in message queue.'}); +$pm->addPermission({module => 'messages', code => 'get_message', description => "Allows to get the messages in message queue."}); +$pm->addPermission({module => 'messages', code => 'create_message', description => "Allows to create a new message and queue it."}); +$pm->addPermission({module => 'messages', code => 'update_message', description => "Allows to update messages in message queue."}); +$pm->addPermission({module => 'messages', code => 'delete_message', description => "Allows to delete a message and queue it."}); +$pm->addPermission({module => 'messages', code => 'resend_message', description => "Allows to resend messages in message queue."}); + +print "Upgrade done (Bug 14843: Add Pemissions for message queue REST operations)\n"; diff --git a/t/db_dependent/api/v1/notices.t b/t/db_dependent/api/v1/notices.t new file mode 100644 index 0000000..88f34fb --- /dev/null +++ b/t/db_dependent/api/v1/notices.t @@ -0,0 +1,411 @@ +#!/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 => 7; +use Test::Mojo; +use t::lib::Mocks; +use t::lib::TestBuilder; + +use C4::Auth; +use C4::Context; + +use Koha::Database; +use Koha::Notice::Messages; + +my $schema = Koha::Database->new->schema; +my $builder = t::lib::TestBuilder->new; + +# FIXME: sessionStorage defaults to mysql, but it seems to break transaction handling +# this affects the other REST api tests +t::lib::Mocks::mock_preference( 'SessionStorage', 'tmp' ); + +my $remote_address = '127.0.0.1'; +my $t = Test::Mojo->new('Koha::REST::V1'); + +subtest 'list() tests' => sub { + plan tests => 24; + + $schema->storage->txn_begin; + + Koha::Notice::Messages->delete; + + my ($patron, $session) = create_user_and_session(); + my ($another_patron, undef) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "get_message" + }); + + my $notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $patron->borrowernumber, + time_queued => '2016-01-01 13:00:00' + } + }); + my $another_notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $another_patron->borrowernumber, + time_queued => '2017-01-01 13:00:00' + } + }); + my $message_id = $notice->{'message_id'}; + my $another_message_id = $another_notice->{'message_id'}; + + my $tx = $t->ua->build_tx(GET => "/api/v1/notices?borrowernumber=" + .$patron->borrowernumber); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0/subject' => $notice->{'subject'}); + + $tx = $t->ua->build_tx(GET => "/api/v1/notices?borrowernumber=" + .$another_patron->borrowernumber); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(GET => "/api/v1/notices?borrowernumber=-1"); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0' => undef); + + $tx = $t->ua->build_tx(GET => "/api/v1/notices?borrowernumber=" + .$patron->borrowernumber); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0/subject' => $notice->{'subject'}); + + $tx = $t->ua->build_tx(GET => '/api/v1/notices?' + .'time_queued_start=2016-12-12 12:00:00'); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0/subject' => $another_notice->{'subject'}) + ->json_hasnt('/1'); + + $tx = $t->ua->build_tx(GET => '/api/v1/notices?' + .'time_queued_end=2016-12-12 12:00:00'); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0/subject' => $notice->{'subject'}) + ->json_hasnt('/1'); + + $tx = $t->ua->build_tx(GET => '/api/v1/notices?' + .'time_queued_start=2014-12-12 12:00:00&time_queued_end=2018-01-01 12:00:00'); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/0/subject' => $notice->{'subject'}) + ->json_is('/1/subject' => $another_notice->{'subject'}) + ->json_hasnt('/2'); + + $schema->storage->txn_rollback; +}; + +subtest 'get() tests' => sub { + plan tests => 8; + + $schema->storage->txn_begin; + + my ($patron, $session) = create_user_and_session(); + my ($another_patron, undef) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "get_message" + }); + + my $notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $patron->borrowernumber, + } + }); + my $another_notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $another_patron->borrowernumber, + } + }); + my $message_id = $notice->{'message_id'}; + my $another_message_id = $another_notice->{'message_id'}; + + my $tx = $t->ua->build_tx(GET => "/api/v1/notices/$message_id"); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/subject' => $notice->{'subject'}); + + $tx = $t->ua->build_tx(GET => "/api/v1/notices/$another_message_id"); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(GET => "/api/v1/notices/$message_id"); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/subject' => $notice->{'subject'}); + + $schema->storage->txn_rollback; +}; + +subtest 'post() tests' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + my ($patron, $session) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "create_message" + }); + + my $notice = { + borrowernumber => 0+$patron->borrowernumber, + subject => 'Bring milk from the store, please!', + content => 'Title says it all', + message_transport_type => 'email', + status => 'failed', + }; + + my $tx = $t->ua->build_tx(POST => "/api/v1/notices" => json => $notice); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(POST => "/api/v1/notices" => json => $notice); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(201) + ->json_is('/subject' => $notice->{'subject'}); + + my $msg = Koha::Notice::Messages->search({}, { + order_by => { '-desc' => 'message_id' } + })->next; + is($msg->subject, $notice->{subject}, 'The notice was really added!'); + + $schema->storage->txn_rollback; +}; + +subtest 'edit() tests' => sub { + plan tests => 5; + + $schema->storage->txn_begin; + + my ($patron, $session) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "update_message" + }); + + my $notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $patron->borrowernumber, + } + }); + + my $new_notice = { + subject => 'Bring milk from the store, please!', + content => 'Title says it all', + message_transport_type => 'email', + status => 'failed', + }; + + my $message_id = $notice->{'message_id'}; + + my $tx = $t->ua->build_tx(PUT => "/api/v1/notices/$message_id" => + json => $new_notice); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(PUT => "/api/v1/notices/$message_id" => + json => $new_notice); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/subject' => $new_notice->{'subject'}); + + $schema->storage->txn_rollback; +}; + +subtest 'put() tests' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + my ($patron, $session) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "update_message" + }); + + my $notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $patron->borrowernumber, + } + }); + + my $new_notice = { + status => 'pending', + }; + + my $message_id = $notice->{'message_id'}; + + my $tx = $t->ua->build_tx(PATCH => "/api/v1/notices/$message_id" => + json => $new_notice); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(PATCH => "/api/v1/notices/$message_id" => + json => $new_notice); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(200) + ->json_is('/subject' => $notice->{'subject'}) + ->json_is('/status' => $new_notice->{'status'}); + + $schema->storage->txn_rollback; +}; + +subtest 'resend() tests' => sub { + plan tests => 6; + + $schema->storage->txn_begin; + + my ($patron, $session) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "resend_message" + }); + + my $notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $patron->borrowernumber, + status => 'failed' + } + }); + + my $message_id = $notice->{'message_id'}; + + my $msg = Koha::Notice::Messages->find($message_id); + is($msg->status, 'failed', 'The notice is in failed status.'); + + my $tx = $t->ua->build_tx(POST => "/api/v1/notices/$message_id/resend"); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(POST => "/api/v1/notices/$message_id/resend"); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(204); + + $msg = Koha::Notice::Messages->find($message_id); + is($msg->status, 'pending', 'The notice has been set to pending!'); + + $schema->storage->txn_rollback; +}; + +subtest 'delete() tests' => sub { + plan tests => 5; + + $schema->storage->txn_begin; + + my ($patron, $session) = create_user_and_session(); + my ($librarian, $librarian_session) = create_user_and_session({ + "messages" => "delete_message" + }); + + my $notice = $builder->build({ + source => 'MessageQueue', + value => { + borrowernumber => $patron->borrowernumber, + } + }); + + my $message_id = $notice->{'message_id'}; + + my $tx = $t->ua->build_tx(DELETE => "/api/v1/notices/$message_id"); + $tx->req->cookies({name => 'CGISESSID', value => $session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(403); + + $tx = $t->ua->build_tx(DELETE => "/api/v1/notices/$message_id"); + $tx->req->cookies({name => 'CGISESSID', value => $librarian_session->id}); + $tx->req->env({REMOTE_ADDR => '127.0.0.1'}); + $t->request_ok($tx) + ->status_is(204); + + my $msg = Koha::Notice::Messages->find($message_id); + is($msg, undef, 'The notice was really deleted!'); + + $schema->storage->txn_rollback; +}; + +sub create_user_and_session { + my ($flags) = @_; + + my $categorycode = $builder->build({ source => 'Category' })->{categorycode}; + my $branchcode = $builder->build({ source => 'Branch' })->{ branchcode }; + + my $borrower = $builder->build({ + source => 'Borrower', + value => { + branchcode => $branchcode, + categorycode => $categorycode, + } + }); + + my $session = C4::Auth::get_session(''); + $session->param('number', $borrower->{ borrowernumber }); + $session->param('id', $borrower->{ userid }); + $session->param('ip', '127.0.0.1'); + $session->param('lasttime', time()); + $session->flush; + my $patron = Koha::Patrons->find($borrower->{borrowernumber}); + if ( $flags ) { + Koha::Auth::PermissionManager->grantPermissions($patron, $flags); + } + + return ($patron, $session); +} -- 2.7.4