notifications-ruby-client 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []