asana 2.0.0 → 2.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/build.yml +1 -1
- data/.rubocop.yml +38 -3
- data/.ruby-version +1 -1
- data/Appraisals +8 -3
- data/Gemfile +7 -3
- data/Gemfile.lock +54 -64
- data/Guardfile +12 -10
- data/README.md +24 -12
- data/Rakefile +14 -17
- data/VERSION +1 -1
- data/asana.gemspec +20 -18
- data/examples/cli_app.rb +2 -2
- data/examples/events.rb +3 -3
- data/examples/personal_access_token.rb +2 -2
- data/lib/asana/authentication/oauth2/access_token_authentication.rb +4 -1
- data/lib/asana/authentication/oauth2/bearer_token_authentication.rb +3 -2
- data/lib/asana/authentication/oauth2/client.rb +2 -0
- data/lib/asana/authentication/oauth2.rb +6 -4
- data/lib/asana/authentication/token_authentication.rb +3 -1
- data/lib/asana/authentication.rb +2 -0
- data/lib/asana/client/configuration.rb +6 -5
- data/lib/asana/client.rb +13 -11
- data/lib/asana/errors.rb +16 -11
- data/lib/asana/http_client/environment_info.rb +9 -8
- data/lib/asana/http_client/error_handling.rb +23 -24
- data/lib/asana/http_client/response.rb +2 -0
- data/lib/asana/http_client.rb +66 -65
- data/lib/asana/resource_includes/attachment_uploading.rb +6 -6
- data/lib/asana/resource_includes/collection.rb +4 -4
- data/lib/asana/resource_includes/event.rb +2 -0
- data/lib/asana/resource_includes/event_subscription.rb +2 -0
- data/lib/asana/resource_includes/events.rb +4 -1
- data/lib/asana/resource_includes/registry.rb +2 -0
- data/lib/asana/resource_includes/resource.rb +8 -5
- data/lib/asana/resource_includes/response_helper.rb +2 -0
- data/lib/asana/resources/audit_log_api.rb +42 -0
- data/lib/asana/resources/gen/attachments_base.rb +1 -1
- data/lib/asana/resources/gen/audit_log_api_base.rb +1 -1
- data/lib/asana/resources/gen/memberships_base.rb +71 -0
- data/lib/asana/resources/gen/tasks_base.rb +1 -1
- data/lib/asana/resources/goal.rb +54 -0
- data/lib/asana/resources/goal_relationship.rb +32 -0
- data/lib/asana/resources/membership.rb +20 -0
- data/lib/asana/resources/project_brief.rb +30 -0
- data/lib/asana/resources/project_template.rb +36 -0
- data/lib/asana/resources/status_update.rb +54 -0
- data/lib/asana/resources/time_period.rb +30 -0
- data/lib/asana/resources/typeahead.rb +1 -1
- data/lib/asana/resources.rb +4 -4
- data/lib/asana/ruby2_0_0_compatibility.rb +2 -0
- data/lib/asana/version.rb +1 -1
- data/lib/asana.rb +2 -0
- data/samples/memberships_sample.yaml +41 -0
- metadata +57 -46
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Asana
|
2
4
|
module Authentication
|
3
5
|
module OAuth2
|
@@ -24,8 +26,7 @@ module Asana
|
|
24
26
|
#
|
25
27
|
# Returns nothing.
|
26
28
|
def configure(connection)
|
27
|
-
connection.authorization
|
28
|
-
connection.request :oauth2, token_type: 'bearer'
|
29
|
+
connection.request :authorization, 'Bearer', @token
|
29
30
|
end
|
30
31
|
end
|
31
32
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'oauth2/bearer_token_authentication'
|
2
4
|
require_relative 'oauth2/access_token_authentication'
|
3
5
|
require_relative 'oauth2/client'
|
@@ -31,10 +33,10 @@ module Asana
|
|
31
33
|
client = Client.new(client_id: client_id,
|
32
34
|
client_secret: client_secret,
|
33
35
|
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob')
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
auth_code =
|
36
|
+
$stdout.puts '1. Go to the following URL to authorize the ' \
|
37
|
+
"application: #{client.authorize_url}"
|
38
|
+
$stdout.puts '2. Paste the authorization code here: '
|
39
|
+
auth_code = $stdin.gets.chomp
|
38
40
|
client.token_from_auth_code(auth_code)
|
39
41
|
end
|
40
42
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Asana
|
2
4
|
module Authentication
|
3
5
|
# Public: Represents an API token authentication mechanism.
|
@@ -13,7 +15,7 @@ module Asana
|
|
13
15
|
#
|
14
16
|
# Returns nothing.
|
15
17
|
def configure(connection)
|
16
|
-
connection.
|
18
|
+
connection.request :authorization, :basic, @token, ''
|
17
19
|
end
|
18
20
|
end
|
19
21
|
end
|
data/lib/asana/authentication.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Asana
|
2
4
|
class Client
|
3
5
|
# Internal: Represents a configuration DSL for an Asana::Client.
|
@@ -17,7 +19,7 @@ module Asana
|
|
17
19
|
# Public: Initializes an empty configuration object.
|
18
20
|
def initialize
|
19
21
|
@configuration = {
|
20
|
-
|
22
|
+
log_asana_change_warnings: true
|
21
23
|
}
|
22
24
|
end
|
23
25
|
|
@@ -100,7 +102,6 @@ module Asana
|
|
100
102
|
#
|
101
103
|
# Raises ArgumentError if the OAuth2 configuration arguments are invalid.
|
102
104
|
#
|
103
|
-
# rubocop:disable Metrics/MethodLength
|
104
105
|
def oauth2(value)
|
105
106
|
case value
|
106
107
|
when ::OAuth2::AccessToken
|
@@ -111,8 +112,8 @@ module Asana
|
|
111
112
|
from_bearer_token(value[:bearer_token])
|
112
113
|
else
|
113
114
|
error 'Invalid OAuth2 configuration: pass in either an ' \
|
114
|
-
|
115
|
-
|
115
|
+
'::OAuth2::AccessToken object of your own or a hash ' \
|
116
|
+
'containing :refresh_token or :bearer_token.'
|
116
117
|
end
|
117
118
|
end
|
118
119
|
|
@@ -158,7 +159,7 @@ module Asana
|
|
158
159
|
end
|
159
160
|
|
160
161
|
def requiring(hash, *keys)
|
161
|
-
missing_keys = keys.
|
162
|
+
missing_keys = keys.reject { |k| hash.key?(k) }
|
162
163
|
missing_keys.any? && error("Missing keys: #{missing_keys.join(', ')}")
|
163
164
|
keys.map { |k| hash[k] }
|
164
165
|
end
|
data/lib/asana/client.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'authentication'
|
2
4
|
require_relative 'client/configuration'
|
3
5
|
require_relative 'resources'
|
@@ -59,12 +61,12 @@ module Asana
|
|
59
61
|
@resource = resource
|
60
62
|
end
|
61
63
|
|
62
|
-
def method_missing(
|
63
|
-
@resource.public_send(
|
64
|
+
def method_missing(method_name, *args, **kwargs, &block)
|
65
|
+
@resource.public_send(method_name, *([@client] + args), **kwargs, &block)
|
64
66
|
end
|
65
67
|
|
66
|
-
def respond_to_missing?(
|
67
|
-
@resource.respond_to?(
|
68
|
+
def respond_to_missing?(method_name, *)
|
69
|
+
@resource.respond_to?(method_name)
|
68
70
|
end
|
69
71
|
end
|
70
72
|
|
@@ -72,15 +74,15 @@ module Asana
|
|
72
74
|
#
|
73
75
|
# Yields a {Asana::Client::Configuration} object as a configuration
|
74
76
|
# DSL. See {Asana::Client} for usage examples.
|
75
|
-
def initialize
|
76
|
-
config = Configuration.new.tap
|
77
|
+
def initialize(&block)
|
78
|
+
config = Configuration.new.tap(&block).to_h
|
77
79
|
@http_client =
|
78
|
-
HttpClient.new(authentication:
|
79
|
-
adapter:
|
80
|
-
user_agent:
|
81
|
-
debug_mode:
|
80
|
+
HttpClient.new(authentication: config.fetch(:authentication),
|
81
|
+
adapter: config[:faraday_adapter],
|
82
|
+
user_agent: config[:user_agent],
|
83
|
+
debug_mode: config[:debug_mode],
|
82
84
|
log_asana_change_warnings: config[:log_asana_change_warnings],
|
83
|
-
default_headers:
|
85
|
+
default_headers: config[:default_headers],
|
84
86
|
&config[:faraday_configuration])
|
85
87
|
end
|
86
88
|
|
data/lib/asana/errors.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Asana
|
2
4
|
# Public: Defines the different errors that the Asana API may throw, which the
|
3
5
|
# client code may want to catch.
|
@@ -19,8 +21,8 @@ module Asana
|
|
19
21
|
# user could not be authenticated.
|
20
22
|
NotAuthorized = Class.new(APIError) do
|
21
23
|
def to_s
|
22
|
-
'Valid credentials were not provided with the request, so the API could '\
|
23
|
-
|
24
|
+
'Valid credentials were not provided with the request, so the API could ' \
|
25
|
+
'not associate a user with the request.'
|
24
26
|
end
|
25
27
|
end
|
26
28
|
|
@@ -28,8 +30,8 @@ module Asana
|
|
28
30
|
# that requires a premium account (Payment Required).
|
29
31
|
PremiumOnly = Class.new(APIError) do
|
30
32
|
def to_s
|
31
|
-
'The endpoint that is being requested is only available to premium '\
|
32
|
-
|
33
|
+
'The endpoint that is being requested is only available to premium ' \
|
34
|
+
'users.'
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -37,18 +39,18 @@ module Asana
|
|
37
39
|
# access the requested resource or to perform the requested action on it.
|
38
40
|
Forbidden = Class.new(APIError) do
|
39
41
|
def to_s
|
40
|
-
'The authorization and request syntax was valid but the server is refusing '\
|
41
|
-
|
42
|
-
|
42
|
+
'The authorization and request syntax was valid but the server is refusing ' \
|
43
|
+
'to complete the request. This can happen if you try to read or write ' \
|
44
|
+
'to objects or properties that the user does not have access to.'
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
48
|
# Public: A 404 error. Raised when the requested resource doesn't exist.
|
47
49
|
NotFound = Class.new(APIError) do
|
48
50
|
def to_s
|
49
|
-
'Either the request method and path supplied do not specify a known '\
|
50
|
-
|
51
|
-
|
51
|
+
'Either the request method and path supplied do not specify a known ' \
|
52
|
+
'action in the API, or the object specified by the request does not ' \
|
53
|
+
'exist.'
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
@@ -59,11 +61,12 @@ module Asana
|
|
59
61
|
attr_accessor :phrase
|
60
62
|
|
61
63
|
def initialize(phrase)
|
64
|
+
super()
|
62
65
|
@phrase = phrase
|
63
66
|
end
|
64
67
|
|
65
68
|
def to_s
|
66
|
-
"There has been an error on Asana's end. Use this unique phrase to "\
|
69
|
+
"There has been an error on Asana's end. Use this unique phrase to " \
|
67
70
|
'identify the problem when contacting support: ' + %("#{@phrase}")
|
68
71
|
end
|
69
72
|
end
|
@@ -74,6 +77,7 @@ module Asana
|
|
74
77
|
attr_accessor :errors
|
75
78
|
|
76
79
|
def initialize(errors)
|
80
|
+
super()
|
77
81
|
@errors = errors
|
78
82
|
end
|
79
83
|
|
@@ -89,6 +93,7 @@ module Asana
|
|
89
93
|
attr_accessor :retry_after_seconds
|
90
94
|
|
91
95
|
def initialize(retry_after_seconds)
|
96
|
+
super()
|
92
97
|
@retry_after_seconds = retry_after_seconds
|
93
98
|
end
|
94
99
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative '../version'
|
2
4
|
require 'openssl'
|
3
5
|
|
@@ -6,7 +8,7 @@ module Asana
|
|
6
8
|
# Internal: Adds environment information to a Faraday request.
|
7
9
|
class EnvironmentInfo
|
8
10
|
# Internal: The default user agent to use in all requests to the API.
|
9
|
-
USER_AGENT = "ruby-asana v#{Asana::VERSION}"
|
11
|
+
USER_AGENT = "ruby-asana v#{Asana::VERSION}"
|
10
12
|
|
11
13
|
def initialize(user_agent = nil)
|
12
14
|
@user_agent = user_agent || USER_AGENT
|
@@ -19,7 +21,7 @@ module Asana
|
|
19
21
|
# environment.
|
20
22
|
def configure(builder)
|
21
23
|
builder.headers[:user_agent] = @user_agent
|
22
|
-
builder.headers[:
|
24
|
+
builder.headers[:'X-Asana-Client-Lib'] = header
|
23
25
|
end
|
24
26
|
|
25
27
|
private
|
@@ -33,21 +35,20 @@ module Asana
|
|
33
35
|
.map { |k, v| "#{k}=#{v}" }.join('&')
|
34
36
|
end
|
35
37
|
|
36
|
-
# rubocop:disable Metrics/MethodLength
|
37
38
|
def os
|
38
|
-
|
39
|
+
case RUBY_PLATFORM
|
40
|
+
when /win32/, /mingw/
|
39
41
|
'windows'
|
40
|
-
|
42
|
+
when /linux/
|
41
43
|
'linux'
|
42
|
-
|
44
|
+
when /darwin/
|
43
45
|
'darwin'
|
44
|
-
|
46
|
+
when /freebsd/
|
45
47
|
'freebsd'
|
46
48
|
else
|
47
49
|
'unknown'
|
48
50
|
end
|
49
51
|
end
|
50
|
-
# rubocop:enable Metrics/MethodLength
|
51
52
|
end
|
52
53
|
end
|
53
54
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative '../errors'
|
4
4
|
|
@@ -27,37 +27,34 @@ module Asana
|
|
27
27
|
# Raises [Asana::Errors::ServerError] when there's a server problem.
|
28
28
|
# Raises [Asana::Errors::APIError] when the API returns an unknown error.
|
29
29
|
#
|
30
|
-
# rubocop:disable
|
31
|
-
def handle(num_retries=0, &request)
|
30
|
+
# rubocop:disable Metrics/AbcSize
|
31
|
+
def handle(num_retries = 0, &request)
|
32
32
|
request.call
|
33
33
|
rescue Faraday::ClientError => e
|
34
34
|
raise e unless e.response
|
35
|
+
|
35
36
|
case e.response[:status]
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
37
|
+
when 400 then raise invalid_request(e.response)
|
38
|
+
when 401 then raise not_authorized(e.response)
|
39
|
+
when 402 then raise payment_required(e.response)
|
40
|
+
when 403 then raise forbidden(e.response)
|
41
|
+
when 404 then raise not_found(e.response)
|
42
|
+
when 412 then recover_response(e.response)
|
43
|
+
when 429 then raise rate_limit_enforced(e.response)
|
44
|
+
when 500 then raise server_error(e.response)
|
45
|
+
else raise api_error(e.response)
|
45
46
|
end
|
46
47
|
# Retry for timeouts or 500s from Asana
|
47
48
|
rescue Faraday::ServerError => e
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
raise server_error(e.response)
|
52
|
-
end
|
49
|
+
raise server_error(e.response) unless num_retries < MAX_RETRIES
|
50
|
+
|
51
|
+
handle(num_retries + 1, &request)
|
53
52
|
rescue Net::ReadTimeout => e
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
raise e
|
58
|
-
end
|
53
|
+
raise e unless num_retries < MAX_RETRIES
|
54
|
+
|
55
|
+
handle(num_retries + 1, &request)
|
59
56
|
end
|
60
|
-
# rubocop:enable
|
57
|
+
# rubocop:enable Metrics/AbcSize
|
61
58
|
|
62
59
|
# Internal: Returns an InvalidRequest exception including a list of
|
63
60
|
# errors.
|
@@ -112,13 +109,15 @@ module Asana
|
|
112
109
|
|
113
110
|
# Internal: Parser a response body from JSON.
|
114
111
|
def body(response)
|
115
|
-
|
112
|
+
JSON.parse(response[:body])
|
116
113
|
end
|
117
114
|
|
115
|
+
# rubocop:disable Style/OpenStructUse
|
118
116
|
def recover_response(response)
|
119
117
|
r = response.dup.tap { |res| res[:body] = body(response) }
|
120
118
|
Response.new(OpenStruct.new(env: OpenStruct.new(r)))
|
121
119
|
end
|
120
|
+
# rubocop:enable Style/OpenStructUse
|
122
121
|
end
|
123
122
|
end
|
124
123
|
end
|
data/lib/asana/http_client.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'faraday'
|
2
|
-
require '
|
3
|
-
require 'faraday_middleware/multi_json'
|
4
|
+
require 'faraday/follow_redirects'
|
4
5
|
|
5
6
|
require_relative 'http_client/error_handling'
|
6
7
|
require_relative 'http_client/environment_info'
|
@@ -11,7 +12,7 @@ module Asana
|
|
11
12
|
# parsing and common options.
|
12
13
|
class HttpClient
|
13
14
|
# Internal: The API base URI.
|
14
|
-
BASE_URI = 'https://app.asana.com/api/1.0'
|
15
|
+
BASE_URI = 'https://app.asana.com/api/1.0'
|
15
16
|
|
16
17
|
# Public: Initializes an HttpClient to make requests to the Asana API.
|
17
18
|
#
|
@@ -130,7 +131,8 @@ module Asana
|
|
130
131
|
yield builder if request_config
|
131
132
|
configure_format(builder)
|
132
133
|
add_middleware(builder)
|
133
|
-
|
134
|
+
configure_redirects(builder)
|
135
|
+
@config&.call(builder)
|
134
136
|
use_adapter(builder, @adapter)
|
135
137
|
end
|
136
138
|
end
|
@@ -147,13 +149,16 @@ module Asana
|
|
147
149
|
end
|
148
150
|
|
149
151
|
def configure_format(builder)
|
150
|
-
builder.request :
|
151
|
-
builder.response :
|
152
|
+
builder.request :json
|
153
|
+
builder.response :json
|
152
154
|
end
|
153
155
|
|
154
156
|
def add_middleware(builder)
|
155
157
|
builder.use Faraday::Response::RaiseError
|
156
|
-
|
158
|
+
end
|
159
|
+
|
160
|
+
def configure_redirects(builder)
|
161
|
+
builder.response :follow_redirects
|
157
162
|
end
|
158
163
|
|
159
164
|
def use_adapter(builder, adapter)
|
@@ -170,79 +175,75 @@ module Asana
|
|
170
175
|
end
|
171
176
|
|
172
177
|
def log_request(method, url, body)
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
+
warn format('[%<klass>s] %<method>s %<url>s (%<bodt>s)',
|
179
|
+
klass: self.class,
|
180
|
+
method: method.to_s.upcase,
|
181
|
+
url: url,
|
182
|
+
body: body.inspect)
|
178
183
|
end
|
179
184
|
|
185
|
+
# rubocop:disable Metrics/AbcSize
|
186
|
+
# rubocop:disable Metrics/MethodLength
|
180
187
|
def log_asana_change_headers(request_headers, response_headers)
|
181
188
|
change_header_key = nil
|
182
189
|
|
183
190
|
response_headers.each_key do |key|
|
184
|
-
if key.downcase == 'asana-change'
|
185
|
-
change_header_key = key
|
186
|
-
end
|
191
|
+
change_header_key = key if key.downcase == 'asana-change'
|
187
192
|
end
|
188
193
|
|
189
|
-
if change_header_key
|
190
|
-
accounted_for_flags = Array.new
|
194
|
+
return if change_header_key.nil?
|
191
195
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
elsif req_header.downcase == 'asana-disable'
|
202
|
-
request_headers[req_header].split(',').each do |flag|
|
203
|
-
accounted_for_flags.push(flag)
|
204
|
-
end
|
196
|
+
accounted_for_flags = []
|
197
|
+
|
198
|
+
request_headers = {} if request_headers.nil?
|
199
|
+
# Grab the request's asana-enable flags
|
200
|
+
request_headers.each_key do |req_header|
|
201
|
+
case req_header.downcase
|
202
|
+
when 'asana-enable', 'asana-disable'
|
203
|
+
request_headers[req_header].split(',').each do |flag|
|
204
|
+
accounted_for_flags.push(flag)
|
205
205
|
end
|
206
206
|
end
|
207
|
+
end
|
208
|
+
|
209
|
+
changes = response_headers[change_header_key].split(',')
|
207
210
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
affected = field[1]
|
228
|
-
end
|
229
|
-
|
230
|
-
# Only show the error if the flag was not in the request's asana-enable header
|
231
|
-
if !(accounted_for_flags.include? name) && (affected == 'true')
|
232
|
-
message1 = 'This request is affected by the "%s"' +
|
233
|
-
' deprecation. Please visit this url for more info: %s'
|
234
|
-
message2 = 'Adding "%s" to your "Asana-Enable" or ' +
|
235
|
-
'"Asana-Disable" header will opt in/out to this deprecation ' +
|
236
|
-
'and suppress this warning.'
|
237
|
-
|
238
|
-
STDERR.puts format(message1, name, info)
|
239
|
-
STDERR.puts format(message2, name)
|
240
|
-
end
|
211
|
+
changes.each do |unsplit_change|
|
212
|
+
change = unsplit_change.split(';')
|
213
|
+
|
214
|
+
name = nil
|
215
|
+
info = nil
|
216
|
+
affected = nil
|
217
|
+
|
218
|
+
change.each do |unsplit_field|
|
219
|
+
field = unsplit_field.split('=')
|
220
|
+
|
221
|
+
field[0].strip!
|
222
|
+
field[1].strip!
|
223
|
+
case field[0]
|
224
|
+
when 'name'
|
225
|
+
name = field[1]
|
226
|
+
when 'info'
|
227
|
+
info = field[1]
|
228
|
+
when 'affected'
|
229
|
+
affected = field[1]
|
241
230
|
end
|
231
|
+
|
232
|
+
# Only show the error if the flag was not in the request's asana-enable header
|
233
|
+
next unless !(accounted_for_flags.include? name) && (affected == 'true')
|
234
|
+
|
235
|
+
message1 = 'This request is affected by the "%s" ' \
|
236
|
+
'deprecation. Please visit this url for more info: %s'
|
237
|
+
message2 = 'Adding "%s" to your "Asana-Enable" or ' \
|
238
|
+
'"Asana-Disable" header will opt in/out to this deprecation ' \
|
239
|
+
'and suppress this warning.'
|
240
|
+
|
241
|
+
warn format(message1, name, info)
|
242
|
+
warn format(message2, name)
|
242
243
|
end
|
243
244
|
end
|
244
245
|
end
|
246
|
+
# rubocop:enable Metrics/AbcSize
|
247
|
+
# rubocop:enable Metrics/MethodLength
|
245
248
|
end
|
246
249
|
end
|
247
|
-
|
248
|
-
|
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'faraday/multipart'
|
4
|
+
|
1
5
|
module Asana
|
2
6
|
module Resources
|
3
7
|
# Internal: Mixin to add the ability to upload an attachment to a specific
|
@@ -11,8 +15,6 @@ module Asana
|
|
11
15
|
# options - [Hash] the request I/O options
|
12
16
|
# data - [Hash] extra attributes to post
|
13
17
|
#
|
14
|
-
# rubocop:disable Metrics/AbcSize
|
15
|
-
# rubocop:disable Metrics/MethodLength
|
16
18
|
def attach(filename: required('filename'),
|
17
19
|
mime: required('mime'),
|
18
20
|
io: nil, options: {}, **data)
|
@@ -21,9 +23,9 @@ module Asana
|
|
21
23
|
path = File.expand_path(filename)
|
22
24
|
raise ArgumentError, "file #{filename} doesn't exist" unless File.exist?(path)
|
23
25
|
|
24
|
-
Faraday::FilePart.new(path, mime)
|
26
|
+
Faraday::Multipart::FilePart.new(path, mime)
|
25
27
|
else
|
26
|
-
Faraday::FilePart.new(io, mime, filename)
|
28
|
+
Faraday::Multipart::FilePart.new(io, mime, filename)
|
27
29
|
end
|
28
30
|
|
29
31
|
response = client.post("/#{self.class.plural_name}/#{gid}/attachments",
|
@@ -33,8 +35,6 @@ module Asana
|
|
33
35
|
|
34
36
|
Attachment.new(parse(response).first, client: client)
|
35
37
|
end
|
36
|
-
# rubocop:enable Metrics/MethodLength
|
37
|
-
# rubocop:enable Metrics/AbcSize
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'response_helper'
|
2
4
|
|
3
5
|
module Asana
|
@@ -40,7 +42,7 @@ module Asana
|
|
40
42
|
def last
|
41
43
|
@elements.last
|
42
44
|
end
|
43
|
-
|
45
|
+
|
44
46
|
# Public: Returns the size of the collection.
|
45
47
|
def size
|
46
48
|
to_a.size
|
@@ -49,9 +51,7 @@ module Asana
|
|
49
51
|
|
50
52
|
# Public: Returns a String representation of the collection.
|
51
53
|
def to_s
|
52
|
-
"#<Asana::Collection<#{@type}> "
|
53
|
-
"[#{@elements.map(&:inspect).join(', ')}" +
|
54
|
-
(@next_page_data ? ', ...' : '') + ']>'
|
54
|
+
"#<Asana::Collection<#{@type}> [#{@elements.map(&:inspect).join(', ')}#{@next_page_data ? ', ...' : ''}]>"
|
55
55
|
end
|
56
56
|
alias inspect to_s
|
57
57
|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require_relative 'event'
|
2
4
|
|
3
5
|
module Asana
|
@@ -89,13 +91,14 @@ module Asana
|
|
89
91
|
|
90
92
|
# Internal: Returns the formatted params for the poll request.
|
91
93
|
def params
|
92
|
-
{ resource: @resource, sync: @sync }.
|
94
|
+
{ resource: @resource, sync: @sync }.compact
|
93
95
|
end
|
94
96
|
|
95
97
|
# Internal: Executes a block if at least @wait seconds have passed since
|
96
98
|
# @last_poll.
|
97
99
|
def rate_limiting
|
98
100
|
return if @last_poll && Time.now - @last_poll <= @wait
|
101
|
+
|
99
102
|
yield.tap { @last_poll = Time.now }
|
100
103
|
end
|
101
104
|
end
|