teamforge 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2013 CollabNet, Inc.
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.rdoc ADDED
@@ -0,0 +1,18 @@
1
+ = TeamForge Ruby SDK
2
+
3
+ * TeamForge Version 6.1.1
4
+ * SDK Version 0.0.2
5
+
6
+ == Description
7
+
8
+ This is a Ruby wrapper for interacting with the CollabNet TeamForge SOAP WebService.
9
+
10
+
11
+ == Install
12
+
13
+ * sudo gem install teamforge
14
+
15
+ == Copyright
16
+ Author:: Patrick Wolf (mailto:pwolf@collab.net)
17
+ Copyright:: 2013 CollabNet, Inc.,
18
+ License:: MIT license
@@ -0,0 +1,189 @@
1
+ module TeamForge
2
+
3
+ # Every call sent to the TeamForge server goes through two methods: request and parse_response. This makes it easier to normalize how messages are sent and received
4
+ # and it also makes it easier to troubleshoot because there is one place to trap messages to and from the server.
5
+ # The request method can be called on its own with no other part of this SDK wrapper if the proper paramters are passed to it.
6
+ # Everything else in the gem package is provided as a placeholder for the CTF Server endpoint, a set of CTF Object types, and convenience methods to generate the proper parameters for each method.
7
+ # E.g. CTF.request(method, message, endpoint, response, proxy=nil)
8
+ # Each request to the CTF server expects the following information:
9
+ # method: This is the function call that the server is expected to complete. A symbol is expected. E.g. :login
10
+ # message: This is the body of the soap call to the server. The expected value is a hash. If a soap object is specified it should be converted to a hash.
11
+ # All objects provided in this SDK include a to_h function to convert all instance variables into a nested hash with the object type.
12
+ # E.g. {:userName=>username, :password=>password, {:order! => [:userName, :password]} }
13
+ # The order! key tells the message the parameter order expected by the server. CTF is picky about parameter order.
14
+ # endpoint: The URL of the specific soap endpoint for this method. Each of the different CTF Web services has its own endpoint. This is specified in each function call within this SDK wrapper.
15
+ # E.g. "http://localhost:8080/ce-soap60/services/TrackerApp"
16
+ # response: The response message name that is expected from a successful call to the CTF server. A symbol is expected
17
+ # E.g. :loginResponse
18
+ # proxy: If a proxy server is being used to connect to the the CTF server it should be specified. It can be left blank.
19
+ def self.request(req_msg, server=nil, proxy=nil)
20
+ return unless req_msg.kind_of? Struct
21
+
22
+ server ||= @server
23
+
24
+ if server.nil?
25
+ raise(TeamForgeError, "No TeamForge server specified")
26
+ else
27
+ @server = format_url(server)
28
+ end
29
+
30
+ proxy ||= @proxy
31
+
32
+ @endpoint, method = req_msg.class.to_s.split("::").pop(2)
33
+ @endpoint == "TeamForge" ? @endpoint = "CollabNet" : @endpoint
34
+
35
+ method = "#{method.slice!(0).downcase}#{method}".to_sym
36
+
37
+ response_msg = "#{method}Response".to_sym
38
+ return_msg = "#{method}Return".to_sym
39
+
40
+
41
+ fq_path = @server + SERVICE_PATH + @endpoint
42
+
43
+
44
+ # The client from Savon is instantiated with the proper namespace, the endpoint for the request, and SSL verification (from HTTPI) turned off
45
+ client = Savon::Client.new {wsdl.namespace = SERVICE_NAMESPACE; wsdl.endpoint = fq_path; http.auth.ssl.verify_mode= :none }
46
+
47
+ # proxy support in case CTF needs to be accessed through a proxy
48
+ if proxy
49
+ client.http.proxy = @proxy
50
+ end
51
+
52
+
53
+ unless req_msg.respond_to? :empty
54
+ message = Hash[req_msg.each_pair.to_a]
55
+
56
+ # if a TeamForge Struct was sent to the function it has to be converted to a hash first to be processed by Savon
57
+ # Luckily there is an easy method to convert a Struct to a Hash
58
+ message.each do |key, value|
59
+ message[key] = rep_blank_with_nil(value)
60
+ end
61
+ end
62
+
63
+ message[:order!] = req_msg.members
64
+
65
+ begin
66
+ # This is the only place that the Savon::Client is currently used. It creates a SOAP requests with the required namespaces, headers, and the SOAP message that was sent to the request method.
67
+ # The response message from the CTF server is a SOAP method.
68
+ ctfresponse = client.request(method) do
69
+ soap.namespaces["xmlns:tns1"] = TYPE_NAMESPACE
70
+ soap.namespaces["xmlns:impl"] = SERVICE_NAMESPACE
71
+ soap.namespaces["xmlns:soapenc"] = SOAP_NAMESPACE
72
+ soap.body = message
73
+ end
74
+ # Return any error messages in a return hash. This error might be SOAP, HTTPI, or generic error. Each method checks for presense of fault but does not raise runtime error.
75
+ # Raising runtime exceptions is left to the calling program
76
+ rescue Exception => e
77
+ raise(TeamForgeError, e.message)
78
+ end
79
+
80
+ # if there are no errors our call to CTF was successful and we need to parse the response
81
+ # Savon does not handle MultiRef responses so we get a Nokogiri XML document and send that to our custom parser
82
+ # The parser must also be told what CTF return message that is expected
83
+ @response_doc = ctfresponse.doc
84
+
85
+ parse_response(response_msg)[return_msg]
86
+
87
+ end
88
+
89
+ # A very basic Nokogiri parser. This function requires two parameters:
90
+ # property: This is the return message that the specific CTF method is expected to return
91
+ # E.g. :loginResponse
92
+ # response: This parameter is expected to be a Nokogiri document.
93
+ # This method returns a hash. The key for hash will be the element name of the return and the value will be the element value.
94
+ # If the element has an "href" attribute the return value is a complex type and must be parsed as a complex type.
95
+ # If DataRows are present then the response is an array of complexTypes and an array must be created to hold these datarows.
96
+ # If it is a complexType this function will return an object of the type specified.
97
+ # E.g. UserSoapDO
98
+ def self.parse_response(doc_node)
99
+ return_msg = {}
100
+ @response_doc.xpath("//#{doc_node.to_s}").children.each do |child|
101
+
102
+ href = child.attribute("href").to_s.gsub("#","")
103
+
104
+ unless href.empty?
105
+ multiref = @response_doc.xpath("//multiRef[@id='#{href}']")
106
+
107
+ if multiref.children.first.name == "dataRows"
108
+ datarows = []
109
+ multiref.children.children.each do |datarow|
110
+ data_href = datarow.attribute("href").to_s.gsub("#","")
111
+ datarows.push(create_struct(@response_doc.xpath("//multiRef[@id='#{data_href}']")))
112
+ end
113
+ return_msg[child.name.to_sym] = datarows
114
+ else
115
+ return_msg[child.name.to_sym] = create_struct(multiref)
116
+ end
117
+ else
118
+ return_msg[child.name.to_sym] = child.text
119
+ end
120
+ end
121
+ return return_msg
122
+ end
123
+
124
+ # Takes a Nokogiri node and parses it into the object type specified
125
+ # The return type is a Ruby object
126
+ def self.create_struct(node)
127
+
128
+ @endpoint == "CollabNet" ? ctfapp="TeamForge" : ctfapp="TeamForge::#{@endpoint}"
129
+ attributes = {}
130
+
131
+ type = node.attribute("type").to_s.split(":")[1]
132
+
133
+ new_struct = eval("#{ctfapp}::#{type}.new")
134
+
135
+ node.children.each do |element|
136
+
137
+ el_type = element.attribute("type").to_s.split(":")[1].to_s.downcase.to_sym
138
+ node_href = element.attribute("href").to_s.gsub("#","")
139
+
140
+ element.name = element.name.snakecase
141
+
142
+ unless node_href.empty?
143
+ new_struct[element.name] = create_struct(@response_doc.xpath("//multiRef[@id='#{node_href}']"))
144
+ else
145
+ if el_type == :array
146
+ unless element.child.nil?
147
+ new_struct[element.name.to_sym] = {element.name.to_sym => element.element_children.map {|chld| chld.text.to_s }, :attributes! => { element.child.name.to_sym => {'xsi:type' => element.child.attribute("type").to_s}}}
148
+ end
149
+ attributes[element.name.to_sym] = {'soapenc:arrayType'=> element.attribute("arrayType").to_s, 'xsi:type' => element.attribute("type").to_s}
150
+ else
151
+ new_struct[element.name] = element.text.to_s
152
+ attributes[element.name.to_sym] = {'xsi:type' => element.attribute("type").to_s}
153
+ end
154
+ end
155
+
156
+ end
157
+
158
+ new_struct[:attributes!] = attributes
159
+
160
+ return new_struct
161
+ end
162
+
163
+ def self.rep_blank_with_nil(value)
164
+
165
+ if value.kind_of? Struct
166
+ struct_param = Hash[value.each_pair.to_a]
167
+
168
+ struct_param.each do |k, v|
169
+ struct_param[k] = rep_blank_with_nil(v)
170
+ end
171
+
172
+ value = struct_param
173
+
174
+ else
175
+ unless value.nil?
176
+ if value.blank?
177
+ value = nil
178
+ end #if
179
+ end #unless
180
+ end #if
181
+ return value
182
+ end #def
183
+
184
+
185
+
186
+ #end
187
+
188
+ end
189
+
@@ -0,0 +1,91 @@
1
+
2
+ module TeamForge
3
+ module CategorizationApp
4
+
5
+ ######################
6
+ # CategorizationApp Messages
7
+ ######################
8
+ AddProjectToCategory = Struct.new(:session_id, :project_id, :category_id) do
9
+ def send (server=nil, proxy=nil)
10
+ TeamForge.request(self, server, proxy)
11
+ end
12
+ end
13
+ CreateCategory = Struct.new(:session_id, :parent_id, :title, :description) do
14
+ def send (server=nil, proxy=nil)
15
+ TeamForge.request(self, server, proxy)
16
+ end
17
+ end
18
+ DeleteCategory = Struct.new(:session_id, :category_id) do
19
+ def send (server=nil, proxy=nil)
20
+ TeamForge.request(self, server, proxy)
21
+ end
22
+ end
23
+ GetAllCategories = Struct.new(:session_id) do
24
+ def send (server=nil, proxy=nil)
25
+ TeamForge.request(self, server, proxy)
26
+ end
27
+ end
28
+ GetCategoryData = Struct.new(:session_id, :category_id) do
29
+ def send (server=nil, proxy=nil)
30
+ TeamForge.request(self, server, proxy)
31
+ end
32
+ end
33
+ GetCategoryProjects = Struct.new(:session_id, :category_id, :include_subcategories) do
34
+ def send (server=nil, proxy=nil)
35
+ TeamForge.request(self, server, proxy)
36
+ end
37
+ end
38
+ GetProjectCategories = Struct.new(:session_id, :project_id) do
39
+ def send (server=nil, proxy=nil)
40
+ TeamForge.request(self, server, proxy)
41
+ end
42
+ end
43
+ GetRootCategoryData = Struct.new(:session_id) do
44
+ def send (server=nil, proxy=nil)
45
+ TeamForge.request(self, server, proxy)
46
+ end
47
+ end
48
+ GetSubcategories = Struct.new(:session_id, :category_id, :recursive) do
49
+ def send (server=nil, proxy=nil)
50
+ TeamForge.request(self, server, proxy)
51
+ end
52
+ end
53
+ GetUncategorizedProjects = Struct.new(:session_id) do
54
+ def send (server=nil, proxy=nil)
55
+ TeamForge.request(self, server, proxy)
56
+ end
57
+ end
58
+ IsCategorizationEnabled = Struct.new(:session_id) do
59
+ def send (server=nil, proxy=nil)
60
+ TeamForge.request(self, server, proxy)
61
+ end
62
+ end
63
+ MoveCategory = Struct.new(:session_id, :category_id, :dst_category_id) do
64
+ def send (server=nil, proxy=nil)
65
+ TeamForge.request(self, server, proxy)
66
+ end
67
+ end
68
+ RemoveProjectFromCategory = Struct.new(:session_id, :project_id, :category_id) do
69
+ def send (server=nil, proxy=nil)
70
+ TeamForge.request(self, server, proxy)
71
+ end
72
+ end
73
+ SetCategoryData = Struct.new(:session_id, :category_data) do
74
+ def send (server=nil, proxy=nil)
75
+ TeamForge.request(self, server, proxy)
76
+ end
77
+ end
78
+
79
+
80
+ ######################
81
+ # CategorizationApp Types
82
+ ######################
83
+
84
+ CategorySoapDO = Struct.new(:created_by,:created_date,:description,:id,:last_modified_by,:last_modified_date,:parent_folder_id,:path,:project_id,:title,:version, :attributes!)
85
+ CategorySoapRow = Struct.new(:created_by,:created_on,:description,:id,:last_modified_by,:last_modified_on,:parent_folder_id,:path,:project_id,:title, :attributes!)
86
+ ProjectSoapRow = Struct.new(:date_created,:description,:hierarchy_path,:id,:locked,:parent_project_id,:path,:title, :attributes!)
87
+
88
+ end # module CategorizationApp
89
+
90
+
91
+ end # module TeamForge