xplanner 0.1.3 → 0.1.4

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/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