Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 92 additions & 24 deletions drivers/cisco/webex/cloud_xapi.cr
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,83 @@ class Cisco::Webex::Cloud < PlaceOS::Driver

command({"UserInterface LedControl Color Set" => :led_colour}, color: Colour)

def list_workspaces(org_id : String? = nil, location_id : String? = nil, workspace_location_id : String? = nil, floor_id : String? = nil,
display_name : String? = nil, capacity : Int32? = nil, workspace_type : String? = nil, start : Int32? = nil, max : Int32? = nil,
calling : String? = nil, supported_devices : String? = nil, calendar : String? = nil, device_hosted_meetings_enabled : Bool? = nil,
device_platform : String? = nil, health_level : String? = nil)
params = URI::Params.build do |form|
form.add("orgId", org_id.to_s) if org_id
form.add("locationId", location_id.to_s) if location_id
form.add("workspaceLocationId", workspace_location_id.to_s) if workspace_location_id
form.add("floorId", floor_id.to_s) if floor_id
form.add("displayName", display_name.to_s) if display_name
form.add("capacity", capacity.to_s) if capacity
form.add("type", workspace_type.to_s) if workspace_type
form.add("start", start.to_s) if start
form.add("max", max.to_s) if max
form.add("calling", calling.to_s) if calling
form.add("supportedDevices", supported_devices.to_s) if supported_devices
form.add("calendar", calendar.to_s) if calendar
form.add("deviceHostedMeetingsEnabled", device_hosted_meetings_enabled.to_s) if device_hosted_meetings_enabled
form.add("devicePlatform", device_platform.to_s) if device_platform
form.add("healthLevel", health_level.to_s) if health_level
end

query = params.empty? ? nil : params.to_s
api_get("/v1/workspaces", query)
end

def workspace_details(workspace_id : String)
api_get("/v1/workspaces/#{workspace_id}")
end

def list_devices(max : Int32? = nil, start : Int32? = nil, display_name : String? = nil, person_id : String? = nil, workspace_id : String? = nil,
org_id : String? = nil, connection_status : String? = nil, product : String? = nil, device_type : String? = nil, serial : String? = nil,
tag : String? = nil, software : String? = nil, upgrade_channel : String? = nil, error_code : String? = nil, capability : String? = nil,
permission : String? = nil, location_id : String? = nil, workspace_location_id : String? = nil, mac : String? = nil, device_platform : String? = nil)
params = URI::Params.build do |form|
form.add("max", max.to_s) if max
form.add("start", start.to_s) if start
form.add("displayName", display_name.to_s) if display_name

form.add("personId", person_id.to_s) if person_id
form.add("workspaceId", workspace_id.to_s) if workspace_id
form.add("orgId", org_id.to_s) if org_id
form.add("connectionStatus", connection_status.to_s) if connection_status
form.add("product", product.to_s) if product
form.add("type", device_type.to_s) if device_type
form.add("tag", tag.to_s) if tag
form.add("serial", serial.to_s) if serial
form.add("software", software.to_s) if software
form.add("upgradeChannel", upgrade_channel.to_s) if upgrade_channel
form.add("errorCode", error_code.to_s) if error_code
form.add("capability", capability.to_s) if capability
form.add("permission", permission.to_s) if permission
form.add("locationId", location_id.to_s) if location_id
form.add("workspaceLocationId", workspace_location_id.to_s) if workspace_location_id
form.add("mac", mac.to_s) if mac
form.add("devicePlatform", device_platform.to_s) if device_platform
end
query = params.empty? ? nil : params.to_s
api_get("/v1/devices", query)
end

def device_details(device_id : String, org_id : String? = nil)
params = URI::Params.build do |form|
form.add("orgId", org_id.to_s) if org_id
end

query = params.empty? ? nil : params.to_s
api_get("/v1/devices/#{device_id}", query)
end

def status(device_id : String, name : String)
query = URI::Params.build do |form|
form.add("deviceId", device_id)
form.add("name", name)
end

headers = HTTP::Headers{
"Authorization" => get_access_token,
"Content-Type" => "application/json",
"Accept" => "application/json",
}

headers = get_headers
logger.debug { {msg: "Status HTTP Data:", headers: headers.to_json, query: query.to_s} } if @debug_payload

response = get("/v1/xapi/status?#{query}", headers: headers)
Expand All @@ -79,30 +144,30 @@ class Cisco::Webex::Cloud < PlaceOS::Driver
end

def command(name : String, payload : String)
headers = HTTP::Headers{
"Authorization" => get_access_token,
"Content-Type" => "application/json",
"Accept" => "application/json",
}
headers = get_headers
logger.debug { {msg: "Command HTTP Data:", headers: headers.to_json, command: name, payload: payload} } if @debug_payload

response = post("/v1/xapi/command/#{name}", headers: headers, body: payload)
raise "failed to execute command #{name}, code #{response.status_code}, body: #{response.body}" unless response.success?
JSON.parse(response.body)
end

def api_get(resource : String, query : String? = nil)
headers = get_headers
logger.debug { {msg: "GET #{resource}:", headers: headers.to_json, query: query.to_s} } if @debug_payload
uri = query.presence ? resource + "?#{query}" : resource
response = get(uri, headers: headers)
raise "failed to get #{resource}, code #{response.status_code}, body: #{response.body}" unless response.success?
JSON.parse(response.body)
end

def config?(device_id : String, name : String)
query = URI::Params.build do |form|
form.add("deviceId", device_id)
form.add("key", name)
end

headers = HTTP::Headers{
"Authorization" => get_access_token,
"Content-Type" => "application/json",
"Accept" => "application/json",
}

headers = get_headers
logger.debug { {msg: "Status HTTP Data:", headers: headers.to_json, query: query.to_s} } if @debug_payload

response = get("/v1/deviceConfigurations?#{query}", headers: headers)
Expand All @@ -125,12 +190,7 @@ class Cisco::Webex::Cloud < PlaceOS::Driver
form.add("deviceId", device_id)
end

headers = HTTP::Headers{
"Authorization" => get_access_token,
"Content-Type" => "application/json-patch+json",
"Accept" => "application/json",
}

headers = get_headers("application/json-patch+json")
logger.debug { {msg: "Config HTTP Data:", headers: headers.to_json, query: query, payload: payload} } if @debug_payload

response = patch("/v1/deviceConfigurations?#{query}", headers: headers, body: payload)
Expand Down Expand Up @@ -185,6 +245,14 @@ class Cisco::Webex::Cloud < PlaceOS::Driver

protected def keep_token_refreshed : Nil
return if @device_token.nil?
refresh_token if 1.minute.from_now <= device_token.refresh_expiry
refresh_token if 1.minute.from_now >= device_token.refresh_expiry
end

private def get_headers(content_type : String = "application/json")
HTTP::Headers{
"Authorization" => get_access_token,
"Content-Type" => content_type,
"Accept" => "application/json",
}
end
end
81 changes: 81 additions & 0 deletions drivers/cisco/webex/cloud_xapi_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,32 @@ DriverSpecs.mock_driver "Cisco::Webex::Cloud" do
end

ret_val.get.try &.as_h["status"].should eq "OK"

ret_val = exec(:list_workspaces)

expect_http_request(2.seconds) do |request, response|
if request.path == "/v1/workspaces" && request.query_params.empty?
response.status_code = 200
response << workspace_resp.to_json
else
response.status_code = 401
end
end

ret_val.get.try &.as_h["items"].as_a.size.should eq 1

ret_val = exec(:workspace_details, "some-workspace-id")

expect_http_request(2.seconds) do |request, response|
if request.path == "/v1/workspaces/some-workspace-id" && request.query_params.empty?
response.status_code = 200
response << workspace_resp[:items][0].to_json
else
response.status_code = 401
end
end

ret_val.get.try &.as_h["capacity"].as_i.should eq 5
end

def color_resp(device_id : String)
Expand All @@ -89,3 +115,58 @@ def device_resp_json
"refresh_token_expires_in": 7697037,
}
end

def workspace_resp
{
"items": [
{
"id": "Y2lzY29zcGFyazovL3VzL1BMQUNFUy81MTAxQjA3Qi00RjhGLTRFRjctQjU2NS1EQjE5QzdCNzIzRjc",
"orgId": "Y2lzY29zcGFyazovL3VzL09SR0FOSVpBVElPTi8xZWI2NWZkZi05NjQzLTQxN2YtOTk3NC1hZDcyY2FlMGUxMGY",
"locationId": "Y2lzY29...",
"workspaceLocationId": "YL34GrT...",
"floorId": "Y2lzY29z...",
"displayName": "SFO-12 Capanina",
"capacity": 5,
"type": "notSet",
"sipAddress": "test_workspace_1@trialorg.room.ciscospark.com",
"created": "2016-04-21T17:00:00.000Z",
"calling": {
"type": "hybridCalling",
"hybridCalling": {
"emailAddress": "workspace@example.com",
},
"webexCalling": {
"licenses": [
"Y2lzY29g4...",
],
},
},
"notes": "this is a note",
"hotdeskingStatus": "on",
"supportedDevices": "collaborationDevices",
"calendar": {
"type": "microsoft",
"emailAddress": "workspace@example.com",
},
"deviceHostedMeetings": {
"enabled": true,
"siteUrl": "'example.webex.com'",
},
"devicePlatform": "cisco",
"health": {
"level": "error",
"issues": [
{
"id": "",
"createdAt": "",
"title": "",
"description": "",
"recommendedAction": "",
"level": "",
},
],
},
},
],
}
end