notifications-ruby-client 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.rubocop.yml +2 -0
- data/CHANGELOG.md +100 -0
- data/CONTRIBUTING.md +39 -0
- data/DOCUMENTATION.md +949 -0
- data/Gemfile +3 -0
- data/LICENSE +21 -0
- data/Makefile +87 -0
- data/README.md +10 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/generate_docker_env.sh +29 -0
- data/bin/setup +8 -0
- data/bin/test_client.rb +454 -0
- data/docker/Dockerfile +26 -0
- data/docker/Makefile +16 -0
- data/lib/notifications/client.rb +153 -0
- data/lib/notifications/client/helper_methods.rb +9 -0
- data/lib/notifications/client/notification.rb +54 -0
- data/lib/notifications/client/notifications_collection.rb +19 -0
- data/lib/notifications/client/received_text.rb +31 -0
- data/lib/notifications/client/received_text_collection.rb +18 -0
- data/lib/notifications/client/request_error.rb +59 -0
- data/lib/notifications/client/response_notification.rb +21 -0
- data/lib/notifications/client/response_precompiled_letter.rb +19 -0
- data/lib/notifications/client/response_template.rb +41 -0
- data/lib/notifications/client/speaker.rb +171 -0
- data/lib/notifications/client/template_collection.rb +16 -0
- data/lib/notifications/client/template_preview.rb +22 -0
- data/lib/notifications/client/uuid_validator.rb +25 -0
- data/lib/notifications/client/version.rb +14 -0
- data/notifications-ruby-client.gemspec +31 -0
- metadata +181 -0
@@ -0,0 +1,171 @@
|
|
1
|
+
require "base64"
|
2
|
+
require "net/https"
|
3
|
+
require "uri"
|
4
|
+
require "jwt"
|
5
|
+
require_relative "request_error"
|
6
|
+
|
7
|
+
module Notifications
|
8
|
+
class Client
|
9
|
+
class Speaker
|
10
|
+
include ErrorHandling
|
11
|
+
|
12
|
+
attr_reader :base_url
|
13
|
+
attr_reader :service_id
|
14
|
+
attr_reader :secret_token
|
15
|
+
|
16
|
+
BASE_PATH = "/v2/notifications".freeze
|
17
|
+
USER_AGENT = "NOTIFY-API-RUBY-CLIENT/#{Notifications::Client::VERSION}".freeze
|
18
|
+
|
19
|
+
##
|
20
|
+
# @param secret [String] your service API secret
|
21
|
+
# @param base_url [String] host URL. This is the address to perform the requests.
|
22
|
+
# If left nil the production url is used.
|
23
|
+
def initialize(secret_token = nil, base_url = nil)
|
24
|
+
@service_id = secret_token[secret_token.length - 73..secret_token.length - 38]
|
25
|
+
@secret_token = secret_token[secret_token.length - 36..secret_token.length]
|
26
|
+
@base_url = base_url || PRODUCTION_BASE_URL
|
27
|
+
|
28
|
+
validate_uuids!
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# @param kind [String] 'email', 'sms' or 'letter'
|
33
|
+
# @param form_data [Hash]
|
34
|
+
# @option form_data [String] :phone_number
|
35
|
+
# phone number of the sms recipient
|
36
|
+
# @option form_data [String] :email_address
|
37
|
+
# email address of the email recipent
|
38
|
+
# @option form_data [String] :template
|
39
|
+
# template to render in notification
|
40
|
+
# @option form_data [Hash] :personalisation
|
41
|
+
# fields to use in the template
|
42
|
+
# @option form_data [String] :reference
|
43
|
+
# A reference specified by the service for the notification. Get all notifications can be filtered by this reference.
|
44
|
+
# This reference can be unique or used used to refer to a batch of notifications.
|
45
|
+
# Can be an empty string or nil, when you do not require a reference for the notifications.
|
46
|
+
# @option form_data [String] :email_reply_to_id
|
47
|
+
# id of the email address that replies to email notifications will be sent to
|
48
|
+
# @option form_data [String] :sms_sender_id
|
49
|
+
# id of the sender to be used for an sms notification
|
50
|
+
# @see #perform_request!
|
51
|
+
def post(kind, form_data)
|
52
|
+
request = Net::HTTP::Post.new(
|
53
|
+
"#{BASE_PATH}/#{kind}",
|
54
|
+
headers
|
55
|
+
)
|
56
|
+
request.body = form_data.is_a?(Hash) ? form_data.to_json : form_data
|
57
|
+
perform_request!(request)
|
58
|
+
end
|
59
|
+
|
60
|
+
##
|
61
|
+
# @param id [String]
|
62
|
+
# @param options [Hash] query
|
63
|
+
# @see #perform_request!
|
64
|
+
def get(id = nil, options = {})
|
65
|
+
path = BASE_PATH.dup
|
66
|
+
path << "/" << id if id
|
67
|
+
path << "?" << URI.encode_www_form(options) if options.any?
|
68
|
+
request = Net::HTTP::Get.new(path, headers)
|
69
|
+
perform_request!(request)
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# @param url path of endpoint
|
74
|
+
# @param id [String]
|
75
|
+
# @param options [Hash] query
|
76
|
+
# @see #perform_request!
|
77
|
+
def get_with_url(url, options = {})
|
78
|
+
path = url
|
79
|
+
path << "?" << URI.encode_www_form(options) if options.any?
|
80
|
+
request = Net::HTTP::Get.new(path, headers)
|
81
|
+
perform_request!(request)
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# @param url [String] path of the endpoint
|
86
|
+
# @param form_data [Hash]
|
87
|
+
# @option form_data [String] :template_id
|
88
|
+
# id of the template to render
|
89
|
+
# @option form_data [Hash] :personalisation
|
90
|
+
# fields to use in the template
|
91
|
+
# @see #perform_request!
|
92
|
+
def post_with_url(url, form_data)
|
93
|
+
request = Net::HTTP::Post.new(
|
94
|
+
url,
|
95
|
+
headers
|
96
|
+
)
|
97
|
+
request.body = form_data.is_a?(Hash) ? form_data.to_json : form_data
|
98
|
+
perform_request!(request)
|
99
|
+
end
|
100
|
+
|
101
|
+
##
|
102
|
+
# @param reference [String] reference of the notification
|
103
|
+
# @param pdf_file [File] PDF file opened for reading
|
104
|
+
# @see #perform_request!
|
105
|
+
def post_precompiled_letter(reference, pdf_file, postage = nil)
|
106
|
+
content = Base64.strict_encode64(pdf_file.read)
|
107
|
+
form_data = { reference: reference, content: content }
|
108
|
+
|
109
|
+
if postage != nil
|
110
|
+
form_data[:postage] = postage
|
111
|
+
end
|
112
|
+
|
113
|
+
request = Net::HTTP::Post.new(
|
114
|
+
"#{BASE_PATH}/letter",
|
115
|
+
headers
|
116
|
+
)
|
117
|
+
request.body = form_data.to_json
|
118
|
+
perform_request!(request)
|
119
|
+
end
|
120
|
+
|
121
|
+
private
|
122
|
+
|
123
|
+
##
|
124
|
+
# @return [Hash] JSON parsed response
|
125
|
+
# @raise [RequestError] if request is
|
126
|
+
# not successful
|
127
|
+
def perform_request!(request)
|
128
|
+
response = open(request)
|
129
|
+
if response.is_a?(Net::HTTPClientError) || response.is_a?(Net::HTTPServerError)
|
130
|
+
raise build_error(response)
|
131
|
+
else
|
132
|
+
JSON.parse(response.body)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def open(request)
|
137
|
+
uri = URI.parse(@base_url)
|
138
|
+
Net::HTTP.start(uri.host, uri.port, :ENV, use_ssl: uri.scheme == 'https') do |http|
|
139
|
+
http.request(request)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def headers
|
144
|
+
{
|
145
|
+
"User-agent" => USER_AGENT,
|
146
|
+
"Content-Type" => "application/json",
|
147
|
+
"Authorization" => "Bearer " + jwt_token
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
def jwt_token
|
152
|
+
payload = {
|
153
|
+
iss: @service_id,
|
154
|
+
iat: Time.now.to_i
|
155
|
+
}
|
156
|
+
JWT.encode payload, @secret_token, "HS256"
|
157
|
+
end
|
158
|
+
|
159
|
+
def validate_uuids!
|
160
|
+
contextual_message = [
|
161
|
+
"This error is probably caused by initializing the Notifications client with an invalid API key.",
|
162
|
+
"You can generate a new API key by logging into Notify and visiting the 'API integration' page:",
|
163
|
+
"https://www.notifications.service.gov.uk",
|
164
|
+
].join("\n")
|
165
|
+
|
166
|
+
UuidValidator.validate!(@service_id, contextual_message)
|
167
|
+
UuidValidator.validate!(@secret_token, contextual_message)
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Notifications
|
2
|
+
class Client
|
3
|
+
class TemplateCollection
|
4
|
+
attr_reader :collection
|
5
|
+
def initialize(response)
|
6
|
+
@collection = collection_from(response["templates"])
|
7
|
+
end
|
8
|
+
|
9
|
+
def collection_from(templates)
|
10
|
+
templates.map do |template|
|
11
|
+
Template.new(template)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Notifications
|
2
|
+
class Client
|
3
|
+
class TemplatePreview
|
4
|
+
FIELDS = %i(
|
5
|
+
id
|
6
|
+
version
|
7
|
+
body
|
8
|
+
subject
|
9
|
+
type
|
10
|
+
html
|
11
|
+
).freeze
|
12
|
+
|
13
|
+
attr_reader(*FIELDS)
|
14
|
+
|
15
|
+
def initialize(notification)
|
16
|
+
FIELDS.each do |field|
|
17
|
+
instance_variable_set(:"@#{field}", notification.fetch(field.to_s, nil))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Notifications
|
2
|
+
class UuidValidator
|
3
|
+
HEX = /[0-9a-f]/
|
4
|
+
REGEX = /^#{HEX}{8}-#{HEX}{4}-#{HEX}{4}-#{HEX}{4}-#{HEX}{12}$/
|
5
|
+
|
6
|
+
attr_accessor :uuid
|
7
|
+
|
8
|
+
def initialize(uuid)
|
9
|
+
self.uuid = uuid
|
10
|
+
end
|
11
|
+
|
12
|
+
def valid?
|
13
|
+
!!(uuid && uuid.match(REGEX))
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.validate!(uuid, contextual_message = nil)
|
17
|
+
return if new(uuid).valid?
|
18
|
+
|
19
|
+
message = "#{uuid.inspect} is not a valid uuid"
|
20
|
+
message += "\n#{contextual_message}" if contextual_message
|
21
|
+
|
22
|
+
raise ArgumentError, message
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# Version numbering follows Semantic Versionning:
|
2
|
+
#
|
3
|
+
# Given a version number MAJOR.MINOR.PATCH, increment the:
|
4
|
+
# - MAJOR version when you make incompatible API changes,
|
5
|
+
# - MINOR version when you add functionality in a backwards-compatible manner, and
|
6
|
+
# - PATCH version when you make backwards-compatible bug fixes.
|
7
|
+
#
|
8
|
+
# -- http://semver.org/
|
9
|
+
|
10
|
+
module Notifications
|
11
|
+
class Client
|
12
|
+
VERSION = "4.0.0".freeze
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'notifications/client/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "notifications-ruby-client"
|
8
|
+
spec.version = Notifications::Client::VERSION
|
9
|
+
spec.authors = [
|
10
|
+
"Government Digital Service"
|
11
|
+
]
|
12
|
+
|
13
|
+
spec.email = ["notify@digital.cabinet-office.gov.uk"]
|
14
|
+
|
15
|
+
spec.summary = "Ruby client for GOV.UK Notifications API"
|
16
|
+
spec.homepage = "https://github.com/alphagov/notifications-ruby-client"
|
17
|
+
|
18
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_runtime_dependency "jwt", ">= 1.5", "< 3"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
26
|
+
spec.add_development_dependency "rake", "~> 12.3"
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.7"
|
28
|
+
spec.add_development_dependency "webmock", "~> 3.4"
|
29
|
+
spec.add_development_dependency "factory_bot", "~> 4.10"
|
30
|
+
spec.add_development_dependency "govuk-lint", "~> 3.8"
|
31
|
+
end
|
metadata
ADDED
@@ -0,0 +1,181 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: notifications-ruby-client
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 4.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Government Digital Service
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-07-02 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: jwt
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.5'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: bundler
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - "~>"
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '1.13'
|
40
|
+
type: :development
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '1.13'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rake
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - "~>"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '12.3'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - "~>"
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '12.3'
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: rspec
|
63
|
+
requirement: !ruby/object:Gem::Requirement
|
64
|
+
requirements:
|
65
|
+
- - "~>"
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '3.7'
|
68
|
+
type: :development
|
69
|
+
prerelease: false
|
70
|
+
version_requirements: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - "~>"
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: '3.7'
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: webmock
|
77
|
+
requirement: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - "~>"
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '3.4'
|
82
|
+
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - "~>"
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '3.4'
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: factory_bot
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - "~>"
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '4.10'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - "~>"
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '4.10'
|
103
|
+
- !ruby/object:Gem::Dependency
|
104
|
+
name: govuk-lint
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - "~>"
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '3.8'
|
110
|
+
type: :development
|
111
|
+
prerelease: false
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - "~>"
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '3.8'
|
117
|
+
description:
|
118
|
+
email:
|
119
|
+
- notify@digital.cabinet-office.gov.uk
|
120
|
+
executables: []
|
121
|
+
extensions: []
|
122
|
+
extra_rdoc_files: []
|
123
|
+
files:
|
124
|
+
- ".github/PULL_REQUEST_TEMPLATE.md"
|
125
|
+
- ".gitignore"
|
126
|
+
- ".rspec"
|
127
|
+
- ".rubocop.yml"
|
128
|
+
- CHANGELOG.md
|
129
|
+
- CONTRIBUTING.md
|
130
|
+
- DOCUMENTATION.md
|
131
|
+
- Gemfile
|
132
|
+
- LICENSE
|
133
|
+
- Makefile
|
134
|
+
- README.md
|
135
|
+
- Rakefile
|
136
|
+
- bin/console
|
137
|
+
- bin/generate_docker_env.sh
|
138
|
+
- bin/setup
|
139
|
+
- bin/test_client.rb
|
140
|
+
- docker/Dockerfile
|
141
|
+
- docker/Makefile
|
142
|
+
- lib/notifications/client.rb
|
143
|
+
- lib/notifications/client/helper_methods.rb
|
144
|
+
- lib/notifications/client/notification.rb
|
145
|
+
- lib/notifications/client/notifications_collection.rb
|
146
|
+
- lib/notifications/client/received_text.rb
|
147
|
+
- lib/notifications/client/received_text_collection.rb
|
148
|
+
- lib/notifications/client/request_error.rb
|
149
|
+
- lib/notifications/client/response_notification.rb
|
150
|
+
- lib/notifications/client/response_precompiled_letter.rb
|
151
|
+
- lib/notifications/client/response_template.rb
|
152
|
+
- lib/notifications/client/speaker.rb
|
153
|
+
- lib/notifications/client/template_collection.rb
|
154
|
+
- lib/notifications/client/template_preview.rb
|
155
|
+
- lib/notifications/client/uuid_validator.rb
|
156
|
+
- lib/notifications/client/version.rb
|
157
|
+
- notifications-ruby-client.gemspec
|
158
|
+
homepage: https://github.com/alphagov/notifications-ruby-client
|
159
|
+
licenses: []
|
160
|
+
metadata: {}
|
161
|
+
post_install_message:
|
162
|
+
rdoc_options: []
|
163
|
+
require_paths:
|
164
|
+
- lib
|
165
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
166
|
+
requirements:
|
167
|
+
- - ">="
|
168
|
+
- !ruby/object:Gem::Version
|
169
|
+
version: '0'
|
170
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
requirements: []
|
176
|
+
rubyforge_project:
|
177
|
+
rubygems_version: 2.7.6
|
178
|
+
signing_key:
|
179
|
+
specification_version: 4
|
180
|
+
summary: Ruby client for GOV.UK Notifications API
|
181
|
+
test_files: []
|