taskmapper-basecamp 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.
Files changed (48) hide show
  1. data/.document +5 -0
  2. data/.travis.yml +4 -0
  3. data/Gemfile +15 -0
  4. data/Gemfile.lock +52 -0
  5. data/LICENSE +20 -0
  6. data/README.md +63 -0
  7. data/Rakefile +41 -0
  8. data/VERSION +1 -0
  9. data/lib/basecamp/basecamp.rb +655 -0
  10. data/lib/provider/basecamp.rb +39 -0
  11. data/lib/provider/comment.rb +63 -0
  12. data/lib/provider/project.rb +94 -0
  13. data/lib/provider/ticket.rb +162 -0
  14. data/lib/taskmapper-basecamp.rb +5 -0
  15. data/spec/comments_spec.rb +103 -0
  16. data/spec/fixtures/comments/74197051.json +1 -0
  17. data/spec/fixtures/comments/74197051.xml +14 -0
  18. data/spec/fixtures/comments/74197096.json +1 -0
  19. data/spec/fixtures/comments/74197096.xml +14 -0
  20. data/spec/fixtures/comments.json +1 -0
  21. data/spec/fixtures/comments.xml +47 -0
  22. data/spec/fixtures/project_count.json +1 -0
  23. data/spec/fixtures/project_count.xml +5 -0
  24. data/spec/fixtures/projects/5220065.json +1 -0
  25. data/spec/fixtures/projects/5220065.xml +16 -0
  26. data/spec/fixtures/projects/create.json +1 -0
  27. data/spec/fixtures/projects/create.xml +2 -0
  28. data/spec/fixtures/projects.json +1 -0
  29. data/spec/fixtures/projects.xml +19 -0
  30. data/spec/fixtures/todo_items/62509330_todo_item.xml +15 -0
  31. data/spec/fixtures/todo_list_9972756.xml +14 -0
  32. data/spec/fixtures/todo_list_with_items.json +1 -0
  33. data/spec/fixtures/todo_list_with_items.xml +3477 -0
  34. data/spec/fixtures/todo_lists/9972756_items.json +1 -0
  35. data/spec/fixtures/todo_lists/9972756_items.xml +93 -0
  36. data/spec/fixtures/todo_lists/9973518_items.json +1 -0
  37. data/spec/fixtures/todo_lists/9973518_items.xml +98 -0
  38. data/spec/fixtures/todo_lists/create.json +1 -0
  39. data/spec/fixtures/todo_lists/create.xml +14 -0
  40. data/spec/fixtures/todo_lists.json +1 -0
  41. data/spec/fixtures/todo_lists.xml +29 -0
  42. data/spec/projects_spec.rb +83 -0
  43. data/spec/spec.opts +1 -0
  44. data/spec/spec_helper.rb +15 -0
  45. data/spec/taskmapper-basecamp_spec.rb +20 -0
  46. data/spec/tickets_spec.rb +87 -0
  47. data/taskmapper-basecamp.gemspec +100 -0
  48. metadata +201 -0
@@ -0,0 +1,63 @@
1
+ module TaskMapper::Provider
2
+ module Basecamp
3
+ # The comment class for taskmapper-basecamp
4
+ #
5
+ # Do any mapping between taskmapper and your system's comment model here
6
+ # versions of the ticket.
7
+ #
8
+ class Comment < TaskMapper::Provider::Base::Comment
9
+ # declare needed overloaded methods here
10
+ API = BasecampAPI::Comment
11
+
12
+ def initialize(*object)
13
+ if object.first
14
+ object = object.first
15
+ unless object.is_a? Hash
16
+ hash = {:id => object.id,
17
+ :body => object.body,
18
+ :author => object.author_name,
19
+ :created_at => object.created_at,
20
+ :project_id => object.project_id,
21
+ :ticket_id => object.ticket_id}
22
+ else
23
+ hash = object
24
+ end
25
+ super hash
26
+ end
27
+ end
28
+
29
+ def self.find_by_id(project_id, ticket_id, id)
30
+ basecamp_comment = self::API.find(id, :params => {:todo_item_id => ticket_id})
31
+ self.new basecamp_comment.attributes.merge!(:project_id => project_id, :ticket_id => ticket_id)
32
+ end
33
+
34
+ def self.find_by_attributes(project_id, ticket_id, attributes = {})
35
+ self.search(project_id, ticket_id, attributes)
36
+ end
37
+
38
+ def self.search(project_id, ticket_id, options = {}, limit = 1000)
39
+ comments = API.find(:all, :params => {:todo_item_id => ticket_id}).collect {|c| self.new(c.attributes.merge!(:project_id => project_id, :ticket_id => ticket_id)) }
40
+ search_by_attribute(comments, options, limit)
41
+ end
42
+
43
+ def self.create(ticket_id, attributes)
44
+ new_comment = API.new attributes.merge(:todo_item_id => ticket_id)
45
+ new_comment.save
46
+
47
+ reloaded_comment = find_bc_comment(ticket_id, new_comment.id)
48
+ self.new reloaded_comment.attributes.merge!(:ticket_id => ticket_id)
49
+ end
50
+
51
+ def save
52
+ bc_comment = self.class.find_bc_comment ticket_id, id
53
+ bc_comment.body = self.body
54
+ bc_comment.save
55
+ end
56
+
57
+ private
58
+ def self.find_bc_comment(ticket_id, id)
59
+ API.find id, :params => { :todo_item_id => ticket_id }
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,94 @@
1
+ module TaskMapper::Provider
2
+ module Basecamp
3
+ # Project class for taskampper-basecamp
4
+ #
5
+ # Remaps
6
+ #
7
+ # description => announcement
8
+ # created_at => created_on
9
+ # updated_at => last_changed_on
10
+ class Project < TaskMapper::Provider::Base::Project
11
+ API = BasecampAPI::Project
12
+
13
+ def initialize(*object)
14
+ if object.first
15
+ object = object.first
16
+ unless object.is_a? Hash
17
+ hash = {:id => object.id,
18
+ :created_at => created_on,
19
+ :updated_at => updated_on,
20
+ :description => object.announcement,
21
+ :name => object.name}
22
+
23
+ else
24
+ hash = object
25
+ end
26
+ super hash
27
+ end
28
+ end
29
+
30
+ def description
31
+ announcement
32
+ end
33
+
34
+ def description=(desc)
35
+ announcement = desc
36
+ end
37
+
38
+ def created_at
39
+ begin
40
+ created_on.to_time
41
+ rescue
42
+ created_on
43
+ end
44
+ end
45
+
46
+ def created_at=(created)
47
+ created_on = created
48
+ end
49
+
50
+ def updated_at
51
+ begin
52
+ last_changed_on.to_time
53
+ rescue
54
+ last_changed_on
55
+ end
56
+ end
57
+
58
+ def updated_at=(updated)
59
+ last_changed_on = updated
60
+ end
61
+
62
+ def ticket!(attributes_hash)
63
+ provider_parent(self.class)::Ticket.create attributes_hash.merge :project_id => id
64
+ end
65
+
66
+ def self.find_by_id(id)
67
+ self.new API.find(id)
68
+ end
69
+
70
+ def self.find_by_attributes(attributes = {})
71
+ self.search(attributes)
72
+ end
73
+
74
+ def self.search(options = {}, limit = 1000)
75
+ projects = API.find(:all).collect { |project| self.new project }
76
+ search_by_attribute(projects, options, limit)
77
+ end
78
+
79
+ # copy from this.copy(that) copies that into this
80
+ def copy(project)
81
+ project.tickets.each do |ticket|
82
+ copy_ticket = self.ticket!(:title => ticket.title, :description => ticket.description)
83
+ ticket.comments.each do |comment|
84
+ copy_ticket.comment!(:body => comment.body)
85
+ sleep 1
86
+ end
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
93
+
94
+
@@ -0,0 +1,162 @@
1
+ module TaskMapper::Provider
2
+ module Basecamp
3
+ # Ticket class for taskmapper-basecamp
4
+ #
5
+ #
6
+ # * status => completed (either completed or incomplete)
7
+ # * priority => position
8
+ # * title => TodoList#name - TodoItem#content (up to 100 characters)
9
+ # * resolution => completed (either completed or '')
10
+ # * updated_at => completed_on
11
+ # * description => content
12
+ # * assignee => responsible_party_name (read-only)
13
+ # * requestor => creator_name (read-only)
14
+ # * project_id
15
+ class Ticket < TaskMapper::Provider::Base::Ticket
16
+ def initialize(*options)
17
+ @system_data ||= {}
18
+ @cache ||= {}
19
+ first = options.first
20
+ case first
21
+ when Hash
22
+ super(first.to_hash)
23
+ else
24
+ @system_data[:client] = first
25
+ super(first.attributes)
26
+ end
27
+ end
28
+
29
+ class << self
30
+
31
+ def find_by_id(project_id, id)
32
+ find_by_attributes(project_id, {:id => id}).first
33
+ end
34
+
35
+ def find_by_attributes(project_id, attributes = {})
36
+ search(project_id, attributes)
37
+ end
38
+
39
+ def search(project_id, options = {}, limit = 1000)
40
+ tickets = todo_items(project_id).map {|ti| self.new ti.attributes.merge :project_id => project_id }
41
+ search_by_attribute(tickets, options, limit)
42
+ end
43
+
44
+ # It expects a single hash
45
+ def create(attributes_hash)
46
+ todo_item_hash = create_todo_item_hash attributes_hash
47
+ todo_item = create_todo_item todo_item_hash
48
+
49
+ return nil unless todo_item.save
50
+
51
+ todo_item.project_id = attributes_hash[:project_id]
52
+ todo_item.todo_list_id = todo_item_hash[:todo_list_id]
53
+ self.new(todo_item)
54
+ end
55
+
56
+ private
57
+ def all_todo_lists
58
+ BasecampAPI::TodoListWithItems.find(:all, :params => {:responsible_party => ''})
59
+ end
60
+
61
+ def project_todo_lists(project_id)
62
+ all_todo_lists.select {|l| l.project_id == project_id }
63
+ end
64
+
65
+ def todo_items(project_id)
66
+ project_todo_lists(project_id).map { |l| l.todo_items }.flatten
67
+ end
68
+
69
+
70
+ def create_todo_item_hash(ticket_hash)
71
+ a = ticket_hash
72
+ validate_ticket_hash a
73
+ todo_item_hash = {
74
+ :content => a[:title],
75
+ :position => a[:priority] || 1,
76
+ :todo_list_id => a[:todo_list_id] || create_todo_list({
77
+ :project_id => a[:project_id],
78
+ :name => "#{a[:title]} list"}).id
79
+ }
80
+ end
81
+
82
+ def create_todo_item(attributes_hash)
83
+ BasecampAPI::TodoItem.new(attributes_hash)
84
+ end
85
+
86
+ def validate_ticket_hash(attributes_hash)
87
+ title = attributes_hash[:title]
88
+ raise ArgumentError.new "Title is required" if title.nil? or title.empty?
89
+ end
90
+
91
+ def create_todo_list(attributes)
92
+ BasecampAPI::TodoList.create(attributes)
93
+ end
94
+ end
95
+
96
+ def copy_to(todo_item)
97
+ todo_item.completed = status
98
+ todo_item.position = priority
99
+ todo_item.name = title
100
+ todo_item.content = title
101
+ todo_item.completed = resolution
102
+ todo_item.responsible_party_name = assignee
103
+ todo_item.creator_name = requestor
104
+ todo_item
105
+ end
106
+
107
+ def save
108
+ todo_item = BasecampAPI::TodoItem.find id, :params => { :todo_list_id => todo_list_id }
109
+ copy_to(todo_item).save
110
+ end
111
+
112
+ def todo_list_id
113
+ self['todo_list_id'].to_i
114
+ end
115
+
116
+ def status
117
+ self.completed ? 'completed' : 'incomplete'
118
+ end
119
+
120
+ def priority
121
+ self.position
122
+ end
123
+
124
+ def priority=(pri)
125
+ self.position = pri
126
+ end
127
+
128
+ def title
129
+ self.content
130
+ end
131
+
132
+ def title=(titl)
133
+ self.content = titl
134
+ end
135
+
136
+ def updated_at=(comp)
137
+ self.completed_on = comp
138
+ end
139
+
140
+ def description
141
+ self.content
142
+ end
143
+
144
+ def description=(desc)
145
+ self.content = desc
146
+ end
147
+
148
+ def assignee
149
+ self.responsible_party_name
150
+ end
151
+
152
+ def requestor
153
+ self.creator_name
154
+ end
155
+
156
+ def comment!(attributes)
157
+ Comment.create id, attributes
158
+ end
159
+
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/basecamp/basecamp.rb'
2
+
3
+ %w{ basecamp ticket project comment }.each do |f|
4
+ require File.dirname(__FILE__) + '/provider/' + f + '.rb';
5
+ end
@@ -0,0 +1,103 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe TaskMapper::Provider::Basecamp::Comment do
4
+ let(:project_id) { 5220065 }
5
+ let(:ticket_id) {133184178 }
6
+ let(:tm) { TaskMapper.new(:basecamp, :domain => 'ticketmaster.basecamphq.com', :token => '000000') }
7
+ let(:comment_class) { TaskMapper::Provider::Basecamp::Comment }
8
+ let(:comment_id) { 74197051 }
9
+
10
+ before(:each) do
11
+ @headers = {'Authorization' => 'Basic MDAwMDAwOkJhc2VjYW1w'}
12
+ gheaders = @headers.merge 'Accept' => 'application/xml'
13
+
14
+ ActiveResource::HttpMock.respond_to do |mock|
15
+ mock.get '/projects/5220065.xml', @headers, fixture_for('projects/5220065'), 200
16
+ mock.get '/todo_lists.xml?responsible_party=', @headers, fixture_for('todo_list_with_items'), 200
17
+ end
18
+ @project = tm.project(project_id)
19
+ @ticket = @project.ticket(ticket_id)
20
+ end
21
+
22
+ describe "Retrieving comments" do
23
+ before(:each) do
24
+ ActiveResource::HttpMock.respond_to do |mock|
25
+ mock.get '/todo_items/133184178/comments.xml', @headers, fixture_for('comments'), 200
26
+ mock.get '/todo_items/133184178/comments/74197051.xml', @headers, fixture_for('comments/74197051'), 200
27
+ mock.get '/todo_items/133184178/comments/74197096.xml', @headers, fixture_for('comments/74197096'), 200
28
+ end
29
+ end
30
+
31
+ context "when #comments is call to a ticket instance" do
32
+ subject { @ticket.comments }
33
+ it { should be_an_instance_of(Array) }
34
+ it { subject.first.should be_an_instance_of(comment_class) }
35
+ end
36
+
37
+ context "when #comments is call to a ticket instance with an array of id's as parameters" do
38
+ subject { @ticket.comments([74197051, 74197096]) }
39
+ it { should be_an_instance_of(Array) }
40
+ it { subject.first.should be_an_instance_of(comment_class) }
41
+ it { subject.first.id.should be_eql(74197051) }
42
+ it { subject.last.id.should be_eql(74197096) }
43
+ end
44
+
45
+ context "when #comments is call to a ticket instance with comments attributes as parameters" do
46
+ subject { @ticket.comments(:id => comment_id) }
47
+ it { should be_an_instance_of(Array) }
48
+ it { subject.first.should be_an_instance_of(comment_class) }
49
+ it { subject.first.id.should be_eql(comment_id) }
50
+ end
51
+ end
52
+
53
+ describe "Retrieve a single comment from a ticket" do
54
+ before(:each) do
55
+ ActiveResource::HttpMock.respond_to do |mock|
56
+ mock.get '/todo_items/133184178/comments.xml', @headers, fixture_for('comments'), 200
57
+ mock.get '/todo_items/133184178/comments/74197051.xml', @headers, fixture_for('comments/74197051'), 200
58
+ end
59
+ end
60
+
61
+ context "when #comment is call with a comment id" do
62
+ subject { @ticket.comment(comment_id) }
63
+ it { should be_an_instance_of(comment_class) }
64
+ it { subject.id.should be_eql(comment_id) }
65
+ end
66
+
67
+ context "when #comment is call with an attribute" do
68
+ subject { @ticket.comment(:id => comment_id) }
69
+ it { should be_an_instance_of(comment_class) }
70
+ it { subject.id.should be_eql(comment_id) }
71
+ end
72
+ end
73
+
74
+ describe "Create and update a comment for a ticket" do
75
+ before(:each) do
76
+ pheaders = @headers.merge 'Content-Type'=>'application/xml'
77
+ ActiveResource::HttpMock.respond_to do |mock|
78
+ mock.get '/todo_items/133184178/comments/74197051.xml', @headers, fixture_for('comments/74197051'), 200
79
+ mock.get '/todo_items/133184178/comments.xml', @headers, fixture_for('comments'), 200
80
+ mock.put '/todo_items/133184178/comments/74197051.xml', @headers, '', 200
81
+ mock.post '/todo_items/133184178/comments.xml', pheaders, fixture_for('comments/74197051'), 200
82
+ end
83
+ end
84
+
85
+ context "when a comment is changed and then called the #save on it" do
86
+ it do
87
+ comment = @ticket.comment(comment_id)
88
+ comment.body = "updated comment"
89
+ comment.save.should be_true
90
+ comment.body.should be_eql("updated comment")
91
+ end
92
+ end
93
+
94
+ context "when #comment! is call" do
95
+ subject { @ticket.comment!(:body => 'hello there boys and girls') }
96
+ it { should be_an_instance_of(comment_class) }
97
+ it { subject.body.should_not be_nil }
98
+ it { subject.id.should_not be_nil }
99
+ it { subject.ticket_id.should_not be_nil }
100
+ end
101
+ end
102
+
103
+ end
@@ -0,0 +1 @@
1
+ {"comment":{"attachments_count":0,"author_id":5654019,"body":"<div>Hello There<br /></div>","commentable_id":62509330,"commentable_type":"TodoItem","created_at":"2010-07-23 23:13:39 UTC","emailed_from":null,"id":74197051,"author_name":"Kia Kroas","attachments":[]}}
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comment>
3
+ <attachments-count type="integer">0</attachments-count>
4
+ <author-id type="integer">5654019</author-id>
5
+ <body>&lt;div&gt;Hello There&lt;br /&gt;&lt;/div&gt;</body>
6
+ <commentable-id type="integer">62509330</commentable-id>
7
+ <commentable-type>TodoItem</commentable-type>
8
+ <created-at type="datetime">2010-07-23T23:13:39Z</created-at>
9
+ <emailed-from nil="true"></emailed-from>
10
+ <id type="integer">74197051</id>
11
+ <author-name>Kia Kroas</author-name>
12
+ <attachments type="array"/>
13
+ </comment>
14
+
@@ -0,0 +1 @@
1
+ {"comment":{"attachments_count":0,"author_id":5654019,"body":"<div>Something's off.<br /></div>","commentable_id":62509330,"commentable_type":"TodoItem","created_at":"2010-07-23 23:14:24 UTC","emailed_from":null,"id":74197096,"author_name":"Kia Kroas","attachments":[]}}
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comment>
3
+ <attachments-count type="integer">0</attachments-count>
4
+ <author-id type="integer">5654019</author-id>
5
+ <body>&lt;div&gt;Something's off.&lt;br /&gt;&lt;/div&gt;</body>
6
+ <commentable-id type="integer">62509330</commentable-id>
7
+ <commentable-type>TodoItem</commentable-type>
8
+ <created-at type="datetime">2010-07-23T23:14:24Z</created-at>
9
+ <emailed-from nil="true"></emailed-from>
10
+ <id type="integer">74197096</id>
11
+ <author-name>Kia Kroas</author-name>
12
+ <attachments type="array"/>
13
+ </comment>
14
+
@@ -0,0 +1 @@
1
+ {"comments":[{"attachments_count":0,"author_id":5654019,"body":"<div>Hello There<br /></div>","commentable_id":62509330,"commentable_type":"TodoItem","created_at":"2010-07-23 23:13:39 UTC","emailed_from":null,"id":74197051,"author_name":"Kia Kroas"},{"attachments_count":0,"author_id":5654019,"body":"<div>Hm, why is the title different?<br /></div>","commentable_id":62509330,"commentable_type":"TodoItem","created_at":"2010-07-23 23:14:06 UTC","emailed_from":null,"id":74197080,"author_name":"Kia Kroas"},{"attachments_count":0,"author_id":5654019,"body":"<div>This doesn't seem right.<br /></div>","commentable_id":62509330,"commentable_type":"TodoItem","created_at":"2010-07-23 23:14:16 UTC","emailed_from":null,"id":74197085,"author_name":"Kia Kroas"},{"attachments_count":0,"author_id":5654019,"body":"<div>Something's off.<br /></div>","commentable_id":62509330,"commentable_type":"TodoItem","created_at":"2010-07-23 23:14:24 UTC","emailed_from":null,"id":74197096,"author_name":"Kia Kroas"}]}
@@ -0,0 +1,47 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comments type="array" count="4">
3
+ <comment>
4
+ <attachments-count type="integer">0</attachments-count>
5
+ <author-id type="integer">5654019</author-id>
6
+ <body>&lt;div&gt;Hello There&lt;br /&gt;&lt;/div&gt;</body>
7
+ <commentable-id type="integer">62509330</commentable-id>
8
+ <commentable-type>TodoItem</commentable-type>
9
+ <created-at type="datetime">2010-07-23T23:13:39Z</created-at>
10
+ <emailed-from nil="true"></emailed-from>
11
+ <id type="integer">74197051</id>
12
+ <author-name>Kia Kroas</author-name>
13
+ </comment>
14
+ <comment>
15
+ <attachments-count type="integer">0</attachments-count>
16
+ <author-id type="integer">5654019</author-id>
17
+ <body>&lt;div&gt;Hm, why is the title different?&lt;br /&gt;&lt;/div&gt;</body>
18
+ <commentable-id type="integer">62509330</commentable-id>
19
+ <commentable-type>TodoItem</commentable-type>
20
+ <created-at type="datetime">2010-07-23T23:14:06Z</created-at>
21
+ <emailed-from nil="true"></emailed-from>
22
+ <id type="integer">74197080</id>
23
+ <author-name>Kia Kroas</author-name>
24
+ </comment>
25
+ <comment>
26
+ <attachments-count type="integer">0</attachments-count>
27
+ <author-id type="integer">5654019</author-id>
28
+ <body>&lt;div&gt;This doesn't seem right.&lt;br /&gt;&lt;/div&gt;</body>
29
+ <commentable-id type="integer">62509330</commentable-id>
30
+ <commentable-type>TodoItem</commentable-type>
31
+ <created-at type="datetime">2010-07-23T23:14:16Z</created-at>
32
+ <emailed-from nil="true"></emailed-from>
33
+ <id type="integer">74197085</id>
34
+ <author-name>Kia Kroas</author-name>
35
+ </comment>
36
+ <comment>
37
+ <attachments-count type="integer">0</attachments-count>
38
+ <author-id type="integer">5654019</author-id>
39
+ <body>&lt;div&gt;Something's off.&lt;br /&gt;&lt;/div&gt;</body>
40
+ <commentable-id type="integer">62509330</commentable-id>
41
+ <commentable-type>TodoItem</commentable-type>
42
+ <created-at type="datetime">2010-07-23T23:14:24Z</created-at>
43
+ <emailed-from nil="true"></emailed-from>
44
+ <id type="integer">74197096</id>
45
+ <author-name>Kia Kroas</author-name>
46
+ </comment>
47
+ </comments>
@@ -0,0 +1 @@
1
+ {"count":{"active":5,"on_hold":2,"archived":11}}
@@ -0,0 +1,5 @@
1
+ <count>
2
+ <active type="integer">5</active>
3
+ <on-hold type="integer">2</on-hold>
4
+ <archived type="integer">11</archived>
5
+ </count>
@@ -0,0 +1 @@
1
+ {"project":{"announcement":"Announcement.","created_on":"2010-07-20","id":5220065,"last_changed_on":"2010-07-23 06:31:39 UTC","name":"Ticketmaster-basecamp","show_announcement":false,"show_writeboards":true,"start_page":"log","status":"active","company":{"id":1971191,"name":"Kia Kroas"}}}
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project>
3
+ <announcement>Announcement.</announcement>
4
+ <created-on type="date">2010-07-20</created-on>
5
+ <id type="integer">5220065</id>
6
+ <last-changed-on type="datetime">2010-07-23T06:31:39Z</last-changed-on>
7
+ <name>Ticketmaster-basecamp</name>
8
+ <show-announcement type="boolean">false</show-announcement>
9
+ <show-writeboards type="boolean">true</show-writeboards>
10
+ <start-page>log</start-page>
11
+ <status>active</status>
12
+ <company>
13
+ <id type="integer">1971191</id>
14
+ <name>Kia Kroas</name>
15
+ </company>
16
+ </project>
@@ -0,0 +1 @@
1
+ {}
@@ -0,0 +1,2 @@
1
+
2
+
@@ -0,0 +1 @@
1
+ {"projects":[{"announcement":"Announcement.","created_on":"2010-07-20","id":5220065,"last_changed_on":"2010-07-23 06:31:39 UTC","name":"Ticketmaster-basecamp","show_announcement":false,"show_writeboards":true,"start_page":"log","status":"active","company":{"id":1971191,"name":"Kia Kroas"}}]}
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projects type="array">
3
+ <project>
4
+ <announcement>Announcement.</announcement>
5
+ <created-on type="date">2010-07-20</created-on>
6
+ <id type="integer">5220065</id>
7
+ <last-changed-on type="datetime">2010-07-23T06:31:39Z</last-changed-on>
8
+ <name>Ticketmaster-basecamp</name>
9
+ <show-announcement type="boolean">false</show-announcement>
10
+ <show-writeboards type="boolean">true</show-writeboards>
11
+ <start-page>log</start-page>
12
+ <status>active</status>
13
+ <company>
14
+ <id type="integer">1971191</id>
15
+ <name>Kia Kroas</name>
16
+ </company>
17
+ </project>
18
+ </projects>
19
+
@@ -0,0 +1,15 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <todo-item>
3
+ <comments-count type="integer">0</comments-count>
4
+ <completed type="boolean">false</completed>
5
+ <content>hudnthdau</content>
6
+ <created-at type="datetime">2010-07-21T01:14:34Z</created-at>
7
+ <updated-at type="datetime">2010-07-20T23:36:49Z</updated-at>
8
+ <creator-id type="integer">5654019</creator-id>
9
+ <due-at type="datetime" nil="true"></due-at>
10
+ <id type="integer">62509330</id>
11
+ <position type="integer">1</position>
12
+ <todo-list-id type="integer">9973518</todo-list-id>
13
+ <created-on type="datetime" deprecated="true">2010-07-21T01:14:34Z</created-on>
14
+ <creator-name>Kia Kroas</creator-name>
15
+ </todo-item>
@@ -0,0 +1,14 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <todo-list>
3
+ <completed-count type="integer">0</completed-count>
4
+ <description>etauhnotehunoteh tnheontu honetuh osneh noe hosneuh toneuh</description>
5
+ <id type="integer">9972756</id>
6
+ <milestone-id type="integer" nil="true"></milestone-id>
7
+ <name>Cheese</name>
8
+ <position type="integer">2</position>
9
+ <private type="boolean">false</private>
10
+ <project-id type="integer">5220065</project-id>
11
+ <tracked type="boolean">false</tracked>
12
+ <uncompleted-count type="integer">6</uncompleted-count>
13
+ <complete>false</complete>
14
+ </todo-list>