Skip to content
This repository was archived by the owner on Dec 12, 2023. It is now read-only.

Commit d0f152f

Browse files
committed
Change strategy
1 parent a06cc5f commit d0f152f

File tree

7 files changed

+75
-169
lines changed

7 files changed

+75
-169
lines changed

Diff for: README.md

+9-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,15 @@ Or install it yourself as:
2222

2323
## Usage
2424

25-
TODO: Write usage instructions here
25+
Currently, the API bindings only expose the following endpoints:
26+
27+
1. [Contacts](https://developers.freshdesk.com/api/#contacts)
28+
2. [Companies](https://developers.freshdesk.com/api/#companies)
29+
3. [Contact Fields](https://developers.freshdesk.com/api/#list_all_contact_fields)
30+
4. [Company Fields](https://developers.freshdesk.com/api/#list_all_company_fields)
31+
32+
Note that while search/filter works for both Companies and Contacts, the API is still not working perfectly.
33+
For example, filtering Contacts by email fails - likely due to encosing issues on Freshdesk's side.
2634

2735
## Development
2836

Diff for: lib/freshdesk_api_v2/base.rb

+33-76
Original file line numberDiff line numberDiff line change
@@ -4,43 +4,44 @@ def initialize(http)
44
@http = http
55
end
66

7+
# pagination_options: page: integer > 0, per_page: integer > 0 && <= 100
78
def list(pagination_options = {})
8-
per_page = pagination_options[:per_page] || Utils::MAX_PAGE_SIZE
9-
raise PaginationException, "Max per page is #{Utils::MAX_PAGE_SIZE}" if per_page.to_i > Utils::MAX_PAGE_SIZE
10-
first_page, last_page = extract_list_pagination(pagination_options)
11-
validate_list_pagination!(first_page, last_page)
12-
paginated_get(first_page, last_page, per_page)
9+
page = pagination_options[:page]
10+
per_page = pagination_options[:per_page]
11+
validate_list_pagination!(page, per_page)
12+
@http.get("#{endpoint}?page=#{page}&per_page=#{per_page}")
1313
end
1414

1515
# TODO - Note that queries that by email or things that have special characters to not work yet in
16-
# Freshdesk
16+
# Freshdesk. This appears to be a bug on their side.
17+
# query: An instance of FreshdeskApiV2::SearchArgs
18+
# pagination_options: page: integer > 0 && <= 10, per_page: integer > 0 && <= 30
1719
def search(query, pagination_options = {})
18-
raise SearchException, 'You must provide a query' if query.nil?
19-
raise SearchException, 'You must provide a query of type FreshdeskApiV2::SearchArgs' unless query.is_a?(FreshdeskApiV2::SearchArgs)
20-
raise SearchException, 'You must provide a query' unless query.valid?
21-
first_page, last_page = extract_search_pagination(pagination_options)
22-
validate_search_pagination!(first_page, last_page)
23-
paginated_search(query.to_query, first_page, last_page)
20+
validate_search_query!(query)
21+
page = pagination_options[:page]
22+
per_page = pagination_options[:per_page]
23+
validate_search_pagination!(page, per_page)
24+
@http.get("#{endpoint}/search/#{endpoint}?page=#{page}&query=#{query}")
2425
end
2526

26-
def show(id)
27-
get(id)
27+
def get(id)
28+
@http.get("/#{endpoint}/#{id}")
2829
end
2930

3031
def create(attributes)
3132
validate_create_attributes!(attributes)
3233
attributes = prepare_attributes!(attributes)
33-
post(attributes)
34+
@http.post(endpoint, attributes)
3435
end
3536

3637
def update(id, attributes)
3738
validate_update_attributes!(attributes)
3839
attributes = prepare_attributes!(attributes)
39-
put(id, attributes)
40+
@http.put("#{endpoint}/#{id}", attributes)
4041
end
4142

4243
def destroy(id)
43-
delete(id)
44+
@http.delete("#{endpoint}/#{id}")
4445
end
4546

4647
protected
@@ -59,16 +60,19 @@ def validate_update_attributes!(attributes)
5960
raise UpdateException, 'Please provide attributes' if attributes.nil? || attributes.count == 0
6061
end
6162

62-
def validate_list_pagination!(first_page, last_page)
63-
raise PaginationException, 'first_page must be a number greater than 0' if first_page.to_i <= 0
64-
raise PaginationException, 'last_page must be a number greater than or equal to first_page' if last_page.to_i < first_page.to_i
63+
def validate_list_pagination!(page, per_page)
64+
raise PaginationException, 'page must be a number greater than 0' if !page.nil? && page.to_i <= 0
65+
unless per_page.nil?
66+
raise PaginationException, 'per_page must be a number greater than 0' if per_page.to_i <= 0
67+
raise PaginationException, "per_page must be a number less than or equal to #{Utils::MAX_LIST_PER_PAGE}" if per_page.to_i > Utils::MAX_LIST_PER_PAGE
68+
end
6569
end
6670

67-
def validate_search_pagination!(first_page, last_page)
68-
raise PaginationException, 'first_page must be a number greater than 0' if first_page.to_i <= 0
69-
unless last_page.nil?
70-
raise PaginationException, "last_page cannot exceed #{Utils::MAX_SEARCH_PAGES}" if last_page.to_i > Utils::MAX_SEARCH_PAGES
71-
raise PaginationException, 'last_page must be a number greater than or equal to first_page' if last_page.to_i < first_page.to_i
71+
def validate_search_pagination!(page, per_page)
72+
raise PaginationException, 'page must be a number greater than 0' if !page.nil? && page.to_i <= 0
73+
unless per_page.nil?
74+
raise PaginationException, 'per_page must be a number greater than 0' if per_page.to_i <= 0
75+
raise PaginationException, "per_page must be a number less than or equal to #{Utils::MAX_SEARCH_PER_PAGE}" if per_page.to_i > Utils::MAX_SEARCH_PER_PAGE
7276
end
7377
end
7478

@@ -82,57 +86,10 @@ def prepare_attributes!(attributes)
8286
clean
8387
end
8488

85-
private
86-
87-
def get(id)
88-
response = @http.get("#{api_url}/#{id}")
89-
JSON.parse(response.body)
90-
end
91-
92-
def post(attributes)
93-
response = @http.post("#{api_url}", attributes)
94-
JSON.parse(response.body)
95-
end
96-
97-
def delete(id)
98-
response = @http.delete("#{api_url}/#{id}")
99-
response.status
100-
end
101-
102-
def put(id, attributes)
103-
response = @http.put("#{api_url}/#{id}", attributes)
104-
JSON.parse(response.body)
105-
end
106-
107-
def paginated_get(first_page, last_page, per_page)
108-
url = "#{api_url}?page=#{first_page}&per_page=#{per_page}"
109-
@http.paginated_get(url, last_page)
110-
end
111-
112-
# For example, see: https://developers.freshdesk.com/api/#filter_contacts
113-
def paginated_search(query, first_page, last_page)
114-
url = "#{base_api_url}/search/#{endpoint}?page=#{first_page}&query=#{query}"
115-
@http.paginated_search(url, last_page)
116-
end
117-
118-
def extract_list_pagination(options)
119-
first_page = options[:first_page] || Utils::DEFAULT_PAGE
120-
last_page = options[:last_page] || Utils::INTEGER_MAX
121-
[first_page, last_page]
122-
end
123-
124-
def extract_search_pagination(options)
125-
first_page = options[:first_page] || Utils::DEFAULT_PAGE
126-
last_page = options[:last_page]
127-
[first_page, last_page]
128-
end
129-
130-
def base_api_url
131-
"https://#{@http.domain}.freshdesk.com/api/v2"
132-
end
133-
134-
def api_url
135-
"#{base_api_url}/#{endpoint}"
89+
def validate_search_query!(query)
90+
raise SearchException, 'You must provide a query' if query.nil?
91+
raise SearchException, 'You must provide a query of type FreshdeskApiV2::SearchArgs' unless query.is_a?(FreshdeskApiV2::SearchArgs)
92+
raise SearchException, 'You must provide a query' unless query.valid?
13693
end
13794
end
13895
end

Diff for: lib/freshdesk_api_v2/client.rb

+5-7
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
module FreshdeskApiV2
22
class Client
3-
attr_reader :configuration
4-
53
def initialize(configuration = nil)
64
if !configuration.nil?
7-
@configuration = Config.new(configuration) if configuration.is_a?(Hash)
8-
@configuration = configuration if configuration.is_a?(FreshdeskApiV2::Config)
5+
configuration = Config.new(configuration) if configuration.is_a?(Hash)
6+
configuration = configuration if configuration.is_a?(FreshdeskApiV2::Config)
97
else
10-
@configuration = FreshdeskApiV2.configuration
8+
configuration = FreshdeskApiV2.configuration
119
end
12-
@configuration.validate!
13-
@http = Http.new(@configuration)
10+
configuration.validate!
11+
@http = Http.new(configuration)
1412
end
1513

1614
def contacts

Diff for: lib/freshdesk_api_v2/http.rb

+13-76
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,35 @@ module FreshdeskApiV2
22
class Http
33
def initialize(configuration)
44
@configuration = configuration
5-
@link_parser = Nitlink::Parser.new
65
end
76

8-
# Freshdesk's search API uses a different pagination mechanism than their
9-
# regular pagination mechanism, so this implementation needs to be different.
10-
def paginated_search(url, last_page, collection = [])
11-
current_page = 1
12-
page_count, items = do_search(url)
13-
collection += items
14-
return collection if page_count == 1
15-
loop do
16-
current_page += 1
17-
# Freshdesk will only return up to a maximum of 10 pages, so
18-
# kill the loop if we get that far OR if we hit the last requested page
19-
break if current_page > Utils::MAX_SEARCH_PAGES || current_page > last_page
20-
url.gsub!("?page=#{current_page - 1}", "?page=#{current_page}")
21-
_, items = do_search(url)
22-
collection += items
23-
break if current_page > page_count
24-
end
25-
collection
26-
end
27-
28-
# This is Freshdesk's normal pagination. It always returns a link to the next
29-
# page in a header called 'link' with a rel of 'next'
30-
def paginated_get(url, last_page, collection = [])
31-
response = get(url)
32-
links = @link_parser.parse(response)
33-
collection += JSON.parse(response.body)
34-
while !links.nil? && links.by_rel('next')
35-
url = links.by_rel('next').target.to_s
36-
next_page = next_page(url)
37-
if next_page.to_i <= last_page.to_i
38-
response = get(url)
39-
links = @link_parser.parse(response)
40-
collection += JSON.parse(response.body)
41-
else
42-
links = nil
43-
end
44-
end
45-
collection
46-
end
47-
48-
def get(url)
49-
res = construct_http_client(url)
7+
def get(path, headers = {})
8+
res = construct_http_client(path, default_headers.merge(headers))
509
res.get
5110
end
5211

53-
def delete(url)
54-
res = construct_http_client(url)
12+
def delete(path, headers = {})
13+
res = construct_http_client(path, default_headers.merge(headers))
5514
res.delete
5615
end
5716

58-
def put(url, attributes)
59-
res = construct_http_client(url)
17+
def put(path, attributes, headers = {})
18+
res = construct_http_client(path, default_headers.merge(headers))
6019
res.put(body: attributes.to_json)
6120
end
6221

63-
def post(url, attributes)
64-
res = construct_http_client(url)
22+
def post(path, attributes, headers = {})
23+
res = construct_http_client(path, default_headers.merge(headers))
6524
res.post(body: attributes.to_json)
6625
end
6726

68-
def domain
69-
@configuration.domain
70-
end
71-
7227
private
7328

74-
def do_search(url)
75-
response = get(url)
76-
payload = JSON.parse(response.body)
77-
total = (payload['total'] || 0).to_f
78-
if total > Utils::MAX_SEARCH_RESULTS_PER_PAGE
79-
page_count = (total / Utils::MAX_SEARCH_RESULTS_PER_PAGE).ceil
80-
else
81-
page_count = 1
82-
end
83-
results = payload['results']
84-
if results.nil? && response.status == 400
85-
error_desc = payload['description']
86-
errors = payload['errors']
87-
raise InvalidSearchException.new(error_desc, errors)
88-
end
89-
[page_count, results]
90-
end
91-
92-
def next_page(url)
93-
url[Utils::PAGE_REGEX, 1]
29+
def base_api_url
30+
"https://#{@configuration.domain}.freshdesk.com/api/v2"
9431
end
9532

96-
def headers
33+
def default_headers
9734
{
9835
'Accept' => 'application/json',
9936
'Content-Type' => 'application/json'
@@ -116,8 +53,8 @@ def username_or_api_key
11653
end
11754
end
11855

119-
def construct_http_client(url)
120-
Excon.new(url,
56+
def construct_http_client(path, headers)
57+
Excon.new("#{base_api_url}/#{path}",
12158
uri_parser: Addressable::URI,
12259
headers: headers,
12360
user: username_or_api_key,

Diff for: lib/freshdesk_api_v2/list_only_base.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@ def initialize(http)
55
end
66

77
def list
8-
response = @http.get(api_url)
9-
JSON.parse(response.body)
8+
@http.get(api_url)
109
end
1110

1211
protected
@@ -19,7 +18,7 @@ def endpoint
1918
private
2019

2120
def base_api_url
22-
"https://#{@http.domain}.freshdesk.com/api/v2"
21+
"https://#{@http.send(:domain)}.freshdesk.com/api/v2"
2322
end
2423

2524
def api_url

Diff for: lib/freshdesk_api_v2/search_args.rb

+6
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,11 @@ def to_query
3737
s = @args.join('')
3838
'"' + s + '"'
3939
end
40+
41+
class << self
42+
def create(field, value)
43+
new().add(field, value)
44+
end
45+
end
4046
end
4147
end

Diff for: lib/freshdesk_api_v2/utils.rb

+7-6
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
module FreshdeskApiV2
22
module Utils
3-
INTEGER_MAX = 2_147_483_647
4-
PAGE_REGEX = /.*[\?\&]page=(\d)*.*/
5-
MAX_SEARCH_RESULTS_PER_PAGE = 30.0
6-
MAX_SEARCH_PAGES = 10
73
DEFAULT_PAGE = 1
8-
MAX_PAGE_SIZE = 100
9-
MAX_PAGE_SIZE_SEARCH = 30
4+
5+
MAX_LIST_PER_PAGE = 100
6+
MIN_LIST_PER_PAGE = 1
7+
8+
MAX_SEARCH_PAGES = 10
9+
MAX_SEARCH_PER_PAGE = 30
10+
MIN_SEARCH_PER_PAGE = 1
1011
end
1112
end

0 commit comments

Comments
 (0)