xplanner 0.1.3 → 0.1.4

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -2,4 +2,9 @@ source :rubygems
2
2
 
3
3
  gem 'savon'
4
4
  gem 'nokogiri'
5
- gem 'activesupport'
5
+ gem 'activesupport'
6
+
7
+ group :test do
8
+ gem 'rspec'
9
+ gem 'uri'
10
+ end
data/README.md CHANGED
@@ -0,0 +1,23 @@
1
+ # XPlanner+ Webservice Wrapper
2
+
3
+ This gem provides a wrapper for manipulating [XPlanner+](http://xplanner-plus.sourceforge.net/) via the SOAP interface.
4
+
5
+ There are models for Projects, Iterations, User Storys, Tasks and People.
6
+
7
+ To get started, you need to provide a config hash to the XPlanner module, like so:
8
+
9
+ ```ruby
10
+ config = {
11
+ :url => 'http://127.0.0.1:8080/xplanner-plus/'
12
+ :user => 'sysadmin'
13
+ :pass => 'admin'
14
+ }
15
+
16
+ XPlanner::setup( config )
17
+ ```
18
+
19
+ Start creating XPlanner objects like so:
20
+
21
+ ```ruby
22
+ @myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
23
+ ```
@@ -4,10 +4,10 @@ module AttrAccessorWithDirtyBit
4
4
 
5
5
  names.each do |name|
6
6
  define_method :"#{name}=" do |v|
7
- if instance_variable_get(:"@#{name}") != v
8
- @dirty_bit = true
9
- instance_variable_set(:"@#{name}", v)
10
- end
7
+ if instance_variable_get(:"@#{name}") != v
8
+ @dirty_bit = true
9
+ instance_variable_set(:"@#{name}", v)
10
+ end
11
11
  end
12
12
  end
13
13
  end
@@ -1,7 +1,7 @@
1
1
  module XPlanner
2
- @@default_config = {
3
- :xplanner_url => "http://192.168.237.1:8080/xplanner-plus/",
4
- :username => 'sysadmin',
5
- :password => 'admin'
6
- }
2
+ @@default_config = {
3
+ :xplanner_url => "http://127.0.0.1:8080/xplanner-plus/",
4
+ :username => 'sysadmin',
5
+ :password => 'admin'
6
+ }
7
7
  end
@@ -12,45 +12,45 @@ HTTPI.log = false
12
12
 
13
13
  # Helper for decoding multi-ref style SOAP responses
14
14
  module Savon
15
- module SOAP
16
- class Response
17
- def decode_soap_response( path = [] )
18
- hash = SoapResponseDecoder.decode( self.to_xml )
19
- path.each { |p| hash = hash[p] }
20
- hash
21
- end
22
- end
23
- end
15
+ module SOAP
16
+ class Response
17
+ def decode_soap_response( path = [] )
18
+ hash = SoapResponseDecoder.decode( self.to_xml )
19
+ path.each { |p| hash = hash[p] }
20
+ hash
21
+ end
22
+ end
23
+ end
24
24
  end
25
25
 
26
26
  # Decode multi-ref soap references.
27
27
  class SoapResponseDecoder
28
- def self.decode( xml_doc )
29
- doc = Nokogiri::XML xml_doc
30
-
31
- while( el = doc.xpath('//soapenv:Body//*[@href]').first )
32
- id = el.attribute('href').value.gsub('#', '')
33
- el.children = doc.xpath("//soapenv:Body//multiRef[@id='#{id}']").children()
34
- el.remove_attribute('href')
35
- end
36
-
37
- hash = convert_hash_keys( Hash.from_xml( doc.to_s ) )[:envelope][:body]
38
- end
39
-
40
-
41
- def self.underscore_key(k)
42
- k.to_s.underscore.to_sym
43
- end
44
-
45
- def self.convert_hash_keys(value)
46
- case value
47
- when Array
48
- value.map { |v| convert_hash_keys(v) }
49
- when Hash
50
- Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] if k != 'xsi:type' }]
51
- else
52
- value
53
- end
54
- end
28
+ def self.decode( xml_doc )
29
+ doc = Nokogiri::XML xml_doc
30
+
31
+ while( el = doc.xpath('//soapenv:Body//*[@href]').first )
32
+ id = el.attribute('href').value.gsub('#', '')
33
+ el.children = doc.xpath("//soapenv:Body//multiRef[@id='#{id}']").children()
34
+ el.remove_attribute('href')
35
+ end
36
+
37
+ hash = convert_hash_keys( Hash.from_xml( doc.to_s ) )[:envelope][:body]
38
+ end
39
+
40
+
41
+ def self.underscore_key(k)
42
+ k.to_s.underscore.to_sym
43
+ end
44
+
45
+ def self.convert_hash_keys(value)
46
+ case value
47
+ when Array
48
+ value.map { |v| convert_hash_keys(v) }
49
+ when Hash
50
+ Hash[value.map { |k, v| [underscore_key(k), convert_hash_keys(v)] if k != 'xsi:type' }]
51
+ else
52
+ value
53
+ end
54
+ end
55
55
 
56
56
  end
@@ -1,3 +1,3 @@
1
1
  module XPlanner
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
@@ -1,23 +1,23 @@
1
1
  module XPlanner
2
- class SoapClient
3
- def initialize( params )
4
- @client = Savon.client do |wsdl, http|
5
- wsdl.document = params[:wsdl]
6
- http.auth.basic params[:username], params[:password]
7
- end
8
- end
2
+ class SoapClient
3
+ def initialize( params )
4
+ @client = Savon.client do |wsdl, http|
5
+ wsdl.document = params[:wsdl]
6
+ http.auth.basic params[:username], params[:password]
7
+ end
8
+ end
9
9
 
10
- def confirm_connection
11
- begin
12
- return @client.wsdl.soap_actions.include? :get_user_story
13
- rescue
14
- return false
15
- end
16
- end
10
+ def confirm_connection
11
+ begin
12
+ return @client.wsdl.soap_actions.include? :get_user_story
13
+ rescue
14
+ return false
15
+ end
16
+ end
17
17
 
18
- # throws exception if xplanner doesn't like it.
19
- def call( rpc, payload=nil)
20
- @client.request( rpc ) { soap.body = payload unless payload.nil? }
21
- end
22
- end
18
+ # throws exception if xplanner doesn't like it.
19
+ def call( rpc, payload=nil)
20
+ @client.request( rpc ) { soap.body = payload unless payload.nil? }
21
+ end
22
+ end
23
23
  end
@@ -1,7 +1,7 @@
1
1
  module XPlanner
2
2
  class Iteration < ModelHelper
3
3
  extend AttrAccessorWithDirtyBit
4
- dirty_accessor :name,
4
+ dirty_accessor :name,
5
5
  :description,
6
6
  :project_id,
7
7
  :status_key,
@@ -21,73 +21,73 @@ module XPlanner
21
21
  :last_update_time
22
22
 
23
23
 
24
- def initialize( iter )
24
+ def initialize( iter )
25
25
  @dirty_bit = false
26
26
 
27
- @id = iter[:id]
28
- @name = iter[:name]
29
- @description = iter[:description]
30
- @project_id = iter[:project_id]
31
- @status_key = iter[:status_key]
32
- @actual_hours = iter[:actual_hours]
33
- @added_hours = iter[:added_hours]
34
- @adjusted_estimated_hours = iter[:adjusted_estimated_hours]
35
- @days_worked = iter[:days_worked]
36
- @estimated_hours = iter[:estimated_hours]
37
- @overestimated_hours = iter[:overestimated_hours]
38
- @postponed_hours = iter[:postponed_hours]
39
- @remaining_hours = iter[:remaining_hours]
40
- @start_date = Iteration.parse_date iter[:start_date]
41
- @end_date = Iteration.parse_date iter[:end_date]
42
- @last_update_time = Iteration.parse_date iter[:last_update_time]
43
- @underestimated_hours = iter[:underestimated_hours]
44
- end
27
+ @id = iter[:id]
28
+ @name = iter[:name]
29
+ @description = iter[:description]
30
+ @project_id = iter[:project_id]
31
+ @status_key = iter[:status_key]
32
+ @actual_hours = iter[:actual_hours]
33
+ @added_hours = iter[:added_hours]
34
+ @adjusted_estimated_hours = iter[:adjusted_estimated_hours]
35
+ @days_worked = iter[:days_worked]
36
+ @estimated_hours = iter[:estimated_hours]
37
+ @overestimated_hours = iter[:overestimated_hours]
38
+ @postponed_hours = iter[:postponed_hours]
39
+ @remaining_hours = iter[:remaining_hours]
40
+ @start_date = Iteration.parse_date iter[:start_date]
41
+ @end_date = Iteration.parse_date iter[:end_date]
42
+ @last_update_time = Iteration.parse_date iter[:last_update_time]
43
+ @underestimated_hours = iter[:underestimated_hours]
44
+ end
45
45
 
46
46
  def self.all( project_id )
47
- rpc = :get_iterations
48
- payload = { :projectId => project_id }
49
- path = [:get_iterations_response, :get_iterations_return, :get_iterations_return]
50
- fetch_from_remote( rpc, payload, path, Iteration )
47
+ rpc = :get_iterations
48
+ payload = { :projectId => project_id }
49
+ path = [:get_iterations_response, :get_iterations_return, :get_iterations_return]
50
+ fetch_from_remote( rpc, payload, path, Iteration )
51
51
  end
52
52
 
53
53
  def self.retrieve( iteration_id )
54
- rpc = :get_iteration
55
- payload = { :iterationId => iteration_id }
56
- path = [:get_iteration_response, :get_iteration_return]
57
- fetch_from_remote( rpc, payload, path, Iteration )
54
+ rpc = :get_iteration
55
+ payload = { :iterationId => iteration_id }
56
+ path = [:get_iteration_response, :get_iteration_return]
57
+ fetch_from_remote( rpc, payload, path, Iteration )
58
58
  end
59
59
 
60
60
  # needs status setting
61
- def self.create( project_id, name, description, start_date, end_date )
62
- rpc = :add_iteration
63
- payload = {
64
- :iterationData => {
65
- :project_id => project_id,
66
- :name => name,
67
- :description => description,
68
- :start_date => start_date,
69
- :end_date => end_date,
61
+ def self.create( project_id, name, description, start_date, end_date )
62
+ rpc = :add_iteration
63
+ payload = {
64
+ :iterationData => {
65
+ :project_id => project_id,
66
+ :name => name,
67
+ :description => description,
68
+ :start_date => start_date,
69
+ :end_date => end_date,
70
70
  :status_key => 'inactive'
71
- }
72
- }
73
- path = [:add_iteration_response, :add_iteration_return]
74
- fetch_from_remote( rpc, payload, path, Iteration )
71
+ }
72
+ }
73
+ path = [:add_iteration_response, :add_iteration_return]
74
+ fetch_from_remote( rpc, payload, path, Iteration )
75
75
  end
76
76
 
77
77
  def self.delete( id )
78
- rpc = :remove_iteration
79
- payload = { :id => id }
78
+ rpc = :remove_iteration
79
+ payload = { :id => id }
80
80
  remote_delete( rpc, payload )
81
81
  end
82
82
 
83
83
  def delete
84
- Iteration.delete( @id )
84
+ Iteration.delete( @id )
85
85
  end
86
86
 
87
87
  def save
88
- rpc = :update
89
- payload = { :iterationData => create_payload }
90
- remote_update( rpc, payload )
88
+ rpc = :update
89
+ payload = { :iterationData => create_payload }
90
+ remote_update( rpc, payload )
91
91
  end
92
92
 
93
93
  end
@@ -67,7 +67,7 @@ module XPlanner
67
67
  end
68
68
 
69
69
  def self.get_userid_from_username( username )
70
- Person.all.each { |u| return Integer(u.id) if u.name == username }
70
+ Person.all.each { |u| return Integer(u.id) if u.user_id == username }
71
71
  return nil
72
72
  end
73
73
  end
@@ -10,45 +10,45 @@ module XPlanner
10
10
  def initialize( p )
11
11
  @dirty_bit = false
12
12
 
13
- @id = p[:id]
14
- @name = p[:name]
15
- @last_update_time = Project.parse_date p[:last_update_time]
16
- @description = p[:description]
13
+ @id = p[:id]
14
+ @name = p[:name]
15
+ @last_update_time = Project.parse_date p[:last_update_time]
16
+ @description = p[:description]
17
17
  end
18
18
 
19
19
  def self.all
20
- rpc = :get_projects
21
- path = [:get_projects_response, :get_projects_return, :get_projects_return]
22
- fetch_from_remote( rpc, {}, path, Project )
20
+ rpc = :get_projects
21
+ path = [:get_projects_response, :get_projects_return, :get_projects_return]
22
+ fetch_from_remote( rpc, {}, path, Project )
23
23
  end
24
24
 
25
25
  def self.retrieve( id )
26
- rpc = :get_project
27
- payload = { :id => id }
28
- path = [:get_project_response, :get_project_return]
26
+ rpc = :get_project
27
+ payload = { :id => id }
28
+ path = [:get_project_response, :get_project_return]
29
29
  fetch_from_remote( rpc, payload, path, Project )
30
30
  end
31
31
 
32
32
  def self.create( name, description )
33
- rpc = :add_project
34
- payload = { :projectData => { :name => name, :description => description } }
33
+ rpc = :add_project
34
+ payload = { :projectData => { :name => name, :description => description } }
35
35
  path = [:add_project_response, :add_project_return]
36
- fetch_from_remote( rpc, payload, path, Project )
36
+ fetch_from_remote( rpc, payload, path, Project )
37
37
  end
38
38
 
39
39
  def self.delete( id )
40
- rpc = :remove_project
41
- payload = { :id => id }
40
+ rpc = :remove_project
41
+ payload = { :id => id }
42
42
  remote_delete( rpc, payload )
43
43
  end
44
44
 
45
45
  def delete
46
- Project.delete @id
46
+ Project.delete @id
47
47
  end
48
48
 
49
49
  def save
50
- rpc = :update
51
- payload = { :projectData => create_payload }
50
+ rpc = :update
51
+ payload = { :projectData => create_payload }
52
52
  remote_update( rpc, payload )
53
53
  end
54
54
 
@@ -43,10 +43,10 @@ module XPlanner
43
43
  end
44
44
 
45
45
  def self.all( iteration_id )
46
- rpc = :get_user_stories
47
- payload = { :containerId => iteration_id }
48
- path = [:get_user_stories_response, :get_user_stories_return, :get_user_stories_return]
49
- fetch_from_remote( rpc, payload, path, Story )
46
+ rpc = :get_user_stories
47
+ payload = { :containerId => iteration_id }
48
+ path = [:get_user_stories_response, :get_user_stories_return, :get_user_stories_return]
49
+ fetch_from_remote( rpc, payload, path, Story )
50
50
  end
51
51
 
52
52
  def self.retrieve( story_id )
@@ -41,10 +41,10 @@ module XPlanner
41
41
  end
42
42
 
43
43
  def self.all( story_id )
44
- rpc = :get_tasks
45
- payload = { :containerId => story_id }
46
- path = [:get_taskss_response, :get_tasks_return, :get_tasks_return]
47
- fetch_from_remote( rpc, payload, path, Task )
44
+ rpc = :get_tasks
45
+ payload = { :containerId => story_id }
46
+ path = [:get_taskss_response, :get_tasks_return, :get_tasks_return]
47
+ fetch_from_remote( rpc, payload, path, Task )
48
48
  end
49
49
 
50
50
  def self.retrieve( task_id )
@@ -2,33 +2,33 @@ project_root = File.expand_path('../', __FILE__)
2
2
  project_dirs = ['config', 'helpers', 'models']
3
3
 
4
4
  project_dirs.each do |d|
5
- Dir.glob(project_root + '/' + d + '/*.rb') {|file| require file}
5
+ Dir.glob(project_root + '/' + d + '/*.rb') {|file| require file}
6
6
  end
7
7
 
8
8
  require 'uri'
9
9
 
10
10
  module XPlanner
11
- def self.setup( config = {} )
12
- url = config[:url] ||= @@default_config[:xplanner_url]
13
- user = config[:user] ||= @@default_config[:username]
14
- pass = config[:pass] ||= @@default_config[:password]
11
+ def self.setup( config = {} )
12
+ url = config[:url] ||= @@default_config[:xplanner_url]
13
+ user = config[:user] ||= @@default_config[:username]
14
+ pass = config[:pass] ||= @@default_config[:password]
15
15
 
16
- wsdl = URI::join(url, 'soap/XPlanner?wsdl').to_s
16
+ wsdl = URI::join(url, 'soap/XPlanner?wsdl').to_s
17
17
 
18
- client_config = {
19
- :wsdl => wsdl,
20
- :username => user,
21
- :password => pass
22
- }
18
+ client_config = {
19
+ :wsdl => wsdl,
20
+ :username => user,
21
+ :password => pass
22
+ }
23
23
 
24
- soap_client = SoapClient.new( client_config )
25
- ModelHelper.soap_client= soap_client
26
- @@connection_successful = soap_client.confirm_connection
24
+ soap_client = SoapClient.new( client_config )
25
+ ModelHelper.soap_client= soap_client
26
+ @@connection_successful = soap_client.confirm_connection
27
27
 
28
- ModelHelper.base_url= url
29
- end
28
+ ModelHelper.base_url= url
29
+ end
30
30
 
31
- def self.connection?
32
- @@connection_successful
33
- end
31
+ def self.connection?
32
+ @@connection_successful
33
+ end
34
34
  end
@@ -46,11 +46,7 @@ describe 'XPlanner+ SOAP interface' do
46
46
  describe 'Model: Iteration' do
47
47
  before(:all) do
48
48
  @myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
49
- @myIteration = XPlanner::Iteration.create( @myProject.id,
50
- 'delete me',
51
- 'delete me: test iteration',
52
- DateTime.now,
53
- DateTime.now+5 )
49
+ @myIteration = XPlanner::Iteration.create( @myProject.id, 'delete me', 'delete me: test iteration', DateTime.now, DateTime.now+5 )
54
50
  end
55
51
 
56
52
  after(:all) do
@@ -90,11 +86,7 @@ describe 'XPlanner+ SOAP interface' do
90
86
  describe 'Model: User Story' do
91
87
  before(:all) do
92
88
  @myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
93
- @myIteration = XPlanner::Iteration.create( @myProject.id,
94
- 'delete me',
95
- 'delete me: test iteration',
96
- DateTime.now,
97
- DateTime.now+5 )
89
+ @myIteration = XPlanner::Iteration.create( @myProject.id, 'delete me', 'delete me: test iteration', DateTime.now, DateTime.now+5 )
98
90
  @myStory = XPlanner::Story.create( @myIteration.id, 'delete me', 'delete me: test story')
99
91
  end
100
92
 
@@ -134,11 +126,7 @@ describe 'XPlanner+ SOAP interface' do
134
126
  describe 'Model: Task' do
135
127
  before(:all) do
136
128
  @myProject = XPlanner::Project.create( 'delete me', 'delete me: test project' )
137
- @myIteration = XPlanner::Iteration.create( @myProject.id,
138
- 'delete me',
139
- 'delete me: test iteration',
140
- DateTime.now,
141
- DateTime.now+5 )
129
+ @myIteration = XPlanner::Iteration.create( @myProject.id, 'delete me', 'delete me: test iteration', DateTime.now, DateTime.now+5 )
142
130
  @myStory = XPlanner::Story.create( @myIteration.id, 'delete me', 'delete me: test story')
143
131
  @myTask = XPlanner::Task.create( @myStory.id, 'delete me', 'delete me: test task')
144
132
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: xplanner
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-08 00:00:00.000000000 Z
12
+ date: 2013-02-18 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: savon