smartsheet 1.0.0.beta.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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/.rubocop.yml +5 -0
  4. data/.travis.yml +6 -0
  5. data/Gemfile +6 -0
  6. data/LICENSE +202 -0
  7. data/README.md +139 -0
  8. data/Rakefile +13 -0
  9. data/bin/console +14 -0
  10. data/bin/setup +8 -0
  11. data/lib/smartsheet.rb +3 -0
  12. data/lib/smartsheet/api/body_builder.rb +26 -0
  13. data/lib/smartsheet/api/endpoint_spec.rb +35 -0
  14. data/lib/smartsheet/api/faraday_adapter/faraday_net_client.rb +42 -0
  15. data/lib/smartsheet/api/faraday_adapter/faraday_response.rb +60 -0
  16. data/lib/smartsheet/api/faraday_adapter/middleware/faraday_error_translator.rb +20 -0
  17. data/lib/smartsheet/api/faraday_adapter/middleware/response_parser.rb +25 -0
  18. data/lib/smartsheet/api/file_spec.rb +28 -0
  19. data/lib/smartsheet/api/header_builder.rb +85 -0
  20. data/lib/smartsheet/api/request.rb +29 -0
  21. data/lib/smartsheet/api/request_client.rb +26 -0
  22. data/lib/smartsheet/api/request_logger.rb +148 -0
  23. data/lib/smartsheet/api/request_spec.rb +43 -0
  24. data/lib/smartsheet/api/response_net_client_decorator.rb +47 -0
  25. data/lib/smartsheet/api/retry_logic.rb +37 -0
  26. data/lib/smartsheet/api/retry_net_client_decorator.rb +36 -0
  27. data/lib/smartsheet/api/url_builder.rb +25 -0
  28. data/lib/smartsheet/client.rb +115 -0
  29. data/lib/smartsheet/constants.rb +16 -0
  30. data/lib/smartsheet/endpoints/contacts/contacts.rb +29 -0
  31. data/lib/smartsheet/endpoints/favorites/favorites.rb +158 -0
  32. data/lib/smartsheet/endpoints/folders/folders.rb +124 -0
  33. data/lib/smartsheet/endpoints/groups/groups.rb +82 -0
  34. data/lib/smartsheet/endpoints/home/home.rb +19 -0
  35. data/lib/smartsheet/endpoints/reports/reports.rb +96 -0
  36. data/lib/smartsheet/endpoints/reports/reports_share.rb +68 -0
  37. data/lib/smartsheet/endpoints/search/search.rb +29 -0
  38. data/lib/smartsheet/endpoints/server_info/server_info.rb +19 -0
  39. data/lib/smartsheet/endpoints/share/share.rb +58 -0
  40. data/lib/smartsheet/endpoints/sheets/cells.rb +80 -0
  41. data/lib/smartsheet/endpoints/sheets/columns.rb +65 -0
  42. data/lib/smartsheet/endpoints/sheets/comments.rb +60 -0
  43. data/lib/smartsheet/endpoints/sheets/comments_attachments.rb +77 -0
  44. data/lib/smartsheet/endpoints/sheets/discussions.rb +80 -0
  45. data/lib/smartsheet/endpoints/sheets/discussions_attachments.rb +21 -0
  46. data/lib/smartsheet/endpoints/sheets/rows.rb +91 -0
  47. data/lib/smartsheet/endpoints/sheets/rows_attachments.rb +91 -0
  48. data/lib/smartsheet/endpoints/sheets/sheets.rb +301 -0
  49. data/lib/smartsheet/endpoints/sheets/sheets_attachments.rb +173 -0
  50. data/lib/smartsheet/endpoints/sheets/sheets_share.rb +68 -0
  51. data/lib/smartsheet/endpoints/sights/sights.rb +97 -0
  52. data/lib/smartsheet/endpoints/sights/sights_share.rb +68 -0
  53. data/lib/smartsheet/endpoints/templates/templates.rb +28 -0
  54. data/lib/smartsheet/endpoints/token/token.rb +57 -0
  55. data/lib/smartsheet/endpoints/update_requests/sent_update_requests.rb +42 -0
  56. data/lib/smartsheet/endpoints/update_requests/update_requests.rb +69 -0
  57. data/lib/smartsheet/endpoints/users/alternate_emails.rb +77 -0
  58. data/lib/smartsheet/endpoints/users/users.rb +73 -0
  59. data/lib/smartsheet/endpoints/webhooks/webhooks.rb +70 -0
  60. data/lib/smartsheet/endpoints/workspaces/workspaces.rb +83 -0
  61. data/lib/smartsheet/endpoints/workspaces/workspaces_share.rb +68 -0
  62. data/lib/smartsheet/error.rb +30 -0
  63. data/lib/smartsheet/general_request.rb +53 -0
  64. data/lib/smartsheet/version.rb +5 -0
  65. data/read-write-sheet/config.json +4 -0
  66. data/read-write-sheet/read_write_sheet.rb +89 -0
  67. data/smartsheet.gemspec +47 -0
  68. metadata +279 -0
@@ -0,0 +1,43 @@
1
+ require 'json'
2
+ require 'awrence'
3
+
4
+ module Smartsheet
5
+ module API
6
+ class RequestSpec
7
+ attr_reader :file_spec, :url_args, :params, :header_overrides, :body, :filename, :content_type
8
+ private :file_spec
9
+
10
+ def initialize(params: {}, header_overrides: {}, body: nil, file_spec: nil, **url_args)
11
+ @url_args = url_args
12
+ @params = params
13
+ @header_overrides = header_overrides
14
+ @body = body
15
+ @file_spec = file_spec
16
+ end
17
+
18
+ def filename
19
+ file_spec.filename
20
+ end
21
+
22
+ def content_type
23
+ file_spec.content_type
24
+ end
25
+
26
+ def file_length
27
+ file_spec.file_length
28
+ end
29
+
30
+ def json_body
31
+ if body.nil? || body.is_a?(String)
32
+ body
33
+ else
34
+ body.to_camelback_keys.to_json
35
+ end
36
+ end
37
+
38
+ def file_body
39
+ file_spec.upload_io
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ require 'plissken'
2
+
3
+ require 'smartsheet/error'
4
+
5
+ module Smartsheet
6
+ module API
7
+ class ResponseNetClientDecorator
8
+ def initialize(client, json_output: false, logger: MuteRequestLogger.new)
9
+ @json_output = json_output
10
+ @client = client
11
+ @logger = logger
12
+ end
13
+
14
+ def make_request(request)
15
+ parse(request, client.make_request(request))
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :json_output, :client, :logger
21
+
22
+ def parse(request, response)
23
+ if response.success?
24
+ logger.log_successful_response(response)
25
+ parse_success(response)
26
+ else
27
+ logger.log_error_response(request, response)
28
+ parse_failure(response)
29
+ end
30
+ end
31
+
32
+ def parse_success(response)
33
+ if json_output
34
+ response.result.to_json
35
+ elsif response.result.respond_to? :to_snake_keys
36
+ response.result.to_snake_keys
37
+ else
38
+ response.result
39
+ end
40
+ end
41
+
42
+ def parse_failure(response)
43
+ raise Smartsheet::ApiError.new(response)
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,37 @@
1
+ require 'smartsheet/constants'
2
+
3
+ module Smartsheet
4
+ module API
5
+ class RetryLogic
6
+ include Smartsheet::Constants
7
+
8
+ def initialize(max_retry_time: DEFAULT_MAX_RETRY_TIME, backoff_method: DEFAULT_BACKOFF_METHOD)
9
+ @max_retry_time = max_retry_time
10
+ @backoff_method = backoff_method
11
+ end
12
+
13
+ def run(should_retry, &method_to_run)
14
+ end_time = Time.now.to_i + max_retry_time
15
+
16
+ _run(method_to_run, should_retry, end_time, 0)
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :backoff_method, :max_retry_time
22
+
23
+ def _run(method_to_run, should_retry, end_time, iteration)
24
+ result = method_to_run.call(iteration)
25
+
26
+ backoff = backoff_method.call(iteration, result)
27
+
28
+ if backoff == :stop || Time.now.to_i + backoff >= end_time || !should_retry.call(result)
29
+ return result
30
+ end
31
+
32
+ sleep backoff
33
+ _run(method_to_run, should_retry, end_time, iteration + 1)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,36 @@
1
+ require 'smartsheet/api/request_logger'
2
+
3
+ module Smartsheet
4
+ module API
5
+ class RetryNetClientDecorator
6
+ SHOULD_RETRY = ->(response) { response.should_retry? }
7
+
8
+ attr_reader :client, :retrier, :logger
9
+ private :client, :retrier, :logger
10
+
11
+ def initialize(client, retrier, logger: MuteRequestLogger.new)
12
+ @client = client
13
+ @retrier = retrier
14
+ @logger = logger
15
+ end
16
+
17
+ def make_request(request)
18
+ total_attempts = 0
19
+
20
+ retried_response = retrier.run(SHOULD_RETRY) do |iteration|
21
+ response = client.make_request(request)
22
+
23
+ total_attempts = iteration + 1
24
+ logger.log_retry_attempt(request, response, total_attempts) if SHOULD_RETRY.call(response)
25
+ response
26
+ end
27
+
28
+ unless retried_response.success?
29
+ logger.log_retry_failure(total_attempts)
30
+ end
31
+
32
+ retried_response
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,25 @@
1
+ require 'smartsheet/constants'
2
+
3
+ module Smartsheet
4
+ module API
5
+ # Methods for building Smartsheet API URLs
6
+ class UrlBuilder
7
+ def initialize(endpoint_spec, request_spec, base_url)
8
+ @segments = endpoint_spec.url_segments
9
+ @args = request_spec.url_args
10
+ @base_url = base_url
11
+ end
12
+
13
+ def build
14
+ segments
15
+ .collect { |seg| seg.is_a?(Symbol) ? args[seg] : seg }
16
+ .unshift(base_url)
17
+ .join('/')
18
+ end
19
+
20
+ private
21
+
22
+ attr_accessor :segments, :args, :base_url
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,115 @@
1
+ require 'smartsheet/api/faraday_adapter/faraday_net_client'
2
+ require 'smartsheet/api/retry_net_client_decorator'
3
+ require 'smartsheet/api/response_net_client_decorator'
4
+ require 'smartsheet/api/request_client'
5
+ require 'smartsheet/api/retry_logic'
6
+ require 'smartsheet/api/request_logger'
7
+ require 'smartsheet/general_request'
8
+
9
+ require 'smartsheet/endpoints/contacts/contacts'
10
+ require 'smartsheet/endpoints/favorites/favorites'
11
+ require 'smartsheet/endpoints/folders/folders'
12
+ require 'smartsheet/endpoints/groups/groups'
13
+ require 'smartsheet/endpoints/home/home'
14
+ require 'smartsheet/endpoints/reports/reports'
15
+ require 'smartsheet/endpoints/search/search'
16
+ require 'smartsheet/endpoints/server_info/server_info'
17
+ require 'smartsheet/endpoints/sheets/sheets'
18
+ require 'smartsheet/endpoints/sights/sights'
19
+ require 'smartsheet/endpoints/templates/templates'
20
+ require 'smartsheet/endpoints/token/token'
21
+ require 'smartsheet/endpoints/update_requests/update_requests'
22
+ require 'smartsheet/endpoints/users/users'
23
+ require 'smartsheet/endpoints/webhooks/webhooks'
24
+ require 'smartsheet/endpoints/workspaces/workspaces'
25
+
26
+
27
+ module Smartsheet
28
+ class Client
29
+ include GeneralRequest
30
+ include Smartsheet::Constants
31
+
32
+ attr_reader :contacts, :favorites, :folders, :groups, :home, :reports, :search, :server_info,
33
+ :sheets, :sights, :templates, :token, :update_requests, :users, :webhooks,
34
+ :workspaces
35
+
36
+ def initialize(
37
+ token: nil,
38
+ assume_user: nil,
39
+ json_output: false,
40
+ max_retry_time: nil,
41
+ backoff_method: nil,
42
+ logger: nil,
43
+ log_full_body: false,
44
+ base_url: API_URL
45
+ )
46
+
47
+ request_logger =
48
+ logger ?
49
+ API::RequestLogger.new(logger, log_full_body) :
50
+ API::MuteRequestLogger.new
51
+
52
+ token = token_env_var if token.nil?
53
+
54
+ net_client = API::FaradayNetClient.new
55
+
56
+ retry_logic = init_retry_logic(max_retry_time, backoff_method)
57
+
58
+ retrying_client = API::RetryNetClientDecorator.new(
59
+ net_client,
60
+ retry_logic,
61
+ logger: request_logger
62
+ )
63
+
64
+ response_client = API::ResponseNetClientDecorator.new(
65
+ retrying_client,
66
+ json_output: json_output
67
+ )
68
+
69
+ @client = API::RequestClient.new(
70
+ token,
71
+ response_client,
72
+ base_url,
73
+ assume_user: assume_user,
74
+ logger: request_logger
75
+ )
76
+
77
+ build_categories
78
+ end
79
+
80
+ private
81
+
82
+ attr_reader :client
83
+
84
+ def build_categories
85
+ @contacts = Contacts.new(client)
86
+ @favorites = Favorites.new(client)
87
+ @folders = Folders.new(client)
88
+ @groups = Groups.new(client)
89
+ @home = Home.new(client)
90
+ @reports = Reports.new(client)
91
+ @search = Search.new(client)
92
+ @server_info = ServerInfo.new(client)
93
+ @sheets = Sheets.new(client)
94
+ @sights = Sights.new(client)
95
+ @token = Token.new(client)
96
+ @templates = Templates.new(client)
97
+ @update_requests = UpdateRequests.new(client)
98
+ @users = Users.new(client)
99
+ @webhooks = Webhooks.new(client)
100
+ @workspaces = Workspaces.new(client)
101
+ end
102
+
103
+ def init_retry_logic(max_retry_time, backoff_method)
104
+ retry_opts = {}
105
+ retry_opts[:max_retry_time] = max_retry_time unless max_retry_time.nil?
106
+ retry_opts[:backoff_method] = backoff_method unless backoff_method.nil?
107
+
108
+ API::RetryLogic.new(**retry_opts)
109
+ end
110
+
111
+ def token_env_var
112
+ ENV['SMARTSHEET_ACCESS_TOKEN']
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,16 @@
1
+ module Smartsheet
2
+ module Constants
3
+ VERSION = '1.0.0.beta.0'.freeze
4
+
5
+ USER_AGENT = 'smartsheet-ruby-sdk'.freeze
6
+ API_URL = 'https://api.smartsheet.com/2.0'.freeze
7
+
8
+ JSON_TYPE = 'application/json'.freeze
9
+ EXCEL_TYPE = 'application/vnd.ms-excel'.freeze
10
+ PDF_TYPE = 'application/pdf'.freeze
11
+ CSV_TYPE = 'text/csv'.freeze
12
+
13
+ DEFAULT_MAX_RETRY_TIME = 15
14
+ DEFAULT_BACKOFF_METHOD = proc { |iteration, _result| 2**iteration + rand }
15
+ end
16
+ end
@@ -0,0 +1,29 @@
1
+ module Smartsheet
2
+ class Contacts
3
+ attr_reader :client
4
+ private :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def get(contact_id:, params: {}, header_overrides: {})
11
+ endpoint_spec = Smartsheet::API::EndpointSpec.new(:get, ['contacts', :contact_id])
12
+ request_spec = Smartsheet::API::RequestSpec.new(
13
+ header_overrides: header_overrides,
14
+ params: params,
15
+ contact_id: contact_id
16
+ )
17
+ client.make_request(endpoint_spec, request_spec)
18
+ end
19
+
20
+ def list(params: {}, header_overrides: {})
21
+ endpoint_spec = Smartsheet::API::EndpointSpec.new(:get, ['contacts'])
22
+ request_spec = Smartsheet::API::RequestSpec.new(
23
+ header_overrides: header_overrides,
24
+ params: params
25
+ )
26
+ client.make_request(endpoint_spec, request_spec)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,158 @@
1
+ module Smartsheet
2
+ class Favorites
3
+ attr_reader :client
4
+ private :client
5
+
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ def add(body:, params: {}, header_overrides: {})
11
+ endpoint_spec = Smartsheet::API::EndpointSpec.new(:post, ['favorites'], body_type: :json)
12
+ request_spec = Smartsheet::API::RequestSpec.new(
13
+ header_overrides: header_overrides,
14
+ params: params,
15
+ body: body
16
+ )
17
+ client.make_request(endpoint_spec, request_spec)
18
+ end
19
+
20
+ def list(params: {}, header_overrides: {})
21
+ endpoint_spec = Smartsheet::API::EndpointSpec.new(:get, ['favorites'])
22
+ request_spec = Smartsheet::API::RequestSpec.new(
23
+ header_overrides: header_overrides,
24
+ params: params
25
+ )
26
+ client.make_request(endpoint_spec, request_spec)
27
+ end
28
+
29
+ def remove_folder(folder_id:, params: {}, header_overrides: {})
30
+ remove_favorite(
31
+ url: ['folder', :folder_id],
32
+ params: params,
33
+ header_overrides: header_overrides,
34
+ folder_id: folder_id
35
+ )
36
+ end
37
+
38
+ def remove_report(report_id:, params: {}, header_overrides: {})
39
+ remove_favorite(
40
+ url: ['report', :report_id],
41
+ params: params,
42
+ header_overrides: header_overrides,
43
+ report_id: report_id
44
+ )
45
+ end
46
+
47
+ def remove_sheet(sheet_id:, params: {}, header_overrides: {})
48
+ remove_favorite(
49
+ url: ['sheet', :sheet_id],
50
+ params: params,
51
+ header_overrides: header_overrides,
52
+ sheet_id: sheet_id
53
+ )
54
+ end
55
+
56
+ def remove_sight(sight_id:, params: {}, header_overrides: {})
57
+ remove_favorite(
58
+ url: ['sights', :sight_id],
59
+ params: params,
60
+ header_overrides: header_overrides,
61
+ sight_id: sight_id
62
+ )
63
+ end
64
+
65
+ def remove_template(template_id:, params: {}, header_overrides: {})
66
+ remove_favorite(
67
+ url: ['template', :template_id],
68
+ params: params,
69
+ header_overrides: header_overrides,
70
+ template_id: template_id
71
+ )
72
+ end
73
+
74
+ def remove_workspace(workspace_id:, params: {}, header_overrides: {})
75
+ remove_favorite(
76
+ url: ['workspace', :workspace_id],
77
+ params: params,
78
+ header_overrides: header_overrides,
79
+ workspace_id: workspace_id
80
+ )
81
+ end
82
+
83
+ def remove_folders(folder_ids:, params: {}, header_overrides: {})
84
+ remove_favorites(
85
+ url: ['folder'],
86
+ params: params,
87
+ header_overrides: header_overrides,
88
+ object_ids: folder_ids
89
+ )
90
+ end
91
+
92
+ def remove_reports(report_ids:, params: {}, header_overrides: {})
93
+ remove_favorites(
94
+ url: ['report'],
95
+ params: params,
96
+ header_overrides: header_overrides,
97
+ object_ids: report_ids
98
+ )
99
+ end
100
+
101
+ def remove_sheets(sheet_ids:, params: {}, header_overrides: {})
102
+ remove_favorites(
103
+ url: ['sheet'],
104
+ params: params,
105
+ header_overrides: header_overrides,
106
+ object_ids: sheet_ids
107
+ )
108
+ end
109
+
110
+ def remove_sights(sight_ids:, params: {}, header_overrides: {})
111
+ remove_favorites(
112
+ url: ['sights'],
113
+ params: params,
114
+ header_overrides: header_overrides,
115
+ object_ids: sight_ids
116
+ )
117
+ end
118
+
119
+ def remove_templates(template_ids:, params: {}, header_overrides: {})
120
+ remove_favorites(
121
+ url: ['template'],
122
+ params: params,
123
+ header_overrides: header_overrides,
124
+ object_ids: template_ids
125
+ )
126
+ end
127
+
128
+ def remove_workspaces(workspace_ids:, params: {}, header_overrides: {})
129
+ remove_favorites(
130
+ url: ['workspace'],
131
+ params: params,
132
+ header_overrides: header_overrides,
133
+ object_ids: workspace_ids
134
+ )
135
+ end
136
+
137
+ private
138
+
139
+ def remove_favorite(url:, params:, header_overrides:, **url_args)
140
+ endpoint_spec = Smartsheet::API::EndpointSpec.new(:delete, ['favorites'] + url)
141
+ request_spec = Smartsheet::API::RequestSpec.new(
142
+ header_overrides: header_overrides,
143
+ params: params,
144
+ **url_args
145
+ )
146
+ client.make_request(endpoint_spec, request_spec)
147
+ end
148
+
149
+ def remove_favorites(object_ids:, url:, params:, header_overrides:)
150
+ endpoint_spec = Smartsheet::API::EndpointSpec.new(:delete, ['favorites'] + url)
151
+ request_spec = Smartsheet::API::RequestSpec.new(
152
+ header_overrides: header_overrides,
153
+ params: params.merge({objectIds: object_ids.join(',')})
154
+ )
155
+ client.make_request(endpoint_spec, request_spec)
156
+ end
157
+ end
158
+ end