Module: TeamForge

Defined in:
lib/teamforge.rb,
lib/teamforge/tftype.rb,
lib/teamforge/ctfsoap.rb,
lib/teamforge/version.rb,
lib/teamforge/tfsoaprequest.rb,
lib/teamforge/services/frsapp.rb,
lib/teamforge/services/scmapp.rb,
lib/teamforge/services/newsapp.rb,
lib/teamforge/services/pageapp.rb,
lib/teamforge/services/rbacapp.rb,
lib/teamforge/services/taskapp.rb,
lib/teamforge/services/wikiapp.rb,
lib/teamforge/services/collabnet.rb,
lib/teamforge/services/trackerapp.rb,
lib/teamforge/services/documentapp.rb,
lib/teamforge/services/planningapp.rb,
lib/teamforge/services/scmlistener.rb,
lib/teamforge/services/pluggableapp.rb,
lib/teamforge/services/discussionapp.rb,
lib/teamforge/services/categorizationapp.rb,
lib/teamforge/services/integrationdataapp.rb,
lib/teamforge/services/simplefilestorageapp.rb

Defined Under Namespace

Modules: CategorizationApp, DiscussionApp, DocumentApp, FrsApp, IntegrationDataApp, NewsApp, PageApp, PlanningApp, PluggableApp, RbacApp, ScmApp, ScmListener, SimpleFileStorageApp, TaskApp, TrackerApp, WikiApp Classes: TFSoapRequest, TFType, TeamForgeError

Constant Summary collapse

SERVICE_NAMESPACE =
"http://schema.open.collab.net/sfee50/soap60/service"
TYPE_NAMESPACE =
"http://schema.open.collab.net/sfee50/soap60/type"
SOAP_NAMESPACE =
"http://schemas.xmlsoap.org/soap/encoding/"
SERVICE_PATH =
"/ce-soap60/services/"
VERSION =
"0.1.9"
AddProjectGroupAdmins =

CollabNet Messages

TFSoapRequest.new(:session_id, :project_group_id, :usernames)
AddProjectGroupMember =
TFSoapRequest.new(:session_id, :project_group_id, :user_name)
AddProjectMember =
TFSoapRequest.new(:session_id, :project_id, :user_name)
AddProjectsToProjectGroup =
TFSoapRequest.new(:session_id, :project_group_id, :project_ids)
AddUserGroupMember =
TFSoapRequest.new(:session_id, :user_group_id, :user_name)
CanReceiveOwnUpdates =
TFSoapRequest.new(:session_id)
ChangeIAObjectTitle =
TFSoapRequest.new(:session_id, :pluggable_object_id, :pluggable_object_title)
ChangePassword =
TFSoapRequest.new(:session_id, :user_name, :new_password)
CreateAssociation =
TFSoapRequest.new(:session_id, :origin_id, :target_id, :description)
CreateAssociationWithTitles =
TFSoapRequest.new(:session_id, :origin_id, :origin_title, :target_id, :target_title, :description)
CreateOrReplaceProjectTemplate =
TFSoapRequest.new(:session_id, :project_id, :title, :description, :content_choices, :template_id)
CreateProjectFromTemplate =
TFSoapRequest.new(:session_id, :template_id, :name, :title, :description)
CreateProjectGroup =
TFSoapRequest.new(:session_id, :title, :description)
CreateProject =
TFSoapRequest.new(:session_id, :name, :title, :description)
CreateSiteWideLinkedApp =
TFSoapRequest.new(:session_id, :title, :application_url, :application_type, :single_signon)
CreateUserGroup =
TFSoapRequest.new(:session_id, :full_name, :description)
CreateUser =
TFSoapRequest.new(:session_id, :user_name, :email, :full_name, :organization, :locale, :time_zone, :license_type, :is_super_user, :is_restricted_user, :password)
DeleteAssociation =
TFSoapRequest.new(:session_id, :origin_id, :target_id)
DeleteAttachment =
TFSoapRequest.new(:session_id, :object_id, :attachment_id)
DeleteProjectGroup =
TFSoapRequest.new(:session_id, :project_group_id, :force_delete_even_if_member_project_found)
DeleteProject =
TFSoapRequest.new(:session_id, :project_id, :no_notification, :force_delete_even_if_child_found)
DeleteUserGroup =
TFSoapRequest.new(:session_id, :group_id)
DoMandatoryPasswordChange =
TFSoapRequest.new(:user_name, :old_password, :new_password)
FindProjects =
TFSoapRequest.new(:session_id, :query_string)
FindUsers =
TFSoapRequest.new(:session_id, :query_string)
GetApiVersion =
TFSoapRequest.new(:empty)
GetAssociationList =
TFSoapRequest.new(:session_id, :object_id)
GetAuditHistoryList =
TFSoapRequest.new(:session_id, :object_id, :include_derived_changes)
GetBroadCastMessage =
TFSoapRequest.new(:session_id)
GetCommentList =
TFSoapRequest.new(:session_id, :object_id)
GetConfigurationValue =
TFSoapRequest.new(:session_id, :key_value)
GetCurrentTime =
TFSoapRequest.new(:session_id)
GetCurrentUserData =
TFSoapRequest.new(:session_id)
GetJSessionBySoapId =
TFSoapRequest.new(:soap_id)
GetJSessionId =
TFSoapRequest.new(:one_time_token)
GetMemberProjectsForProjectGroup =
TFSoapRequest.new(:session_id, :project_group_id)
GetProjectAccessLevel =
TFSoapRequest.new(:session_id, :project_id)
GetProjectByPath =
TFSoapRequest.new(:session_id, :project_path)
GetProjectData =
TFSoapRequest.new(:session_id, :project_id)
GetProjectDiskUsage =
TFSoapRequest.new(:session_id, :project_id)
GetProjectGroupData =
TFSoapRequest.new(:session_id, :project_group_id)
GetProjectGroupMemberList =
TFSoapRequest.new(:session_id, :project_group_id)
GetProjectGroupsForProject =
TFSoapRequest.new(:session_id, :project_id)
GetProjectHierarchyPaths =
TFSoapRequest.new(:session_id, :project_ids)
GetProjectListForUser =
TFSoapRequest.new(:session_id, :username, :fetch_hierarchy_path, :include_group_membership)
GetProjectList =
TFSoapRequest.new(:session_id, :fetch_hierarchy_path)
GetProjectMemberList =
TFSoapRequest.new(:session_id, :project_id)
GetProjectQuota =
TFSoapRequest.new(:session_id, :project_id)
GetSessionId =
TFSoapRequest.new(:one_time_token)
GetSubprojectList =
TFSoapRequest.new(:session_id, :project_id, :fetch_hierarchy_path)
GetUserByEmail =
TFSoapRequest.new(:session_id, :email)
GetUserByName =
TFSoapRequest.new(:session_id, :fullname)
GetUserData2 =
TFSoapRequest.new(:session_id, :username)
GetUserData =
TFSoapRequest.new(:session_id, :username)
GetUserEffectiveMode =
TFSoapRequest.new(:session_id)
GetUserGroupData =
TFSoapRequest.new(:session_id, :group_id)
GetUserGroupListForProject =
TFSoapRequest.new(:session_id, :project_or_project_group_id)
GetUserGroupListForUser =
TFSoapRequest.new(:session_id, :username)
GetUserGroupList =
TFSoapRequest.new(:session_id)
GetUserGroupMembers =
TFSoapRequest.new(:session_id, :group_id)
GetUserList =
TFSoapRequest.new(:session_id, :soap_filter)
GetUserSessionBySoapId =
TFSoapRequest.new(:soap_id)
GetVersionInformationList =
TFSoapRequest.new(:session_id, :folder_id)
GetVersion =
TFSoapRequest.new(:session_id)
GetWebAndSoapSessionId =
TFSoapRequest.new(:one_time_token)
HasGeneralPermission =
TFSoapRequest.new(:session_id, :username, :project_id, :operation_string, :object_id)
HasPermission2 =
TFSoapRequest.new(:session_id, :project_id, :operation_string, :object_id)
HasPermission =
TFSoapRequest.new(:session_id, :username, :project_id, :operation_string, :object_id)
HasSitewideRolePermission =
TFSoapRequest.new(:session_id, :operation_string)
IsHostedMode =
TFSoapRequest.new(:session_id)
KeepAlive =
TFSoapRequest.new(:session_id)
ListAttachments =
TFSoapRequest.new(:session_id, :object_id)
ListGroupsWithGeneralPermission =
TFSoapRequest.new(:session_id, :project_id, :operation_string, :folder_id, :include_inherited)
ListProjectAdmins =
TFSoapRequest.new(:session_id, :project_id)
ListProjectGroups =
TFSoapRequest.new(:session_id)
ListTemplates =
TFSoapRequest.new(:session_id)
ListUsersWithGeneralPermission =
TFSoapRequest.new(:session_id, :project_id, :operation_string, :folder_id)
ListUsersWithPermissionOnObject =
TFSoapRequest.new(:session_id, :operation_string, :object_id, :flag)
LockProject =
TFSoapRequest.new(:session_id, :project_id)
LoginAnonymous =
TFSoapRequest.new(:anon_shared_secret)
Login =
TFSoapRequest.new(:user_name, :password)
LoginWithToken =
TFSoapRequest.new(:username, :one_time_token)
Logoff =
TFSoapRequest.new(:user_name, :session_id)
ReindexObject =
TFSoapRequest.new(:session_id, :object_id)
RemoveProjectGroupAdmins =
TFSoapRequest.new(:session_id, :project_group_id, :usernames)
RemoveProjectGroupMember =
TFSoapRequest.new(:session_id, :project_group_id, :user_name)
RemoveProjectMember =
TFSoapRequest.new(:session_id, :project_id, :user_name)
RemoveProjectsFromProjectGroup =
TFSoapRequest.new(:session_id, :project_member_ids, :project_group_id)
RemoveUserGroupMember =
TFSoapRequest.new(:session_id, :user_group_id, :user_name)
SetParentProject =
TFSoapRequest.new(:session_id, :project_id, :parent_project_id)
SetProjectAccessLevel =
TFSoapRequest.new(:session_id, :project_id, :access_level)
SetProjectGroupData =
TFSoapRequest.new(:session_id, :project_group_data)
SetProjectQuota =
TFSoapRequest.new(:session_id, :project_id, :quota)
SetUserData =
TFSoapRequest.new(:session_id, :user_data)
SetUserGroupData =
TFSoapRequest.new(:session_id, :group_data)
UnLockProject =
TFSoapRequest.new(:session_id, :project_id)
AssociationSoapRow =

CollabNet Types

TFType.new(:created_by,:creator_full_name,:date_created,:date_last_modified,:description,:origin_id,:origin_title,:origin_version,:target_id,:target_title,:target_version, :attributes!)
AttachmentSoapRow =
TFType.new(:attachment_id,:created_by,:created_by_fullname,:date_created,:file_name,:file_size,:mimetype,:raw_file_id,:stored_file_id,:transaction_id, :attributes!)
AuditHistorySoapRow =
TFType.new(:comment,:date_modified,:modified_by,:modifier_full_name,:new_value,:old_value,:operation,:property_name, :attributes!)
CommentSoapRow =
TFType.new(:created_by,:created_by_fullname,:date_created,:description,:id,:transaction_id, :attributes!)
ProjectGroupMemberSoapRow =
TFType.new(:email,:full_name,:user_name, :attributes!)
ProjectGroupSoapDO =
TFType.new(:created_by,:created_date,:description,:id,:last_modified_by,:last_modified_date,:path,:title,:version, :attributes!)
ProjectGroupSoapRow =
TFType.new(:date_created,:description,:id,:member_projects,:path,:title, :attributes!)
ProjectMemberSoapRow =
TFType.new(:email,:full_name,:user_name, :attributes!)
ProjectSoapDO =
TFType.new(:created_by,:created_date,:description,:hierarchy_path,:id,:last_modified_by,:last_modified_date,:locked,:parent_project_id,:path,:title,:version, :attributes!)
ProjectSoapRow =
TFType.new(:date_created,:description,:hierarchy_path,:id,:locked,:parent_project_id,:path,:title, :attributes!)
SoapFilter =
TFType.new(:name,:value, :attributes!)
SoapNamedValues =
TFType.new(:names,:values, :attributes!)
User2SoapDO =
TFType.new(:alternate_email1,:alternate_email2,:alternate_email3,:created_by,:created_date,:email,:full_name,:id,:last_login,:last_modified_by,:last_modified_date,:license_type,:locale,:organization,:profile_picture_link,:restricted_user,:status,:super_user,:time_zone,:username,:version, :attributes!)
UserGroupSoapDO =
TFType.new(:created_by,:created_date,:description,:full_name,:id,:last_modified_by,:last_modified_date,:version, :attributes!)
UserGroupSoapRow =
TFType.new(:description,:full_name,:id, :attributes!)
UserSoapDO =
TFType.new(:alternate_email1,:alternate_email2,:alternate_email3,:created_by,:created_date,:email,:full_name,:id,:last_login,:last_modified_by,:last_modified_date,:license_type,:locale,:organization,:restricted_user,:status,:super_user,:time_zone,:username,:version, :attributes!)
UserSoapRow =
TFType.new(:alternate_email1,:alternate_email2,:alternate_email3,:email,:full_name,:last_login,:license_type,:locale,:organization,:restricted_user,:status,:super_user,:time_zone,:user_name, :attributes!)
VersionInformationSoapRow =
TFType.new(:id,:is_folder,:last_modified_date,:version, :attributes!)

Class Method Summary collapse

Class Method Details

.create_struct(node) ⇒ Object

Takes a Nokogiri node and parses it into the object type specified The return type is a Ruby object



139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/teamforge/ctfsoap.rb', line 139

def self.create_struct(node)
  
  @endpoint == "CollabNet" ? ctfapp="TeamForge" : ctfapp="TeamForge::#{@endpoint}"
  attributes = {}

  type = node.attribute("type").to_s.split(":")[1]
  
  new_struct = eval("#{ctfapp}::#{type}.new")
  
  node.children.each do |element| 
    
    el_type = element.attribute("type").to_s.split(":")[1].to_s.downcase.to_sym
    node_href = element.attribute("href").to_s.gsub("#","")
    
    element.name = element.name.snakecase
    
    unless node_href.empty?
      new_struct[element.name] = create_struct(@response_doc.xpath("//multiRef[@id='#{node_href}']"))
    else
      if el_type == :array
        unless element.child.nil?
          new_struct[element.name.to_sym] = {element.name.to_sym => element.element_children.map {|chld| rep_blank_with_nil(chld.text.to_s) }, :attributes! => { element.child.name.to_sym => {'xsi:type' => element.child.attribute("type").to_s}}}
        end
        attributes[element.name.to_sym] = {'soapenc:arrayType'=> element.attribute("arrayType").to_s, 'xsi:type' => element.attribute("type").to_s}
      else 
        new_struct[element.name] = rep_blank_with_nil(element.text.to_s)
        attributes[element.name.to_sym] = {'xsi:type' => element.attribute("type").to_s}
      end
    end
    
  end
  
  new_struct[:attributes!] = attributes

  return new_struct
end

.format_url(url, ssl = nil) ⇒ Object



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/teamforge.rb', line 72

def self.format_url(url, ssl=nil)
 
  @use_ssl.nil? ? @use_ssl = true : @use_ssl
  
  ssl.nil? ? ssl = @use_ssl : @use_ssl = ssl
  
  if ssl 
    url = "https://#{url.gsub(/^http(|s):\/\/?/i,'')}"
  else
    url = "http://#{url.gsub(/^http(|s):\/\/?/i,'')}"
  end
  
  uri = URI.parse url
  unless uri.kind_of? URI::HTTP
    raise TeamForgeError "Invalid Server URL"
  end
      
  return url
  
end

.hash_recursive(msg) ⇒ Object

def



198
199
200
201
202
203
204
205
# File 'lib/teamforge/ctfsoap.rb', line 198

def self.hash_recursive(msg)
  return msg unless msg.kind_of? Struct
  
  struct_param = Hash[msg.each_pair.to_a]
      struct_param.each do |k, v| 
        struct_param[k] = hash_recursive(v)
      end
end

.parse_response(doc_node) ⇒ Object

A very basic Nokogiri parser. This function requires two parameters:

property: This is the return message that the specific CTF method is expected to return
  E.g.  :loginResponse
response: This parameter is expected to be a Nokogiri document.

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. If the element has an “href” attribute the return value is a complex type and must be parsed as a complex type. If DataRows are present then the response is an array of complexTypes and an array must be created to hold these datarows. If it is a complexType this function will return an object of the type specified.

E.g. UserSoapDO


107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/teamforge/ctfsoap.rb', line 107

def self.parse_response(doc_node)
   return_msg = {}
   @response_doc.xpath("//#{doc_node.to_s}").children.each do |child|
     
     href = child.attribute("href").to_s.gsub("#","")
     
     unless href.empty?
       multiref = @response_doc.xpath("//multiRef[@id='#{href}']")
       
      if multiref.children.first.name == "dataRows"
        datarows = []
        multiref.children.children.each do |datarow|
          if datarow.name == "dataRows"
            data_href = datarow.attribute("href").to_s.gsub("#","")
            datarows.push(create_struct(@response_doc.xpath("//multiRef[@id='#{data_href}']")))
           else
             datarows.push({datarow.parent.name.snakecase.to_sym => rep_blank_with_nil(datarow.text)})
           end
        end
        return_msg[child.name.to_sym] = datarows
      else
        return_msg[child.name.to_sym] = create_struct(multiref)
      end
    else
      return_msg[child.name.to_sym] = rep_blank_with_nil(child.text)
    end
  end
  return return_msg
end

.proxyObject



36
37
38
# File 'lib/teamforge.rb', line 36

def self.proxy
  @proxy
end

.proxy=(proxy) ⇒ Object



40
41
42
# File 'lib/teamforge.rb', line 40

def self.proxy=(proxy)
  @proxy=format_url(proxy)
end

.rep_blank_with_nil(value) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/teamforge/ctfsoap.rb', line 176

def self.rep_blank_with_nil(value)
  
  # if value.kind_of? Struct
  #         struct_param = Hash[value.each_pair.to_a]
  #         
  #         struct_param.each do |k, v| 
  #           struct_param[k] = rep_blank_with_nil(v)
  #         end
  #         
  #         value = struct_param
  #         
  #       else
    unless value.nil?
      if value.blank?
        value = nil
      end #if
      
    end #unless
 # end #if
  return value
end

.request(req_msg, server = nil, ssl = nil, proxy = nil) ⇒ Object

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 and it also makes it easier to troubleshoot because there is one place to trap messages to and from the server. 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. 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.

E.g. CTF.request(method, message, endpoint, response, proxy=nil)

Each request to the CTF server expects the following information:

method: This is the function call that the server is expected to complete. A symbol is expected. E.g. :login
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. 
  All objects provided in this SDK include a to_h function to convert all instance variables into a nested hash with the object type.
  E.g. {:userName=>username, :password=>password, {:order! => [:userName, :password]} }
  The order! key tells the message the parameter order expected by the server. CTF is picky about parameter order.
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.
  E.g. "http://localhost:8080/ce-soap60/services/TrackerApp"
response: The response message name that is expected from a successful call to the CTF server.  A symbol is expected
  E.g. :loginResponse
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
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/teamforge/ctfsoap.rb', line 19

def self.request(req_msg, server=nil, ssl=nil, proxy=nil)
  return unless req_msg.kind_of? Struct
  
  server ||= @server
  
  if server.nil?
    raise(TeamForgeError, "No TeamForge server specified")
  else
    @server = format_url(server, ssl)
  end
  
  proxy ||= @proxy
  
  @endpoint, method = req_msg.class.to_s.split("::").pop(2)
  @endpoint == "TeamForge" ? @endpoint = "CollabNet" : @endpoint
  
  method = "#{method.slice!(0).downcase}#{method}".to_sym 
  
  response_msg = "#{method}Response".to_sym
  return_msg = "#{method}Return".to_sym
    
  soap_service_path = (@endpoint == 'ScmListener') ? '/ce-soap/services/' : SERVICE_PATH
  fq_path = @server + soap_service_path + @endpoint
  
  
  @verbose ||= false
  
  Savon.configure do |config|
    config.log = verbose?            # disable logging
    config.log_level = :info      # changing the log level
  end
  HTTPI.log = verbose?     # disable HTTPI logging

  
  # The client from Savon is instantiated with the proper namespace, the endpoint for the request, and SSL verification (from HTTPI) turned off
  client = Savon::Client.new {wsdl.namespace = SERVICE_NAMESPACE; wsdl.endpoint = fq_path; http.auth.ssl.verify_mode= :none }

  # proxy support in case CTF needs to be accessed through a proxy
  if proxy
    client.http.proxy = @proxy
  end

  
  unless req_msg.respond_to? :empty
    message = Hash[req_msg.each_pair.to_a]

    message.each do |key, value|
        message[key] = hash_recursive(value)
    end
  end
         
  message[:order!] = req_msg.members
  xml_request = ""

  begin
    # 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.
    # The response message from the CTF server is a SOAP method.  
    ctfresponse = client.request(method) do
      soap.namespaces["xmlns:tns1"] = TYPE_NAMESPACE  
      soap.namespaces["xmlns:impl"] = SERVICE_NAMESPACE 
      soap.namespaces["xmlns:soapenc"] = SOAP_NAMESPACE
      soap.body = message
      xml_request = http
    end
    # 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. 
    # Raising runtime exceptions is left to the calling program
  rescue Exception => e  
    raise TeamForgeError.new(e.message, xml_request.body)
  end
  
  # if there are no errors our call to CTF was successful and we need to parse the response
  # Savon does not handle MultiRef responses so we get a Nokogiri XML document and send that to our custom parser
  # The parser must also be told what CTF return message that is expected
  @response_doc = ctfresponse.doc
  
  parse_response(response_msg)[return_msg]

end

.serverObject



44
45
46
# File 'lib/teamforge.rb', line 44

def self.server
  @server
end

.server=(server) ⇒ Object



48
49
50
# File 'lib/teamforge.rb', line 48

def self.server=(server)
  @server=format_url(server, @use_ssl)
end

.use_sslObject



64
65
66
# File 'lib/teamforge.rb', line 64

def self.use_ssl
  @use_ssl
end

.use_ssl=(use_ssl) ⇒ Object



68
69
70
# File 'lib/teamforge.rb', line 68

def self.use_ssl=(use_ssl)
  @use_ssl = use_ssl
end

.verbose=(verbose) ⇒ Object



56
57
58
59
60
61
62
# File 'lib/teamforge.rb', line 56

def self.verbose=(verbose)
  if !!verbose == true && verbose != 0
    @verbose=true
  else
    @verbose=false
  end
end

.verbose?Boolean

Returns:

  • (Boolean)


52
53
54
# File 'lib/teamforge.rb', line 52

def self.verbose?
  @verbose
end