taskmapper-unfuddle 0.7.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/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm 1.9.2@taskmapper-unfuddle --create
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.8.7
4
+ - 1.9.2
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ gem "taskmapper", "~> 0.8"
7
+ gem "addressable", "~> 2.2"
8
+ # Add dependencies to develop your gem here.
9
+ # Include everything needed to run rake, tests, features, etc.
10
+ group :development do
11
+ gem "rspec", "~> 2.8"
12
+ gem "bundler", "~> 1.1"
13
+ gem "jeweler", "~> 1.6"
14
+ gem "simplecov", "~> 0.5", :platforms => :ruby_19
15
+ gem "rcov", "~> 1.0", :platforms => :ruby_18
16
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,57 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ activemodel (3.2.3)
5
+ activesupport (= 3.2.3)
6
+ builder (~> 3.0.0)
7
+ activeresource (3.2.3)
8
+ activemodel (= 3.2.3)
9
+ activesupport (= 3.2.3)
10
+ activesupport (3.2.3)
11
+ i18n (~> 0.6)
12
+ multi_json (~> 1.0)
13
+ addressable (2.2.8)
14
+ builder (3.0.0)
15
+ diff-lcs (1.1.3)
16
+ git (1.2.5)
17
+ hashie (1.2.0)
18
+ i18n (0.6.0)
19
+ jeweler (1.8.3)
20
+ bundler (~> 1.0)
21
+ git (>= 1.2.5)
22
+ rake
23
+ rdoc
24
+ json (1.7.3)
25
+ multi_json (1.3.5)
26
+ rake (0.9.2.2)
27
+ rcov (1.0.0)
28
+ rdoc (3.12)
29
+ json (~> 1.4)
30
+ rspec (2.10.0)
31
+ rspec-core (~> 2.10.0)
32
+ rspec-expectations (~> 2.10.0)
33
+ rspec-mocks (~> 2.10.0)
34
+ rspec-core (2.10.0)
35
+ rspec-expectations (2.10.0)
36
+ diff-lcs (~> 1.1.3)
37
+ rspec-mocks (2.10.1)
38
+ simplecov (0.6.4)
39
+ multi_json (~> 1.0)
40
+ simplecov-html (~> 0.5.3)
41
+ simplecov-html (0.5.3)
42
+ taskmapper (0.8.0)
43
+ activeresource (~> 3.0)
44
+ activesupport (~> 3.0)
45
+ hashie (~> 1.2)
46
+
47
+ PLATFORMS
48
+ ruby
49
+
50
+ DEPENDENCIES
51
+ addressable (~> 2.2)
52
+ bundler (~> 1.1)
53
+ jeweler (~> 1.6)
54
+ rcov (~> 1.0)
55
+ rspec (~> 2.8)
56
+ simplecov (~> 0.5)
57
+ taskmapper (~> 0.8)
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2010 Hybrid Group
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # taskmapper-unfuddle
2
+
3
+ TaskMapper provider for Unfuddle.
4
+
5
+ ## Usage
6
+
7
+ Instantiate the TaskMapper instance
8
+
9
+ unfuddle = TaskMapper.new(:unfuddle, :username => "user", :password => "p4ss!", :account => 'unfud')
10
+
11
+ if this gives you trouble when trying to access projects or tickets, you can set the protocol explicitly. By default,
12
+ as of version 0.4.0, the protocol is 'https'. Some older projects may need to set to 'http'.
13
+
14
+ unfuddle = TaskMapper.new(:unfuddle, :username => "user", :password => "p4ss!", :account => 'unfud', :protocol => 'http')
15
+
16
+ ## Note on Patches/Pull Requests
17
+
18
+ * Fork the project.
19
+ * Make your feature addition or bug fix.
20
+ * Add tests for it. This is important so I don't break it in a
21
+ future version unintentionally.
22
+ * Commit, do not mess with rakefile, version, or history.
23
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
24
+ * Send me a pull request. Bonus points for topic branches.
25
+
26
+ ## Copyright
27
+
28
+ Copyright (c) 2010 [Hybrid Group](http://hybridgroup.com). See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "taskmapper-unfuddle"
8
+ gem.summary = %Q{The Unfuddle provider for taskmapper.}
9
+ gem.description = %Q{Unfuddle provider for taskmapper implemented with ActiveResource}
10
+ gem.email = "luis@hybridgroup.com"
11
+ gem.homepage = "http://github.com/hybridgroup/taskmapper-unfuddle"
12
+ gem.authors = ["Luis Hurtado"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ end
15
+ Jeweler::GemcutterTasks.new
16
+ rescue LoadError
17
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
18
+ end
19
+
20
+ require 'rspec/core'
21
+ require 'rspec/core/rake_task'
22
+ RSpec::Core::RakeTask.new(:spec) do |spec|
23
+ spec.pattern = FileList['spec/**/*_spec.rb']
24
+ end
25
+
26
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
27
+ spec.pattern = 'spec/**/*_spec.rb'
28
+ spec.rcov = true
29
+ end
30
+
31
+ task :default => :spec
32
+
33
+ require 'rake/rdoctask' # TODO This produces a warning
34
+ require 'rdoc/task'
35
+ Rake::RDocTask.new do |rdoc|
36
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
37
+
38
+ rdoc.rdoc_dir = 'rdoc'
39
+ rdoc.title = "taskmapper-kanbanpad#{version}"
40
+ rdoc.rdoc_files.include('README*')
41
+ rdoc.rdoc_files.include('lib/**/*.rb')
42
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.7.0
@@ -0,0 +1,45 @@
1
+ module TaskMapper::Provider
2
+ module Unfuddle
3
+ # The comment class for taskmapper-unfuddle
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
+ API = UnfuddleAPI::Comment # The class to access the api's comments
10
+ # declare needed overloaded methods here
11
+
12
+ def initialize(*options)
13
+ @system_data ||= {}
14
+ @cache ||= {}
15
+ first = options.shift
16
+ case first
17
+ when Hash
18
+ super first.to_hash
19
+ else
20
+ @system_data[:client] = first
21
+ super first.attributes.merge!(
22
+ :project_id => first.prefix_options[:project_id],
23
+ :ticket_id => first.prefix_options[:ticket_id])
24
+ end
25
+ end
26
+
27
+ def author
28
+ @author ||= begin
29
+ UnfuddleAPI::People.find(self[:author_id]).username
30
+ rescue
31
+ ''
32
+ end
33
+ end
34
+
35
+ def created_at
36
+ @created_at ||= self[:created_at] ? Time.parse(self[:created_at]) : nil
37
+ end
38
+
39
+ def updated_at
40
+ @updated_at ||= self[:updated_at] ? Time.parse(self[:updated_at]) : nil
41
+ end
42
+
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,50 @@
1
+ module TaskMapper::Provider
2
+ module Unfuddle
3
+ # Project class for taskmapper-unfuddle
4
+ #
5
+ #
6
+ class Project < TaskMapper::Provider::Base::Project
7
+ API = UnfuddleAPI::Project # The class to access the api's projects
8
+ # declare needed overloaded methods here
9
+
10
+ def initialize(*options)
11
+ @system_data ||= {}
12
+ @cache ||= {}
13
+ first = options.shift
14
+ case first
15
+ when Hash
16
+ super(first.to_hash)
17
+ else
18
+ @system_data[:client] = first
19
+ super(first.attributes)
20
+ end
21
+ end
22
+
23
+ def name
24
+ self.title
25
+ end
26
+
27
+ def created_at
28
+ @created_at ||= self[:created_at] ? Time.parse(self[:created_at]) : nil
29
+ end
30
+
31
+ def updated_at
32
+ @updated_at ||= self[:updated_at] ? Time.parse(self[:updated_at]) : nil
33
+ end
34
+
35
+ # copy from this.copy(that) copies that into this
36
+ def copy(project)
37
+ project.tickets.each do |ticket|
38
+ copy_ticket = self.ticket!(:title => ticket.title, :description => ticket.description)
39
+ ticket.comments.each do |comment|
40
+ copy_ticket.comment!(:body => comment.body)
41
+ sleep 1
42
+ end
43
+ end
44
+ end
45
+
46
+ end
47
+ end
48
+ end
49
+
50
+
@@ -0,0 +1,53 @@
1
+ module TaskMapper::Provider
2
+ module Unfuddle
3
+ # Ticket class for taskmapper-unfuddle
4
+ #
5
+
6
+ class Ticket < TaskMapper::Provider::Base::Ticket
7
+ API = UnfuddleAPI::Ticket # The class to access the api's tickets
8
+ # declare needed overloaded methods here
9
+
10
+ def initialize(*options)
11
+ @system_data ||= {}
12
+ @cache ||= {}
13
+ first = options.shift
14
+ case first
15
+ when Hash
16
+ super first.to_hash
17
+ else
18
+ @system_data[:client] = first
19
+ super first.attributes.merge! :project_id => first.prefix_options[:project_id]
20
+ end
21
+ end
22
+
23
+ def title
24
+ self.summary
25
+ end
26
+
27
+ def created_at
28
+ @created_at ||= self[:created_at] ? Time.parse(self[:created_at]) : nil
29
+ end
30
+
31
+ def updated_at
32
+ @updated_at ||= self[:updated_at] ? Time.parse(self[:updated_at]) : nil
33
+ end
34
+
35
+ def assignee
36
+ @assignee ||= begin
37
+ UnfuddleAPI::People.find(self[:assignee_id]).username
38
+ rescue
39
+ ''
40
+ end
41
+ end
42
+
43
+ def requestor
44
+ @requestor ||= begin
45
+ UnfuddleAPI::People.find(self[:reporter_id]).username
46
+ rescue
47
+ ''
48
+ end
49
+ end
50
+
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,39 @@
1
+ module TaskMapper::Provider
2
+ # This is the Unfuddle Provider for taskmapper
3
+ module Unfuddle
4
+ include TaskMapper::Provider::Base
5
+ TICKET_API = UnfuddleAPI::Ticket # The class to access the api's tickets
6
+ PROJECT_API = UnfuddleAPI::Project # The class to access the api's projects
7
+
8
+ # This is for cases when you want to instantiate using TaskMapper::Provider::Unfuddle.new(auth)
9
+ def self.new(auth = {})
10
+ TaskMapper.new(:unfuddle, auth)
11
+ end
12
+
13
+ # Providers must define an authorize method. This is used to initialize and set authentication
14
+ # parameters to access the API
15
+ def authorize(auth = {})
16
+ @authentication ||= TaskMapper::Authenticator.new(auth)
17
+ auth = @authentication
18
+ if (auth.account.nil? and auth.subdomain.nil?) or auth.username.nil? or auth.password.nil?
19
+ raise "Please provide at least an account (subdomain), username and password)"
20
+ end
21
+ UnfuddleAPI.protocol = auth.protocol if auth.protocol?
22
+ UnfuddleAPI.account = auth.account || auth.subdomain
23
+ UnfuddleAPI.authenticate(auth.username, auth.password)
24
+ end
25
+
26
+ # declare needed overloaded methods here
27
+
28
+ def valid?
29
+ begin
30
+ PROJECT_API.find(:first)
31
+ true
32
+ rescue
33
+ false
34
+ end
35
+ end
36
+ end
37
+ end
38
+
39
+
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/unfuddle/unfuddle-api'
2
+
3
+ %w{ unfuddle ticket project comment }.each do |f|
4
+ require File.dirname(__FILE__) + '/provider/' + f + '.rb';
5
+ end
@@ -0,0 +1,153 @@
1
+ require 'rubygems'
2
+
3
+ begin
4
+ require 'uri'
5
+ require 'addressable/uri'
6
+
7
+ module URI
8
+ def decode(*args)
9
+ Addressable::URI.decode(*args)
10
+ end
11
+
12
+ def escape(*args)
13
+ Addressable::URI.escape(*args)
14
+ end
15
+
16
+ def parse(*args)
17
+ Addressable::URI.parse(*args)
18
+ end
19
+ end
20
+ rescue LoadError => e
21
+ puts "Install the Addressable gem (with dependencies) to support accounts with subdomains."
22
+ puts "# sudo gem install addressable --development"
23
+ puts e.message
24
+ end
25
+
26
+ require 'active_support'
27
+ require 'active_resource'
28
+
29
+ # Ruby lib for working with the Unfuddle API's XML interface.
30
+ # The first thing you need to set is the account name. This is the same
31
+ # as the web address for your account.
32
+ #
33
+ # UnfuddleAPI.account = 'activereload'
34
+ #
35
+ # Then, you should set the authentication with HTTP Basic Authentication.
36
+ #
37
+ # # with basic authentication
38
+ # UnfuddleAPI.authenticate('rick', 'spacemonkey')
39
+ #
40
+ #
41
+ # This library is a small wrapper around the REST interface. You should read the docs at
42
+ # http://unfuddle.com/docs/api
43
+ #
44
+ module UnfuddleAPI
45
+ class Error < StandardError; end
46
+ class << self
47
+ attr_accessor :username, :password, :host_format, :domain_format, :protocol, :port
48
+ attr_reader :account
49
+
50
+ # Sets the account name, and updates all the resources with the new domain.
51
+ def account=(name)
52
+ resources.each do |klass|
53
+ klass.site = klass.site_format % (host_format % [protocol, domain_format % name, ":#{port}"])
54
+ end
55
+ @account = name
56
+ end
57
+
58
+ # Sets up basic authentication credentials for all the resources.
59
+ def authenticate(username, password)
60
+ @username = username
61
+ @password = password
62
+ self::Base.user = username
63
+ self::Base.password = password
64
+ end
65
+
66
+ def resources
67
+ @resources ||= []
68
+ end
69
+ end
70
+
71
+ self.host_format = '%s://%s%s/api/v1'
72
+ self.domain_format = '%s.unfuddle.com'
73
+ self.protocol = 'https'
74
+ self.port = ''
75
+
76
+ class Base < ActiveResource::Base
77
+ self.format = :xml
78
+ def self.inherited(base)
79
+ UnfuddleAPI.resources << base
80
+ class << base
81
+ attr_accessor :site_format
82
+ end
83
+ base.site_format = '%s'
84
+ super
85
+ end
86
+ end
87
+
88
+ # Find projects
89
+ #
90
+ # UnfuddleAPI::Project.find(:all) # find all projects for the current account.
91
+ # UnfuddleAPI::Project.find(44) # find individual project by ID
92
+ #
93
+ # Creating a Project
94
+ #
95
+ # project = UnfuddleAPI::Project.new(:name => 'Ninja Whammy Jammy')
96
+ # project.save
97
+ # # => true
98
+ #
99
+ #
100
+ # Updating a Project
101
+ #
102
+ # project = UnfuddleAPI::Project.find(44)
103
+ # project.name = "Lighthouse Issues"
104
+ # project.public = false
105
+ # project.save
106
+ #
107
+ # Finding tickets
108
+ #
109
+ # project = LighthouseAPI::Project.find(44)
110
+ # project.tickets
111
+ #
112
+ class Project < Base
113
+ def tickets(options = {})
114
+ Ticket.find(:all, :params => options.update(:project_id => id))
115
+ end
116
+
117
+ def messages(options = {})
118
+ Message.find(:all, :params => options.update(:project_id => id))
119
+ end
120
+
121
+ def milestones(options = {})
122
+ Milestone.find(:all, :params => options.update(:project_id => id))
123
+ end
124
+ end
125
+
126
+ # Find tickets
127
+ #
128
+ # UnfuddleAPI::Ticket.find(:all, :params => { :project_id => 44 })
129
+ # UnfuddleAPI::Ticket.find(:all, :params => { :project_id => 44, :q => "status:closed" })
130
+ #
131
+ # project = UnfuddleAPI::Project.find(44)
132
+ # project.tickets
133
+ # project.tickets(:q => "status:closed")
134
+ # project.tickets(:params => {:status => 'closed'})
135
+ #
136
+ #
137
+ #
138
+ class Ticket < Base
139
+ site_format << '/projects/:project_id'
140
+ end
141
+
142
+ class Comment < Base
143
+ site_format << '/projects/:project_id/tickets/:ticket_id'
144
+ end
145
+
146
+ class Message < Base
147
+ site_format << '/projects/:project_id'
148
+ end
149
+
150
+ class People < Base
151
+ end
152
+
153
+ end
@@ -0,0 +1,76 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
2
+
3
+ describe TaskMapper::Provider::Unfuddle::Comment do
4
+ before(:each) do
5
+ @headers = {'Authorization' => 'Basic Zm9vOjAwMDAwMA==', 'Accept' => 'application/xml'}
6
+ @headers_post_put = {'Authorization' => 'Basic Zm9vOjAwMDAwMA==', 'Content-Type' => 'application/xml'}
7
+ ActiveResource::HttpMock.respond_to do |mock|
8
+ mock.get '/api/v1/projects/33042.xml', @headers, fixture_for('projects/33042'), 200
9
+ mock.get '/api/v1/projects/33042/tickets/476834.xml', @headers, fixture_for('tickets/476834'), 200
10
+ end
11
+ @project = taskmapper.project(project_id)
12
+ @ticket = @project.ticket(ticket_id)
13
+ end
14
+ let(:project_id) { 33042 }
15
+ let(:ticket_id) { 476834 }
16
+ let(:taskmapper) { TaskMapper.new(:unfuddle, :account => 'taskmapper', :password => '000000', :username => 'foo') }
17
+ let(:comment_class) { TaskMapper::Provider::Unfuddle::Comment }
18
+
19
+ describe "Retrieving all comments" do
20
+ before(:each) do
21
+ ActiveResource::HttpMock.respond_to do |mock|
22
+ mock.get '/api/v1/projects/33042/tickets/476834/comments.xml', @headers, fixture_for('comments'), 200
23
+ mock.get '/api/v1/projects/33042/tickets/476834/comments/0.xml', @headers, fixture_for('comments/0'), 200
24
+ mock.get '/api/v1/projects/33042/tickets/476834/comments/2.xml', @headers, fixture_for('comments/2'), 200
25
+ mock.get '/api/v1/projects/33042/tickets/476834/comments/3.xml', @headers, fixture_for('comments/3'), 200
26
+ end
27
+ end
28
+
29
+ context "when calling #comments to a ticket instance" do
30
+ subject { @ticket.comments }
31
+ it { should be_an_instance_of Array }
32
+ it { subject.first.should be_an_instance_of comment_class }
33
+ end
34
+
35
+ context "when calling #comments with an array of id's" do
36
+ subject { @ticket.comments([0,2,3]) }
37
+ it { should be_an_instance_of Array }
38
+ it { subject.first.id.should be_eql 0 }
39
+ it { subject.last.id.should be_eql 3 }
40
+ end
41
+
42
+ context "when calling #comments with a hash of attributes" do
43
+ subject { @ticket.comments :parent_id => @ticket.id }
44
+ it { should be_an_instance_of Array }
45
+ it { subject.first.should be_an_instance_of comment_class }
46
+ it { subject.first.id.should be_eql 2 }
47
+ end
48
+ end
49
+
50
+ describe "Retrieve a single comment" do
51
+ before(:each) do
52
+ ActiveResource::HttpMock.respond_to do |mock|
53
+ mock.get '/api/v1/projects/33042/tickets/476834/comments/0.xml', @headers, fixture_for('comments/0'), 200
54
+ mock.get '/api/v1/projects/33042/tickets/476834/comments.xml', @headers, fixture_for('comments'), 200
55
+ end
56
+ end
57
+
58
+ context "when calling #comment with an id" do
59
+ subject { @ticket.comment 0 }
60
+ it { should be_an_instance_of comment_class }
61
+ it { subject.id.should be_eql 0 }
62
+ end
63
+
64
+ context "when calling #comment with an attribute hash" do
65
+ subject { @ticket.comment :parent_id => @ticket.id }
66
+ it { should be_an_instance_of comment_class }
67
+ it { subject.id.should be_eql 2 }
68
+ end
69
+ end
70
+
71
+ it "should be able to create a comment" do
72
+ pending
73
+ @comment = @ticket.comment!(:body => 'New comment created.', :body_format => 'markdown')
74
+ @comment.should be_an_instance_of(@klass)
75
+ end
76
+ end
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comment>
3
+ <author-id type="integer">47763</author-id>
4
+ <body>I found Devise as a very complete solution for authentication, also found that it takes care of sessions expiration(Timeoutable) and sign in tracking(Trackable) too (http://github.com/plataformatec/devise), and the better is that it seems not to be a very difficult task to get it implemented in the app.</body>
5
+ <body-format>markdown</body-format>
6
+ <id type="integer">0</id>
7
+ <parent-id type="integer">476834</parent-id>
8
+ <parent-type>Ticket</parent-type>
9
+ <created-at>2009-11-26T17:19:22Z</created-at>
10
+ <updated-at>2009-11-26T17:19:22Z</updated-at>
11
+ </comment>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comment>
3
+ <author-id type="integer">47763</author-id>
4
+ <body>This is comment 2.</body>
5
+ <body-format>markdown</body-format>
6
+ <id type="integer">2</id>
7
+ <parent-id type="integer">476834</parent-id>
8
+ <parent-type>Ticket</parent-type>
9
+ <created-at>2009-11-26T17:19:22Z</created-at>
10
+ <updated-at>2009-11-26T17:19:22Z</updated-at>
11
+ </comment>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comment>
3
+ <author-id type="integer">47763</author-id>
4
+ <body>This is comment 3.</body>
5
+ <body-format>markdown</body-format>
6
+ <id type="integer">3</id>
7
+ <parent-id type="integer">476834</parent-id>
8
+ <parent-type>Ticket</parent-type>
9
+ <created-at>2009-11-26T17:19:22Z</created-at>
10
+ <updated-at>2009-11-26T17:19:22Z</updated-at>
11
+ </comment>
@@ -0,0 +1,11 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comment>
3
+ <author-id type="integer">47763</author-id>
4
+ <body>New comment created.</body>
5
+ <body-format>markdown</body-format>
6
+ <id type="integer">4</id>
7
+ <parent-id type="integer">476834</parent-id>
8
+ <parent-type>Ticket</parent-type>
9
+ <created-at>2009-11-26T17:19:22Z</created-at>
10
+ <updated-at>2009-11-26T17:19:22Z</updated-at>
11
+ </comment>
@@ -0,0 +1,13 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <comments type="array">
3
+ <comment>
4
+ <author-id type="integer">47763</author-id>
5
+ <body>I found Devise as a very complete solution for authentication, also found that it takes care of sessions expiration(Timeoutable) and sign in tracking(Trackable) too (http://github.com/plataformatec/devise), and the better is that it seems not to be a very difficult task to get it implemented in the app.</body>
6
+ <body-format>markdown</body-format>
7
+ <id type="integer">2</id>
8
+ <parent-id type="integer">476834</parent-id>
9
+ <parent-type>Ticket</parent-type>
10
+ <created-at>2009-11-26T17:19:22Z</created-at>
11
+ <updated-at>2009-11-26T17:19:22Z</updated-at>
12
+ </comment>
13
+ </comments>