confuddle 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.passwd_to_unfuddle.example.yml +7 -0
- data/README.md +40 -0
- data/bin/un +833 -0
- data/bin/un.cmd +1 -0
- data/confuddle.gemspec +22 -0
- data/lib/graft/README.rdoc +138 -0
- data/lib/graft/Rakefile +43 -0
- data/lib/graft/lib/graft/core_ext/hash.rb +9 -0
- data/lib/graft/lib/graft/json.rb +14 -0
- data/lib/graft/lib/graft/json/attribute.rb +18 -0
- data/lib/graft/lib/graft/json/model.rb +28 -0
- data/lib/graft/lib/graft/model.rb +43 -0
- data/lib/graft/lib/graft/version.rb +13 -0
- data/lib/graft/lib/graft/xml.rb +19 -0
- data/lib/graft/lib/graft/xml/attribute.rb +55 -0
- data/lib/graft/lib/graft/xml/model.rb +49 -0
- data/lib/graft/lib/graft/xml/type.rb +91 -0
- data/lib/graft/test/test_helper.rb +38 -0
- data/lib/graft/test/unit/core_ext/hash_test.rb +29 -0
- data/lib/graft/test/unit/json/attribute_test.rb +51 -0
- data/lib/graft/test/unit/json/model_test.rb +86 -0
- data/lib/graft/test/unit/xml/attribute_test.rb +161 -0
- data/lib/graft/test/unit/xml/model_test.rb +173 -0
- data/lib/graft/test/unit/xml/type_test.rb +65 -0
- data/lib/unfuzzle/.gitignore +4 -0
- data/lib/unfuzzle/README.rdoc +129 -0
- data/lib/unfuzzle/Rakefile +39 -0
- data/lib/unfuzzle/lib/unfuzzle.rb +87 -0
- data/lib/unfuzzle/lib/unfuzzle/comment.rb +37 -0
- data/lib/unfuzzle/lib/unfuzzle/component.rb +31 -0
- data/lib/unfuzzle/lib/unfuzzle/milestone.rb +54 -0
- data/lib/unfuzzle/lib/unfuzzle/person.rb +20 -0
- data/lib/unfuzzle/lib/unfuzzle/priority.rb +30 -0
- data/lib/unfuzzle/lib/unfuzzle/project.rb +62 -0
- data/lib/unfuzzle/lib/unfuzzle/request.rb +75 -0
- data/lib/unfuzzle/lib/unfuzzle/response.rb +25 -0
- data/lib/unfuzzle/lib/unfuzzle/severity.rb +31 -0
- data/lib/unfuzzle/lib/unfuzzle/ticket.rb +156 -0
- data/lib/unfuzzle/lib/unfuzzle/ticket_report.rb +29 -0
- data/lib/unfuzzle/lib/unfuzzle/time_entry.rb +75 -0
- data/lib/unfuzzle/lib/unfuzzle/version.rb +13 -0
- data/lib/unfuzzle/test/fixtures/component.xml +8 -0
- data/lib/unfuzzle/test/fixtures/components.xml +17 -0
- data/lib/unfuzzle/test/fixtures/milestone.xml +12 -0
- data/lib/unfuzzle/test/fixtures/milestones.xml +25 -0
- data/lib/unfuzzle/test/fixtures/project.xml +17 -0
- data/lib/unfuzzle/test/fixtures/projects.xml +35 -0
- data/lib/unfuzzle/test/fixtures/severities.xml +24 -0
- data/lib/unfuzzle/test/fixtures/severity.xml +8 -0
- data/lib/unfuzzle/test/fixtures/ticket.xml +25 -0
- data/lib/unfuzzle/test/fixtures/tickets.xml +51 -0
- data/lib/unfuzzle/test/test_helper.rb +60 -0
- data/lib/unfuzzle/test/unit/unfuzzle/component_test.rb +36 -0
- data/lib/unfuzzle/test/unit/unfuzzle/milestone_test.rb +100 -0
- data/lib/unfuzzle/test/unit/unfuzzle/priority_test.rb +25 -0
- data/lib/unfuzzle/test/unit/unfuzzle/project_test.rb +87 -0
- data/lib/unfuzzle/test/unit/unfuzzle/request_test.rb +104 -0
- data/lib/unfuzzle/test/unit/unfuzzle/response_test.rb +37 -0
- data/lib/unfuzzle/test/unit/unfuzzle/severity_test.rb +36 -0
- data/lib/unfuzzle/test/unit/unfuzzle/ticket_test.rb +181 -0
- data/lib/unfuzzle/test/unit/unfuzzle_test.rb +39 -0
- data/lib/unfuzzle/unfuzzle.gemspec +31 -0
- data/lib/version.rb +3 -0
- metadata +176 -0
@@ -0,0 +1,37 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
#
|
4
|
+
class Comment
|
5
|
+
|
6
|
+
include Graft
|
7
|
+
|
8
|
+
attribute :id
|
9
|
+
attribute :created_at
|
10
|
+
attribute :body
|
11
|
+
attribute :author_id, :from => "author-id", :type => :integer
|
12
|
+
|
13
|
+
# Hash representation of this ticket's data (for updating)
|
14
|
+
def to_hash
|
15
|
+
{
|
16
|
+
'id' => id,
|
17
|
+
'body' => body,
|
18
|
+
'author-id' => author_id
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return a list of all tickets for an individual project
|
23
|
+
def self.all_by_project_and_ticket(project_id, ticket_id)
|
24
|
+
response = Request.get("/projects/{id}/tickets/{id}/comments")
|
25
|
+
collection_from(response.body, 'comments/comment')
|
26
|
+
end
|
27
|
+
|
28
|
+
# Create a comment
|
29
|
+
def create(project_id, ticket_id)
|
30
|
+
resource_path = "/projects/#{project_id}/tickets/#{ticket_id}/comments"
|
31
|
+
Request.post(resource_path, self.to_xml('comment'))
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Component
|
4
|
+
#
|
5
|
+
# Represents a Component in an Unfuddle project. These are user-configurable
|
6
|
+
# and are custom for each project you have. Examples include 'Administration',
|
7
|
+
# 'User Registration', etc.. A component has the following attributes:
|
8
|
+
#
|
9
|
+
# [id] The unique id for this component
|
10
|
+
# [name] The name of this component (e.g User Registration)
|
11
|
+
# [created_at] The date/time that this component was created
|
12
|
+
# [updated_at] The date/time that this component was last updated
|
13
|
+
#
|
14
|
+
class Component
|
15
|
+
|
16
|
+
include Graft
|
17
|
+
|
18
|
+
attribute :id, :type => :integer
|
19
|
+
attribute :name
|
20
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
21
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
22
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
23
|
+
|
24
|
+
# Find a component by ID for a given project
|
25
|
+
def self.find_by_project_id_and_component_id(project_id, component_id)
|
26
|
+
response = Request.get("/projects/#{project_id}/components/#{component_id}")
|
27
|
+
new response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Milestone
|
4
|
+
#
|
5
|
+
# A representation of an Unfuddle Milestone. Has the following attributes:
|
6
|
+
#
|
7
|
+
# [id] Unique identifier for this milestone
|
8
|
+
# [name] Name of the milestone
|
9
|
+
# [archived] The archived status of this milestone (see Milestone#archived?)
|
10
|
+
# [due_on] The due date for this milestone
|
11
|
+
# [created_at] The date/time that this milestone was created
|
12
|
+
# [updated_at] The date/time that this milestone was last updated
|
13
|
+
#
|
14
|
+
class Milestone
|
15
|
+
|
16
|
+
include Graft
|
17
|
+
|
18
|
+
attribute :id, :type => :integer
|
19
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
20
|
+
attribute :archived, :type => :boolean
|
21
|
+
attribute :name, :from => 'title'
|
22
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
23
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
24
|
+
attribute :due_on, :from => 'due-on', :type => :date
|
25
|
+
|
26
|
+
# Return a list of all milestones for a given project
|
27
|
+
def self.find_all_by_project_id(project_id)
|
28
|
+
response = Request.get("/projects/#{project_id}/milestones")
|
29
|
+
collection_from(response.body, 'milestones/milestone')
|
30
|
+
end
|
31
|
+
|
32
|
+
# Find a milestone by ID for a given project
|
33
|
+
def self.find_by_project_id_and_milestone_id(project_id, milestone_id)
|
34
|
+
response = Request.get("/projects/#{project_id}/milestones/#{milestone_id}")
|
35
|
+
new response.body
|
36
|
+
end
|
37
|
+
|
38
|
+
# Has this milestone been archived?
|
39
|
+
def archived?
|
40
|
+
archived == true
|
41
|
+
end
|
42
|
+
|
43
|
+
# Does this milestone occur in the past?
|
44
|
+
def past?
|
45
|
+
due_on < Date.today
|
46
|
+
end
|
47
|
+
|
48
|
+
# The collection of Tickets associated to this milestone
|
49
|
+
def tickets
|
50
|
+
Ticket.find_all_by_project_id_and_milestone_id(project_id, id)
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
class Person
|
3
|
+
include Graft
|
4
|
+
attribute :id, :type => :integer
|
5
|
+
attribute :first_name, :from => 'first-name'
|
6
|
+
attribute :last_name, :from => 'last-name'
|
7
|
+
attribute :username, :from => 'username'
|
8
|
+
|
9
|
+
def self.all
|
10
|
+
response = Request.get("/people")
|
11
|
+
collection_from(response.body, 'people/person')
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.all_for_project(project_id)
|
15
|
+
response = Request.get("/projects/#{project_id}/people")
|
16
|
+
collection_from(response.body, 'people/person')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Priority
|
4
|
+
#
|
5
|
+
# Represents a priority for a ticket.
|
6
|
+
#
|
7
|
+
class Priority
|
8
|
+
|
9
|
+
def initialize(id)
|
10
|
+
@id = id
|
11
|
+
end
|
12
|
+
|
13
|
+
# The name of the priority based on the supplied ID
|
14
|
+
def name
|
15
|
+
mapping[@id]
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
def mapping
|
20
|
+
{
|
21
|
+
5 => 'Highest',
|
22
|
+
4 => 'High',
|
23
|
+
3 => 'Normal',
|
24
|
+
2 => 'Low',
|
25
|
+
1 => 'Lowest'
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Project
|
4
|
+
#
|
5
|
+
# Represents an Unfuddle project. Has the following attributes:
|
6
|
+
#
|
7
|
+
# [id] The unique identifier for this project
|
8
|
+
# [slug] The "short name" for this project
|
9
|
+
# [name] The name of this project
|
10
|
+
# [description] The description for the project
|
11
|
+
# [archived] The archived status of this project (see Project#archived?)
|
12
|
+
# [created_at] The date/time that this project was created
|
13
|
+
# [updated_at] The date/time that this project was last updated
|
14
|
+
#
|
15
|
+
class Project
|
16
|
+
|
17
|
+
include Graft
|
18
|
+
|
19
|
+
attribute :id, :type => :integer
|
20
|
+
attribute :slug, :from => 'short-name'
|
21
|
+
attribute :archived, :type => :boolean
|
22
|
+
attribute :name, :from => 'title'
|
23
|
+
attribute :description
|
24
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
25
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
26
|
+
attribute :disk_usage, :from => 'disk-usage'
|
27
|
+
|
28
|
+
# Return a list of all projects to which the current user has access
|
29
|
+
def self.all
|
30
|
+
response = Request.get('/projects')
|
31
|
+
collection_from(response.body, 'projects/project')
|
32
|
+
end
|
33
|
+
|
34
|
+
# Find a single project by its slug (short name)
|
35
|
+
def self.find_by_slug(slug)
|
36
|
+
response = Request.get("/projects/by_short_name/#{slug}")
|
37
|
+
new(response.body)
|
38
|
+
end
|
39
|
+
|
40
|
+
# Find a single project by its ID
|
41
|
+
def self.find_by_id(id)
|
42
|
+
response = Request.get("/projects/#{id}")
|
43
|
+
new(response.body)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Has this project been archived?
|
47
|
+
def archived?
|
48
|
+
archived == true
|
49
|
+
end
|
50
|
+
|
51
|
+
# The collection of Milestones associated to this project
|
52
|
+
def milestones
|
53
|
+
Milestone.find_all_by_project_id(id)
|
54
|
+
end
|
55
|
+
|
56
|
+
# The collection of Tickets associated to this project
|
57
|
+
def tickets
|
58
|
+
Ticket.find_all_by_project_id(id)
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Request
|
4
|
+
#
|
5
|
+
# A basic wrapper for GET requests to the Unfuddle API
|
6
|
+
#
|
7
|
+
class Request
|
8
|
+
|
9
|
+
# Retrieve a response from the given resource path
|
10
|
+
def self.get(resource_path, query = nil)
|
11
|
+
request = new(resource_path, nil, query)
|
12
|
+
request.get
|
13
|
+
end
|
14
|
+
|
15
|
+
# Send a POST request with data and retrieve a Response
|
16
|
+
def self.post(resource_path, payload)
|
17
|
+
request = new(resource_path, payload)
|
18
|
+
request.post
|
19
|
+
end
|
20
|
+
|
21
|
+
# Send a PUT request with data and retrieve a Response
|
22
|
+
def self.put(resource_path, payload)
|
23
|
+
request = new(resource_path, payload)
|
24
|
+
request.put
|
25
|
+
end
|
26
|
+
|
27
|
+
# Create a new request for the given resource path
|
28
|
+
def initialize(resource_path, payload = nil, query = nil)
|
29
|
+
@resource_path = resource_path
|
30
|
+
@payload = payload
|
31
|
+
@query = query
|
32
|
+
end
|
33
|
+
|
34
|
+
def endpoint_uri # :nodoc:
|
35
|
+
url = "https://#{Unfuzzle.subdomain}.unfuddle.com/api/v1#{@resource_path}.xml"
|
36
|
+
url += @query if @query
|
37
|
+
URI.parse(url)
|
38
|
+
end
|
39
|
+
|
40
|
+
def client # :nodoc:
|
41
|
+
http = Net::HTTP.new(endpoint_uri.host, endpoint_uri.port)
|
42
|
+
if Unfuzzle.use_ssl
|
43
|
+
http.use_ssl = true
|
44
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
45
|
+
end
|
46
|
+
http
|
47
|
+
end
|
48
|
+
|
49
|
+
# Retrieve a response from the current resource path
|
50
|
+
def get
|
51
|
+
request = Net::HTTP::Get.new(endpoint_uri.request_uri)
|
52
|
+
request.basic_auth Unfuzzle.username, Unfuzzle.password
|
53
|
+
Response.new(client.request(request))
|
54
|
+
end
|
55
|
+
|
56
|
+
# Send a POST request to the configured endpoint
|
57
|
+
def post
|
58
|
+
request = Net::HTTP::Post.new(endpoint_uri.request_uri)
|
59
|
+
request.basic_auth Unfuzzle.username, Unfuzzle.password
|
60
|
+
request.content_type = 'application/xml'
|
61
|
+
|
62
|
+
Response.new(client.request(request, @payload))
|
63
|
+
end
|
64
|
+
|
65
|
+
# Send a PUT request to the configured endpoint
|
66
|
+
def put
|
67
|
+
request = Net::HTTP::Put.new(endpoint_uri.request_uri)
|
68
|
+
request.basic_auth Unfuzzle.username, Unfuzzle.password
|
69
|
+
request.content_type = 'application/xml'
|
70
|
+
|
71
|
+
Response.new(client.request(request, @payload))
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Response
|
4
|
+
#
|
5
|
+
# A simple wrapper around an HTTP response from the Unfuddle API
|
6
|
+
#
|
7
|
+
class Response
|
8
|
+
|
9
|
+
# Create a new response from an HTTP response object
|
10
|
+
def initialize(http_response)
|
11
|
+
@http_response = http_response
|
12
|
+
end
|
13
|
+
|
14
|
+
# Was there an error produced as part of the request?
|
15
|
+
def error?
|
16
|
+
!@http_response.is_a?(Net::HTTPSuccess)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Raw body of the HTTP response
|
20
|
+
def body
|
21
|
+
@http_response.body
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Severity
|
4
|
+
#
|
5
|
+
# Represents a Severity in an Unfuddle project. These are user-configurable
|
6
|
+
# and are custom for each project you have. Examples include 'Story',
|
7
|
+
# 'Defect', etc.. A severity has the following attributes:
|
8
|
+
#
|
9
|
+
# [id] The unique identifier for this severity
|
10
|
+
# [name] The name of this severity
|
11
|
+
# [created_at] The date/time that this severity was created
|
12
|
+
# [updated_at] The date/time that this severity was last updated
|
13
|
+
#
|
14
|
+
class Severity
|
15
|
+
|
16
|
+
include Graft
|
17
|
+
|
18
|
+
attribute :id, :type => :integer
|
19
|
+
attribute :name
|
20
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
21
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
22
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
23
|
+
|
24
|
+
# Find the severity by ID for a given project
|
25
|
+
def self.find_by_project_id_and_severity_id(project_id, severity_id)
|
26
|
+
response = Request.get("/projects/#{project_id}/severities/#{severity_id}")
|
27
|
+
new response.body
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
module Unfuzzle
|
2
|
+
|
3
|
+
# = Ticket
|
4
|
+
#
|
5
|
+
# Represents a single Unfuddle Ticket - is associated to a project
|
6
|
+
# and optionally a project's milestone. Has the following attributes:
|
7
|
+
#
|
8
|
+
# [id] The unique identifier for this ticket
|
9
|
+
# [number] The ticket's number - this is displayed in the web interface
|
10
|
+
# [title] The title of the ticket (short)
|
11
|
+
# [description] The full description of the ticket
|
12
|
+
# [status] The ticket's status (new / accepted / resolved / closed)
|
13
|
+
# [due_on] The due date for this ticket
|
14
|
+
# [created_at] The date/time that this ticket was created
|
15
|
+
# [updated_at] The date/time that this ticket was last updated
|
16
|
+
#
|
17
|
+
class Ticket
|
18
|
+
|
19
|
+
include Graft
|
20
|
+
|
21
|
+
attribute :id, :type => :integer
|
22
|
+
attribute :project_id, :from => 'project-id', :type => :integer
|
23
|
+
attribute :milestone_id, :from => 'milestone-id', :type => :integer
|
24
|
+
attribute :component_id, :from => 'component-id', :type => :integer
|
25
|
+
attribute :priority, :type => :integer
|
26
|
+
attribute :number, :type => :integer
|
27
|
+
attribute :title, :from => 'summary'
|
28
|
+
attribute :description
|
29
|
+
attribute :due_on, :from => 'due-on', :type => :date
|
30
|
+
attribute :created_at, :from => 'created-at', :type => :time
|
31
|
+
attribute :updated_at, :from => 'updated-at', :type => :time
|
32
|
+
attribute :severity_id, :from => 'severity-id', :type => :integer
|
33
|
+
attribute :assignee_id, :from => 'assignee-id', :type => :integer
|
34
|
+
attribute :reporter_id, :from => 'reporter-id', :type => :integer
|
35
|
+
attribute :status
|
36
|
+
attribute :hours, :from => 'hours-estimate-current'
|
37
|
+
|
38
|
+
|
39
|
+
def initialize(*args)
|
40
|
+
self.priority = 3
|
41
|
+
self.status = "new"
|
42
|
+
super(*args)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Return a list of all tickets for an individual project
|
46
|
+
def self.find_all_by_project_id(project_id)
|
47
|
+
response = Request.get("/projects/#{project_id}/tickets")
|
48
|
+
collection_from(response.body, 'tickets/ticket')
|
49
|
+
end
|
50
|
+
|
51
|
+
# Return a list of all tickets for a given milestone as part of a project
|
52
|
+
def self.find_all_by_project_id_and_milestone_id(project_id, milestone_id)
|
53
|
+
response = Request.get("/projects/#{project_id}/milestones/#{milestone_id}/tickets")
|
54
|
+
collection_from(response.body, 'tickets/ticket')
|
55
|
+
end
|
56
|
+
|
57
|
+
# Return a list of all tickets for a given milestone as part of a project
|
58
|
+
def self.find_first_by_project_id_and_number(project_id, number)
|
59
|
+
response = Request.get("/projects/#{project_id}/tickets/by_number/#{number}")
|
60
|
+
new(response.body)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Return a list of all tickets for a given milestone as part of a project
|
64
|
+
def self.find_first_by_project_id_and_number_with_comments(project_id, number)
|
65
|
+
response = Request.get("/projects/#{project_id}/tickets/by_number/#{number}", "?comments=true")
|
66
|
+
[new(response.body), Comment.collection_from(response.body, 'comments/comment')]
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
def self.find_all_by_project_and_report(project_id, report_id)
|
71
|
+
response = Request.get("/projects/#{project_id}/ticket_reports/#{report_id}/generate")
|
72
|
+
collection_from(response.body, 'tickets/ticket')
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
def self.all_by_dinamic_report(with_project_ids = nil, only_my_tickets = false)
|
77
|
+
query = "?title=Dynamic&conditions_string=status-neq-closed"
|
78
|
+
query += ",assignee-eq-current" if only_my_tickets
|
79
|
+
query += "&fields_string=id,number,title,hours,assignee,status,reporter"
|
80
|
+
|
81
|
+
res = []
|
82
|
+
|
83
|
+
if with_project_ids.blank?
|
84
|
+
response = Request.get("/ticket_reports/dynamic", query)
|
85
|
+
res = collection_from(response.body, 'tickets/ticket')
|
86
|
+
else
|
87
|
+
with_project_ids.each do |id|
|
88
|
+
response = Request.get("/projects/#{id}/ticket_reports/dynamic", query)
|
89
|
+
res << collection_from(response.body, 'tickets/ticket')
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
res.flatten
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# The Milestone associated with this ticket
|
98
|
+
def milestone
|
99
|
+
Milestone.find_by_project_id_and_milestone_id(project_id, milestone_id)
|
100
|
+
end
|
101
|
+
|
102
|
+
# The Severity associated with this ticket
|
103
|
+
def severity
|
104
|
+
Severity.find_by_project_id_and_severity_id(project_id, severity_id) unless severity_id.nil?
|
105
|
+
end
|
106
|
+
|
107
|
+
def severity_name
|
108
|
+
severity.name unless severity.nil?
|
109
|
+
end
|
110
|
+
|
111
|
+
def priority_name
|
112
|
+
# priority.name
|
113
|
+
Priority.new(priority).name
|
114
|
+
end
|
115
|
+
|
116
|
+
# The Component associated with this ticket
|
117
|
+
def component
|
118
|
+
Component.find_by_project_id_and_component_id(project_id, component_id) unless component_id.nil?
|
119
|
+
end
|
120
|
+
|
121
|
+
def component_name
|
122
|
+
component.name unless component.nil?
|
123
|
+
end
|
124
|
+
|
125
|
+
# Hash representation of this ticket's data (for updating)
|
126
|
+
def to_hash
|
127
|
+
{
|
128
|
+
'id' => id,
|
129
|
+
'project-id' => project_id,
|
130
|
+
'milestone-id' => milestone_id,
|
131
|
+
'priority' => priority,
|
132
|
+
'severity-id' => severity_id,
|
133
|
+
'number' => number,
|
134
|
+
'summary' => title,
|
135
|
+
'description' => description,
|
136
|
+
'status' => status,
|
137
|
+
'assignee-id' => assignee_id,
|
138
|
+
'reporter-id' => reporter_id#,
|
139
|
+
#'hours' => hours
|
140
|
+
}
|
141
|
+
end
|
142
|
+
|
143
|
+
# Update the ticket's data in unfuddle
|
144
|
+
def update
|
145
|
+
resource_path = "/projects/#{project_id}/tickets/#{id}"
|
146
|
+
Request.put(resource_path, self.to_xml('ticket'))
|
147
|
+
end
|
148
|
+
|
149
|
+
# Create a ticket in unfuddle
|
150
|
+
def create
|
151
|
+
resource_path = "/projects/#{project_id}/tickets"
|
152
|
+
Request.post(resource_path, self.to_xml('ticket'))
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|