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.
@@ -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: []