From 23ceac22d498cd563040e824a9b7372f744270c9 Mon Sep 17 00:00:00 2001 From: Lari Taskula Date: Mon, 7 Sep 2015 15:18:06 +0300 Subject: [PATCH] Bug 14843: Notifications and messages via REST API This patch adds notifications/messages to REST API. The purpose is to let user with permissions get/create/update/delete/resend messages in message_queue. For the operations we have to introduce new functionalities to C4::Letters. Currently it is not possible to delete/update notifications or get message by id. With this patch we are able to do these operations. Two new subroutines are: C4::Letters::DequeueLetter and C4::Letters::UpdateQueuedMessage There are specific permissions for each operation. Under pemission module 'messages', the following permissions can be found: - get_message - create_message - update_message (also allows resend via status change) - delete_message - resend_message Endpoints that this patch adds are: GET /api/v1/messages (GETs all messages) POST /api/v1/messages (creates new message) GET /api/v1/messages/{messagenumber} (GETs specific message) PUT /api/v1/messages/{messagenumber} (modifies specific message) DELETE /api/v1/messages/{messagenumber} (deletes specific message) POST /api/v1/messages/{messagenumber}/resend (makes new resend for a message) See Swagger definitions for more precise descriptions. Includes REST tests and unit tests for new subroutines in C4::Letters. --- C4/Letters.pm | 118 ++++++++- Koha/REST/V1/Messages.pm | 262 ++++++++++++++++++++ api/v1/swagger.json | 262 ++++++++++++++++++++ ...ermissions_for_message_queue_REST_operations.pl | 38 +++ t/db_dependent/Api/V1/Messages.pm | 272 +++++++++++++++++++++ t/db_dependent/Letters.t | 15 +- 6 files changed, 965 insertions(+), 2 deletions(-) create mode 100644 Koha/REST/V1/Messages.pm create mode 100644 installer/data/mysql/atomicupdate/Bug14767-Add_Permissions_for_message_queue_REST_operations.pl create mode 100644 t/db_dependent/Api/V1/Messages.pm diff --git a/C4/Letters.pm b/C4/Letters.pm index 518830c..01a4282 100644 --- a/C4/Letters.pm +++ b/C4/Letters.pm @@ -935,6 +935,34 @@ ENDSQL return $dbh->last_insert_id(undef,undef,'message_queue', undef); } +=head2 DequeueLetter + + my $success = DequeueLetter( { message_id => $message_id } ) + +Removes a message from message_queue + +return 1 on success, otherwise 0 + +=cut + +sub DequeueLetter { + my $params = shift or return; + + return unless exists $params->{'message_id'} or not $params->{'message_id'}; + + my $dbh = C4::Context->dbh(); + my $statement = << 'ENDSQL'; +DELETE FROM message_queue +WHERE message_id = ? +ENDSQL + + my $sth = $dbh->prepare($statement); + my $result = $sth->execute( + $params->{'message_id'}, # message_id + ); + return ($result > 0); +} + =head2 SendQueuedMessages ([$hashref]) my $sent = SendQueuedMessages( { verbose => 1 } ); @@ -1026,7 +1054,7 @@ sub GetQueuedMessages { my $dbh = C4::Context->dbh(); my $statement = << 'ENDSQL'; -SELECT message_id, borrowernumber, subject, content, message_transport_type, status, time_queued, delivery_note +SELECT message_id, borrowernumber, subject, content, metadata, letter_code, message_transport_type, status, time_queued, to_address, from_address, content_type, delivery_note FROM message_queue ENDSQL @@ -1051,6 +1079,94 @@ ENDSQL return $sth->fetchall_arrayref({}); } + +=head2 UpdateQueuedMessage ([$hashref]) + + my $message = UpdateQueuedMessage( { + borrowernumber => '123', message_id => '100', + letter => { subject => "New subject", content => "New content" }, + } ); + +Updates the message in message_queue. Message is identified by +required parameter message_id. + +returns: +1 on success, otherwise 0 + +=cut + +sub UpdateQueuedMessage { + my $params = shift; + + if (not $params->{'message_id'}) { + warn __PACKAGE__."::UpdateQueuedMessage: param message_id is required"; + return; + } + + my $dbh = C4::Context->dbh(); + my $statement = << 'ENDSQL'; +UPDATE message_queue +SET +ENDSQL + + my @query_params; + + if ($params->{'borrowernumber'}) { + $statement .= " borrowernumber = ?, "; + push @query_params, $params->{'borrowernumber'}; + } + if ($params->{'subject'}) { + $statement .= " subject = ?, "; + push @query_params, $params->{'subject'}; + } + if ($params->{'content'}) { + $statement .= " content = ?, "; + push @query_params, $params->{'content'}; + } + if ($params->{'metadata'}) { + $statement .= " metadata = ?, "; + push @query_params, $params->{'metadata'}; + } + if ($params->{'letter_code'}) { + $statement .= " letter_code = ?, "; + push @query_params, $params->{'letter_code'}; + } + if ($params->{'content_type'}) { + $statement .= " content_type = ?, "; + push @query_params, $params->{'content_type'}; + } + if ($params->{'message_transport_type'}) { + $statement .= " message_transport_type = ?, "; + push @query_params, $params->{'message_transport_type'}; + } + if ($params->{'status'}) { + $statement .= " status = ?, "; + push @query_params, $params->{'status'}; + } + if ($params->{'to_address'}) { + $statement .= " to_address = ?, "; + push @query_params, $params->{'to_address'}; + } + if ($params->{'from_address'}) { + $statement .= " from_address = ?, "; + push @query_params, $params->{'from_address'}; + } + if ($params->{'delivery_note'}) { + $statement .= " delivery_note = ?, "; + push @query_params, $params->{'delivery_note'}; + } + return 0 if $statement =~ /SET(\s*)$/; + $statement =~ s/,(\s*)$//g; # remove last , + + $statement .= " WHERE message_id = ?"; + push @query_params, $params->{'message_id'}; + + my $sth = $dbh->prepare( $statement ); + my $result = $sth->execute( @query_params ); + return ($result > 0); +} + + =head2 GetMessageTransportTypes my @mtt = GetMessageTransportTypes(); diff --git a/Koha/REST/V1/Messages.pm b/Koha/REST/V1/Messages.pm new file mode 100644 index 0000000..79aad2d --- /dev/null +++ b/Koha/REST/V1/Messages.pm @@ -0,0 +1,262 @@ +package Koha::REST::V1::Messages; + +use Modern::Perl; + +use Mojo::Base 'Mojolicious::Controller'; + +use C4::Letters; +use Data::Dumper; + + + +=head2 list_messages($c, $args, $cb) + +Lists all messages from message_queue. + +=cut +sub list_messages { + my ($c, $args, $cb) = @_; + + my $messages = C4::Letters::GetQueuedMessages(); + + if (@$messages > 0) { + my $return_messages; + foreach my $message (@$messages){ + push @$return_messages, _set_default_values({ message => $message }); + } + return $c->$cb($return_messages , 200); + } + $c->$cb({ error => "No messages found." }, 404); +} + + + +=head2 create_message($c, $args, $cb) + +Creates a new message into message queue. + +=cut +sub create_message { + my ($c, $args, $cb) = @_; + + # Content is required. Check for missing content. + if (exists $args->{body}->{content}) { + my $content = $args->{body}->{content}; + $content =~ s/\s+//g if(defined $content); + if ( not $content ) { + return $c->$cb({ error => "Property cannot be empty in: /body/content" }, 400); + } + } else { + return $c->$cb({ error => "Missing property: /body/content" }, 400); + } + + if (exists $args->{body}->{borrowernumber}) { + my $content = $args->{body}->{borrowernumber}; + $content =~ s/\s+//g if(defined $content); + if ( not $content ) { + return $c->$cb({ error => "Property cannot be empty in: /body/borrowernumber" }, 400); + } + } else { + return $c->$cb({ error => "Missing property: /body/borrowernumber" }, 400); + } + + + # message_transport_type is required. Check for missing parameter. + my $transport_type = $args->{body}->{message_transport_type}; + $transport_type =~ s/\s+//g if(defined $transport_type); + if ( not $transport_type ) { + return $c->$cb({ error => "Missing property: /body/message_transport_type" }, 400); + } + + # message_transport_type also must be one of the predefined values + my $transport_types = C4::Letters::GetMessageTransportTypes(); + if ( !grep( /^$transport_type$/, @$transport_types ) ) { + return $c->$cb({ error => "Invalid value '".$transport_type."' in: /body/message_transport_type. Valid values are ". join(', ', @$transport_types) }, 400); + } + + # Make some changes in names of parameters due to inconsistent naming in C4::Letters + + # Enqueue the letter + my $message = C4::Letters::EnqueueLetter(_convert_to_enqueue({ message => $args->{'body'} })); + + # Check if the message was enqueued + if ($message){ + # Get the newly created message and return it + $message = C4::Letters::GetMessage( $message ); + + $message = _set_default_values({ message => $message }); + + return $c->$cb($message, 201); + } + $c->$cb({ error => "Message could not be created." }, 404) +} + + + +=head2 update_message($c, $args, $cb) + +Updates the message in message_queue. + +=cut +sub update_message { + my ($c, $args, $cb) = @_; + + # Content is required. Check for missing content. + if (exists $args->{body}->{content}) { + my $content = $args->{body}->{content}; + $content =~ s/\s+//g if(defined $content); + if ( $content eq '' ) { + return $c->$cb({ error => "Property cannot be empty in: /body/content" }, 400); + } + } + + if (exists $args->{body}->{message_transport_type}) { + my $transport_type = $args->{body}->{message_transport_type}; + # message_transport_type also must be one of the predefined values + my $transport_types = C4::Letters::GetMessageTransportTypes(); + if ( !grep( /^$transport_type$/, @$transport_types ) ) { + return $c->$cb({ error => "Invalid value '".$transport_type + ."' in: /body/message_transport_type. Valid values are " + . join(', ', @$transport_types) }, 400); + } + } + + # create update hash + my $update = $args->{'body'}; + $update->{'message_id'} = $args->{'messagenumber'}; + + my $message = C4::Letters::UpdateQueuedMessage( $update ); + return $c->$cb({ error => "Message could not be found." }, 404) if not $message; + + $message = C4::Letters::GetMessage($args->{'messagenumber'}); + + if ($message){ + $message = _set_default_values({ message => $message }); + return $c->$cb($message, 200); + } + $c->$cb({ error => "Message could not be updated." }, 404); +} + + + +=head2 delete_message($c, $args, $cb) + +Delete the message from message_queue. + +=cut +sub delete_message { + my ($c, $args, $cb) = @_; + + my $message = C4::Letters::DequeueLetter({ message_id => $args->{'messagenumber'} }); + + if ($message){ + return $c->$cb('', 204); + } + + $c->$cb({ error => "Message could not be found." }, 404) +} + + + +=head2 get_message($c, $args, $cb) + +Returns a message from message_queue. + +=cut +sub get_message { + my ($c, $args, $cb) = @_; + + my $message = C4::Letters::GetMessage($args->{'messagenumber'}); + + if ($message) { + my $message = _set_default_values({ message => $message }); + + return $c->$cb($message, 200); + } + + return $c->$cb({ error => "Could not find the message" }, 404); +} + + + +=head2 create_resend($c, $args, $cb) + +Attempts to resend a message. + +=cut +sub create_resend { + my ($c, $args, $cb) = @_; + + + my $message = C4::Letters::GetMessage($args->{'messagenumber'}); + + if ($message) { + if (C4::Letters::ResendMessage($args->{'messagenumber'})) { + + return $c->$cb('', 204); + } + } + + return $c->$cb({ error => "Could not find the message" }, 404); +} + + + +=head2 _set_default_values({ message => $message }) + +=cut +sub _set_default_values { + my $params = shift; + + return unless exists $params->{'message'} or not defined $params->{'message'}; + + # Convert the returned message into C4::Letters::EnqueueLetter format + return { + message_id => int($params->{'message'}->{'message_id'}), + borrowernumber => int($params->{'message'}->{'borrowernumber'}), + subject => $params->{'message'}->{'subject'} || '', + content => $params->{'message'}->{'content'} || '', + letter_code => $params->{'message'}->{'letter_code'} || '', + content_type => $params->{'message'}->{'content_type'} || '', + metadata => $params->{'message'}->{'metadata'} || '', + message_transport_type => $params->{'message'}->{'message_transport_type'} || '', + to_address => $params->{'message'}->{'to_address'} || '', + from_address => $params->{'message'}->{'from_address'} || '', + delivery_note => $params->{'message'}->{'delivery_note'} || '', + status => $params->{'message'}->{'status'} || '', + time_queued => $params->{'message'}->{'time_queued'} || '' + }; +} + + + +=head2 _convert_to_message({ message => $message }) + +Due to inconsistent naming in C4::Letters::EnqueueLetter, we use the +database format and convert it in this function into the format that +EnqueueLetter supports. + +=cut +sub _convert_to_enqueue { + my $params = shift; + + return unless exists $params->{'message'} or not defined $params->{'message'}; + + # Convert the returned message into C4::Letters::EnqueueLetter format + return { + borrowernumber => int($params->{'message'}->{'borrowernumber'}), + letter => { + title => $params->{'message'}->{'subject'} || '', + content => $params->{'message'}->{'content'} || '', + code => $params->{'message'}->{'letter_code'} || '', + 'content-type' => $params->{'message'}->{'content_type'} || '', + metadata => $params->{'message'}->{'metadata'} || '', + }, + message_transport_type => $params->{'message'}->{'message_transport_type'} || '', + to_address => $params->{'message'}->{'to_address'} || '', + from_address => $params->{'message'}->{'from_address'} || '', + delivery_note => $params->{'message'}->{'delivery_note'} || '' + }; +} + +1; diff --git a/api/v1/swagger.json b/api/v1/swagger.json index 2477452..5d37123 100644 --- a/api/v1/swagger.json +++ b/api/v1/swagger.json @@ -309,6 +309,204 @@ } } } + }, + "/messages": { + "get": { + "x-mojo-controller": "Koha::REST::V1::Messages", + "operationId": "listMessages", + "x-koha-permission": { + "messages": "get_message" + }, + "tags": ["messages"], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A list of messages", + "schema": { + "type": "array", + "items": { + "$ref" : "#/definitions/message" + } + } + }, + "404": { + "description": "Messages not found", + "schema": { + "$ref": "#/definitions/error" + } + } + } + }, + "post": { + "x-mojo-controller": "Koha::REST::V1::Messages", + "operationId": "createMessage", + "x-koha-permission": { + "messages": "create_message" + }, + "tags": ["messages"], + "parameters": [ + { + "name": "body", + "in": "body", + "description": "A JSON object containing informations about the new message", + "required": true, + "schema": { "$ref": "#/definitions/message" } + } + ], + "produces": [ + "application/json" + ], + "responses": { + "201": { + "description": "A message", + "schema": { + "$ref": "#/definitions/message" + } + }, + "400": { + "description": "Missing or wrong parameters", + "schema": { "$ref": "#/definitions/error" } + } + } + } + }, + "/messages/{messagenumber}": { + "put": { + "x-mojo-controller": "Koha::REST::V1::Messages", + "operationId": "updateMessage", + "x-koha-permission": { + "messages": "update_message" + }, + "tags": ["messages"], + "parameters": [ + { + "name": "body", + "in": "body", + "description": "A JSON object containing informations about the new message", + "required": false, + "schema": { "$ref": "#/definitions/message" } + }, + { + "$ref": "#/parameters/messagenumberPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A message", + "schema": { + "$ref" : "#/definitions/message" + } + }, + "400": { + "description": "Missing or wrong parameters", + "schema": { "$ref": "#/definitions/error" } + }, + "404": { + "description": "Message not found", + "schema": { + "$ref": "#/definitions/error" + } + } + } + }, + "delete": { + "x-mojo-controller": "Koha::REST::V1::Messages", + "operationId": "deleteMessage", + "x-koha-permission": { + "messages": "delete_message" + }, + "tags": ["messages"], + "parameters": [ + { + "$ref": "#/parameters/messagenumberPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "204": { + "description": "Deleting the message succeeded.", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Message not found.", + "schema": { + "$ref": "#/definitions/error" + } + } + } + }, + "get": { + "x-mojo-controller": "Koha::REST::V1::Messages", + "operationId": "getMessage", + "x-koha-permission": { + "messages": "get_message" + }, + "tags": ["messages"], + "parameters": [ + { + "$ref": "#/parameters/messagenumberPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "A message", + "schema": { + "$ref" : "#/definitions/message" + } + }, + "404": { + "description": "Message not found", + "schema": { + "$ref": "#/definitions/error" + } + } + } + } + }, + "/messages/{messagenumber}/resend": { + "post": { + "x-mojo-controller": "Koha::REST::V1::Messages", + "operationId": "createResend", + "description": "Resends a message.", + "x-koha-permission": { + "messages": "resend_message" + }, + "tags": ["messages"], + "parameters": [ + { + "$ref": "#/parameters/messagenumberPathParam" + } + ], + "produces": [ + "application/json" + ], + "responses": { + "204": { + "description": "Resending the message succeeded.", + "schema": { + "type": "string" + } + }, + "404": { + "description": "Message not found", + "schema": { + "$ref": "#/definitions/error" + } + } + } + } } }, "definitions": { @@ -485,12 +683,69 @@ "borrowernumber": { "description": "Borrower internal identifier" }, + "branchcode": { "description": "Branch code" }, "itemnumber": { "description": "Item internal identifier" }, + "message": { + "type": "object", + "properties": { + "message_id": { + "description": "Message internal identifier", + "type": "integer" + }, + "time_queued": { + "description": "Date and time of when message was placed in queue", + "type": "string" + }, + "borrowernumber": { + "$ref": "#/definitions/borrowernumber" + }, + "subject": { + "description": "Subject of the message", + "type": "string" + }, + "content": { + "description": "Content of the message", + "type": "string" + }, + "metadata": { + "description": "", + "type": "string" + }, + "letter_code": { + "description": "", + "type": "string" + }, + "content_type": { + "description": "Content type", + "type": "string" + }, + "message_transport_type": { + "description": "Transport method. Values accepted by default are 'email', 'sms', 'phone' and 'print'", + "type": "string" + }, + "status": { + "description": "Delivery status", + "type": "string" + }, + "to_address": { + "description": "Destination email address", + "type": "string" + }, + "from_address": { + "description": "Source address of email", + "type": "string" + }, + "delivery_note": { + "description": "Additional delivery notes", + "type": "string" + } + } + }, "error": { "type": "object", "properties": { @@ -529,6 +784,13 @@ "description": "Internal item identifier", "required": "true", "type": "integer" + }, + "messagenumberPathParam": { + "name": "messagenumber", + "in": "path", + "description": "Internal message identifier", + "required": "true", + "type": "integer" } }, "securityDefinitions": { diff --git a/installer/data/mysql/atomicupdate/Bug14767-Add_Permissions_for_message_queue_REST_operations.pl b/installer/data/mysql/atomicupdate/Bug14767-Add_Permissions_for_message_queue_REST_operations.pl new file mode 100644 index 0000000..a91db80 --- /dev/null +++ b/installer/data/mysql/atomicupdate/Bug14767-Add_Permissions_for_message_queue_REST_operations.pl @@ -0,0 +1,38 @@ +#!/usr/bin/perl + +# Copyright Open Source Freedom Fighters +# +# 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(); + +unless($atomicUpdater->find('Bug14767-Add_Permissions_for_message_queue_REST_operations.pl')) { + + 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 14767: Add Pemissions for message queue REST operations)\n"; +} diff --git a/t/db_dependent/Api/V1/Messages.pm b/t/db_dependent/Api/V1/Messages.pm new file mode 100644 index 0000000..359335c --- /dev/null +++ b/t/db_dependent/Api/V1/Messages.pm @@ -0,0 +1,272 @@ +package t::db_dependent::Api::V1::Messages; + +use Modern::Perl; +use Test::More; + +use t::lib::TestObjects::ObjectFactory; +use t::lib::TestObjects::MessageQueueFactory; + +use C4::Letters; + +sub get200 { + my ($class, $restTest, $driver) = @_; + my $testContext = $restTest->get_testContext(); + my $activeUser = $restTest->get_activeBorrower(); + my $path = $restTest->get_routePath(); + + #Create the test context. + my $messages = t::lib::TestObjects::MessageQueueFactory->createTestGroup( + { + subject => "The quick brown fox", + content => "Jumps over the lazy dog.", + cardnumber => $activeUser->{'_result'}->{'_column_data'}->{cardnumber}, + message_transport_type => 'sms', + from_address => '11A001@example.com', + }, undef, $testContext, undef, undef); + + my $messagenumber = $messages->{'11A001@example.com'}->{message_id}; + + $driver->get_ok($path => {Accept => 'text/json'}); + $driver->status_is(200); + + $driver->json_has("message_id", "Message id in JSON."); + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); + return 1; +} + +sub get404 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + my $testContext = $restTest->get_testContext(); + + # clear test context before checking for 404 + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); + + $driver->get_ok($path => {Accept => 'text/json'}); + $driver->status_is(404); + + return 1; +} + +sub get_n_200 { + my ($class, $restTest, $driver) = @_; + my $testContext = $restTest->get_testContext(); + my $activeUser = $restTest->get_activeBorrower(); + my $path = $restTest->get_routePath(); + + #Create the test context. + my $messages = t::lib::TestObjects::MessageQueueFactory->createTestGroup( + { + subject => "The quick brown fox", + content => "Jumps over the lazy dog.", + cardnumber => $activeUser->{'_result'}->{'_column_data'}->{cardnumber}, + message_transport_type => 'sms', + from_address => '11A002@example.com', + }, undef, $testContext, undef, undef); + + my $messagenumber = $messages->{'11A002@example.com'}->{message_id}; + $path =~ s/\{messagenumber\}/$messagenumber/; + + $driver->get_ok($path => {Accept => 'text/json'}); + $driver->status_is(200); + + $driver->json_is('/message_id' => $messagenumber, "Message $messagenumber found!"); + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); + return 1; +} + +sub get_n_404 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + + $path =~ s/\{messagenumber\}/12349329003007/; + $driver->get_ok($path => {Accept => 'text/json'}); + $driver->status_is(404); + + return 1; +} + +sub post201 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + my $activeUser = $restTest->get_activeBorrower(); + + $driver->post_ok($path => {Accept => 'text/json'} => json => { + subject => "hello", + content => "world", + message_transport_type => "email", + borrowernumber => $activeUser->{'_result'}->{'_column_data'}->{borrowernumber}, + }); + $driver->status_is(201); + + # dequeue the message right after so that get 404 tests will work + my $json = $driver->tx->res->json(); + C4::Letters::DequeueLetter({ message_id => $json->{message_id} }); + + return 1; +} + +sub post400 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + my $activeUser = $restTest->get_activeBorrower(); + + #post with missing mandatory parameters + $driver->post_ok($path => {Accept => 'text/json'} => json => { + subject => "hello" + }); + $driver->status_is(400); + + return 1; +} + +sub post_n_resend204 { + my ($class, $restTest, $driver) = @_; + my $testContext = $restTest->get_testContext(); + my $activeUser = $restTest->get_activeBorrower(); + my $path = $restTest->get_routePath(); + + #Create the test context. + my $messages = t::lib::TestObjects::MessageQueueFactory->createTestGroup( + { + subject => "The quick brown fox", + content => "Jumps over the lazy dog.", + cardnumber => $activeUser->{'_result'}->{'_column_data'}->{cardnumber}, + message_transport_type => 'sms', + from_address => '11A003@example.com', + }, undef, $testContext, undef, undef); + + # send and get the message + C4::Letters::SendQueuedMessages(); + my $message = C4::Letters::GetMessage($messages->{'11A003@example.com'}->{message_id}); + my $messagenumber = $messages->{'11A003@example.com'}->{message_id}; + $path =~ s/\{messagenumber\}/$messagenumber/; + + # sms status should be failed + is($message->{status}, "failed", "Send failed correctly"); + + $driver->post_ok($path => {Accept => 'text/json'}); + $driver->status_is(204); + + $message = C4::Letters::GetMessage($messages->{'11A003@example.com'}->{message_id}); + is($message->{status}, "pending", "Resend set message status to pending correctly"); + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); + + return 1; +} + +sub post_n_resend404 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + + $path =~ s/\{messagenumber\}/12349329003007/; + $driver->post_ok($path => {Accept => 'text/json'}); + $driver->status_is(404); + + return 1; +} + +sub put_n_200 { + my ($class, $restTest, $driver) = @_; + my $testContext = $restTest->get_testContext(); + my $activeUser = $restTest->get_activeBorrower(); + my $path = $restTest->get_routePath(); + + #Create the test context. + my $messages = t::lib::TestObjects::MessageQueueFactory->createTestGroup( + { + subject => "The quick brown fox", + content => "Jumps over the lazy dog.", + cardnumber => $activeUser->{'_result'}->{'_column_data'}->{cardnumber}, + message_transport_type => 'sms', + from_address => '11A003@example.com', + }, undef, $testContext, undef, undef); + + my $messagenumber = $messages->{'11A003@example.com'}->{message_id}; + $path =~ s/\{messagenumber\}/$messagenumber/; + + $driver->put_ok($path => {Accept => 'text/json'} => json => { + subject => "hello", + content => "world", + }); + $driver->status_is(200); + + my $json = $driver->tx->res->json(); + is($json->{subject}, "hello", "Put updated message subject correctly"); + + t::lib::TestObjects::ObjectFactory->tearDownTestContext($testContext); + + return 1; +} + +sub put_n_400 { + my ($class, $restTest, $driver) = @_; + my $testContext = $restTest->get_testContext(); + my $activeUser = $restTest->get_activeBorrower(); + my $path = $restTest->get_routePath(); + + $path =~ s/\{messagenumber\}/12349329003007/; + $driver->put_ok($path => {Accept => 'text/json'} => json => { + message_transport_type => "hello", #invalid transport type + }); + $driver->status_is(400); + + return 1; +} + +sub put_n_404 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + + $path =~ s/\{messagenumber\}/12349329003007/; + $driver->put_ok($path => {Accept => 'text/json'}); + $driver->status_is(404); + + return 1; +} + +sub delete_n_204 { + my ($class, $restTest, $driver) = @_; + my $testContext = $restTest->get_testContext(); + my $activeUser = $restTest->get_activeBorrower(); + my $path = $restTest->get_routePath(); + + #Create the test context. + my $messages = t::lib::TestObjects::MessageQueueFactory->createTestGroup( + { + subject => "The quick brown fox", + content => "Jumps over the lazy dog.", + cardnumber => $activeUser->{'_result'}->{'_column_data'}->{cardnumber}, + message_transport_type => 'sms', + from_address => '11A004@example.com', + }, undef, $testContext, undef, undef); + + my $messagenumber = $messages->{'11A004@example.com'}->{message_id}; + $path =~ s/\{messagenumber\}/$messagenumber/; + + $driver->delete_ok($path => {Accept => 'text/json'}); + $driver->status_is(204); + + # if DELETE was successfull, delete it from testContext too. + if ($driver->{tx}->{res}->{code} == 204) { + delete $restTest->{testContext}->{messagequeue}->{'11A004@example.com'}; + } + + return 1; +} + +sub delete_n_404 { + my ($class, $restTest, $driver) = @_; + my $path = $restTest->get_routePath(); + + $path =~ s/\{messagenumber\}/12349329003007/; + $driver->delete_ok($path => {Accept => 'text/json'}); + $driver->status_is(404); + + return 1; +} + +1; \ No newline at end of file diff --git a/t/db_dependent/Letters.t b/t/db_dependent/Letters.t index ad02c04..2f03a0f 100644 --- a/t/db_dependent/Letters.t +++ b/t/db_dependent/Letters.t @@ -18,7 +18,7 @@ # along with Koha; if not, see . use Modern::Perl; -use Test::More tests => 74; +use Test::More tests => 79; use Test::MockModule; use Test::Warn; @@ -134,6 +134,9 @@ is( $messages->[0]->{message_transport_type}, $my_message->{message_transport_ty is( $messages->[0]->{status}, 'pending', 'EnqueueLetter stores the status pending correctly' ); is( $messages->[0]->{delivery_note}, '', 'Delivery note for successful message correctly empty'); +my $message_by_id = C4::Letters::GetQueuedMessages({ message_id => $messages->[0]->{message_id} }); +is ($messages->[0]->{message_id}, $message_by_id->[0]->{message_id}, "GetQueuedMessages by message_id gets correct one"); + # SendQueuedMessages my $messages_processed = C4::Letters::SendQueuedMessages(); is($messages_processed, 1, 'all queued messages processed'); @@ -158,6 +161,11 @@ is( $resent, undef, 'ResendMessage should return undef if not message_id given' # Delivery notes is($messages->[0]->{delivery_note}, 'Missing SMS number', 'Delivery note for no smsalertnumber correctly set'); +# UpdateQueuedMessage +is(C4::Letters::UpdateQueuedMessage({ message_id => $messages->[0]->{message_id}, content => "changed content" } ), 1, "Message updated correctly"); +$messages = C4::Letters::GetQueuedMessages(); +is($messages->[0]->{content}, "changed content", "Message content was changed correctly"); + # Test connectivity Exception (Bug 14791) ModMember(borrowernumber => $borrowernumber, smsalertnumber => "+1234567890"); warning_is { $messages_processed = C4::Letters::SendQueuedMessages(); } @@ -169,6 +177,11 @@ is( $messages->[0]->{status}, 'pending', is( $messages->[0]->{delivery_note}, 'Connection failed. Attempting to resend.', 'Message has correct delivery note about resending' ); +#DequeueLetter +is(C4::Letters::DequeueLetter( { message_id => $messages->[0]->{message_id} } ), 1, "message successfully dequeued"); +$messages = C4::Letters::GetQueuedMessages(); +is( @$messages, 0, 'no messages left after dequeue' ); + # GetLetters my $letters = C4::Letters::GetLetters(); is( @$letters, 0, 'GetLetters returns the correct number of letters' ); -- 1.9.1