turingstudio-basecamp-rb 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +21 -0
- data/lib/basecamp/attachment.rb +23 -23
- data/lib/basecamp/attachment_category.rb +10 -0
- data/lib/basecamp/base.rb +5 -109
- data/lib/basecamp/company.rb +10 -0
- data/lib/basecamp/message.rb +24 -22
- data/lib/basecamp/milestone.rb +50 -0
- data/lib/basecamp/person.rb +18 -0
- data/lib/basecamp/post_category.rb +10 -0
- data/lib/basecamp/project.rb +22 -0
- data/lib/basecamp/record.rb +42 -13
- data/lib/basecamp/resource.rb +9 -9
- data/lib/basecamp/time_entry.rb +11 -9
- data/lib/basecamp/todoitem.rb +6 -6
- data/lib/basecamp/todolist.rb +16 -14
- data/lib/basecamp/version.rb +1 -1
- data/lib/basecamp.rb +7 -1
- data/spec/lib/basecamp/attachment_category_spec.rb +12 -0
- data/spec/lib/basecamp/attachment_spec.rb +26 -0
- data/spec/lib/basecamp/base_spec.rb +44 -0
- data/spec/lib/basecamp/company_spec.rb +13 -0
- data/spec/lib/basecamp/message_spec.rb +45 -0
- data/spec/lib/basecamp/milestone_spec.rb +44 -0
- data/spec/lib/basecamp/person_spec.rb +18 -0
- data/spec/lib/basecamp/post_category_spec.rb +13 -0
- data/spec/lib/basecamp/project_spec.rb +12 -0
- data/spec/lib/basecamp/record_spec.rb +57 -0
- data/spec/lib/basecamp/time_entry_spec.rb +23 -0
- data/spec/lib/basecamp/todo_item_spec.rb +38 -0
- data/spec/lib/basecamp/todo_list_spec.rb +36 -0
- data/spec/spec_helper.rb +68 -1
- metadata +44 -18
- data/spec/basecamp_spec.rb +0 -61
- data/spec/lib/basecamp_base.rb +0 -75
- data/spec/lib/basecamp_message_spec.rb +0 -42
- data/spec/lib/basecamp_todo_item_spec.rb +0 -40
- data/spec/lib/basecamp_todo_list_spec.rb +0 -32
data/Rakefile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }
|
2
|
+
require File.dirname(__FILE__) + '/lib/basecamp/version'
|
3
|
+
|
4
|
+
# Generate all the Rake tasks
|
5
|
+
# Run 'rake -T' to see list of generated tasks (from gem root directory)
|
6
|
+
$hoe = Hoe.new('basecamp-rb', Basecamp::VERSION) do |p|
|
7
|
+
p.developer('The Turing Studio, Inc.', 'support@turingstudio.com')
|
8
|
+
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
9
|
+
p.extra_deps = [
|
10
|
+
['xml-simple','>= 1.0.11'],
|
11
|
+
['activesupport','>= 2.2.2'],
|
12
|
+
['activeresource','>= 2.2.2']
|
13
|
+
]
|
14
|
+
p.extra_dev_deps = [
|
15
|
+
['newgem', ">= #{::Newgem::VERSION}"]
|
16
|
+
]
|
17
|
+
p.clean_globs |= %w[**/.DS_Store tmp *.log]
|
18
|
+
end
|
19
|
+
|
20
|
+
require 'newgem/tasks'
|
21
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
data/lib/basecamp/attachment.rb
CHANGED
@@ -1,28 +1,20 @@
|
|
1
|
+
# === Attaching Files to a Resource
|
2
|
+
#
|
3
|
+
# If the resource accepts file attachments, the +attachments+ parameter should
|
4
|
+
# be an array of Basecamp::Attachment objects. Example:
|
5
|
+
#
|
6
|
+
# a1 = Basecamp::Atachment.create('primary', File.read('primary.doc'))
|
7
|
+
# a2 = Basecamp::Atachment.create('another', File.read('another.doc'))
|
8
|
+
#
|
9
|
+
# m = Basecamp::Message.new(:project_id => 1037)
|
10
|
+
# ...
|
11
|
+
# m.attachments = [a1, a2]
|
12
|
+
# m.save # => true
|
13
|
+
#
|
1
14
|
module Basecamp
|
2
|
-
class Attachment
|
3
|
-
|
4
|
-
# === Attaching Files to a Resource
|
5
|
-
#
|
6
|
-
# If the resource accepts file attachments, the +attachments+ parameter should
|
7
|
-
# be an array of Basecamp::Attachment objects. Example:
|
8
|
-
#
|
9
|
-
# a1 = Basecamp::Atachment.create('primary', File.read('primary.doc'))
|
10
|
-
# a2 = Basecamp::Atachment.create('another', File.read('another.doc'))
|
11
|
-
#
|
12
|
-
# m = Basecamp::Message.new(:project_id => 1037)
|
13
|
-
# ...
|
14
|
-
# m.attachments = [a1, a2]
|
15
|
-
# m.save # => true
|
16
|
-
#
|
17
|
-
|
15
|
+
class Attachment
|
18
16
|
attr_accessor :id, :filename, :content, :content_type
|
19
|
-
|
20
|
-
def self.create(filename, content)
|
21
|
-
returning new(filename, content) do |attachment|
|
22
|
-
attachment.save
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
17
|
+
|
26
18
|
def initialize(filename, content, content_type = 'application/octet-stream')
|
27
19
|
@filename, @content, @content_type = filename, content, content_type
|
28
20
|
end
|
@@ -49,5 +41,13 @@ module Basecamp
|
|
49
41
|
raise "Could not save attachment: #{response.message} (#{response.code})"
|
50
42
|
end
|
51
43
|
end
|
44
|
+
|
45
|
+
class << self
|
46
|
+
def create(filename, content)
|
47
|
+
returning new(filename, content) do |attachment|
|
48
|
+
attachment.save
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
52
|
end
|
53
53
|
end
|
data/lib/basecamp/base.rb
CHANGED
@@ -26,128 +26,24 @@ module Basecamp
|
|
26
26
|
@use_xml = false
|
27
27
|
end
|
28
28
|
|
29
|
-
# ==========================================================================
|
30
|
-
# GENERAL
|
31
|
-
# ==========================================================================
|
32
|
-
|
33
|
-
# Return the list of all accessible projects
|
34
|
-
def projects
|
35
|
-
records "project", "/project/list"
|
36
|
-
end
|
37
|
-
|
38
|
-
# Returns the list of message categories for the given project
|
39
|
-
def message_categories(project_id)
|
40
|
-
records "post-category", "/projects/#{project_id}/post_categories"
|
41
|
-
end
|
42
|
-
|
43
|
-
# Returns the list of file categories for the given project
|
44
|
-
def file_categories(project_id)
|
45
|
-
records "attachment-category", "/projects/#{project_id}/attachment_categories"
|
46
|
-
end
|
47
|
-
|
48
|
-
# ==========================================================================
|
49
|
-
# CONTACT MANAGEMENT
|
50
|
-
# ==========================================================================
|
51
|
-
|
52
|
-
# Return information for the company with the given id
|
53
|
-
def company(id)
|
54
|
-
record "/contacts/company/#{id}"
|
55
|
-
end
|
56
|
-
|
57
|
-
# Return an array of the people in the given company. If the project-id is
|
58
|
-
# given, only people who have access to the given project will be returned.
|
59
|
-
def people(company_id, project_id=nil)
|
60
|
-
url = project_id ? "/projects/#{project_id}" : ""
|
61
|
-
url << "/contacts/people/#{company_id}"
|
62
|
-
records "person", url
|
63
|
-
end
|
64
|
-
|
65
|
-
# Return information about the person with the given id
|
66
|
-
def person(id)
|
67
|
-
record "/contacts/person/#{id}"
|
68
|
-
end
|
69
|
-
|
70
|
-
# ==========================================================================
|
71
|
-
# MILESTONES
|
72
|
-
# ==========================================================================
|
73
|
-
|
74
|
-
# Complete the milestone with the given id
|
75
|
-
def complete_milestone(id)
|
76
|
-
record "/milestones/complete/#{id}"
|
77
|
-
end
|
78
|
-
|
79
|
-
# Create a new milestone for the given project. +data+ must be hash of the
|
80
|
-
# values to set, including +title+, +deadline+, +responsible_party+, and
|
81
|
-
# +notify+.
|
82
|
-
def create_milestone(project_id, data)
|
83
|
-
create_milestones(project_id, [data]).first
|
84
|
-
end
|
85
|
-
|
86
|
-
# As #create_milestone, but can create multiple milestones in a single
|
87
|
-
# request. The +milestones+ parameter must be an array of milestone values as
|
88
|
-
# descrbed in #create_milestone.
|
89
|
-
def create_milestones(project_id, milestones)
|
90
|
-
records "milestone", "/projects/#{project_id}/milestones/create", :milestone => milestones
|
91
|
-
end
|
92
|
-
|
93
|
-
# Destroys the milestone with the given id.
|
94
|
-
def delete_milestone(id)
|
95
|
-
record "/milestones/delete/#{id}"
|
96
|
-
end
|
97
|
-
|
98
|
-
# Returns a list of all milestones for the given project, optionally filtered
|
99
|
-
# by whether they are completed, late, or upcoming.
|
100
|
-
def milestones(project_id, find="all")
|
101
|
-
records "milestone", "/projects/#{project_id}/milestones/list", :find => find
|
102
|
-
end
|
103
|
-
|
104
|
-
# Uncomplete the milestone with the given id
|
105
|
-
def uncomplete_milestone(id)
|
106
|
-
record "/milestones/uncomplete/#{id}"
|
107
|
-
end
|
108
|
-
|
109
|
-
# Updates an existing milestone.
|
110
|
-
def update_milestone(id, data, move=false, move_off_weekends=false)
|
111
|
-
record "/milestones/update/#{id}", :milestone => data,
|
112
|
-
:move_upcoming_milestones => move,
|
113
|
-
:move_upcoming_milestones_off_weekends => move_off_weekends
|
114
|
-
end
|
115
|
-
|
116
|
-
private
|
117
|
-
|
118
29
|
# Make a raw web-service request to Basecamp. This will return a Hash of
|
119
30
|
# Arrays of the response, and may seem a little odd to the uninitiated.
|
120
31
|
def request(path, parameters = {})
|
121
32
|
response = Base.connection.post(path, convert_body(parameters), "Content-Type" => content_type)
|
122
|
-
|
33
|
+
|
123
34
|
if response.code.to_i / 100 == 2
|
124
35
|
result = XmlSimple.xml_in(response.body, 'keeproot' => true, 'contentkey' => '__content__', 'forcecontent' => true)
|
125
|
-
typecast_value(result)
|
36
|
+
typecast_value(result)
|
126
37
|
else
|
127
38
|
raise "#{response.message} (#{response.code})"
|
128
39
|
end
|
129
40
|
end
|
130
41
|
|
131
|
-
|
132
|
-
|
133
|
-
def record(path, parameters={})
|
134
|
-
result = request(path, parameters)
|
135
|
-
(result && !result.empty?) ? Record.new(result.keys.first, result.values.first) : nil
|
136
|
-
end
|
137
|
-
|
138
|
-
# A convenience method for wrapping the result of a query in Record
|
139
|
-
# objects. This assumes that the result is a collection--any singleton
|
140
|
-
# result will be wrapped in an array.
|
141
|
-
def records(node, path, parameters={})
|
142
|
-
result = request(path, parameters).values.first or return []
|
143
|
-
result = result[node] or return []
|
144
|
-
result = [result] unless Array === result
|
145
|
-
result.map { |row| Record.new(node, row) }
|
146
|
-
end
|
147
|
-
|
42
|
+
private
|
43
|
+
|
148
44
|
def convert_body(body)
|
149
45
|
body = use_xml ? body.to_legacy_xml : body.to_yaml
|
150
|
-
end
|
46
|
+
end
|
151
47
|
|
152
48
|
def content_type
|
153
49
|
use_xml ? "application/xml" : "application/x-yaml"
|
data/lib/basecamp/message.rb
CHANGED
@@ -3,30 +3,32 @@ module Basecamp
|
|
3
3
|
parent_resources :project
|
4
4
|
self.element_name = 'post'
|
5
5
|
|
6
|
-
# Returns the most recent 25 messages in the given project (and category,
|
7
|
-
# if specified). If you need to retrieve older messages, use the archive
|
8
|
-
# method instead. Example:
|
9
|
-
#
|
10
|
-
# Basecamp::Message.list(1037)
|
11
|
-
# Basecamp::Message.list(1037, :category_id => 7301)
|
12
|
-
#
|
13
|
-
def self.list(project_id, options = {})
|
14
|
-
find(:all, :params => options.merge(:project_id => project_id))
|
15
|
-
end
|
16
|
-
|
17
|
-
# Returns a summary of all messages in the given project (and category, if
|
18
|
-
# specified). The summary is simply the title and category of the message,
|
19
|
-
# as well as the number of attachments (if any). Example:
|
20
|
-
#
|
21
|
-
# Basecamp::Message.archive(1037)
|
22
|
-
# Basecamp::Message.archive(1037, :category_id => 7301)
|
23
|
-
#
|
24
|
-
def self.archive(project_id, options = {})
|
25
|
-
find(:all, :params => options.merge(:project_id => project_id), :from => :archive)
|
26
|
-
end
|
27
|
-
|
28
6
|
def comments(options = {})
|
29
7
|
@comments ||= Comment.find(:all, :params => options.merge(:post_id => id))
|
30
8
|
end
|
9
|
+
|
10
|
+
class << self
|
11
|
+
# Returns the most recent 25 messages in the given project (and category,
|
12
|
+
# if specified). If you need to retrieve older messages, use the archive
|
13
|
+
# method instead. Example:
|
14
|
+
#
|
15
|
+
# Basecamp::Message.list(1037)
|
16
|
+
# Basecamp::Message.list(1037, :category_id => 7301)
|
17
|
+
#
|
18
|
+
def list(project_id, options = {})
|
19
|
+
find(:all, :params => options.merge(:project_id => project_id))
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns a summary of all messages in the given project (and category, if
|
23
|
+
# specified). The summary is simply the title and category of the message,
|
24
|
+
# as well as the number of attachments (if any). Example:
|
25
|
+
#
|
26
|
+
# Basecamp::Message.archive(1037)
|
27
|
+
# Basecamp::Message.archive(1037, :category_id => 7301)
|
28
|
+
#
|
29
|
+
def archive(project_id, options = {})
|
30
|
+
find(:all, :params => options.merge(:project_id => project_id), :from => :archive)
|
31
|
+
end
|
32
|
+
end
|
31
33
|
end
|
32
34
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Basecamp
|
2
|
+
class Milestone < Record
|
3
|
+
# Updates an existing milestone.
|
4
|
+
def update_attributes(params = {})
|
5
|
+
data = params.dup
|
6
|
+
move = data.delete :move
|
7
|
+
move_off_weekends = data.delete :move_off_weekends
|
8
|
+
record "/milestones/update/#{id}",
|
9
|
+
:milestone => data,
|
10
|
+
:move_upcoming_milestones => move,
|
11
|
+
:move_upcoming_milestones_off_weekends => move_off_weekends
|
12
|
+
end
|
13
|
+
|
14
|
+
# Destroys the milestone
|
15
|
+
def destroy
|
16
|
+
record "/milestones/delete/#{id}"
|
17
|
+
end
|
18
|
+
|
19
|
+
# Complete the milestone
|
20
|
+
def complete!
|
21
|
+
record "/milestones/complete/#{id}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# Uncomplete the milestone
|
25
|
+
def uncomplete!
|
26
|
+
record "/milestones/uncomplete/#{id}"
|
27
|
+
end
|
28
|
+
|
29
|
+
class << self
|
30
|
+
def list(project_id, find = "all")
|
31
|
+
records "/projects/#{project_id}/milestones/list", :find => find
|
32
|
+
end
|
33
|
+
|
34
|
+
# Create a new milestone for the given project. +data+ must be hash of the
|
35
|
+
# values to set, including +title+, +deadline+, +responsible_party+, and
|
36
|
+
# +notify+.
|
37
|
+
def create(project_id, data = {})
|
38
|
+
create_milestones(project_id, [data]).first
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
# As #create_milestone, but can create multiple milestones in a single
|
43
|
+
# request. The +milestones+ parameter must be an array of milestone values as
|
44
|
+
# descrbed in #create_milestone.
|
45
|
+
def create_milestones(project_id, milestones)
|
46
|
+
records "/projects/#{project_id}/milestones/create", :milestone => milestones
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Basecamp
|
2
|
+
class Person < Record
|
3
|
+
class << self
|
4
|
+
# Return an array of the people in the given company. If the project-id is
|
5
|
+
# given, only people who have access to the given project will be returned.
|
6
|
+
def list(company_id, project_id = nil)
|
7
|
+
url = project_id ? "/projects/#{project_id}" : ""
|
8
|
+
url << "/contacts/people/#{company_id}"
|
9
|
+
records url
|
10
|
+
end
|
11
|
+
|
12
|
+
# Return information about the person with the given id
|
13
|
+
def find(id)
|
14
|
+
record "/contacts/person/#{id}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Basecamp
|
2
|
+
class Project < Record
|
3
|
+
class << self
|
4
|
+
# Return the list of all accessible projects
|
5
|
+
def list
|
6
|
+
records "/project/list"
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
# def messages(options = {})
|
11
|
+
# Message.list(id, options)
|
12
|
+
# end
|
13
|
+
#
|
14
|
+
# def message_archive(options = {})
|
15
|
+
# @message_archive ||= Message.archive(id, options)
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
# def milestones(find="all")
|
19
|
+
# Milestone.list(id, find)
|
20
|
+
# end
|
21
|
+
end
|
22
|
+
end
|
data/lib/basecamp/record.rb
CHANGED
@@ -1,20 +1,22 @@
|
|
1
1
|
module Basecamp
|
2
2
|
class Record #:nodoc:
|
3
3
|
attr_reader :type
|
4
|
-
|
5
|
-
def initialize(
|
6
|
-
|
4
|
+
|
5
|
+
def initialize(hash)
|
6
|
+
# type = self.class.to_s
|
7
|
+
@hash = hash
|
7
8
|
end
|
8
9
|
|
9
10
|
def [](name)
|
10
|
-
name =
|
11
|
+
name = name.to_s.dasherize
|
11
12
|
|
12
13
|
case @hash[name]
|
13
14
|
when Hash then
|
15
|
+
puts @hash[name].inspect
|
14
16
|
@hash[name] = if (@hash[name].keys.length == 1 && @hash[name].values.first.is_a?(Array))
|
15
|
-
@hash[name].values.first.map { |v|
|
17
|
+
@hash[name].values.first.map { |v| self.class.new_with_type(@hash[name].keys.first, v) }
|
16
18
|
else
|
17
|
-
|
19
|
+
self.class.new_with_type(name, @hash[name])
|
18
20
|
end
|
19
21
|
else
|
20
22
|
@hash[name]
|
@@ -30,7 +32,7 @@ module Basecamp
|
|
30
32
|
end
|
31
33
|
|
32
34
|
def respond_to?(sym)
|
33
|
-
super || @hash.has_key?(
|
35
|
+
super || @hash.has_key?(sym.to_s.dasherize)
|
34
36
|
end
|
35
37
|
|
36
38
|
def method_missing(sym, *args)
|
@@ -42,17 +44,44 @@ module Basecamp
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def to_s
|
45
|
-
"\#<Record(#{
|
47
|
+
"\#<Record(#{self.class}) #{@hash.inspect[1..-2]}>"
|
46
48
|
end
|
47
49
|
|
48
50
|
def inspect
|
49
51
|
to_s
|
50
52
|
end
|
51
53
|
|
52
|
-
|
53
|
-
|
54
|
-
def
|
55
|
-
|
54
|
+
# A convenience method for wrapping the result of a query in a Record
|
55
|
+
# object. This assumes that the result is a singleton, not a collection.
|
56
|
+
def record(path, parameters = {})
|
57
|
+
self.class.record(path, parameters)
|
56
58
|
end
|
57
|
-
|
59
|
+
|
60
|
+
class << self
|
61
|
+
def new_with_type(type, hash)
|
62
|
+
"Basecamp::#{type.classify}".constantize.new(hash)
|
63
|
+
end
|
64
|
+
|
65
|
+
def record(path, parameters = {})
|
66
|
+
result = Basecamp::Base.new.request(path, parameters)
|
67
|
+
(result && !result.empty?) ? new(result.values.first) : nil
|
68
|
+
end
|
69
|
+
|
70
|
+
# A convenience method for wrapping the result of a query in Record
|
71
|
+
# objects. This assumes that the result is a collection--any singleton
|
72
|
+
# result will be wrapped in an array.
|
73
|
+
def records(path, parameters = {})
|
74
|
+
result = Basecamp::Base.new.request(path, parameters)
|
75
|
+
node_singular = name.demodulize.underscore.dasherize
|
76
|
+
node_plural = node_singular.pluralize
|
77
|
+
|
78
|
+
# FIX: rename FileCategory class to AttachmentCategory
|
79
|
+
# node_plural = 'attachment-categories' if node_plural == 'file-categories'
|
80
|
+
|
81
|
+
result = result[node_plural][node_singular] or return []
|
82
|
+
result = [result] unless Array === result
|
83
|
+
result.map { |row| new(row) }
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
58
87
|
end
|
data/lib/basecamp/resource.rb
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
module Basecamp
|
2
2
|
class Resource < ActiveResource::Base #:nodoc:
|
3
|
+
def prefix_options
|
4
|
+
id ? {} : super
|
5
|
+
end
|
6
|
+
|
3
7
|
class << self
|
4
8
|
def parent_resources(*parents)
|
5
9
|
@parent_resources = parents
|
6
10
|
end
|
7
|
-
|
11
|
+
|
8
12
|
def element_name
|
9
13
|
name.split(/::/).last.underscore
|
10
14
|
end
|
11
|
-
|
15
|
+
|
12
16
|
def prefix_source
|
13
17
|
@parent_resources.map { |resource| "/#{resource.to_s.pluralize}/:#{resource}_id/" }.join
|
14
18
|
end
|
15
|
-
|
19
|
+
|
16
20
|
def prefix(options={})
|
17
21
|
if options.any?
|
18
22
|
options.map { |name, value| "/#{name.to_s.chomp('_id').pluralize}/#{value}/" }.join
|
19
23
|
else
|
20
|
-
|
24
|
+
'/'
|
21
25
|
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def prefix_options
|
26
|
-
id ? {} : super
|
26
|
+
end
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
data/lib/basecamp/time_entry.rb
CHANGED
@@ -1,17 +1,19 @@
|
|
1
1
|
module Basecamp
|
2
2
|
class TimeEntry < Resource
|
3
3
|
parent_resources :project, :todo_item
|
4
|
-
|
5
|
-
def
|
6
|
-
|
4
|
+
|
5
|
+
def todo_item(options={})
|
6
|
+
@todo_item ||= todo_item_id && TodoItem.find(todo_item_id, options)
|
7
7
|
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def all(project_id, page=0)
|
11
|
+
find(:all, :params => { :project_id => project_id, :page => page })
|
12
|
+
end
|
8
13
|
|
9
|
-
|
10
|
-
|
14
|
+
def report(options={})
|
15
|
+
find(:all, :from => :report, :params => options)
|
16
|
+
end
|
11
17
|
end
|
12
|
-
|
13
|
-
def todo_item(options={})
|
14
|
-
@todo_item ||= todo_item_id && TodoItem.find(todo_item_id, options)
|
15
|
-
end
|
16
18
|
end
|
17
19
|
end
|
data/lib/basecamp/todoitem.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
module Basecamp
|
2
2
|
class TodoItem < Resource
|
3
3
|
parent_resources :todo_list
|
4
|
-
|
4
|
+
|
5
5
|
def todo_list(options={})
|
6
|
-
@todo_list ||= TodoList.find(todo_list_id, options)
|
6
|
+
@todo_list ||= TodoList.find(self.todo_list_id, options)
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def time_entries(options={})
|
10
10
|
@time_entries ||= TimeEntry.find(:all, :params => options.merge(:todo_item_id => id))
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
def comments(options = {})
|
14
14
|
@comments ||= Comment.find(:all, :params => options.merge(:todo_item_id => id))
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
def complete!
|
18
18
|
put(:complete)
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
21
|
def uncomplete!
|
22
22
|
put(:uncomplete)
|
23
23
|
end
|
data/lib/basecamp/todolist.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
1
|
module Basecamp
|
2
2
|
class TodoList < Resource
|
3
3
|
parent_resources :project
|
4
|
-
|
5
|
-
# Returns all lists for a project. If complete is true, only completed lists
|
6
|
-
# are returned. If complete is false, only uncompleted lists are returned.
|
7
|
-
def self.all(project_id, complete=nil)
|
8
|
-
filter = case complete
|
9
|
-
when nil then "all"
|
10
|
-
when true then "finished"
|
11
|
-
when false then "pending"
|
12
|
-
else raise ArgumentError, "invalid value for `complete'"
|
13
|
-
end
|
14
|
-
|
15
|
-
find(:all, :params => { :project_id => project_id, :filter => filter })
|
16
|
-
end
|
17
|
-
|
4
|
+
|
18
5
|
def todo_items(options={})
|
19
6
|
@todo_items ||= TodoItem.find(:all, :params => options.merge(:todo_list_id => id))
|
20
7
|
end
|
8
|
+
|
9
|
+
class << self
|
10
|
+
# Returns all lists for a project. If complete is true, only completed lists
|
11
|
+
# are returned. If complete is false, only uncompleted lists are returned.
|
12
|
+
def all(project_id, complete=nil)
|
13
|
+
filter = case complete
|
14
|
+
when nil then "all"
|
15
|
+
when true then "finished"
|
16
|
+
when false then "pending"
|
17
|
+
else raise ArgumentError, "invalid value for `complete'"
|
18
|
+
end
|
19
|
+
|
20
|
+
find(:all, :params => { :project_id => project_id, :filter => filter })
|
21
|
+
end
|
22
|
+
end
|
21
23
|
end
|
22
24
|
end
|
data/lib/basecamp/version.rb
CHANGED
data/lib/basecamp.rb
CHANGED
@@ -8,11 +8,17 @@ require 'activeresource'
|
|
8
8
|
|
9
9
|
require 'basecamp/base'
|
10
10
|
require 'basecamp/resource'
|
11
|
+
require 'basecamp/record'
|
11
12
|
require 'basecamp/attachment'
|
12
13
|
require 'basecamp/comment'
|
14
|
+
require 'basecamp/company'
|
13
15
|
require 'basecamp/connection'
|
16
|
+
require 'basecamp/file_category'
|
14
17
|
require 'basecamp/message'
|
15
|
-
require 'basecamp/
|
18
|
+
require 'basecamp/milestone'
|
19
|
+
require 'basecamp/project'
|
20
|
+
require 'basecamp/person'
|
21
|
+
require 'basecamp/post_category'
|
16
22
|
require 'basecamp/time_entry'
|
17
23
|
require 'basecamp/todoitem'
|
18
24
|
require 'basecamp/todolist'
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper.rb'
|
2
|
+
|
3
|
+
describe Basecamp::AttachmentCategory do
|
4
|
+
before(:each) do
|
5
|
+
establish_connection
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should return the list of file categories for the given project" do
|
9
|
+
list = Basecamp::AttachmentCategory.list(TEST_PROJECT_ID)
|
10
|
+
list.should be_kind_of(Array)
|
11
|
+
end
|
12
|
+
end
|