ruby-trello 0.4.4.3 → 0.5.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.
- data/README.md +81 -8
- data/lib/trello.rb +25 -9
- data/lib/trello/action.rb +5 -5
- data/lib/trello/association_proxy.rb +3 -3
- data/lib/trello/authorization.rb +105 -49
- data/lib/trello/basic_data.rb +48 -4
- data/lib/trello/board.rb +10 -9
- data/lib/trello/card.rb +38 -35
- data/lib/trello/checklist.rb +10 -8
- data/lib/trello/client.rb +98 -29
- data/lib/trello/configuration.rb +68 -0
- data/lib/trello/has_actions.rb +1 -1
- data/lib/trello/list.rb +9 -7
- data/lib/trello/member.rb +3 -3
- data/lib/trello/multi_association.rb +4 -2
- data/lib/trello/notification.rb +8 -8
- data/lib/trello/organization.rb +3 -3
- data/lib/trello/token.rb +4 -4
- data/spec/action_spec.rb +30 -18
- data/spec/basic_auth_policy_spec.rb +1 -0
- data/spec/board_spec.rb +141 -120
- data/spec/card_spec.rb +104 -82
- data/spec/checklist_spec.rb +35 -6
- data/spec/client_spec.rb +56 -19
- data/spec/configuration_spec.rb +114 -0
- data/spec/integration/how_to_authorize_spec.rb +1 -1
- data/spec/list_spec.rb +74 -20
- data/spec/member_spec.rb +37 -23
- data/spec/notification_spec.rb +28 -24
- data/spec/oauth_policy_spec.rb +55 -9
- data/spec/organization_spec.rb +18 -7
- data/spec/spec_helper.rb +5 -0
- data/spec/token_spec.rb +25 -8
- data/spec/trello_spec.rb +73 -0
- metadata +10 -6
data/lib/trello/board.rb
CHANGED
@@ -11,17 +11,18 @@ module Trello
|
|
11
11
|
class << self
|
12
12
|
# Finds a board.
|
13
13
|
def find(id)
|
14
|
-
|
14
|
+
client.find(:board, id)
|
15
15
|
end
|
16
16
|
|
17
17
|
def create(fields)
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
client.create(:board,
|
19
|
+
'name' => fields[:name],
|
20
|
+
'desc' => fields[:description],
|
21
|
+
'closed' => fields[:closed] || false)
|
21
22
|
end
|
22
23
|
|
23
24
|
def all
|
24
|
-
|
25
|
+
client.get("/members/#{Member.find(:me).username}/boards").json_into(self)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -32,7 +33,7 @@ module Trello
|
|
32
33
|
fields.merge!(:desc => description) if description
|
33
34
|
fields.merge!(:idOrganization => organization_id) if organization_id
|
34
35
|
|
35
|
-
|
36
|
+
client.post("/boards", fields).json_into(self)
|
36
37
|
end
|
37
38
|
|
38
39
|
def update!
|
@@ -41,7 +42,7 @@ module Trello
|
|
41
42
|
@previously_changed = changes
|
42
43
|
@changed_attributes.clear
|
43
44
|
|
44
|
-
|
45
|
+
client.put("/boards/#{self.id}/", {
|
45
46
|
:name => attributes[:name],
|
46
47
|
:description => attributes[:description],
|
47
48
|
:closed => attributes[:closed]
|
@@ -68,7 +69,7 @@ module Trello
|
|
68
69
|
end
|
69
70
|
|
70
71
|
def find_card(card_id)
|
71
|
-
|
72
|
+
client.get("/boards/#{self.id}/cards/#{card_id}").json_into(Card)
|
72
73
|
end
|
73
74
|
|
74
75
|
# Return all the cards on this board.
|
@@ -93,7 +94,7 @@ module Trello
|
|
93
94
|
many :members, :filter => :all
|
94
95
|
|
95
96
|
# Returns a reference to the organization this board belongs to.
|
96
|
-
one :organization, :using => :organization_id
|
97
|
+
one :organization, :path => :organizations, :using => :organization_id
|
97
98
|
|
98
99
|
# :nodoc:
|
99
100
|
def request_prefix
|
data/lib/trello/card.rb
CHANGED
@@ -12,14 +12,15 @@ module Trello
|
|
12
12
|
class << self
|
13
13
|
# Find a specific card by its id.
|
14
14
|
def find(id)
|
15
|
-
|
15
|
+
client.find(:card, id)
|
16
16
|
end
|
17
17
|
|
18
18
|
# Create a new card and save it on Trello.
|
19
19
|
def create(options)
|
20
|
-
|
20
|
+
client.create(:card,
|
21
|
+
'name' => options[:name],
|
21
22
|
'idList' => options[:list_id],
|
22
|
-
'desc' => options[:description])
|
23
|
+
'desc' => options[:description])
|
23
24
|
end
|
24
25
|
end
|
25
26
|
|
@@ -43,7 +44,7 @@ module Trello
|
|
43
44
|
end
|
44
45
|
|
45
46
|
# Returns a reference to the board this card is part of.
|
46
|
-
one :board, :using => :board_id
|
47
|
+
one :board, :path => :boards, :using => :board_id
|
47
48
|
|
48
49
|
# Returns a list of checklists associated with the card.
|
49
50
|
#
|
@@ -53,18 +54,18 @@ module Trello
|
|
53
54
|
many :checklists, :filter => :all
|
54
55
|
|
55
56
|
def check_item_states
|
56
|
-
states =
|
57
|
+
states = client.get("/cards/#{self.id}/checkItemStates").json_into(CheckItemState)
|
57
58
|
MultiAssociation.new(self, states).proxy
|
58
59
|
end
|
59
60
|
|
60
61
|
|
61
62
|
# Returns a reference to the list this card is currently in.
|
62
|
-
one :list, :using => :list_id
|
63
|
+
one :list, :path => :lists, :using => :list_id
|
63
64
|
|
64
65
|
# Returns a list of members who are assigned to this card.
|
65
66
|
def members
|
66
67
|
members = member_ids.map do |member_id|
|
67
|
-
|
68
|
+
client.get("/members/#{member_id}").json_into(Member)
|
68
69
|
end
|
69
70
|
MultiAssociation.new(self, members).proxy
|
70
71
|
end
|
@@ -74,7 +75,7 @@ module Trello
|
|
74
75
|
# If we have an id, just update our fields.
|
75
76
|
return update! if id
|
76
77
|
|
77
|
-
|
78
|
+
client.post("/cards", {
|
78
79
|
:name => name,
|
79
80
|
:desc => description,
|
80
81
|
:idList => list_id
|
@@ -87,18 +88,16 @@ module Trello
|
|
87
88
|
# this object before making your changes, and before updating the record.
|
88
89
|
def update!
|
89
90
|
@previously_changed = changes
|
91
|
+
# extract only new values to build payload
|
92
|
+
payload = Hash[changes.map { |key, values| [key.to_sym, values[1]] }]
|
90
93
|
@changed_attributes.clear
|
91
94
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
:idBoard => board_id,
|
99
|
-
:idMembers => member_ids,
|
100
|
-
:pos => pos
|
101
|
-
})
|
95
|
+
client.put("/cards/#{id}", payload)
|
96
|
+
end
|
97
|
+
|
98
|
+
# Delete this card
|
99
|
+
def delete
|
100
|
+
client.delete("/cards/#{id}")
|
102
101
|
end
|
103
102
|
|
104
103
|
# Check if the card is not active anymore.
|
@@ -122,45 +121,49 @@ module Trello
|
|
122
121
|
|
123
122
|
# Add a comment with the supplied text.
|
124
123
|
def add_comment(text)
|
125
|
-
|
124
|
+
client.post("/cards/#{id}/actions/comments", :text => text)
|
126
125
|
end
|
127
126
|
|
128
127
|
# Add a checklist to this card
|
129
128
|
def add_checklist(checklist)
|
130
|
-
|
129
|
+
client.post("/cards/#{id}/checklists", {
|
131
130
|
:value => checklist.id
|
132
131
|
})
|
133
132
|
end
|
134
133
|
|
135
134
|
# Move this card to the given list
|
136
135
|
def move_to_list(list)
|
137
|
-
|
138
|
-
|
139
|
-
|
136
|
+
unless list_id == list.id
|
137
|
+
client.put("/cards/#{id}/idList", {
|
138
|
+
:value => list.id
|
139
|
+
})
|
140
|
+
end
|
140
141
|
end
|
141
142
|
|
142
143
|
# Move this card to the given board (and optional list on this board)
|
143
144
|
def move_to_board(new_board, new_list = nil)
|
144
|
-
|
145
|
-
|
146
|
-
|
145
|
+
unless board_id == new_board.id
|
146
|
+
payload = { :value => new_board.id }
|
147
|
+
payload[:idList] = new_list.id if new_list
|
148
|
+
client.put("/cards/#{id}/idBoard", payload)
|
149
|
+
end
|
147
150
|
end
|
148
151
|
|
149
152
|
# Add a member to this card
|
150
153
|
def add_member(member)
|
151
|
-
|
154
|
+
client.post("/cards/#{id}/members", {
|
152
155
|
:value => member.id
|
153
156
|
})
|
154
157
|
end
|
155
158
|
|
156
159
|
# Remove a member from this card
|
157
160
|
def remove_member(member)
|
158
|
-
|
161
|
+
client.delete("/cards/#{id}/members/#{member.id}")
|
159
162
|
end
|
160
163
|
|
161
164
|
# Retrieve a list of labels
|
162
165
|
def labels
|
163
|
-
labels =
|
166
|
+
labels = client.get("/cards/#{id}/labels").json_into(Label)
|
164
167
|
MultiAssociation.new(self, labels).proxy
|
165
168
|
end
|
166
169
|
|
@@ -170,7 +173,7 @@ module Trello
|
|
170
173
|
errors.add(:label, "colour '#{colour}' does not exist")
|
171
174
|
return Trello.logger.warn "The label colour '#{colour}' does not exist."
|
172
175
|
end
|
173
|
-
|
176
|
+
client.post("/cards/#{id}/labels", { :value => colour })
|
174
177
|
end
|
175
178
|
|
176
179
|
# Remove a label
|
@@ -179,18 +182,18 @@ module Trello
|
|
179
182
|
errors.add(:label, "colour '#{colour}' does not exist")
|
180
183
|
return Trello.logger.warn "The label colour '#{colour}' does not exist." unless %w{green yellow orange red purple blue}.include? colour
|
181
184
|
end
|
182
|
-
|
185
|
+
client.delete("/cards/#{id}/labels/#{colour}")
|
183
186
|
end
|
184
187
|
|
185
188
|
# Add an attachment to this card
|
186
189
|
def add_attachment(attachment, name='')
|
187
190
|
if attachment.is_a? File
|
188
|
-
|
191
|
+
client.post("/cards/#{id}/attachments", {
|
189
192
|
:file => attachment,
|
190
193
|
:name => name
|
191
194
|
})
|
192
195
|
else
|
193
|
-
|
196
|
+
client.post("/cards/#{id}/attachments", {
|
194
197
|
:url => attachment,
|
195
198
|
:name => name
|
196
199
|
})
|
@@ -199,13 +202,13 @@ module Trello
|
|
199
202
|
|
200
203
|
# Retrieve a list of attachments
|
201
204
|
def attachments
|
202
|
-
attachments =
|
205
|
+
attachments = client.get("/cards/#{id}/attachments").json_into(Attachment)
|
203
206
|
MultiAssociation.new(self, attachments).proxy
|
204
207
|
end
|
205
208
|
|
206
209
|
# Remove an attachment from this card
|
207
210
|
def remove_attachment(attachment)
|
208
|
-
|
211
|
+
client.delete("/cards/#{id}/attachments/#{attachment.id}")
|
209
212
|
end
|
210
213
|
|
211
214
|
# :nodoc:
|
data/lib/trello/checklist.rb
CHANGED
@@ -9,12 +9,13 @@ module Trello
|
|
9
9
|
class << self
|
10
10
|
# Locate a specific checklist by its id.
|
11
11
|
def find(id)
|
12
|
-
|
12
|
+
client.find(:checklist, id)
|
13
13
|
end
|
14
14
|
|
15
15
|
def create(options)
|
16
|
-
|
17
|
-
|
16
|
+
client.create(:checklist,
|
17
|
+
'name' => options[:name],
|
18
|
+
'idBoard' => options[:board_id])
|
18
19
|
end
|
19
20
|
end
|
20
21
|
|
@@ -30,6 +31,7 @@ module Trello
|
|
30
31
|
attributes[:url] = fields['url']
|
31
32
|
attributes[:check_items] = fields['checkItems']
|
32
33
|
attributes[:board_id] = fields['idBoard']
|
34
|
+
attributes[:list_id] = fields['idList']
|
33
35
|
attributes[:member_ids] = fields['idMembers']
|
34
36
|
self
|
35
37
|
end
|
@@ -43,14 +45,14 @@ module Trello
|
|
43
45
|
def save
|
44
46
|
return update! if id
|
45
47
|
|
46
|
-
|
48
|
+
client.post("/checklists", {
|
47
49
|
:name => name,
|
48
50
|
:idBoard => board_id
|
49
51
|
}).json_into(self)
|
50
52
|
end
|
51
53
|
|
52
54
|
def update!
|
53
|
-
|
55
|
+
client.put("/checklists/#{id}", { :name => name }).json_into(self)
|
54
56
|
end
|
55
57
|
|
56
58
|
# Return a list of items on the checklist.
|
@@ -61,10 +63,10 @@ module Trello
|
|
61
63
|
end
|
62
64
|
|
63
65
|
# Return a reference to the board the checklist is on.
|
64
|
-
one :board, :using => :board_id
|
66
|
+
one :board, :path => :checklists, :using => :board_id
|
65
67
|
|
66
68
|
# Return a reference to the list the checklist is on.
|
67
|
-
one :list, :using => :list_id
|
69
|
+
one :list, :path => :lists, :using => :list_id
|
68
70
|
|
69
71
|
# Return a list of members active in this checklist.
|
70
72
|
def members
|
@@ -76,7 +78,7 @@ module Trello
|
|
76
78
|
|
77
79
|
# Add an item to the checklist
|
78
80
|
def add_item(name)
|
79
|
-
|
81
|
+
client.post("/checklists/#{id}/checkItems", { :name => name })
|
80
82
|
end
|
81
83
|
end
|
82
84
|
end
|
data/lib/trello/client.rb
CHANGED
@@ -2,48 +2,117 @@ require 'addressable/uri'
|
|
2
2
|
|
3
3
|
module Trello
|
4
4
|
class Client
|
5
|
-
extend
|
5
|
+
extend Forwardable
|
6
|
+
include Authorization
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
def_delegators :configuration, :credentials, *Configuration.configurable_attributes
|
9
|
+
|
10
|
+
def initialize(attrs = {})
|
11
|
+
self.configuration.attributes = attrs
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(path, params = {})
|
15
|
+
uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
|
16
|
+
uri.query_values = params unless params.empty?
|
17
|
+
invoke_verb(:get, uri)
|
18
|
+
end
|
19
|
+
|
20
|
+
def post(path, body = {})
|
21
|
+
uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
|
22
|
+
invoke_verb(:post, uri, body)
|
23
|
+
end
|
13
24
|
|
14
|
-
|
15
|
-
|
16
|
-
|
25
|
+
def put(path, body = {})
|
26
|
+
uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
|
27
|
+
invoke_verb(:put, uri, body)
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(path)
|
31
|
+
uri = Addressable::URI.parse("https://api.trello.com/#{API_VERSION}#{path}")
|
32
|
+
invoke_verb(:delete, uri)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Finds given resource by id
|
36
|
+
#
|
37
|
+
# Examples:
|
38
|
+
# client.find(:board, "board1234")
|
39
|
+
# client.find(:member, "user1234")
|
40
|
+
#
|
41
|
+
def find(path, id)
|
42
|
+
response = get("/#{path.to_s.pluralize}/#{id}")
|
43
|
+
trello_class = class_from_path(path)
|
44
|
+
trello_class.parse response do |data|
|
45
|
+
data.client = self
|
17
46
|
end
|
47
|
+
end
|
18
48
|
|
19
|
-
|
20
|
-
|
21
|
-
|
49
|
+
# Finds given resource by path with params
|
50
|
+
def find_many(trello_class, path, params = {})
|
51
|
+
response = get(path, params)
|
52
|
+
trello_class.parse_many response do |data|
|
53
|
+
data.client = self
|
22
54
|
end
|
55
|
+
end
|
23
56
|
|
24
|
-
|
25
|
-
|
26
|
-
|
57
|
+
# Creates resource with given options (attributes)
|
58
|
+
#
|
59
|
+
# Examples:
|
60
|
+
# client.create(:member, options)
|
61
|
+
# client.create(:board, options)
|
62
|
+
#
|
63
|
+
def create(path, options)
|
64
|
+
trello_class = class_from_path(path)
|
65
|
+
trello_class.save options do |data|
|
66
|
+
data.client = self
|
27
67
|
end
|
68
|
+
end
|
28
69
|
|
29
|
-
|
30
|
-
|
31
|
-
|
70
|
+
def configure
|
71
|
+
yield configuration if block_given?
|
72
|
+
end
|
73
|
+
|
74
|
+
def configuration
|
75
|
+
@configuration ||= Configuration.new
|
76
|
+
end
|
32
77
|
|
33
|
-
|
78
|
+
def auth_policy
|
79
|
+
@auth_policy ||= auth_policy_class.new(credentials)
|
80
|
+
end
|
34
81
|
|
35
|
-
|
36
|
-
Trello.logger.error("[401 #{name.to_s.upcase} #{uri}]: Your access token has expired.")
|
37
|
-
raise InvalidAccessToken, response.body
|
38
|
-
end
|
82
|
+
private
|
39
83
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
84
|
+
def invoke_verb(name, uri, body = nil)
|
85
|
+
request = Request.new name, uri, {}, body
|
86
|
+
response = TInternet.execute auth_policy.authorize(request)
|
87
|
+
|
88
|
+
return '' unless response
|
89
|
+
|
90
|
+
if response.code.to_i == 401 && response.body =~ /expired token/
|
91
|
+
Trello.logger.error("[401 #{name.to_s.upcase} #{uri}]: Your access token has expired.")
|
92
|
+
raise InvalidAccessToken, response.body
|
93
|
+
end
|
44
94
|
|
45
|
-
|
95
|
+
unless [200, 201].include? response.code
|
96
|
+
Trello.logger.error("[#{response.code} #{name.to_s.upcase} #{uri}]: #{response.body}")
|
97
|
+
raise Error, response.body
|
46
98
|
end
|
99
|
+
|
100
|
+
response.body
|
101
|
+
end
|
102
|
+
|
103
|
+
def auth_policy_class
|
104
|
+
if configuration.oauth?
|
105
|
+
OAuthPolicy
|
106
|
+
elsif configuration.basic?
|
107
|
+
BasicAuthPolicy
|
108
|
+
else
|
109
|
+
AuthPolicy
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def class_from_path(path_or_class)
|
114
|
+
return path_or_class if path_or_class.is_a?(Class)
|
115
|
+
Trello.const_get(path_or_class.to_s.singularize.camelize)
|
47
116
|
end
|
48
117
|
end
|
49
118
|
end
|