nokotime-ruby-client 0.1.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/.gitignore +20 -0
- data/.rspec +3 -0
- data/.rubocop.yml +21 -0
- data/.travis.yml +7 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +155 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +9 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/nokotime.rb +40 -0
- data/lib/nokotime/authentication.rb +28 -0
- data/lib/nokotime/client/entries.rb +41 -0
- data/lib/nokotime/client/project_groups.rb +33 -0
- data/lib/nokotime/client/projects.rb +41 -0
- data/lib/nokotime/client/tags.rb +33 -0
- data/lib/nokotime/client/users.rb +41 -0
- data/lib/nokotime/configuration.rb +44 -0
- data/lib/nokotime/connection.rb +87 -0
- data/lib/nokotime/errors/configuration.rb +5 -0
- data/lib/nokotime/errors/connection.rb +7 -0
- data/lib/nokotime/errors/invalid_params.rb +5 -0
- data/lib/nokotime/paginator.rb +67 -0
- data/lib/nokotime/request/multiple_pages.rb +50 -0
- data/lib/nokotime/request/single_page.rb +71 -0
- data/lib/nokotime/validator/entry_schema.rb +74 -0
- data/lib/nokotime/validator/project_group_schema.rb +28 -0
- data/lib/nokotime/validator/project_schema.rb +49 -0
- data/lib/nokotime/validator/restricted_hash.rb +11 -0
- data/lib/nokotime/validator/tag_schema.rb +28 -0
- data/lib/nokotime/validator/user_schema.rb +41 -0
- data/lib/nokotime/validator/validation.yml +14 -0
- data/lib/nokotime/version.rb +3 -0
- data/nokotime-ruby-client.gemspec +45 -0
- metadata +304 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module Nokotime
|
2
|
+
module Authentication
|
3
|
+
AUTHENTICATION_TYPE = [
|
4
|
+
:noko_token
|
5
|
+
].freeze
|
6
|
+
|
7
|
+
def valid_auth?(type)
|
8
|
+
AUTHENTICATION_TYPE.include? type
|
9
|
+
end
|
10
|
+
|
11
|
+
def authorize_request(request)
|
12
|
+
case auth_type
|
13
|
+
when :noko_token
|
14
|
+
request.headers["X-NokoToken"] = token
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def token
|
21
|
+
Nokotime.configuration.token
|
22
|
+
end
|
23
|
+
|
24
|
+
def auth_type
|
25
|
+
Nokotime.configuration.auth_type
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Nokotime
|
2
|
+
module Client
|
3
|
+
class Entries
|
4
|
+
ENDPOINT = "/v2/entries".freeze
|
5
|
+
|
6
|
+
attr_reader :params
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
multiple_pages.get(ENDPOINT, params: entry_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def show(id)
|
17
|
+
single_page.get("#{ENDPOINT}/#{id}")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def multiple_pages
|
23
|
+
@multiple_pages ||= Request::MultiplePages.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def single_page
|
27
|
+
@single_page ||= Request::SinglePage.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def entry_params
|
31
|
+
return params if validation.success?
|
32
|
+
|
33
|
+
raise Errors::InvalidParams, validation.messages
|
34
|
+
end
|
35
|
+
|
36
|
+
def validation
|
37
|
+
@validation ||= Validator::EntrySchema.validate(params)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Nokotime
|
2
|
+
module Client
|
3
|
+
class ProjectGroups
|
4
|
+
ENDPOINT = "/v2/project_groups".freeze
|
5
|
+
|
6
|
+
attr_reader :params
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
multiple_pages.get(ENDPOINT, params: project_group_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def multiple_pages
|
19
|
+
@multiple_pages ||= Request::MultiplePages.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def project_group_params
|
23
|
+
return params if validation.success?
|
24
|
+
|
25
|
+
raise Errors::InvalidParams, validation.messages
|
26
|
+
end
|
27
|
+
|
28
|
+
def validation
|
29
|
+
@validation ||= Validator::ProjectGroupSchema.validate(params)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Nokotime
|
2
|
+
module Client
|
3
|
+
class Projects
|
4
|
+
ENDPOINT = "/v2/projects".freeze
|
5
|
+
|
6
|
+
attr_reader :params
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
multiple_pages.get(ENDPOINT, params: project_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def show(id)
|
17
|
+
single_page.get("#{ENDPOINT}/#{id}")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def multiple_pages
|
23
|
+
@multiple_pages ||= Request::MultiplePages.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def single_page
|
27
|
+
@single_page ||= Request::SinglePage.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def project_params
|
31
|
+
return params if validation.success?
|
32
|
+
|
33
|
+
raise Errors::InvalidParams, validation.messages
|
34
|
+
end
|
35
|
+
|
36
|
+
def validation
|
37
|
+
@validation ||= Validator::ProjectSchema.validate(params)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Nokotime
|
2
|
+
module Client
|
3
|
+
class Tags
|
4
|
+
ENDPOINT = "/v2/tags".freeze
|
5
|
+
|
6
|
+
attr_reader :params
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
multiple_pages.get(ENDPOINT, params: tag_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def multiple_pages
|
19
|
+
@multiple_pages ||= Request::MultiplePages.new
|
20
|
+
end
|
21
|
+
|
22
|
+
def tag_params
|
23
|
+
return params if validation.success?
|
24
|
+
|
25
|
+
raise Errors::InvalidParams, validation.messages
|
26
|
+
end
|
27
|
+
|
28
|
+
def validation
|
29
|
+
@validation ||= Validator::TagSchema.validate(params)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Nokotime
|
2
|
+
module Client
|
3
|
+
class Users
|
4
|
+
ENDPOINT = "/v2/users".freeze
|
5
|
+
|
6
|
+
attr_reader :params
|
7
|
+
|
8
|
+
def initialize(params = {})
|
9
|
+
@params = params
|
10
|
+
end
|
11
|
+
|
12
|
+
def all
|
13
|
+
multiple_pages.get(ENDPOINT, params: user_params)
|
14
|
+
end
|
15
|
+
|
16
|
+
def show(id)
|
17
|
+
single_page.get("#{ENDPOINT}/#{id}")
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def multiple_pages
|
23
|
+
@multiple_pages ||= Request::MultiplePages.new
|
24
|
+
end
|
25
|
+
|
26
|
+
def single_page
|
27
|
+
@single_page ||= Request::SinglePage.new
|
28
|
+
end
|
29
|
+
|
30
|
+
def user_params
|
31
|
+
return params if validation.success?
|
32
|
+
|
33
|
+
raise Errors::InvalidParams, validation.messages
|
34
|
+
end
|
35
|
+
|
36
|
+
def validation
|
37
|
+
@validation ||= Validator::UserSchema.validate(params)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Nokotime
|
2
|
+
class Configuration
|
3
|
+
include Nokotime::Authentication
|
4
|
+
|
5
|
+
attr_writer :auth_type
|
6
|
+
attr_writer :max_concurrency
|
7
|
+
attr_writer :token
|
8
|
+
attr_accessor :url
|
9
|
+
|
10
|
+
DEFAULT_URL = "https://api.nokotime.com".freeze
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@auth_type = nil
|
14
|
+
@max_concurrency = nil
|
15
|
+
@token = nil
|
16
|
+
@url = DEFAULT_URL
|
17
|
+
end
|
18
|
+
|
19
|
+
def auth_type
|
20
|
+
unless valid_auth?(@auth_type)
|
21
|
+
raise(
|
22
|
+
Errors::Configuration,
|
23
|
+
"#{@auth_type} isn't valid type authentication."
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
@auth_type || raise(
|
28
|
+
Errors::Configuration, "Authentication type missing."
|
29
|
+
)
|
30
|
+
end
|
31
|
+
|
32
|
+
def max_concurrency
|
33
|
+
@max_concurrency || raise(
|
34
|
+
Errors::Configuration, "Max concurrency missing."
|
35
|
+
)
|
36
|
+
end
|
37
|
+
|
38
|
+
def token
|
39
|
+
@token || raise(
|
40
|
+
Errors::Configuration, "Token missing."
|
41
|
+
)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Nokotime
|
2
|
+
class Connection
|
3
|
+
include Nokotime::Authentication
|
4
|
+
|
5
|
+
# rubocop:disable Metrics/MethodLength
|
6
|
+
def get(path, params: {}, request_options: {})
|
7
|
+
response = connection.get do |request|
|
8
|
+
authorize_request(request)
|
9
|
+
set_request_options(request, request_options)
|
10
|
+
request.url path, params
|
11
|
+
end
|
12
|
+
|
13
|
+
response
|
14
|
+
rescue Faraday::ConnectionFailed => e
|
15
|
+
raise Errors::ConnectionFailed.new(e), e.message
|
16
|
+
rescue Faraday::ResourceNotFound => e
|
17
|
+
raise Errors::ResourceNotFound.new(e), e.message
|
18
|
+
rescue Faraday::ClientError => e
|
19
|
+
raise Errors::ClientError.new(e), e.message
|
20
|
+
end
|
21
|
+
# rubocop:enable Metrics/MethodLength
|
22
|
+
|
23
|
+
# rubocop:disable Metrics/AbcSize
|
24
|
+
# rubocop:disable Metrics/MethodLength
|
25
|
+
def get_in_parallel(
|
26
|
+
path,
|
27
|
+
from_page_number,
|
28
|
+
to_page_number,
|
29
|
+
params: {},
|
30
|
+
request_options: {}
|
31
|
+
)
|
32
|
+
responses = []
|
33
|
+
|
34
|
+
connection.in_parallel(manager) do
|
35
|
+
(from_page_number..to_page_number).each do |page|
|
36
|
+
merged_params = {page: page}.merge(params)
|
37
|
+
|
38
|
+
responses << get(
|
39
|
+
path, params: merged_params, request_options: request_options
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
responses
|
45
|
+
rescue Faraday::ConnectionFailed => e
|
46
|
+
raise Errors::ConnectionFailed.new(e), e.message
|
47
|
+
rescue Faraday::ResourceNotFound => e
|
48
|
+
raise Errors::ResourceNotFound.new(e), e.message
|
49
|
+
rescue Faraday::ClientError => e
|
50
|
+
raise Errors::ClientError.new(e), e.message
|
51
|
+
end
|
52
|
+
# rubocop:enable Metrics/MethodLength
|
53
|
+
# rubocop:enable Metrics/AbcSize
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def connection
|
58
|
+
@connection ||= Faraday.new(default_options) do |connection|
|
59
|
+
connection.request :json
|
60
|
+
connection.response :json, content_type: /\bjson$/
|
61
|
+
connection.response :raise_error
|
62
|
+
connection.adapter :typhoeus
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def default_options
|
67
|
+
{
|
68
|
+
url: Nokotime.configuration.url,
|
69
|
+
headers: {
|
70
|
+
user_agent: "MyNokoBot/1.0",
|
71
|
+
accept: "application/json"
|
72
|
+
}
|
73
|
+
}
|
74
|
+
end
|
75
|
+
|
76
|
+
def set_request_options(request, options)
|
77
|
+
request.options.timeout = options[:timeout]
|
78
|
+
request.options.open_timeout = options[:open_timeout]
|
79
|
+
end
|
80
|
+
|
81
|
+
def manager
|
82
|
+
@manager ||= Typhoeus::Hydra.new(
|
83
|
+
max_concurrency: Nokotime.configuration.max_concurrency
|
84
|
+
)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module Nokotime
|
2
|
+
class Paginator
|
3
|
+
attr_reader :raw_links
|
4
|
+
|
5
|
+
def initialize(raw_links)
|
6
|
+
@raw_links = raw_links
|
7
|
+
end
|
8
|
+
|
9
|
+
def next
|
10
|
+
find("next")&.dig(:url)
|
11
|
+
end
|
12
|
+
|
13
|
+
def prev
|
14
|
+
find("prev")&.dig(:url)
|
15
|
+
end
|
16
|
+
|
17
|
+
def first
|
18
|
+
find("first")&.dig(:url)
|
19
|
+
end
|
20
|
+
|
21
|
+
def last
|
22
|
+
find("last")&.dig(:url)
|
23
|
+
end
|
24
|
+
|
25
|
+
def total_pages
|
26
|
+
find("last")&.dig(:number_page)
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def find(rel)
|
32
|
+
pages.find { |page| page[:rel] == rel }
|
33
|
+
end
|
34
|
+
|
35
|
+
def pages
|
36
|
+
return {} if raw_links.empty?
|
37
|
+
|
38
|
+
@pages ||=
|
39
|
+
raw_links.split(",").map do |link|
|
40
|
+
url, rel, number_page = split_and_clean_link(link)
|
41
|
+
|
42
|
+
{
|
43
|
+
url: "#{url.path}?#{url.query}",
|
44
|
+
rel: rel,
|
45
|
+
number_page: number_page
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Example of link response headers:
|
51
|
+
# "<https://api.nokotime.com/v2/users?page=2>; rel=\"last\""
|
52
|
+
#
|
53
|
+
# The first element is an URI. "Rel" means the relative position
|
54
|
+
# of the current page, in this case is last page.
|
55
|
+
|
56
|
+
def split_and_clean_link(link)
|
57
|
+
raw_url, rel = link.split(";").map(&:strip)
|
58
|
+
|
59
|
+
raw_url = raw_url.gsub(/<|>/, "")
|
60
|
+
rel = rel.gsub(/(rel=)?"/, "")
|
61
|
+
url = URI.parse(raw_url)
|
62
|
+
page = CGI.parse(url.query)["page"].first
|
63
|
+
|
64
|
+
[url, rel, page]
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|