diff --git a/LearnositySDK/Request/Init.cs b/LearnositySDK/Request/Init.cs
old mode 100755
new mode 100644
index 87695c1..28ea379
--- a/LearnositySDK/Request/Init.cs
+++ b/LearnositySDK/Request/Init.cs
@@ -1,9 +1,9 @@
using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
using LearnositySDK.Utils;
using System.Web;
+using System.Runtime.InteropServices;
namespace LearnositySDK.Request
{
@@ -77,6 +77,11 @@ public class Init
///
private string algorithm;
+ ///
+ /// Determines if telemetry is enabled; default is true
+ ///
+ private static bool telemetryEnabled = true;
+
///
/// Instantiate this class with all security and request data. It will be used to create a signature.
///
@@ -153,6 +158,7 @@ private void Initialize(string service, JsonObject securityPacket, string secret
//try
//{
this.validate(this.service, ref this.securityPacket, this.secret, this.requestPacket, this.action);
+ this.addTelemetryData();
this.requestString = this.generateRequestString();
this.setServiceOptions();
this.securityPacket.set("signature", this.generateSignature());
@@ -180,7 +186,7 @@ private string generateRequestString()
{
throw new Exception("Invalid data, please check you request packet.");
}
-
+
return request;
}
@@ -191,7 +197,7 @@ private string generateRequestString()
/// - the `action` value if passed
///
/// A signature hash for the request authentication
- private string generateSignature()
+ public string generateSignature()
{
List signatureList = new List();
string temp = null;
@@ -256,7 +262,7 @@ public string generate()
{
return this.generateData(output);
}
- else if(this.service == "assess")
+ else if (this.service == "assess")
{
output = this.generateAssess(output);
}
@@ -277,7 +283,7 @@ public string generate()
// do nothing
break;
}
-
+
return output.toJson();
}
@@ -291,7 +297,7 @@ private string generateData(JsonObject output)
StringBuilder sb = new StringBuilder();
JsonObject obj = null;
string str = "";
-
+
obj = output.getJsonObject("security");
if (!Tools.empty(obj))
{
@@ -380,7 +386,7 @@ private void setServiceOptions()
case "assess":
// fall-through
case "questions":
-
+
this.signRequestData = false;
if (this.service == "assess" && Tools.array_key_exists("questionsApiActivity", this.requestPacket))
@@ -456,18 +462,21 @@ private void setServiceOptions()
this.signRequestData = false;
JsonObject requestPackageUsers = this.requestPacket.getJsonObject("users");
- if (requestPackageUsers != null) {
- string[] users = requestPackageUsers.getValuesArray();
- if (users != null && users.Length > 0) {
+ if (requestPackageUsers != null)
+ {
+ string[] users = requestPackageUsers.getValuesArray();
+ if (users != null && users.Length > 0)
+ {
hashedUsers = new JsonObject();
- for (int i = 0; i < users.Length; i++) {
+ for (int i = 0; i < users.Length; i++)
+ {
string user_id = users[i];
hashedUsers.set(user_id, Tools.hash(this.algorithm, user_id + this.secret));
}
this.requestPacket.set("users", hashedUsers);
}
}
-
+
break;
default:
// do nothing
@@ -518,5 +527,111 @@ public void validate(string service, ref JsonObject securityPacket, string secre
throw new Exception("The `secret` argument must be a valid string");
}
}
+
+ ///
+ /// Adds a meta field with SDK information in it to the requestPacket
+ ///
+ public void addTelemetryData()
+ {
+ if (this.isTelemetryEnabled())
+ {
+ JsonObject meta;
+ if (this.requestPacket.getJsonObject("meta") != null)
+ {
+ meta = this.requestPacket.getJsonObject("meta");
+ }
+ else
+ {
+ meta = new JsonObject();
+ }
+
+ meta.set("sdk", this.getSdkMeta());
+ this.requestPacket.set("meta", meta);
+ }
+ }
+
+ public bool isTelemetryEnabled()
+ {
+ return telemetryEnabled;
+ }
+
+ public JsonObject getSdkMeta()
+ {
+ JsonObject sdkMeta = new JsonObject();
+ sdkMeta.set("version", this.getSdkVersion());
+ sdkMeta.set("lang", "asp.net");
+ sdkMeta.set("lang_version", this.getLanguageVersion());
+ sdkMeta.set("platform", this.getPlatform());
+ sdkMeta.set("platform_version", this.getPlatformVersion());
+
+ return sdkMeta;
+ }
+
+ ///
+ /// Returns the version number of ASP.NET
+ ///
+ ///
+ public string getLanguageVersion()
+ {
+ return Environment.Version.ToString();
+ }
+
+ ///
+ /// Returns the name of the platform the code is running on
+ ///
+ ///
+ public string getPlatform()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return "darwin";
+ }
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return "win";
+ }
+
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return "linux";
+ }
+
+ return Environment.OSVersion.Platform.ToString();
+ }
+
+ ///
+ /// Returns the version number of the platform the code is running on
+ ///
+ ///
+ public string getPlatformVersion()
+ {
+ var os = Environment.OSVersion;
+ return string.Concat(os.Version.Major, '.', os.Version.Minor);
+ }
+
+ ///
+ /// Extracts the version number of this SDK from the project meta data
+ ///
+ /// The version number
+ public string getSdkVersion()
+ {
+ return GetType().Assembly.GetName().Version.ToString();
+ }
+
+ ///
+ /// We use telemetry to enable better support and feature planning.
+ /// It will not interfere with any usage.
+ /// However, it is not advised to disable it.
+ ///
+ public static void disableTelemetry()
+ {
+ telemetryEnabled = false;
+ }
+
+ public static void enableTelemetry()
+ {
+ telemetryEnabled = true;
+ }
}
}
diff --git a/LearnositySDKIntegrationTests/LearnositySDKIntegrationTests.cs b/LearnositySDKIntegrationTests/LearnositySDKIntegrationTests.cs
index a01bc3c..0b33c63 100644
--- a/LearnositySDKIntegrationTests/LearnositySDKIntegrationTests.cs
+++ b/LearnositySDKIntegrationTests/LearnositySDKIntegrationTests.cs
@@ -1,5 +1,6 @@
using System;
using Xunit;
+using System.IO;
using LearnositySDK.Utils;
using LearnositySDK.Request;
@@ -69,5 +70,147 @@ private static string BuildDataAPIBaseUrl(string env, string region, string vers
return "https://data" + regionDomain + envDomain + ".learnosity.com/" + versionPath;
}
+
+ [Fact]
+ public void InitGeneratesExactSameSignature()
+ {
+ string action = "get";
+
+ JsonObject security = this.generateSecurityObject();
+
+ JsonObject request = new JsonObject();
+ request.set("limit", 100);
+
+ Init.disableTelemetry();
+ Init init = new Init("data", security, this.consumerSecret, request, action);
+
+ // Assert signature is still the same
+ Assert.Equal(
+ init.generateSignature(),
+ "e1eae0b86148df69173cb3b824275ea73c9c93967f7d17d6957fcdd299c8a4fe"
+ );
+
+ // Assert telemetry is turned off
+ Assert.False(init.isTelemetryEnabled());
+ Init.enableTelemetry();
+ }
+
+ [Fact]
+ public void InitGenerateBuildsNonEmptyRequest()
+ {
+ string action = "get";
+
+ JsonObject security = this.generateSecurityObject();
+
+ JsonObject request = new JsonObject();
+ request.set("page", 1);
+
+ Init init = new Init("data", security, this.consumerSecret, request, action);
+ string generatedString = init.generate();
+
+ // Assert generated string is not empty
+ Assert.NotEmpty(generatedString);
+
+ // Assert telemetry is turned on
+ Assert.True(init.isTelemetryEnabled());
+ }
+
+ [Fact]
+ public void EnabledTelemetryAddsSdkField()
+ {
+ string action = "get";
+ JsonObject security = this.generateSecurityObject();
+
+ JsonObject request = new JsonObject();
+ request.set("page", 1);
+
+ Init init = new Init("data", security, this.consumerSecret, request, action);
+ string generatedString = init.generate();
+
+ Assert.Contains("meta", generatedString);
+ Assert.Contains("sdk", generatedString);
+ }
+
+ [Fact]
+ public void EnabledTelemetryPreservesOtherMetaProps()
+ {
+ string action = "get";
+ JsonObject security = this.generateSecurityObject();
+
+ JsonObject metaField = new JsonObject();
+ metaField.set("test_key_string", "test-string");
+ metaField.set("test_key_integer", 12345);
+
+ JsonObject request = new JsonObject();
+ request.set("page", 1);
+ request.set("meta", metaField);
+
+ Init init = new Init("data", security, this.consumerSecret, request, action);
+ string generatedString = init.generate();
+
+ Assert.Contains("meta", generatedString);
+ Assert.Contains("sdk", generatedString);
+ Assert.Contains("test_key_string", generatedString);
+ Assert.Contains("test_key_integer", generatedString);
+ }
+
+ [Fact]
+ public void DisabledTelemetryPreservesEmptyProps()
+ {
+ string action = "get";
+ JsonObject security = this.generateSecurityObject();
+
+ Init.disableTelemetry();
+
+ JsonObject request = new JsonObject();
+ request.set("page", 1);
+
+ Init init = new Init("data", security, this.consumerSecret, request, action);
+ string generatedString = init.generate();
+
+ Assert.DoesNotContain("meta", generatedString);
+ Assert.DoesNotContain("sdk", generatedString);
+
+ Init.enableTelemetry();
+ }
+
+ [Fact]
+ public void DisabledTelemetryPreservesFilledProps()
+ {
+ string action = "get";
+ JsonObject security = this.generateSecurityObject();
+
+ Init.disableTelemetry();
+
+ JsonObject metaField = new JsonObject();
+ metaField.set("test_key_string", "test-string");
+ metaField.set("test_key_integer", 12345);
+
+ JsonObject request = new JsonObject();
+ request.set("page", 1);
+ request.set("meta", metaField);
+
+ Init init = new Init("data", security, this.consumerSecret, request, action);
+ string generatedString = init.generate();
+
+ Assert.Contains("meta", generatedString);
+ Assert.DoesNotContain("sdk", generatedString);
+ Assert.Contains("test_key_string", generatedString);
+ Assert.Contains("test_key_integer", generatedString);
+
+ Init.enableTelemetry();
+ }
+
+ private JsonObject generateSecurityObject()
+ {
+ string timestamp = "20140626-0528";
+
+ JsonObject security = new JsonObject();
+ security.set("consumer_key", this.consumerKey);
+ security.set("domain", this.domain);
+ security.set("timestamp", timestamp);
+
+ return security;
+ }
}
}