knockapi 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: df2a97ad8702bbb6843e12eeca370179e4ce14e1c591312d8bc6462c9114fd07
4
+ data.tar.gz: bdaae5b1b47ef4e022ff4fa81f59250705880801ef6075af337b41ee657ef79a
5
+ SHA512:
6
+ metadata.gz: 799e436d7ca5514f82b76f789f7fcf031fb67ed1d5f2705b34c9313c3a9369b04b450bd72e4e18c1d29d4119cf65a353729a5102fabfb1be3ef3ade48a9bd047
7
+ data.tar.gz: aec1077db54be921685100263417cc360af0ede27c382282a0f117bf59bce26d41d1af7db4775dadfb7b19b27e3b53ceae1fab1c8b4c73b43f56dbd045ebc3a8
data/.gitignore ADDED
@@ -0,0 +1,49 @@
1
+ *.gem
2
+ *.rbc
3
+ *.DS_Store
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ # Used by dotenv library to load environment variables.
15
+ # .env
16
+
17
+ # Ignore Byebug command history file.
18
+ .byebug_history
19
+
20
+ ## Specific to RubyMotion (use of CocoaPods):
21
+ #
22
+ # We recommend against adding the Pods directory to your .gitignore. However
23
+ # you should judge for yourself, the pros and cons are mentioned at:
24
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
25
+ #
26
+ # vendor/Pods/
27
+
28
+ ## Documentation cache and generated files:
29
+ /.yardoc/
30
+ /_yardoc/
31
+ /doc/
32
+ /rdoc/
33
+
34
+ ## Environment normalization:
35
+ /.bundle/
36
+ /vendor/bundle
37
+ /lib/bundler/man/
38
+
39
+ # for a library or gem, you might want to ignore these files since the code is
40
+ # intended to run in multiple environments; otherwise, check them in:
41
+ # Gemfile.lock
42
+ # .ruby-version
43
+ # .ruby-gemset
44
+
45
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
46
+ .rvmrc
47
+
48
+ # Used by RuboCop. Remote config files pulled in from inherit_from directive.
49
+ # .rubocop-https?--*
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.0.2
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,47 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ knockapi (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.4.2)
10
+ parallel (1.20.1)
11
+ parser (3.0.2.0)
12
+ ast (~> 2.4.1)
13
+ rainbow (3.0.0)
14
+ rake (13.0.6)
15
+ regexp_parser (2.1.1)
16
+ rexml (3.2.5)
17
+ rubocop (1.18.4)
18
+ parallel (~> 1.10)
19
+ parser (>= 3.0.0.0)
20
+ rainbow (>= 2.2.2, < 4.0)
21
+ regexp_parser (>= 1.8, < 3.0)
22
+ rexml
23
+ rubocop-ast (>= 1.8.0, < 2.0)
24
+ ruby-progressbar (~> 1.7)
25
+ unicode-display_width (>= 1.4.0, < 3.0)
26
+ rubocop-ast (1.10.0)
27
+ parser (>= 3.0.1.1)
28
+ rubocop-performance (1.11.4)
29
+ rubocop (>= 1.7.0, < 2.0)
30
+ rubocop-ast (>= 0.4.0)
31
+ ruby-progressbar (1.11.0)
32
+ standard (1.1.7)
33
+ rubocop (= 1.18.4)
34
+ rubocop-performance (= 1.11.4)
35
+ unicode-display_width (2.0.0)
36
+
37
+ PLATFORMS
38
+ x86_64-darwin-19
39
+
40
+ DEPENDENCIES
41
+ bundler (>= 2.0.1)
42
+ knockapi!
43
+ rake
44
+ standard
45
+
46
+ BUNDLED WITH
47
+ 2.2.22
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2021 Knock Labs, Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,151 @@
1
+ # Knock Ruby library
2
+
3
+ Knock API access for applications written in Ruby.
4
+
5
+ ## Documentation
6
+
7
+ See the documentation for Ruby usage examples.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ gem install knockapi
13
+ ```
14
+
15
+ ## Configuration
16
+
17
+ To use the library you must provide a secret API key, provided in the Knock dashboard.
18
+
19
+ You can set it as an environment variable:
20
+
21
+ ```bash
22
+ KNOCK_API_KEY="sk_12345"
23
+ ```
24
+
25
+ Or, you may set the key yourself in an initializer:
26
+
27
+ ```ruby
28
+ # /config/initializers/knock.rb
29
+ Knock.key = 'sk_12345'
30
+ ```
31
+
32
+ ## Usage
33
+
34
+ ### Identifying users
35
+
36
+ ```ruby
37
+ require "knockapi"
38
+
39
+ Knock.key = "sk_12345"
40
+
41
+ Knock::Users.identify(
42
+ id: "jhammond",
43
+ data: {
44
+ name: "John Hammond",
45
+ email: "jhammond@ingen.net",
46
+ }
47
+ )
48
+ ```
49
+
50
+ ### Sending notifies (triggering workflows)
51
+
52
+ ```ruby
53
+ require "knockapi"
54
+
55
+ Knock.key = "sk_12345"
56
+
57
+ # The key of the workflow (from Knock dashboard)
58
+ Knock::Workflows.trigger(
59
+ key: "dinosaurs-loose",
60
+ # user id of who performed the action
61
+ actor: "dnedry",
62
+ # list of user ids for who should receive the notif
63
+ recipients: ["jhammond", "agrant", "imalcolm", "esattler"],
64
+ # data payload to send through
65
+ data: {
66
+ type: "trex",
67
+ priority: 1,
68
+ },
69
+ # an optional key to provide to cancel a notify
70
+ cancellation_key: trigger_alert.id,
71
+ )
72
+ ```
73
+
74
+ ### Retrieving users
75
+
76
+ ```ruby
77
+ require "knockapi"
78
+
79
+ Knock.key = "sk_12345"
80
+
81
+ Knock::Users.get(id: "jhammond")
82
+ ```
83
+
84
+ ### Deleting users
85
+
86
+ ```ruby
87
+ require "knockapi"
88
+
89
+ Knock.key = "sk_12345"
90
+
91
+ Knock::Users.delete(id: "jhammond")
92
+ ```
93
+
94
+ ### Preferences
95
+
96
+ ```ruby
97
+ require "knockapi"
98
+ Knock.key = "sk_12345"
99
+
100
+ # Set an entire preference set
101
+ Knock::Preferences.set(
102
+ user_id: "jhammond",
103
+ channel_types: { email: true, sms: false },
104
+ workflows: {
105
+ 'dinosaurs-loose': {
106
+ channel_types: { email: false, in_app_feed: false }
107
+ }
108
+ }
109
+ )
110
+
111
+ # Get an entire preference set
112
+ Knock::Preferences.get(user_id: "jhammond")
113
+ ```
114
+
115
+ ### Cancelling workflows
116
+
117
+ ```ruby
118
+ require "knockapi"
119
+ Knock.key = "sk_12345"
120
+
121
+ Knock::Workflows.cancel(
122
+ key: "dinosaurs-loose",
123
+ cancellation_key: trigger_alert.id,
124
+ # Optionally, you can provide recipients to cancel for
125
+ recipients: ["jhammond"]
126
+ )
127
+ ```
128
+
129
+ ### Signing JWTs
130
+
131
+ You can use the `jwt` gem to sign JWTs easily. You will need to generate an environment specific signing key, which you can find in the Knock dashboard.
132
+
133
+ If you're using a signing token you will need to pass this to your client to perform authentication. You can read more about [clientside authentication here](https://docs.knock.app/client-integration/authenticating-users).
134
+
135
+ ```ruby
136
+ require 'jwt'
137
+
138
+ secret = ENV['KNOCK_SIGNING_KEY']
139
+ now = Time.now.to_i
140
+
141
+ payload = {
142
+ # The subject of the token
143
+ sub: 'jhammond',
144
+ # When the token was issued
145
+ iat: now,
146
+ # Expire the token in 1 week
147
+ exp: now + (24 * 7 * 3600)
148
+ }
149
+
150
+ JWT.encode(payload, secret, 'RS256')
151
+ ```
data/bin/console ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "knock"
5
+
6
+ require "irb"
7
+ IRB.start(__FILE__)
data/knockapi.gemspec ADDED
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = File.expand_path("lib", __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require "knock/version"
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = "knockapi"
9
+ spec.version = Knock::VERSION
10
+ spec.authors = ["Knock Labs, Inc."]
11
+ spec.email = ["support@knock.app"]
12
+ spec.description = "API client for Knock"
13
+ spec.summary = "API client for Knock"
14
+ spec.homepage = "https://github.com/knocklabs/knock-ruby"
15
+ spec.license = "MIT"
16
+ spec.metadata = {
17
+ "documentation_uri" => "https://docs.knock.app"
18
+ }
19
+
20
+ spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
21
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
22
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
23
+ spec.require_paths = ["lib"]
24
+
25
+ spec.add_development_dependency "bundler", ">= 2.0.1"
26
+ spec.add_development_dependency "rake"
27
+ spec.add_development_dependency "standard"
28
+
29
+ spec.required_ruby_version = ">= 2.5"
30
+ end
data/lib/knock.rb ADDED
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "knock/version"
4
+ require "json"
5
+
6
+ module Knock
7
+ API_HOSTNAME = ENV["KNOCK_API_HOSTNAME"] || "api.knock.app"
8
+
9
+ def self.key=(value)
10
+ Base.key = value
11
+ end
12
+
13
+ def self.key
14
+ Base.key
15
+ end
16
+
17
+ def self.key!
18
+ key || raise("Knock.key not set")
19
+ end
20
+
21
+ autoload :Base, "knock/base"
22
+ autoload :Client, "knock/client"
23
+
24
+ # Resources
25
+ autoload :Preferences, "knock/preferences"
26
+ autoload :Users, "knock/users"
27
+ autoload :Workflows, "knock/workflows"
28
+
29
+ # Errors
30
+ autoload :APIError, "knock/errors"
31
+ autoload :AuthenticationError, "knock/errors"
32
+ autoload :InvalidRequestError, "knock/errors"
33
+
34
+ key = ENV["KNOCK_API_KEY"]
35
+ Knock.key = key unless key.nil?
36
+
37
+ # Triggers the workflow with the given key
38
+ #
39
+ # @param [String] key The workflow key
40
+ # @param [String] actor The actor ID
41
+ # @param [Array<String>] recipients The recipient IDs
42
+ # @param [Hash] data The data to pass to the workflow
43
+ # @param [String] cancellation_key An optional key to identify this workflow
44
+ # invocation for cancelling
45
+ # @param [String] tenant An optional tenant identifier
46
+ #
47
+ # @return [Hash] A workflow trigger result
48
+ def self.notify(**args)
49
+ Knock::Workflows.trigger(**args)
50
+ end
51
+ end
data/lib/knock/base.rb ADDED
@@ -0,0 +1,11 @@
1
+ module Knock
2
+ ## The Base class handles setting and reading the Knock API Key for authentication
3
+ module Base
4
+ attr_accessor :key
5
+
6
+ class << self
7
+ attr_writer :key
8
+ attr_reader :key
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,116 @@
1
+ module Knock
2
+ # A Net::HTTP based API client for interacting with the Knock API
3
+ module Client
4
+ include Kernel
5
+
6
+ def client
7
+ return @client if defined?(@client)
8
+
9
+ @client = Net::HTTP.new(Knock::API_HOSTNAME, 443)
10
+ @client.use_ssl = true
11
+
12
+ @client
13
+ end
14
+
15
+ def execute_request(request:)
16
+ response = client.request(request)
17
+
18
+ http_status = response.code.to_i
19
+ handle_error_response(response: response) if http_status >= 400
20
+
21
+ JSON.parse(response.body)
22
+ end
23
+
24
+ def get_request(path:, auth: false, params: {}, access_token: nil)
25
+ uri = URI(path)
26
+ uri.query = URI.encode_www_form(params) if params
27
+
28
+ request = Net::HTTP::Get.new(
29
+ uri.to_s,
30
+ "Content-Type" => "application/json"
31
+ )
32
+
33
+ request["Authorization"] = "Bearer #{access_token || Knock.key!}" if auth
34
+ request["User-Agent"] = user_agent
35
+ request
36
+ end
37
+
38
+ def post_request(path:, auth: false, idempotency_key: nil, body: nil)
39
+ request = Net::HTTP::Post.new(path, "Content-Type" => "application/json")
40
+ request.body = body.to_json if body
41
+ request["Authorization"] = "Bearer #{Knock.key!}" if auth
42
+ request["User-Agent"] = user_agent
43
+ request
44
+ end
45
+
46
+ def delete_request(path:, auth: false, params: {})
47
+ uri = URI(path)
48
+ uri.query = URI.encode_www_form(params) if params
49
+
50
+ request = Net::HTTP::Delete.new(
51
+ uri.to_s,
52
+ "Content-Type" => "application/json"
53
+ )
54
+
55
+ request["Authorization"] = "Bearer #{Knock.key!}" if auth
56
+ request["User-Agent"] = user_agent
57
+ request
58
+ end
59
+
60
+ def put_request(path:, auth: false, idempotency_key: nil, body: nil)
61
+ request = Net::HTTP::Put.new(path, "Content-Type" => "application/json")
62
+ request.body = body.to_json if body
63
+ request["Authorization"] = "Bearer #{Knock.key!}" if auth
64
+ request["User-Agent"] = user_agent
65
+ request
66
+ end
67
+
68
+ def user_agent
69
+ "Knock Ruby - v#{Knock::VERSION}"
70
+ end
71
+
72
+ def handle_error_response(response:)
73
+ http_status = response.code.to_i
74
+ json = JSON.parse(response.body)
75
+
76
+ case http_status
77
+ when 400
78
+ raise InvalidRequestError.new(
79
+ message: json["message"],
80
+ http_status: http_status,
81
+ request_id: response["x-request-id"]
82
+ )
83
+ when 401
84
+ raise AuthenticationError.new(
85
+ message: json["message"],
86
+ http_status: http_status,
87
+ request_id: response["x-request-id"]
88
+ )
89
+ when 404
90
+ raise APIError.new(
91
+ message: json["message"],
92
+ http_status: http_status,
93
+ request_id: response["x-request-id"]
94
+ )
95
+ when 422
96
+ message = json["message"]
97
+ errors = extract_error(json["errors"]) if json["errors"]
98
+ message += " (#{errors})" if errors
99
+
100
+ raise InvalidRequestError.new(
101
+ message: message,
102
+ http_status: http_status,
103
+ request_id: response["x-request-id"]
104
+ )
105
+ end
106
+ end
107
+
108
+ private
109
+
110
+ def extract_error(errors)
111
+ errors.map do |error|
112
+ "#{error["field"]}: #{error["message"]} (#{error["type"]})"
113
+ end.join("; ")
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,42 @@
1
+ module Knock
2
+ class KnockError < StandardError
3
+ attr_reader :http_status
4
+ attr_reader :request_id
5
+
6
+ def initialize(message: nil, error: nil, error_description: nil, http_status: nil, request_id: nil)
7
+ @message = message
8
+ @error = error
9
+ @error_description = error_description
10
+ @http_status = http_status
11
+ @request_id = request_id
12
+ end
13
+
14
+ def to_s
15
+ status_string = @http_status.nil? ? "" : "Status #{@http_status}, "
16
+ id_string = @request_id.nil? ? "" : " - request ID: #{@request_id}"
17
+
18
+ if @error && @error_description
19
+ error_string = "error: #{@error}, error_description: #{@error_description}"
20
+ "#{status_string}#{error_string}#{id_string}"
21
+ elsif @error
22
+ "#{status_string}#{@error}#{id_string}"
23
+ else
24
+ "#{status_string}#{@message}#{id_string}"
25
+ end
26
+ end
27
+ end
28
+
29
+ # APIError is a generic error that may be raised in cases where none of the
30
+ # other named errors cover the problem. It could also be raised in the case
31
+ # that a new error has been introduced in the API, but this version of the
32
+ # Ruby SDK doesn't know how to handle it.
33
+ class APIError < KnockError; end
34
+
35
+ # AuthenticationError is raised when invalid credentials are used to connect
36
+ # to Knock's servers.
37
+ class AuthenticationError < KnockError; end
38
+
39
+ # InvalidRequestError is raised when a request is initiated with invalid
40
+ # parameters.
41
+ class InvalidRequestError < KnockError; end
42
+ end
@@ -0,0 +1,141 @@
1
+ require "net/http"
2
+ require "uri"
3
+
4
+ module Knock
5
+ # Provides convienience methods for working with preferences
6
+ module Preferences
7
+ class << self
8
+ include Base
9
+ include Client
10
+
11
+ DEFAULT_SET_ID = "default"
12
+
13
+ # Returns all preference sets for the user
14
+ #
15
+ # @param [String] user_id The ID of the user to retrieve preferences for
16
+ #
17
+ # @return [Hash] The preference sets
18
+ def get_all(user_id:)
19
+ endpoint = "/v1/users/#{user_id}/preferences"
20
+
21
+ request = get_request(
22
+ auth: true,
23
+ path: endpoint
24
+ )
25
+
26
+ execute_request(request: request)
27
+ end
28
+
29
+ # Gets a single preference set, defaults to the 'default' set
30
+ # for the user given.
31
+ #
32
+ # @param [String] user_id The ID of the user to retrieve preferences for
33
+ # @param [String] preference_set The preference set ID (defaults to `default`)
34
+ #
35
+ # @return [Hash] The preference set (if it exists)
36
+ def get(user_id:, preference_set: DEFAULT_SET_ID)
37
+ endpoint = "/v1/users/#{user_id}/preferences/#{preference_set}"
38
+
39
+ request = get_request(
40
+ auth: true,
41
+ path: endpoint
42
+ )
43
+
44
+ execute_request(request: request)
45
+ end
46
+
47
+ # Sets multiple preferences at once for the preference set.
48
+ #
49
+ # @param [String] user_id The ID of the user to set preferences for
50
+ # @param [String] preference_set The preference set ID (defaults to `default`)
51
+ # @param [Hash] preferences The preferences hash to set
52
+ #
53
+ #  @return [Hash] The preference set
54
+ def update(
55
+ user_id:,
56
+ channel_types: nil,
57
+ workflows: nil,
58
+ categories: nil,
59
+ preference_set: DEFAULT_SET_ID
60
+ )
61
+ endpoint = "/v1/users/#{user_id}/preferences/#{preference_set}"
62
+
63
+ request = put_request(
64
+ auth: true,
65
+ path: endpoint,
66
+ body: {
67
+ channel_types: channel_types,
68
+ workflows: workflows,
69
+ categories: categories
70
+ }
71
+ )
72
+
73
+ execute_request(request: request)
74
+ end
75
+
76
+ # Sets preferences for the given channel type
77
+ #
78
+ # @param [String] user_id The ID of the user to set preferences for
79
+ # @param [String] preference_set The preference set ID (defaults to `default`)
80
+ # @param [String] channel_type The channel type to set
81
+ # @param [Bool] setting Whether the channel type is enabled or not
82
+ #
83
+ #  @return [Hash] The preference set
84
+ def set_channel_type(user_id:, channel_type:, setting:, preference_set: DEFAULT_SET_ID)
85
+ endpoint = "/v1/users/#{user_id}/preferences/#{preference_set}/channel_types/#{channel_type}"
86
+
87
+ request = put_request(
88
+ auth: true,
89
+ path: endpoint,
90
+ body: {subscribed: setting}
91
+ )
92
+
93
+ execute_request(request: request)
94
+ end
95
+
96
+ # Sets preferences for the given workflow
97
+ #
98
+ # @param [String] user_id The ID of the user to set preferences for
99
+ # @param [String] preference_set The preference set ID (defaults to `default`)
100
+ # @param [String] workflow The workflow to set preferences for
101
+ # @param [Bool | Hash] setting Either a boolean to indicate if the type is enabled
102
+ # or a hash containing channel types and settings
103
+ #
104
+ #  @return [Hash] The preference set
105
+ def set_workflow(user_id:, workflow:, setting:, preference_set: DEFAULT_SET_ID)
106
+ params = setting.is_a?(Hash) ? setting : {subscribed: setting}
107
+ endpoint = "/v1/users/#{user_id}/preferences/#{preference_set}/workflows/#{workflow}"
108
+
109
+ request = put_request(
110
+ auth: true,
111
+ path: endpoint,
112
+ body: params
113
+ )
114
+
115
+ execute_request(request: request)
116
+ end
117
+
118
+ # Sets preferences for the given category
119
+ #
120
+ # @param [String] user_id The ID of the user to set preferences for
121
+ # @param [String] preference_set The preference set ID (defaults to `default`)
122
+ # @param [String] category The category to set preferences for
123
+ # @param [Bool | Hash] setting Either a boolean to indicate if the type is enabled
124
+ # or a hash containing channel types and settings
125
+ #
126
+ #  @return [Hash] The preference set
127
+ def set_category(user_id:, category:, setting:, preference_set: DEFAULT_SET_ID)
128
+ params = setting.is_a?(Hash) ? setting : {subscribed: setting}
129
+ endpoint = "/v1/users/#{user_id}/preferences/#{preference_set}/categories/#{category}"
130
+
131
+ request = put_request(
132
+ auth: true,
133
+ path: endpoint,
134
+ body: params
135
+ )
136
+
137
+ execute_request(request: request)
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,56 @@
1
+ require "net/http"
2
+ require "uri"
3
+
4
+ module Knock
5
+ # Provides convienience methods for working with users
6
+ module Users
7
+ class << self
8
+ include Base
9
+ include Client
10
+
11
+ # Identifies the user
12
+ #
13
+ # @param [String] id The user ID
14
+ # @param [Hash] data The traits to attach to the user
15
+ #
16
+ # @return [Hash] The user
17
+ def identify(id:, data: {})
18
+ request = put_request(
19
+ auth: true,
20
+ path: "/v1/users/#{id}",
21
+ body: data
22
+ )
23
+
24
+ execute_request(request: request)
25
+ end
26
+
27
+ # Retrieves the given user
28
+ #
29
+ # @param [String] id The user ID
30
+ #
31
+ # @return [Hash] The user
32
+ def get(id:)
33
+ request = get_request(
34
+ auth: true,
35
+ path: "/v1/users/#{id}"
36
+ )
37
+
38
+ execute_request(request: request)
39
+ end
40
+
41
+ # Deletes the user
42
+ #
43
+ # @param [String] id the user ID
44
+ #
45
+ # @return [Hash] the user
46
+ def delete(id:)
47
+ request = delete_request(
48
+ auth: true,
49
+ path: "/v1/users/#{id}"
50
+ )
51
+
52
+ execute_request(request: request)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Knock
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,63 @@
1
+ require "net/http"
2
+ require "uri"
3
+
4
+ module Knock
5
+ # Methods for interacting with workflows in Knock
6
+ module Workflows
7
+ class << self
8
+ include Base
9
+ include Client
10
+
11
+ # Triggers the workflow with the given key
12
+ #
13
+ # @param [String] key The workflow key
14
+ # @param [String] actor The actor ID
15
+ # @param [Array<String>] recipients The recipient IDs
16
+ # @param [Hash] data The data to pass to the workflow
17
+ # @param [String] cancellation_key An optional key to identify this workflow
18
+ # invocation for cancelling
19
+ # @param [String] tenant An optional tenant identifier
20
+ #
21
+ # @return [Hash] A workflow trigger result
22
+ def trigger(key:, actor:, recipients:, data: {}, cancellation_key: nil, tenant: nil)
23
+ attrs = {
24
+ actor: actor,
25
+ recipients: recipients,
26
+ data: data,
27
+ cancellation_key: cancellation_key,
28
+ tenant: tenant
29
+ }
30
+
31
+ request = post_request(
32
+ auth: true,
33
+ path: "/v1/workflows/#{key}/trigger",
34
+ body: attrs
35
+ )
36
+
37
+ execute_request(request: request)
38
+ end
39
+
40
+ # Cancels the workflow with the given key and cancellation key
41
+ #
42
+ # @param [String] key The workflow key
43
+ # @param [String] cancellation_key The cancellation key
44
+ # @param [Array<String>] recipients The recipient IDs to cancel for
45
+ #
46
+ # @return [Hash] - Cancellation result
47
+ def cancel(key:, cancellation_key:, recipients: nil)
48
+ attrs = {
49
+ cancellation_key: cancellation_key,
50
+ recipients: recipients
51
+ }
52
+
53
+ request = post_request(
54
+ auth: true,
55
+ path: "/v1/workflows/#{key}/cancel",
56
+ body: attrs
57
+ )
58
+
59
+ execute_request(request: request)
60
+ end
61
+ end
62
+ end
63
+ end
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knockapi
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Knock Labs, Inc.
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-08-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 2.0.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: 2.0.1
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: standard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: API client for Knock
56
+ email:
57
+ - support@knock.app
58
+ executables:
59
+ - console
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - ".gitignore"
64
+ - ".ruby-version"
65
+ - Gemfile
66
+ - Gemfile.lock
67
+ - LICENSE
68
+ - README.md
69
+ - bin/console
70
+ - knockapi.gemspec
71
+ - lib/knock.rb
72
+ - lib/knock/base.rb
73
+ - lib/knock/client.rb
74
+ - lib/knock/errors.rb
75
+ - lib/knock/preferences.rb
76
+ - lib/knock/users.rb
77
+ - lib/knock/version.rb
78
+ - lib/knock/workflows.rb
79
+ homepage: https://github.com/knocklabs/knock-ruby
80
+ licenses:
81
+ - MIT
82
+ metadata:
83
+ documentation_uri: https://docs.knock.app
84
+ post_install_message:
85
+ rdoc_options: []
86
+ require_paths:
87
+ - lib
88
+ required_ruby_version: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ">="
91
+ - !ruby/object:Gem::Version
92
+ version: '2.5'
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ requirements: []
99
+ rubygems_version: 3.2.22
100
+ signing_key:
101
+ specification_version: 4
102
+ summary: API client for Knock
103
+ test_files: []