@@ -, +, @@
Driver reports
- user: username, loaded from koha conf smsProviders->labyrintti
- password: password, loaded from koha conf smsProviders->labyrintti
- dests: destination phone number
- text: content of the message
- report: the URL that SMS Gateway provider will update the status of this delivery,
loaded from koha conf (with REST API, it should be http://yourhost.com/v1/messages)
smsProviders->labyrintti
if there was an error with the phone number. If so, we return it to Letters.pm via HASH:
{ status => 1/0, delivery_note => the message of error/success }
report. If the given status is "ERROR" (this is our example provider's protocol), we will
update the message status (and add delivery note) in message_queue for the given message_id.
---
C4/Installer/PerlDependencies.pm | 5 ++
C4/SMS.pm | 1 +
Koha/REST/V1/Messages.pm | 39 +++++++++++
SMS/Send/Labyrintti/Driver.pm | 140 +++++++++++++++++++++++++++++++++++++++
api/v1/swagger.json | 69 ++++++++++++++++++-
etc/koha-conf.xml | 12 ++++
etc/koha-httpd.conf | 9 +++
7 files changed, 274 insertions(+), 1 deletion(-)
create mode 100644 Koha/REST/V1/Messages.pm
create mode 100644 SMS/Send/Labyrintti/Driver.pm
--- a/C4/Installer/PerlDependencies.pm
+++ a/C4/Installer/PerlDependencies.pm
@@ -787,6 +787,11 @@ our $PERL_DEPS = {
'required' => '0',
'min_ver' => '0.28',
},
+ 'LWP::Curl' => {
+ 'usage' => 'Curl',
+ 'required' => '1',
+ 'min_ver' => '0.12',
+ },
};
1;
--- a/C4/SMS.pm
+++ a/C4/SMS.pm
@@ -87,6 +87,7 @@ sub send_sms {
# Send a message
$sent = $sender->send_sms( to => $params->{'destination'},
text => $params->{'message'},
+ message_id => $params->{'message_id'},
);
};
#We might die because SMS::Send $driver is not defined or the sms-number has a bad format
--- a/Koha/REST/V1/Messages.pm
+++ a/Koha/REST/V1/Messages.pm
@@ -0,0 +1,39 @@
+package Koha::REST::V1::Messages;
+
+use Modern::Perl;
+
+use Mojo::Base 'Mojolicious::Controller';
+
+use C4::Letters;
+use Data::Dumper;
+
+
+=head2 delivery_report($c, $args, $cb)
+
+SMS provider returns us with a report on state of the SMS delivery.
+If the delivery is unsuccessful, we will change its status.
+
+=cut
+# SMS provider returns us with a report on state of the SMS delivery.
+#
+sub delivery_report {
+ my ($c, $args, $cb) = @_;
+
+ if ($args->{status} eq "ERROR") {
+ C4::Letters::_set_message_status({
+ status => "failed",
+ message_id => $args->{messagenumber},
+ delivery_note => $args->{message}
+ });
+ }
+
+ my $return = {
+ message=> $args->{messagenumber},
+ status => $args->{status}
+ };
+
+ $c->$cb($return, 200);
+
+}
+1;
+
--- a/SMS/Send/Labyrintti/Driver.pm
+++ a/SMS/Send/Labyrintti/Driver.pm
@@ -0,0 +1,140 @@
+=head IN THIS FILE
+
+This module extends the SMS::Send::Driver interface
+
+to implement a driver compatible with the Labyrintti SMS Gateway HTTP interface.
+
+
+
+Module parameters are sanitated against injection attacks.
+
+Labyrintti responds:
+
+ success
+
+phone-number OK message-count description
++358401234567 OK 1 message accepted for sending
+
+ failure
+
+phone-number ERROR error-code message-count description
+e.g: 12345 ERROR 2 1 message failed: Too short phone number
+
+=cut
+
+
+
+
+
+
+
+package SMS::Send::Labyrintti::Driver;
+
+
+
+#use Modern::Perl; #Can't use this since SMS::Send uses hash keys starting with _
+
+
+
+use utf8;
+
+
+
+use SMS::Send::Driver ();
+
+use LWP::Curl;
+use LWP::UserAgent;
+
+use URI::Escape;
+use C4::Context;
+use Encode;
+
+use vars qw{$VERSION @ISA};
+BEGIN {
+ $VERSION = '0.06';
+ @ISA = 'SMS::Send::Driver';
+}
+
+
+#####################################################################
+# Constructor
+
+sub new {
+ my $class = shift;
+ my $params = {@_};
+ my $username = $params->{_login} ? $params->{_login} : C4::Context->config('smsProviders')->{'labyrintti'}->{'user'};
+ my $password = $params->{_password} ? $params->{_password} : C4::Context->config('smsProviders')->{'labyrintti'}->{'passwd'};
+
+ if (! defined $username ) {
+ warn "->send_sms(_login) must be defined!";
+ return;
+ }
+ if (! defined $password ) {
+ warn "->send_sms(_password) must be defined!";
+ return;
+ }
+
+ #Prevent injection attack
+ $self->{_login} =~ s/'//g;
+ $self->{_password} =~ s/'//g;
+
+ # Create the object
+ my $self = bless {}, $class;
+
+ $self->{UserAgent} = LWP::UserAgent->new(timeout => 5);
+ $self->{_login} = $username;
+ $self->{_password} = $password;
+
+ return $self;
+}
+
+sub send_sms {
+ my $self = shift;
+ my $params = {@_};
+ my $message = $params->{text};
+ my $recipientNumber = $params->{to};
+
+ if (! defined $message ) {
+ warn "->send_sms(text) must be defined!";
+ return;
+ }
+ if (! defined $recipientNumber ) {
+ warn "->send_sms(to) must be defined!";
+ return;
+ }
+
+ #Prevent injection attack!
+ $recipientNumber =~ s/'//g;
+ $message =~ s/(")|(\$\()|(`)/\\"/g; #Sanitate " so it won't break the system( iconv'ed curl command )
+
+ my $base_url = "https://gw.labyrintti.com:28443/sendsms";
+ my $parameters = {
+ 'user' => $self->{_login},
+ 'password' => $self->{_password},
+ 'dests' => $recipientNumber,
+ 'text' => $message,
+ 'unicode' => 'yes',
+ 'report' => C4::Context->config('smsProviders')->{'labyrintti'}->{'reportUrl'}."/".$params->{_message_id}."/report"
+ };
+
+ my $lwpcurl = LWP::Curl->new(auto_encode => 0);
+ my $return = $lwpcurl->post($base_url, $parameters);
+
+
+ my $delivery_note = $return;
+
+ # remove unneccessary stuff from beginning
+ if (my $status = ($return =~ m/OK [1-9](\d*)?/)) {
+ $delivery_note =~ "";
+ } else {
+ $delivery_note =~ s/^(\S+\s*){4}//;
+ }
+
+ return {
+ status => $status,
+ delivery_note => $delivery_note,
+ };
+}
+
+1;
+
--- a/api/v1/swagger.json
+++ a/api/v1/swagger.json
@@ -78,6 +78,41 @@
]
}
}
+ "/messages/{messagenumber}/report": {
+ "post": {
+ "x-mojo-controller": "Koha::REST::V1::Messages",
+ "operationId": "deliveryReport",
+ "tags": ["messages"],
+ "parameters": [
+ {
+ "$ref": "#/parameters/messagenumberPathParam"
+ },
+ {
+ "$ref": "#/parameters/messageStatusFormParam"
+ },
+ {
+ "$ref": "#/parameters/messageDeliveryNoteFormParam"
+ }
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "responses": {
+ "200": {
+ "description": "Response for receiving report",
+ "schema": {
+ "$ref": "#/definitions/messageStatus"
+ }
+ },
+ "404": {
+ "description": "Message not found",
+ "schema": {
+ "$ref": "#/definitions/error"
+ }
+ }
+ }
+ }
+ },
},
"definitions": {
"borrower": {
@@ -108,7 +143,18 @@
"type": "string"
}
}
- }
+ },
+ "messageStatus": {
+ "type": "object",
+ "properties": {
+ "message": {
+ "description": "Message identification number"
+ },
+ "status": {
+ "description": "Message delivery status"
+ }
+ }
+ },
},
"parameters": {
"borrowernumberPathParam": {
@@ -117,6 +163,27 @@
"description": "Internal borrower identifier",
"required": "true",
"type": "integer"
+ },
+ "messagenumberPathParam": {
+ "name": "messagenumber",
+ "in": "path",
+ "description": "Internal message number",
+ "required": "true",
+ "type": "integer"
+ },
+ "messageStatusFormParam": {
+ "name": "status",
+ "in": "formData",
+ "description": "Status of message delivery",
+ "required": "true",
+ "type": "string"
+ },
+ "messageDeliveryNoteFormParam": {
+ "name": "message",
+ "in": "formData",
+ "description": "Description of message delivery status",
+ "required": "true",
+ "type": "string"
}
},
"securityDefinitions": {
--- a/etc/koha-conf.xml
+++ a/etc/koha-conf.xml
@@ -145,5 +145,17 @@ __PAZPAR2_TOGGLE_XML_POST__
+
+
+
+
+
+
+
+
+
--- a/etc/koha-httpd.conf
+++ a/etc/koha-httpd.conf
@@ -39,6 +39,15 @@
ProxyPassReverse /v1/ http://localhost:8081/v1/
##REVERSE PROXYING OK
+# Uncomment the following block to restrict access for changing
+# message status via reports to only from certain IPs.
+#
+# Order Deny,Allow
+# Deny from all
+# Allow from 101.123.213.10
+# Allow from 101.123.213.11
+#
+
Options -Indexes
--