nokotime-ruby-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|