asana 0.6.3 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3a918da44ed24274296db1a40bda628d24e48ca40ea53622ba13f4309784a3b0
4
- data.tar.gz: 1c0b2ffaee3b5bc3dc207c60122da6dd97f97009f538163037cf8e135fad29b8
3
+ metadata.gz: 7d310a2dce08f1a0d3184d739bca9be4cd8ad88368337595f1ec7ac31330d745
4
+ data.tar.gz: eef90d3cc06cf5a93725f20ab4b67e6b369c97a20952c6d50ed249f1c08dc666
5
5
  SHA512:
6
- metadata.gz: d73d39ad30a783c5849a6e7d3bdb4fccf69c27837f8def2cefa3ef93b0e7b14e721eda1b4e05251887b5347837b1de03d084cc45ec3cf17c07323b3071f73017
7
- data.tar.gz: 9bbca4c1b400bbac20484c473288aff9d867d76544b6552ee807050ac0ea4ed9f85fb2b2a33397ac848f6d7fbad3c1fd1c637fa748797cff9669aa15fd8877d6
6
+ metadata.gz: 44a15f43e827a51b5f215d892248d9304dd1fc5c584d8a0b6b15a197f550f5ce61b7f7a8c6181eb14581b2a2ff99d60403e7e71b82a342d111fe5e47bfae6f7e
7
+ data.tar.gz: 707eb76c9827419e3b89188680bf979cc6007b81eb090b56c319f9b2cf8b4b90712f68796459f95bcda296c6d6df2d6ac27b5b99fc14708a1820f0539085daef
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: ..
3
3
  specs:
4
- asana (0.6.3)
4
+ asana (0.8.0)
5
5
  faraday (~> 0.9)
6
6
  faraday_middleware (~> 0.9)
7
7
  faraday_middleware-multi_json (~> 0.0)
@@ -19,7 +19,7 @@ module Asana
19
19
  # user could not be authenticated.
20
20
  NotAuthorized = Class.new(APIError) do
21
21
  def to_s
22
- 'A valid API key was not provided with the request, so the API could '\
22
+ 'Valid credentials were not provided with the request, so the API could '\
23
23
  'not associate a user with the request.'
24
24
  end
25
25
  end
@@ -37,7 +37,7 @@ module Asana
37
37
  # access the requested resource or to perform the requested action on it.
38
38
  Forbidden = Class.new(APIError) do
39
39
  def to_s
40
- 'The API key and request syntax was valid but the server is refusing '\
40
+ 'The authorization and request syntax was valid but the server is refusing '\
41
41
  'to complete the request. This can happen if you try to read or write '\
42
42
  'to objects or properties that the user does not have access to.'
43
43
  end
@@ -11,7 +11,7 @@ module Asana
11
11
 
12
12
  module_function
13
13
 
14
- PREMIUM_ONLY_STR = 'not available for free'.freeze
14
+ MAX_TIMEOUTS = 5
15
15
 
16
16
  # Public: Perform a request handling any API errors correspondingly.
17
17
  #
@@ -28,7 +28,7 @@ module Asana
28
28
  # Raises [Asana::Errors::APIError] when the API returns an unknown error.
29
29
  #
30
30
  # rubocop:disable all
31
- def handle(&request)
31
+ def handle(num_timeouts=0, &request)
32
32
  request.call
33
33
  rescue Faraday::ClientError => e
34
34
  raise e unless e.response
@@ -36,25 +36,19 @@ module Asana
36
36
  when 400 then raise invalid_request(e.response)
37
37
  when 401 then raise not_authorized(e.response)
38
38
  when 402 then raise payment_required(e.response)
39
- when 403
40
- begin
41
- body = body(e.response)
42
- errors_str = body['errors'].collect {
43
- |err| err['message']
44
- }.join('; ')
45
- if errors_str.include? PREMIUM_ONLY_STR
46
- raise payment_required(e.response)
47
- end
48
- rescue
49
- raise forbidden(e.response)
50
- end
51
- raise forbidden(e.response)
39
+ when 403 then raise forbidden(e.response)
52
40
  when 404 then raise not_found(e.response)
53
41
  when 412 then recover_response(e.response)
54
42
  when 429 then raise rate_limit_enforced(e.response)
55
43
  when 500 then raise server_error(e.response)
56
44
  else raise api_error(e.response)
57
45
  end
46
+ rescue Net::ReadTimeout => e
47
+ if num_timeouts < MAX_TIMEOUTS
48
+ handle(num_timeouts + 1, &request)
49
+ else
50
+ raise e
51
+ end
58
52
  end
59
53
  # rubocop:enable all
60
54
 
@@ -53,4 +53,4 @@ module Asana
53
53
 
54
54
  end
55
55
  end
56
- end
56
+ end
@@ -30,13 +30,14 @@ module Asana
30
30
  # Returns a list of all of the custom fields settings on a project, in compact form. Note that, as in all queries to collections which return compact representation, `opt_fields` and `opt_expand` can be used to include more data than is returned in the compact representation. See the getting started guide on [input/output options](/developers/documentation/getting-started/input-output-options) for more information.
31
31
  #
32
32
  # project - [Id] The ID of the project for which to list custom field settings
33
+ # per_page - [Integer] the number of records to fetch per page.
33
34
  # options - [Hash] the request I/O options.
34
- def find_by_project(client, project: required("project"), options: {})
35
-
36
- Resource.new(parse(client.get("/projects/#{project}/custom_field_settings", options: options)).first, client: client)
35
+ def find_by_project(client, project: required("project"), per_page: 20, options: {})
36
+ params = { limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
37
+ Collection.new(parse(client.get("/projects/#{project}/custom_field_settings", params: params, options: options)), type: Resource, client: client)
37
38
  end
38
39
  end
39
40
 
40
41
  end
41
42
  end
42
- end
43
+ end
@@ -13,10 +13,10 @@ module Asana
13
13
 
14
14
  attr_reader :id
15
15
 
16
- attr_reader :created_at
17
-
18
16
  attr_reader :name
19
17
 
18
+ attr_reader :description
19
+
20
20
  attr_reader :type
21
21
 
22
22
  attr_reader :enum_options
@@ -29,6 +29,25 @@ module Asana
29
29
  'custom_fields'
30
30
  end
31
31
 
32
+ # Creates a new custom field in a workspace. Every custom field is required to be created in a specific workspace, and this workspace cannot be changed once set.
33
+ #
34
+ # A custom field's `name` must be unique within a workspace and not conflict with names of existing task properties such as 'Due Date' or 'Assignee'. A custom field's `type` must be one of 'text', 'enum', or 'number'.
35
+ #
36
+ # Returns the full record of the newly created custom field.
37
+ #
38
+ # workspace - [Id] The workspace to create a custom field in.
39
+ # type - [String] The type of the custom field.
40
+ # name - [String] The name of the custom field.
41
+ # description - [String] The description of the custom field.
42
+ # precision - [Integer] The number of decimal places for the numerical values. Required if the custom field is of type 'number'.
43
+ # enum_options - [String] The discrete values the custom field can assume. Required if the custom field is of type 'enum'.
44
+ # options - [Hash] the request I/O options.
45
+ # data - [Hash] the attributes to post.
46
+ def create(client, workspace: required("workspace"), type: required("type"), name: required("name"), description: nil, precision: nil, enum_options: nil, options: {}, **data)
47
+ with_params = data.merge(workspace: workspace, type: type, name: name, description: description, precision: precision, enum_options: enum_options).reject { |_,v| v.nil? || Array(v).empty? }
48
+ Resource.new(parse(client.post("/custom_fields", body: with_params, options: options)).first, client: client)
49
+ end
50
+
32
51
  # Returns the complete definition of a custom field's metadata.
33
52
  #
34
53
  # id - [Id] Globally unique identifier for the custom field.
@@ -42,13 +61,88 @@ module Asana
42
61
  # Returns a list of the compact representation of all of the custom fields in a workspace.
43
62
  #
44
63
  # workspace - [Id] The workspace or organization to find custom field definitions in.
64
+ # per_page - [Integer] the number of records to fetch per page.
65
+ # options - [Hash] the request I/O options.
66
+ def find_by_workspace(client, workspace: required("workspace"), per_page: 20, options: {})
67
+ params = { limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
68
+ Collection.new(parse(client.get("/workspaces/#{workspace}/custom_fields", params: params, options: options)), type: Resource, client: client)
69
+ end
70
+
71
+ # Creates an enum option and adds it to this custom field's list of enum options. A custom field can have at most 50 enum options (including disabled options). By default new enum options are inserted at the end of a custom field's list.
72
+ #
73
+ # Returns the full record of the newly created enum option.
74
+ #
75
+ # custom_field - [Id] Globally unique identifier for the custom field.
76
+ #
77
+ # name - [String] The name of the enum option.
78
+ # color - [String] The color of the enum option. Defaults to 'none'.
79
+ # insert_before - [Id] An existing enum option within this custom field before which the new enum option should be inserted. Cannot be provided together with after_enum_option.
80
+ # insert_after - [Id] An existing enum option within this custom field after which the new enum option should be inserted. Cannot be provided together with before_enum_option.
45
81
  # options - [Hash] the request I/O options.
46
- def find_by_workspace(client, workspace: required("workspace"), options: {})
82
+ # data - [Hash] the attributes to post.
83
+ def add_enum_option(client, custom_field: required("custom_field"), name: required("name"), color: nil, insert_before: nil, insert_after: nil, options: {}, **data)
84
+ with_params = data.merge(name: name, color: color, insert_before: insert_before, insert_after: insert_after).reject { |_,v| v.nil? || Array(v).empty? }
85
+ Resource.new(parse(client.post("/custom_fields/#{custom_field}/enum_options", body: with_params, options: options)).first, client: client)
86
+ end
47
87
 
48
- Resource.new(parse(client.get("/workspaces/#{workspace}/custom_fields", options: options)).first, client: client)
88
+ # Moves a particular enum option to be either before or after another specified enum option in the custom field.
89
+ #
90
+ # custom_field - [Id] Globally unique identifier for the custom field.
91
+ #
92
+ # enum_option - [Id] The ID of the enum option to relocate.
93
+ # name - [String] The name of the enum option.
94
+ # color - [String] The color of the enum option. Defaults to 'none'.
95
+ # before_enum_option - [Id] An existing enum option within this custom field before which the new enum option should be inserted. Cannot be provided together with after_enum_option.
96
+ # after_enum_option - [Id] An existing enum option within this custom field after which the new enum option should be inserted. Cannot be provided together with before_enum_option.
97
+ # options - [Hash] the request I/O options.
98
+ # data - [Hash] the attributes to post.
99
+ def reorder_enum_option(client, custom_field: required("custom_field"), enum_option: required("enum_option"), name: required("name"), color: nil, before_enum_option: nil, after_enum_option: nil, options: {}, **data)
100
+ with_params = data.merge(enum_option: enum_option, name: name, color: color, before_enum_option: before_enum_option, after_enum_option: after_enum_option).reject { |_,v| v.nil? || Array(v).empty? }
101
+ Resource.new(parse(client.post("/custom_fields/#{custom_field}/enum_options/insert", body: with_params, options: options)).first, client: client)
49
102
  end
50
103
  end
51
104
 
105
+ # A specific, existing custom field can be updated by making a PUT request on the URL for that custom field. Only the fields provided in the `data` block will be updated; any unspecified fields will remain unchanged
106
+ #
107
+ # When using this method, it is best to specify only those fields you wish to change, or else you may overwrite changes made by another user since you last retrieved the custom field.
108
+ #
109
+ # A custom field's `type` cannot be updated.
110
+ #
111
+ # An enum custom field's `enum_options` cannot be updated with this endpoint. Instead see "Work With Enum Options" for information on how to update `enum_options`.
112
+ #
113
+ # Returns the complete updated custom field record.
114
+ #
115
+ # options - [Hash] the request I/O options.
116
+ # data - [Hash] the attributes to post.
117
+ def update(options: {}, **data)
118
+
119
+ refresh_with(parse(client.put("/custom_fields/#{id}", body: data, options: options)).first)
120
+ end
121
+
122
+ # A specific, existing custom field can be deleted by making a DELETE request on the URL for that custom field.
123
+ #
124
+ # Returns an empty data record.
125
+ def delete()
126
+
127
+ client.delete("/custom_fields/#{id}") && true
128
+ end
129
+
130
+ # Updates an existing enum option. Enum custom fields require at least one enabled enum option.
131
+ #
132
+ # Returns the full record of the updated enum option.
133
+ #
134
+ # enum_option - [Id] Globally unique identifier for the enum option.
135
+ #
136
+ # name - [String] The name of the enum option.
137
+ # color - [String] The color of the enum option. Defaults to 'none'.
138
+ # enabled - [Boolean] Whether or not the enum option is a selectable value for the custom field.
139
+ # options - [Hash] the request I/O options.
140
+ # data - [Hash] the attributes to post.
141
+ def update_enum_option(enum_option: required("enum_option"), name: required("name"), color: nil, enabled: nil, options: {}, **data)
142
+ with_params = data.merge(name: name, color: color, enabled: enabled).reject { |_,v| v.nil? || Array(v).empty? }
143
+ refresh_with(parse(client.put("/enum_options/#{enum_option}", body: with_params, options: options)).first)
144
+ end
145
+
52
146
  end
53
147
  end
54
- end
148
+ end
@@ -0,0 +1,63 @@
1
+ ### WARNING: This file is auto-generated by the asana-api-meta repo. Do not
2
+ ### edit it manually.
3
+
4
+ module Asana
5
+ module Resources
6
+ # An _organization_export_ object represents a request to export the complete data of an Organization
7
+ # in JSON format.
8
+ #
9
+ # To export an Organization using this API:
10
+ #
11
+ # * Create an `organization_export` [request](#create) and store the id that is returned.\
12
+ # * Request the `organization_export` every few minutes, until the `state` field contains 'finished'.\
13
+ # * Download the file located at the URL in the `download_url` field.
14
+ #
15
+ # Exports can take a long time, from several minutes to a few hours for large Organizations.
16
+ #
17
+ # **Note:** These endpoints are only available to [Service Accounts](/guide/help/premium/service-accounts)
18
+ # of an [Enterprise](/enterprise) Organization.
19
+ class OrganizationExport < Resource
20
+
21
+
22
+ attr_reader :id
23
+
24
+ attr_reader :created_at
25
+
26
+ attr_reader :download_url
27
+
28
+ attr_reader :state
29
+
30
+ attr_reader :organization
31
+
32
+ class << self
33
+ # Returns the plural name of the resource.
34
+ def plural_name
35
+ 'organization_exports'
36
+ end
37
+
38
+ # Returns details of a previously-requested Organization export.
39
+ #
40
+ # id - [Id] Globally unique identifier for the Organization export.
41
+ #
42
+ # options - [Hash] the request I/O options.
43
+ def find_by_id(client, id, options: {})
44
+
45
+ self.new(parse(client.get("/organization_exports/#{id}", options: options)).first, client: client)
46
+ end
47
+
48
+ # This method creates a request to export an Organization. Asana will complete the export at some
49
+ # point after you create the request.
50
+ #
51
+ # organization - [Id] Globally unique identifier for the workspace or organization.
52
+ #
53
+ # options - [Hash] the request I/O options.
54
+ # data - [Hash] the attributes to post.
55
+ def create(client, organization: required("organization"), options: {}, **data)
56
+ with_params = data.merge(organization: organization).reject { |_,v| v.nil? || Array(v).empty? }
57
+ Resource.new(parse(client.post("/organization_exports", body: with_params, options: options)).first, client: client)
58
+ end
59
+ end
60
+
61
+ end
62
+ end
63
+ end
@@ -3,14 +3,15 @@
3
3
 
4
4
  module Asana
5
5
  module Resources
6
- # A _project_ represents a prioritized list of tasks in Asana. It exists in a
7
- # single workspace or organization and is accessible to a subset of users in
8
- # that workspace or organization, depending on its permissions.
6
+ # A _project_ represents a prioritized list of tasks in Asana or a board with
7
+ # columns of tasks represented as cards. It exists in a single workspace or
8
+ # organization and is accessible to a subset of users in that workspace or
9
+ # organization, depending on its permissions.
9
10
  #
10
11
  # Projects in organizations are shared with a single team. You cannot currently
11
12
  # change the team of a project via the API. Non-organization workspaces do not
12
- # have teams and so you should not specify the team of project in a
13
- # regular workspace.
13
+ # have teams and so you should not specify the team of project in a regular
14
+ # workspace.
14
15
  class Project < Resource
15
16
 
16
17
  include EventSubscription
@@ -26,6 +27,8 @@ module Asana
26
27
 
27
28
  attr_reader :due_date
28
29
 
30
+ attr_reader :start_on
31
+
29
32
  attr_reader :created_at
30
33
 
31
34
  attr_reader :modified_at
@@ -48,6 +51,8 @@ module Asana
48
51
 
49
52
  attr_reader :team
50
53
 
54
+ attr_reader :layout
55
+
51
56
  class << self
52
57
  # Returns the plural name of the resource.
53
58
  def plural_name
@@ -179,15 +184,6 @@ module Asana
179
184
  client.delete("/projects/#{id}") && true
180
185
  end
181
186
 
182
- # Returns compact records for all sections in the specified project.
183
- #
184
- # per_page - [Integer] the number of records to fetch per page.
185
- # options - [Hash] the request I/O options.
186
- def sections(per_page: 20, options: {})
187
- params = { limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
188
- Collection.new(parse(client.get("/projects/#{id}/sections", params: params, options: options)), type: Resource, client: client)
189
- end
190
-
191
187
  # Returns the compact task records for all tasks within the given project,
192
188
  # ordered by their priority within the project. Tasks can exist in more than one project at a time.
193
189
  #
@@ -271,4 +267,4 @@ module Asana
271
267
 
272
268
  end
273
269
  end
274
- end
270
+ end
@@ -0,0 +1,51 @@
1
+ ### WARNING: This file is auto-generated by the asana-api-meta repo. Do not
2
+ ### edit it manually.
3
+
4
+ module Asana
5
+ module Resources
6
+ # With the introduction of "comment-only" projects in Asana, a user's membership
7
+ # in a project comes with associated permissions. These permissions (whether a
8
+ # user has full access to the project or comment-only access) are accessible
9
+ # through the project memberships endpoints described here.
10
+ class ProjectMembership < Resource
11
+
12
+
13
+ attr_reader :id
14
+
15
+ attr_reader :user
16
+
17
+ attr_reader :project
18
+
19
+ attr_reader :write_access
20
+
21
+ class << self
22
+ # Returns the plural name of the resource.
23
+ def plural_name
24
+ 'project_memberships'
25
+ end
26
+
27
+ # Returns the compact project membership records for the project.
28
+ #
29
+ # project - [Id] The project for which to fetch memberships.
30
+ # user - [String] If present, the user to filter the memberships to.
31
+ # per_page - [Integer] the number of records to fetch per page.
32
+ # options - [Hash] the request I/O options.
33
+ def get_many(client, project: required("project"), user: nil, per_page: 20, options: {})
34
+ params = { user: user, limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
35
+ Collection.new(parse(client.get("/projects/#{project}/project_memberships", params: params, options: options)), type: Resource, client: client)
36
+ end
37
+
38
+ # Returns the project membership record.
39
+ #
40
+ # project - [Id] Globally unique identifier for the project membership.
41
+ #
42
+ # options - [Hash] the request I/O options.
43
+ def get_single(client, project: required("project"), options: {})
44
+
45
+ Resource.new(parse(client.get("/project_memberships/#{project}", options: options)).first, client: client)
46
+ end
47
+ end
48
+
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,79 @@
1
+ ### WARNING: This file is auto-generated by the asana-api-meta repo. Do not
2
+ ### edit it manually.
3
+
4
+ module Asana
5
+ module Resources
6
+ # A _project status_ is an update on the progress of a particular project, and is sent out to all project
7
+ # followers when created. These updates include both text describing the update and a color code intended to
8
+ # represent the overall state of the project: "green" for projects that are on track, "yellow" for projects
9
+ # at risk, and "red" for projects that are behind.
10
+ #
11
+ # Project statuses can be created and deleted, but not modified.
12
+ class ProjectStatus < Resource
13
+
14
+
15
+ attr_reader :id
16
+
17
+ attr_reader :title
18
+
19
+ attr_reader :text
20
+
21
+ attr_reader :color
22
+
23
+ attr_reader :created_by
24
+
25
+ attr_reader :created_at
26
+
27
+ class << self
28
+ # Returns the plural name of the resource.
29
+ def plural_name
30
+ 'project_statuses'
31
+ end
32
+
33
+ # Creates a new status update on the project.
34
+ #
35
+ # Returns the full record of the newly created project status update.
36
+ #
37
+ # project - [Id] The project on which to create a status update.
38
+ # text - [String] The text of the project status update.
39
+ #
40
+ # color - [String] The color to associate with the status update. Must be one of `"red"`, `"yellow"`, or `"green"`.
41
+ #
42
+ # options - [Hash] the request I/O options.
43
+ # data - [Hash] the attributes to post.
44
+ def create(client, project: required("project"), text: required("text"), color: required("color"), options: {}, **data)
45
+ with_params = data.merge(text: text, color: color).reject { |_,v| v.nil? || Array(v).empty? }
46
+ Resource.new(parse(client.post("/projects/#{project}/project_statuses", body: with_params, options: options)).first, client: client)
47
+ end
48
+
49
+ # Returns the compact project status update records for all updates on the project.
50
+ #
51
+ # project - [Id] The project to find status updates for.
52
+ # per_page - [Integer] the number of records to fetch per page.
53
+ # options - [Hash] the request I/O options.
54
+ def find_by_project(client, project: required("project"), per_page: 20, options: {})
55
+ params = { limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
56
+ Collection.new(parse(client.get("/projects/#{project}/project_statuses", params: params, options: options)), type: Resource, client: client)
57
+ end
58
+
59
+ # Returns the complete record for a single status update.
60
+ #
61
+ # id - [Id] The project status update to get.
62
+ # options - [Hash] the request I/O options.
63
+ def find_by_id(client, id, options: {})
64
+
65
+ self.new(parse(client.get("/project_statuses/#{id}", options: options)).first, client: client)
66
+ end
67
+ end
68
+
69
+ # Deletes a specific, existing project status update.
70
+ #
71
+ # Returns an empty data record.
72
+ def delete()
73
+
74
+ client.delete("/project_statuses/#{id}") && true
75
+ end
76
+
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,110 @@
1
+ ### WARNING: This file is auto-generated by the asana-api-meta repo. Do not
2
+ ### edit it manually.
3
+
4
+ module Asana
5
+ module Resources
6
+ # A _section_ is a subdivision of a project that groups tasks together. It can
7
+ # either be a header above a list of tasks in a list view or a column in a
8
+ # board view of a project.
9
+ class Section < Resource
10
+
11
+
12
+ attr_reader :id
13
+
14
+ attr_reader :name
15
+
16
+ attr_reader :project
17
+
18
+ attr_reader :created_at
19
+
20
+ class << self
21
+ # Returns the plural name of the resource.
22
+ def plural_name
23
+ 'sections'
24
+ end
25
+
26
+ # Creates a new section in a project.
27
+ #
28
+ # Returns the full record of the newly created section.
29
+ #
30
+ # project - [Id] The project to create the section in
31
+ # name - [String] The text to be displayed as the section name. This cannot be an empty string.
32
+ # options - [Hash] the request I/O options.
33
+ # data - [Hash] the attributes to post.
34
+ def create_in_project(client, project: required("project"), name: required("name"), options: {}, **data)
35
+ with_params = data.merge(name: name).reject { |_,v| v.nil? || Array(v).empty? }
36
+ self.new(parse(client.post("/projects/#{project}/sections", body: with_params, options: options)).first, client: client)
37
+ end
38
+
39
+ # Returns the compact records for all sections in the specified project.
40
+ #
41
+ # project - [Id] The project to get sections from.
42
+ # options - [Hash] the request I/O options.
43
+ def find_by_project(client, project: required("project"), options: {})
44
+
45
+ self.new(parse(client.get("/projects/#{project}/sections", options: options)).first, client: client)
46
+ end
47
+
48
+ # Returns the complete record for a single section.
49
+ #
50
+ # id - [Id] The section to get.
51
+ # options - [Hash] the request I/O options.
52
+ def find_by_id(client, id, options: {})
53
+
54
+ self.new(parse(client.get("/sections/#{id}", options: options)).first, client: client)
55
+ end
56
+ end
57
+
58
+ # A specific, existing section can be updated by making a PUT request on
59
+ # the URL for that project. Only the fields provided in the `data` block
60
+ # will be updated; any unspecified fields will remain unchanged. (note that
61
+ # at this time, the only field that can be updated is the `name` field.)
62
+ #
63
+ # When using this method, it is best to specify only those fields you wish
64
+ # to change, or else you may overwrite changes made by another user since
65
+ # you last retrieved the task.
66
+ #
67
+ # Returns the complete updated section record.
68
+ #
69
+ # options - [Hash] the request I/O options.
70
+ # data - [Hash] the attributes to post.
71
+ def update(options: {}, **data)
72
+
73
+ refresh_with(parse(client.put("/sections/#{id}", body: data, options: options)).first)
74
+ end
75
+
76
+ # A specific, existing section can be deleted by making a DELETE request
77
+ # on the URL for that section.
78
+ #
79
+ # Note that sections must be empty to be deleted.
80
+ #
81
+ # The last remaining section in a board view cannot be deleted.
82
+ #
83
+ # Returns an empty data block.
84
+ def delete()
85
+
86
+ client.delete("/sections/#{id}") && true
87
+ end
88
+
89
+ # Move sections relative to each other in a board view. One of
90
+ # `before_section` or `after_section` is required.
91
+ #
92
+ # Sections cannot be moved between projects.
93
+ #
94
+ # At this point in time, moving sections is not supported in list views, only board views.
95
+ #
96
+ # Returns an empty data block.
97
+ #
98
+ # project - [Id] The project in which to reorder the given section
99
+ # before_section - [Id] Insert the given section immediately before the section specified by this parameter.
100
+ # after_section - [Id] Insert the given section immediately after the section specified by this parameter.
101
+ # options - [Hash] the request I/O options.
102
+ # data - [Hash] the attributes to post.
103
+ def insert_in_project(project: required("project"), before_section: nil, after_section: nil, options: {}, **data)
104
+ with_params = data.merge(before_section: before_section, after_section: after_section).reject { |_,v| v.nil? || Array(v).empty? }
105
+ client.post("/projects/#{project}/sections/insert", body: with_params, options: options) && true
106
+ end
107
+
108
+ end
109
+ end
110
+ end
@@ -19,18 +19,31 @@ module Asana
19
19
 
20
20
  attr_reader :created_by
21
21
 
22
+ # DEPRECATED: prefer "liked"
22
23
  attr_reader :hearted
23
24
 
25
+ # DEPRECATED: prefer "likes"
24
26
  attr_reader :hearts
25
27
 
28
+ # DEPRECATED: prefer "num_likes"
26
29
  attr_reader :num_hearts
27
30
 
31
+ attr_reader :liked
32
+
33
+ attr_reader :likes
34
+
35
+ attr_reader :num_likes
36
+
28
37
  attr_reader :text
29
38
 
30
39
  attr_reader :html_text
31
40
 
32
41
  attr_reader :target
33
42
 
43
+ attr_reader :is_pinned
44
+
45
+ attr_reader :is_edited
46
+
34
47
  attr_reader :source
35
48
 
36
49
  attr_reader :type
@@ -79,6 +92,27 @@ module Asana
79
92
  end
80
93
  end
81
94
 
95
+ # Updates the story and returns the full record for the updated story.
96
+ # Only comment stories can have their text updated, and only comment stories and
97
+ # attachment stories can be pinned. Only one of `text` and `html_text` can be specified.
98
+ #
99
+ # text - [String] The plain text with which to update the comment.
100
+ #
101
+ # html_text - [String] The rich text with which to update the comment.
102
+ # is_pinned - [Boolean] Whether the story should be pinned on the resource.
103
+ # options - [Hash] the request I/O options.
104
+ # data - [Hash] the attributes to post.
105
+ def update(text: nil, html_text: nil, is_pinned: nil, options: {}, **data)
106
+ with_params = data.merge(text: text, html_text: html_text, is_pinned: is_pinned).reject { |_,v| v.nil? || Array(v).empty? }
107
+ refresh_with(parse(client.put("/stories/#{id}", body: with_params, options: options)).first)
108
+ end
109
+
110
+ # Deletes a story. A user can only delete stories they have created. Returns an empty data record.
111
+ def delete()
112
+
113
+ client.delete("/stories/#{id}") && true
114
+ end
115
+
82
116
  end
83
117
  end
84
- end
118
+ end
@@ -23,8 +23,6 @@ module Asana
23
23
 
24
24
  attr_reader :color
25
25
 
26
- attr_reader :notes
27
-
28
26
  attr_reader :workspace
29
27
 
30
28
  class << self
@@ -139,4 +137,4 @@ module Asana
139
137
 
140
138
  end
141
139
  end
142
- end
140
+ end
@@ -28,6 +28,10 @@ module Asana
28
28
 
29
29
  attr_reader :custom_fields
30
30
 
31
+ attr_reader :dependencies
32
+
33
+ attr_reader :dependents
34
+
31
35
  attr_reader :due_on
32
36
 
33
37
  attr_reader :due_at
@@ -36,22 +40,33 @@ module Asana
36
40
 
37
41
  attr_reader :followers
38
42
 
43
+ # DEPRECATED: prefer "liked"
39
44
  attr_reader :hearted
40
45
 
46
+ # DEPRECATED: prefer "likes"
41
47
  attr_reader :hearts
42
48
 
49
+ attr_reader :liked
50
+
51
+ attr_reader :likes
52
+
43
53
  attr_reader :modified_at
44
54
 
45
55
  attr_reader :name
46
56
 
47
57
  attr_reader :notes
48
58
 
59
+ # DEPRECATED: prefer "num_likes"
49
60
  attr_reader :num_hearts
50
61
 
62
+ attr_reader :num_likes
63
+
51
64
  attr_reader :projects
52
65
 
53
66
  attr_reader :parent
54
67
 
68
+ attr_reader :start_on
69
+
55
70
  attr_reader :workspace
56
71
 
57
72
  attr_reader :memberships
@@ -129,12 +144,23 @@ module Asana
129
144
  Collection.new(parse(client.get("/tags/#{tag}/tasks", params: params, options: options)), type: self, client: client)
130
145
  end
131
146
 
147
+ # <b>Board view only:</b> Returns the compact section records for all tasks within the given section.
148
+ #
149
+ # section - [Id] The section in which to search for tasks.
150
+ # per_page - [Integer] the number of records to fetch per page.
151
+ # options - [Hash] the request I/O options.
152
+ def find_by_section(client, section: required("section"), per_page: 20, options: {})
153
+ params = { limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
154
+ Collection.new(parse(client.get("/sections/#{section}/tasks", params: params, options: options)), type: self, client: client)
155
+ end
156
+
132
157
  # Returns the compact task records for some filtered set of tasks. Use one
133
158
  # or more of the parameters provided to filter the tasks returned. You must
134
159
  # specify a `project` or `tag` if you do not specify `assignee` and `workspace`.
135
160
  #
136
161
  # assignee - [String] The assignee to filter tasks on.
137
162
  # project - [Id] The project to filter tasks on.
163
+ # section - [Id] The section to filter tasks on.
138
164
  # workspace - [Id] The workspace or organization to filter tasks on.
139
165
  # completed_since - [String] Only return tasks that are either incomplete or that have been
140
166
  # completed since this time.
@@ -147,6 +173,8 @@ module Asana
147
173
  #
148
174
  # If you specify `assignee`, you must also specify the `workspace` to filter on.
149
175
  #
176
+ # Currently, this is only supported in board views.
177
+ #
150
178
  # If you specify `workspace`, you must also specify the `assignee` to filter on.
151
179
  #
152
180
  # A task is considered "modified" if any of its properties change,
@@ -155,10 +183,20 @@ module Asana
155
183
  # just because another object it is associated with (e.g. a subtask)
156
184
  # is modified. Actions that count as modifying the task include
157
185
  # assigning, renaming, completing, and adding stories.
158
- def find_all(client, assignee: nil, project: nil, workspace: nil, completed_since: nil, modified_since: nil, per_page: 20, options: {})
159
- params = { assignee: assignee, project: project, workspace: workspace, completed_since: completed_since, modified_since: modified_since, limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
186
+ def find_all(client, assignee: nil, project: nil, section: nil, workspace: nil, completed_since: nil, modified_since: nil, per_page: 20, options: {})
187
+ params = { assignee: assignee, project: project, section: section, workspace: workspace, completed_since: completed_since, modified_since: modified_since, limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
160
188
  Collection.new(parse(client.get("/tasks", params: params, options: options)), type: self, client: client)
161
189
  end
190
+
191
+ # The search endpoint allows you to build complex queries to find and fetch exactly the data you need from Asana. For a more comprehensive description of all the query parameters and limitations of this endpoint, see our [long-form documentation](/developers/documentation/getting-started/search-api) for this feature.
192
+ #
193
+ # workspace - [Id] The workspace or organization in which to search for tasks.
194
+ # per_page - [Integer] the number of records to fetch per page.
195
+ # options - [Hash] the request I/O options.
196
+ def search(client, workspace: required("workspace"), per_page: 20, options: {})
197
+ params = { limit: per_page }.reject { |_,v| v.nil? || Array(v).empty? }
198
+ Collection.new(parse(client.get("/workspaces/#{workspace}/tasks/search", params: params, options: options)), type: Resource, client: client)
199
+ end
162
200
  end
163
201
 
164
202
  # A specific, existing task can be updated by making a PUT request on the
@@ -189,6 +227,64 @@ module Asana
189
227
  client.delete("/tasks/#{id}") && true
190
228
  end
191
229
 
230
+ # Returns the compact representations of all of the dependencies of a task.
231
+ #
232
+ # options - [Hash] the request I/O options.
233
+ def dependencies(options: {})
234
+
235
+ Resource.new(parse(client.get("/tasks/#{id}/dependencies", options: options)).first, client: client)
236
+ end
237
+
238
+ # Returns the compact representations of all of the dependents of a task.
239
+ #
240
+ # options - [Hash] the request I/O options.
241
+ def dependents(options: {})
242
+
243
+ Resource.new(parse(client.get("/tasks/#{id}/dependents", options: options)).first, client: client)
244
+ end
245
+
246
+ # Marks a set of tasks as dependencies of this task, if they are not
247
+ # already dependencies. *A task can have at most 15 dependencies.*
248
+ #
249
+ # dependencies - [Array] An array of task IDs that this task should depend on.
250
+ # options - [Hash] the request I/O options.
251
+ # data - [Hash] the attributes to post.
252
+ def add_dependencies(dependencies: required("dependencies"), options: {}, **data)
253
+ with_params = data.merge(dependencies: dependencies).reject { |_,v| v.nil? || Array(v).empty? }
254
+ Resource.new(parse(client.post("/tasks/#{id}/addDependencies", body: with_params, options: options)).first, client: client)
255
+ end
256
+
257
+ # Marks a set of tasks as dependents of this task, if they are not already
258
+ # dependents. *A task can have at most 30 dependents.*
259
+ #
260
+ # dependents - [Array] An array of task IDs that should depend on this task.
261
+ # options - [Hash] the request I/O options.
262
+ # data - [Hash] the attributes to post.
263
+ def add_dependents(dependents: required("dependents"), options: {}, **data)
264
+ with_params = data.merge(dependents: dependents).reject { |_,v| v.nil? || Array(v).empty? }
265
+ Resource.new(parse(client.post("/tasks/#{id}/addDependents", body: with_params, options: options)).first, client: client)
266
+ end
267
+
268
+ # Unlinks a set of dependencies from this task.
269
+ #
270
+ # dependencies - [Array] An array of task IDs to remove as dependencies.
271
+ # options - [Hash] the request I/O options.
272
+ # data - [Hash] the attributes to post.
273
+ def remove_dependencies(dependencies: required("dependencies"), options: {}, **data)
274
+ with_params = data.merge(dependencies: dependencies).reject { |_,v| v.nil? || Array(v).empty? }
275
+ Resource.new(parse(client.post("/tasks/#{id}/removeDependencies", body: with_params, options: options)).first, client: client)
276
+ end
277
+
278
+ # Unlinks a set of dependents from this task.
279
+ #
280
+ # dependents - [Array] An array of task IDs to remove as dependents.
281
+ # options - [Hash] the request I/O options.
282
+ # data - [Hash] the attributes to post.
283
+ def remove_dependents(dependents: required("dependents"), options: {}, **data)
284
+ with_params = data.merge(dependents: dependents).reject { |_,v| v.nil? || Array(v).empty? }
285
+ Resource.new(parse(client.post("/tasks/#{id}/removeDependents", body: with_params, options: options)).first, client: client)
286
+ end
287
+
192
288
  # Adds each of the specified followers to the task, if they are not already
193
289
  # following. Returns the complete, updated record for the affected task.
194
290
  #
@@ -222,11 +318,17 @@ module Asana
222
318
 
223
319
  # Adds the task to the specified project, in the optional location
224
320
  # specified. If no location arguments are given, the task will be added to
225
- # the beginning of the project.
321
+ # the end of the project.
226
322
  #
227
- # `addProject` can also be used to reorder a task within a project that
323
+ # `addProject` can also be used to reorder a task within a project or section that
228
324
  # already contains it.
229
325
  #
326
+ # At most one of `insert_before`, `insert_after`, or `section` should be
327
+ # specified. Inserting into a section in an non-order-dependent way can be
328
+ # done by specifying `section`, otherwise, to insert within a section in a
329
+ # particular place, specify `insert_before` or `insert_after` and a task
330
+ # within the section to anchor the position of this task.
331
+ #
230
332
  # Returns an empty data block.
231
333
  #
232
334
  # project - [Id] The project to add the task to.
@@ -237,7 +339,7 @@ module Asana
237
339
  # insert at the end of the list.
238
340
  #
239
341
  # section - [Id] A section in the project to insert the task into. The task will be
240
- # inserted at the top of the section.
342
+ # inserted at the bottom of the section.
241
343
  #
242
344
  # options - [Hash] the request I/O options.
243
345
  # data - [Hash] the attributes to post.
@@ -308,13 +410,21 @@ module Asana
308
410
  end
309
411
 
310
412
  # Changes the parent of a task. Each task may only be a subtask of a single
311
- # parent, or no parent task at all. Returns an empty data block.
413
+ # parent, or no parent task at all. Returns an empty data block. When using `insert_before` and `insert_after`,
414
+ # at most one of those two options can be specified, and they must already be subtasks
415
+ # of the parent.
312
416
  #
313
417
  # parent - [Id] The new parent of the task, or `null` for no parent.
418
+ # insert_after - [Id] A subtask of the parent to insert the task after, or `null` to
419
+ # insert at the beginning of the list.
420
+ #
421
+ # insert_before - [Id] A subtask of the parent to insert the task before, or `null` to
422
+ # insert at the end of the list.
423
+ #
314
424
  # options - [Hash] the request I/O options.
315
425
  # data - [Hash] the attributes to post.
316
- def set_parent(parent: required("parent"), options: {}, **data)
317
- with_params = data.merge(parent: parent).reject { |_,v| v.nil? || Array(v).empty? }
426
+ def set_parent(parent: required("parent"), insert_after: nil, insert_before: nil, options: {}, **data)
427
+ with_params = data.merge(parent: parent, insert_after: insert_after, insert_before: insert_before).reject { |_,v| v.nil? || Array(v).empty? }
318
428
  client.post("/tasks/#{id}/setParent", body: with_params, options: options) && true
319
429
  end
320
430
 
@@ -343,4 +453,4 @@ module Asana
343
453
 
344
454
  end
345
455
  end
346
- end
456
+ end
@@ -96,4 +96,4 @@ module Asana
96
96
 
97
97
  end
98
98
  end
99
- end
99
+ end
@@ -74,4 +74,4 @@ module Asana
74
74
 
75
75
  end
76
76
  end
77
- end
77
+ end
@@ -134,4 +134,4 @@ module Asana
134
134
 
135
135
  end
136
136
  end
137
- end
137
+ end
@@ -73,7 +73,8 @@ module Asana
73
73
  # result set is limited to a single page of results with a maximum size,
74
74
  # so you won't be able to fetch large numbers of results.
75
75
  #
76
- # type - [Enum] The type of values the typeahead should return.
76
+ # type - [Enum] The type of values the typeahead should return. You can choose from
77
+ # one of the following: custom_field, project, tag, task, and user.
77
78
  # Note that unlike in the names of endpoints, the types listed here are
78
79
  # in singular form (e.g. `task`). Using multiple types is not yet supported.
79
80
  #
@@ -122,4 +123,4 @@ module Asana
122
123
 
123
124
  end
124
125
  end
125
- end
126
+ end
@@ -1,5 +1,5 @@
1
1
  #:nodoc:
2
2
  module Asana
3
3
  # Public: Version of the gem.
4
- VERSION = '0.6.3'.freeze
4
+ VERSION = '0.8.0'.freeze
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asana
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.3
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Txus
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-02-09 00:00:00.000000000 Z
11
+ date: 2018-08-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oauth2
@@ -183,7 +183,11 @@ files:
183
183
  - lib/asana/resources/attachment.rb
184
184
  - lib/asana/resources/custom_field_settings.rb
185
185
  - lib/asana/resources/custom_fields.rb
186
+ - lib/asana/resources/organization_export.rb
186
187
  - lib/asana/resources/project.rb
188
+ - lib/asana/resources/project_membership.rb
189
+ - lib/asana/resources/project_status.rb
190
+ - lib/asana/resources/section.rb
187
191
  - lib/asana/resources/story.rb
188
192
  - lib/asana/resources/tag.rb
189
193
  - lib/asana/resources/task.rb
@@ -216,7 +220,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
216
220
  version: '0'
217
221
  requirements: []
218
222
  rubyforge_project:
219
- rubygems_version: 2.7.5
223
+ rubygems_version: 2.7.7
220
224
  signing_key:
221
225
  specification_version: 4
222
226
  summary: Official Ruby client for the Asana API