class DynamicsCRM::Client
Constants
- OCP_LOGIN_URL
- REGION
Attributes
caller_id[RW]
hostname[R]
logger[RW]
login_url[R]
organization_endpoint[R]
region[R]
timeout[RW]
Public Class Methods
new(config={organization_name: nil, hostname: nil, caller_id: nil, login_url: nil, region: nil})
click to toggle source
Initializes Client
instance. Requires: organization_name Optional: hostname
# File lib/dynamics_crm/client.rb, line 40 def initialize(config={organization_name: nil, hostname: nil, caller_id: nil, login_url: nil, region: nil}) raise RuntimeError.new("organization_name or hostname is required") if config[:organization_name].nil? && config[:hostname].nil? @organization_name = config[:organization_name] @hostname = config[:hostname] || "#{@organization_name}.api.crm.dynamics.com" @organization_endpoint = "https://#{@hostname}/XRMServices/2011/Organization.svc" REGION.default = @organization_endpoint @caller_id = config[:caller_id] @timeout = config[:timeout] || 120 # The Login URL and Region are located in the client's Organization WSDL. # https://tinderboxdev.api.crm.dynamics.com/XRMServices/2011/Organization.svc?wsdl=wsdl0 # # Login URL: Policy -> Issuer -> Address # Region: SecureTokenService -> AppliesTo @login_url = config[:login_url] @region = config[:region] || determine_region end
Public Instance Methods
associate(entity_name, guid, relationship, related_entities)
click to toggle source
# File lib/dynamics_crm/client.rb, line 190 def associate(entity_name, guid, relationship, related_entities) request = associate_request(entity_name, guid, relationship, related_entities) xml_response = post(organization_endpoint, request) Response::AssociateResponse.new(xml_response) end
authenticate(username, password)
click to toggle source
Public: Authenticate User
Examples
client.authenticate('test@orgnam.onmicrosoft.com', 'password') # => true || raised Fault
Returns true on success or raises Fault
# File lib/dynamics_crm/client.rb, line 67 def authenticate(username, password) @username = username @password = password auth_request = if on_premise? build_on_premise_request(username, password, region, login_url) else build_ocp_request(username, password, region, login_url) end soap_response = post(login_url, auth_request) document = REXML::Document.new(soap_response) # Check for Fault fault_xml = document.get_elements("//[local-name() = 'Fault']") raise XML::Fault.new(fault_xml) if fault_xml.any? if on_premise? @security_token0 = document.get_elements("//e:CipherValue").first.text.to_s @security_token1 = document.get_elements("//xenc:CipherValue").last.text.to_s @key_identifier = document.get_elements("//o:KeyIdentifier").first.text @cert_issuer_name = document.get_elements("//X509IssuerName").first.text @cert_serial_number = document.get_elements("//X509SerialNumber").first.text @server_secret = document.get_elements("//trust:BinarySecret").first.text @header_current_time = get_current_time @header_expires_time = get_current_time_plus_hour @timestamp = '<u:Timestamp xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" u:Id="_0"><u:Created>' + @header_current_time + '</u:Created><u:Expires>' + @header_expires_time + '</u:Expires></u:Timestamp>' @digest_value = Digest::SHA1.base64digest @timestamp @signature = '<SignedInfo xmlns="http://www.w3.org/2000/09/xmldsig#"><CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></CanonicalizationMethod><SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#hmac-sha1"></SignatureMethod><Reference URI="#_0"><Transforms><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"></Transform></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"></DigestMethod><DigestValue>' + @digest_value + '</DigestValue></Reference></SignedInfo>' @signature_value = Base64.encode64(OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha1'), Base64.decode64(@server_secret), @signature)).chomp else cipher_values = document.get_elements("//CipherValue") if cipher_values && cipher_values.length > 0 @security_token0 = cipher_values[0].text @security_token1 = cipher_values[1].text # Use local-name() to ignore namespace. @key_identifier = document.get_elements("//[local-name() = 'KeyIdentifier']").first.text else raise RuntimeError.new(soap_response) end end true end
create(entity_name, attributes)
click to toggle source
These are all the operations defined by the Dynamics WSDL. Tag names are case-sensitive.
# File lib/dynamics_crm/client.rb, line 116 def create(entity_name, attributes) entity = XML::Entity.new(entity_name) entity.attributes = XML::Attributes.new(attributes) xml_response = post(organization_endpoint, create_request(entity)) Response::CreateResult.new(xml_response) end
create_attachment(entity_name, entity_id, options={})
click to toggle source
# File lib/dynamics_crm/client.rb, line 202 def create_attachment(entity_name, entity_id, options={}) raise "options must contain a document entry" unless options[:document] file_name = options[:filename] document = options[:document] subject = options[:subject] text = options[:text] || "" if document.is_a?(String) && File.exists?(document) file = File.new(document) elsif document.is_a?(String) && document.start_with?("http") require 'open-uri' file = open(document) else file = document end if file.respond_to?(:base_uri) file_name ||= File.basename(file.base_uri.path) mime_type = MimeMagic.by_path(file.base_uri.path) elsif file.respond_to?(:path) file_name ||= File.basename(file.path) mime_type = MimeMagic.by_path(file.path) else raise "file must be a valid File object, file path or URL" end documentbody = file.read attributes = { objectid: {id: entity_id, logical_name: entity_name}, subject: subject || file_name, notetext: text || "", filename: file_name, isdocument: true, documentbody: ::Base64.encode64(documentbody), filesize: documentbody.length, mimetype: mime_type } self.create("annotation", attributes) end
delete(entity_name, guid)
click to toggle source
# File lib/dynamics_crm/client.rb, line 175 def delete(entity_name, guid) request = delete_request(entity_name, guid) xml_response = post(organization_endpoint, request) Response::DeleteResponse.new(xml_response) end
disassociate(entity_name, guid, relationship, related_entities)
click to toggle source
# File lib/dynamics_crm/client.rb, line 196 def disassociate(entity_name, guid, relationship, related_entities) request = disassociate_request(entity_name, guid, relationship, related_entities) xml_response = post(organization_endpoint, request) Response::DisassociateResponse.new(xml_response) end
execute(action, parameters={}, response_class=nil)
click to toggle source
# File lib/dynamics_crm/client.rb, line 182 def execute(action, parameters={}, response_class=nil) request = execute_request(action, parameters) xml_response = post(organization_endpoint, request) response_class ||= Response::ExecuteResult response_class.new(xml_response) end
fetch(fetchxml)
click to toggle source
# File lib/dynamics_crm/client.rb, line 156 def fetch(fetchxml) response = self.execute("RetrieveMultiple", { Query: XML::FetchExpression.new(fetchxml) }) response['EntityCollection'] end
load_entity(logical_name, id)
click to toggle source
# File lib/dynamics_crm/client.rb, line 290 def load_entity(logical_name, id) case logical_name when "opportunity" Model::Opportunity.new(id, self) else Model::Entity.new(logical_name, id, self) end end
retrieve(entity_name, guid, columns=[])
click to toggle source
crmtroubleshoot.blogspot.com.au/2013/07/dynamics-crm-2011-php-and-soap-calls.html
# File lib/dynamics_crm/client.rb, line 125 def retrieve(entity_name, guid, columns=[]) column_set = XML::ColumnSet.new(columns) request = retrieve_request(entity_name, guid, column_set) xml_response = post(organization_endpoint, request) Response::RetrieveResult.new(xml_response) end
retrieve_all_entities()
click to toggle source
Metadata
Calls EntityFilters Enum: Default, Entity, Attributes, Privileges, Relationships, All
# File lib/dynamics_crm/client.rb, line 250 def retrieve_all_entities response = self.execute("RetrieveAllEntities", { EntityFilters: "Entity", RetrieveAsIfPublished: true }, Metadata::RetrieveAllEntitiesResponse) end
retrieve_attachments(entity_id, columns=["filename", "documentbody", "mimetype"])
click to toggle source
# File lib/dynamics_crm/client.rb, line 244 def retrieve_attachments(entity_id, columns=["filename", "documentbody", "mimetype"]) self.retrieve_multiple("annotation", [["objectid", "Equal", entity_id], ["isdocument", "Equal", true]], columns) end
retrieve_attribute(entity_logical_name, logical_name)
click to toggle source
# File lib/dynamics_crm/client.rb, line 269 def retrieve_attribute(entity_logical_name, logical_name) self.execute("RetrieveAttribute", { EntityLogicalName: entity_logical_name, LogicalName: logical_name, MetadataId: "00000000-0000-0000-0000-000000000000", RetrieveAsIfPublished: true }, Metadata::RetrieveAttributeResponse) end
retrieve_entity(logical_name, entity_filter="Attributes")
click to toggle source
EntityFilters Enum: Default, Entity, Attributes, Privileges, Relationships, All
# File lib/dynamics_crm/client.rb, line 259 def retrieve_entity(logical_name, entity_filter="Attributes") self.execute("RetrieveEntity", { LogicalName: logical_name, MetadataId: "00000000-0000-0000-0000-000000000000", EntityFilters: entity_filter, RetrieveAsIfPublished: true }, Metadata::RetrieveEntityResponse) end
retrieve_metadata_changes(entity_query)
click to toggle source
# File lib/dynamics_crm/client.rb, line 279 def retrieve_metadata_changes(entity_query) self.execute("RetrieveMetadataChanges", { Query: entity_query }, Metadata::RetrieveMetadataChangesResponse) end
retrieve_multiple(entity_name, criteria = [], columns = [], operator = nil)
click to toggle source
Suports parameter list or QueryExpression object.
# File lib/dynamics_crm/client.rb, line 142 def retrieve_multiple(entity_name, criteria = [], columns = [], operator = nil) if entity_name.is_a?(XML::QueryExpression) query = entity_name else query = XML::QueryExpression.new(entity_name) query.columns = columns query.criteria = XML::Criteria.new(criteria, filter_operator: operator) end request = retrieve_multiple_request(query) xml_response = post(organization_endpoint, request) Response::RetrieveMultipleResult.new(xml_response) end
rollup(target_entity, query, rollup_type="Related")
click to toggle source
# File lib/dynamics_crm/client.rb, line 133 def rollup(target_entity, query, rollup_type="Related") self.execute("Rollup", { Target: target_entity, Query: query, RollupType: rollup_type }) end
update(entity_name, guid, attributes)
click to toggle source
Update entity attributes
# File lib/dynamics_crm/client.rb, line 164 def update(entity_name, guid, attributes) entity = XML::Entity.new(entity_name) entity.id = guid entity.attributes = XML::Attributes.new(attributes) request = update_request(entity) xml_response = post(organization_endpoint, request) Response::UpdateResponse.new(xml_response) end
who_am_i()
click to toggle source
# File lib/dynamics_crm/client.rb, line 286 def who_am_i self.execute('WhoAmI') end
Protected Instance Methods
determine_region()
click to toggle source
# File lib/dynamics_crm/client.rb, line 318 def determine_region hostname.match(/(crm\d?\.dynamics.com)/) REGION[$1] end
formatter()
click to toggle source
# File lib/dynamics_crm/client.rb, line 355 def formatter unless @formatter @formatter = REXML::Formatters::Pretty.new(2) @formatter.compact = true # This is the magic line that does what you need! end @formatter end
log_xml(title, xml)
click to toggle source
# File lib/dynamics_crm/client.rb, line 345 def log_xml(title, xml) return unless logger logger.debug(title) doc = REXML::Document.new(xml) formatter.write(doc.root, logger) logger.debug("\n") end
on_premise?()
click to toggle source
# File lib/dynamics_crm/client.rb, line 301 def on_premise? @on_premise ||= !(hostname =~ /\.dynamics\.com/i) end
organization_wsdl()
click to toggle source
# File lib/dynamics_crm/client.rb, line 305 def organization_wsdl wsdl = open(organization_endpoint + "?wsdl=wsdl0").read @organization_wsdl ||= REXML::Document.new(wsdl) end
post(url, request)
click to toggle source
# File lib/dynamics_crm/client.rb, line 323 def post(url, request) log_xml('REQUEST', request) uri = URI.parse(url) http = Net::HTTP.new uri.host, uri.port http.use_ssl = true http.verify_mode = OpenSSL::SSL::VERIFY_PEER req = Net::HTTP::Post.new(uri.request_uri, 'Connection' => 'Keep-Alive', 'Content-type' => 'application/soap+xml; charset=UTF-8', 'Content-length' => request.bytesize.to_s ) req.body = request response = http.request(req) response_body = response.body log_xml('RESPONSE', response_body) response_body end