Initial version of Spring Global connector (#1183)

* Updates for LMS365 connector (#851)

* add empty schema definition for responses which may contain some data

* Add Admins field to Course details

* Remove ContentType property as it's not needed anymore

* Added "WithoutWire Inventory Platform"

* Improvements according to pull request review

* Fix publisher

* New vesrion of WithoutWire Inventory Platform connector

* New version of WithoutWire Inventory Platform connector. Fixes and improvements according to recommendations

* New version of WithoutWire Inventory Platform connector. Fixes and improvements according to recommendations

* New version of WithoutWire Inventory Platform connector. Fixes and improvements according to recommendations

* Initial version of Spring Global connector

* Code improvements

* Initial version of Spring Global connector (with improvements according to code review)

Co-authored-by: Alexei Gus <32488384+elearningforce-ag@users.noreply.github.com>
Co-authored-by: Mahbub Murshed <mamurshe@microsoft.com>
Co-authored-by: Pavlo Nikulin <taufaq@ukr.net>
This commit is contained in:
PavloNikulinEnavate 2021-10-15 01:51:18 +03:00 коммит произвёл GitHub
Родитель d7cc19617f
Коммит be51597a02
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 777 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,520 @@
{
"swagger": "2.0",
"info": {
"title": "Spring Global",
"description": "The connector contains a trigger to handle surver execution events and methods get relevant information about survey execution and users",
"version": "1.0",
"contact": {
"name": "Spring Global Team",
"url": "https://www.springglobal.com/contact-us",
"email": "sustaining.br@springglobal.com"
}
},
"host": "sg.azurewebsites.net",
"basePath": "/",
"schemes": [
"https"
],
"consumes": [],
"produces": [],
"paths": {
"/survey-service/execution/{executionId}": {
"get": {
"responses": {
"200": {
"description": "200",
"schema": {
"type": "object",
"x-ms-dynamic-schema": {
"operationId": "GetSurveyPublicationSchema",
"parameters": {
"publicationIdValue": {
"parameter": "publicationId"
}
},
"value-path": "schemaDefinition"
},
"x-ms-dynamic-properties": {
"operationId": "GetSurveyPublicationSchema",
"parameters": {
"publicationIdValue": {
"parameterReference": "publicationId"
}
},
"itemValuePath": "schemaDefinition"
}
}
}
},
"summary": "Get Survey Execution Data",
"description": "Get Survey Execution Data",
"operationId": "GetExecutionById",
"parameters": [
{
"name": "executionId",
"in": "path",
"required": true,
"type": "string",
"description": "Execution Id (unique identifier)",
"x-ms-summary": "Execution Id",
"x-ms-url-encoding": "single"
},
{
"name": "surveyId",
"in": "header",
"type": "string",
"required": true,
"x-ms-dynamic-values": {
"operationId": "GetSurveys",
"value-path": "id",
"value-title": "name"
},
"description": "Select a survey",
"x-ms-summary": "Survey"
},
{
"name": "publicationId",
"in": "header",
"type": "string",
"required": true,
"x-ms-dynamic-values": {
"operationId": "GetPublications",
"value-path": "id",
"value-title": "name",
"parameters": {
"surveyId": {
"parameter": "surveyId"
}
}
},
"x-ms-dynamic-list": {
"operationId": "GetPublications",
"itemValuePath": "id",
"itemTitlePath": "name",
"parameters": {
"surveyId": {
"parameterReference": "surveyId"
}
}
},
"description": "Select a survey publication",
"x-ms-summary": "Publication"
}
]
}
},
"/survey-service/list/": {
"get": {
"responses": {
"200": {
"description": "200",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Survey Id"
},
"tenantId": {
"type": "string",
"description": "Tenant Id"
},
"name": {
"type": "string",
"description": "Survey name"
},
"description": {
"type": "string",
"description": "Survey description"
},
"status": {
"type": "string",
"description": "Status"
},
"lastDateModified": {
"type": "string",
"description": "Last modified date"
},
"creator": {
"type": "string",
"description": "Created by"
}
}
}
}
}
},
"parameters": [],
"summary": "Get Survey List",
"description": "Get Survey List",
"operationId": "GetSurveys",
"x-ms-visibility": "internal"
}
},
"/survey-service/getPublication/{publicationIdValue}": {
"get": {
"responses": {
"200": {
"description": "200",
"schema": {
"type": "object",
"properties": {
"schemaDefinition": {
"type": "object",
"description": "Schema definition"
}
}
}
}
},
"summary": "Get Survey Publication Schema",
"description": "Get Survey Publication Schema",
"operationId": "GetSurveyPublicationSchema",
"parameters": [
{
"name": "publicationIdValue",
"in": "path",
"required": true,
"type": "string",
"description": "Publication Id (unique identifier)",
"x-ms-summary": "Publication Id (unique identifier)",
"x-ms-url-encoding": "single"
}
],
"x-ms-visibility": "internal"
}
},
"/webhook-service/subscribe/surveyexecution": {
"x-ms-notification-content": {
"description": "On Survey Execution Input Data",
"schema": {
"type": "object",
"properties": {
"tenantId": {
"type": "string",
"description": "Tenant Id"
},
"action": {
"type": "string",
"description": "Action"
},
"event": {
"type": "string",
"description": "Event"
},
"parameters": {
"type": "object",
"properties": {
"publicationId": {
"type": "string",
"description": "Publication Id"
}
},
"description": "Parameters"
},
"payload": {
"type": "object",
"properties": {
"executionId": {
"type": "string",
"description": "Execution Id"
}
},
"description": "Payload"
}
}
}
},
"post": {
"responses": {
"200": {
"description": "200"
}
},
"summary": "On Survey Execution",
"description": "On Survey Execution",
"operationId": "OnSurveyExecution",
"x-ms-trigger": "single",
"parameters": [
{
"name": "body",
"in": "body",
"required": false,
"schema": {
"type": "object",
"properties": {
"callback": {
"type": "string",
"description": "callback",
"x-ms-notification-url": true,
"x-ms-visibility": "internal",
"title": ""
},
"parameters": {
"type": "object",
"properties": {
"surveyId": {
"type": "string",
"description": "Select a survey",
"title": "Survey Id",
"x-ms-dynamic-values": {
"operationId": "GetSurveys",
"value-path": "id",
"value-title": "name"
},
"default": "Survey"
},
"publicationId": {
"type": "string",
"description": "Select a survey publication",
"title": "Publication Id",
"x-ms-dynamic-values": {
"operationId": "GetPublications",
"value-path": "id",
"value-title": "name",
"parameters": {
"surveyId": {
"parameter": "parameters.surveyId"
}
}
},
"x-ms-dynamic-list": {
"operationId": "GetPublications",
"itemValuePath": "id",
"itemTitlePath": "name",
"parameters": {
"surveyId": {
"parameterReference": "body/parameters/surveyId"
}
}
},
"default": "Publication"
}
},
"description": "Parameters",
"required": [
"surveyId",
"publicationId"
]
}
},
"required": [
"callback",
"parameters"
]
}
}
],
"consumes": [
"application/json"
]
}
},
"/webhook-service/unsubscribe/{token}": {
"delete": {
"responses": {
"200": {
"description": "200",
"schema": {}
}
},
"summary": "Unsubscribe Web Hook Events",
"description": "Unsubscribe Web Hook Events",
"operationId": "UnsubscribeWebHookEvents",
"parameters": [
{
"name": "token",
"in": "path",
"required": true,
"type": "string",
"x-ms-url-encoding": "single"
}
],
"x-ms-visibility": "internal"
}
},
"/survey-service/publication/getAllPublications/{surveyId}": {
"get": {
"responses": {
"200": {
"description": "200",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Publication Id"
},
"tenantId": {
"type": "string",
"description": "Tenant Id"
},
"partitionKey": {
"type": "string",
"description": "Partition Key"
},
"surveyId": {
"type": "string",
"description": "Survey Id"
},
"oneTimeSurvey": {
"type": "boolean",
"description": "Is it one-time survey?"
},
"sendEmailNotification": {
"type": "boolean",
"description": "Is email notification is sent?"
},
"users": {
"type": "array",
"items": {
"type": "object",
"properties": {
"user": {
"type": "string",
"description": "User name"
},
"id": {
"type": "string",
"description": "User Id"
}
}
},
"description": "Users"
},
"name": {
"type": "string",
"description": "Name"
},
"validityStart": {
"type": "string",
"description": "Validity start"
},
"lastModifiedDate": {
"type": "string",
"description": "Last modified date"
},
"validityEnd": {
"type": "string",
"description": "Validity end"
}
}
}
}
}
},
"summary": "Get All Survey`s Publications (Versions)",
"description": "Get All Survey`s Publications (Versions)",
"operationId": "GetPublications",
"parameters": [
{
"name": "surveyId",
"in": "path",
"required": true,
"type": "string",
"description": "Survey Id (unique identifier)",
"x-ms-summary": "Survey Id (unique identifier)",
"x-ms-url-encoding": "single"
}
],
"x-ms-visibility": "internal"
}
},
"/identity-service/user/{userId}": {
"get": {
"responses": {
"200": {
"description": "200",
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "User Id",
"title": "User Id"
},
"code": {
"type": "string",
"description": "User code",
"title": "User code"
},
"firstName": {
"type": "string",
"description": "First Name",
"title": "First Name"
},
"secondName": {
"type": "string",
"description": "Second (Middle) Name",
"title": "Second (Middle) Name"
},
"surname": {
"type": "string",
"description": "Surname",
"title": "Surname"
},
"username": {
"type": "string",
"description": "User name",
"title": "Username (Login)"
},
"email": {
"type": "string",
"description": "Email",
"title": "User email"
}
}
}
}
},
"summary": "Get User Info",
"operationId": "GetUserById",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"type": "string",
"description": "User Id (guid)",
"x-ms-summary": "User",
"x-ms-url-encoding": "single"
}
],
"description": "Get User Info"
}
}
},
"parameters": {},
"responses": {},
"securityDefinitions": {
"API Key": {
"type": "apiKey",
"in": "header",
"name": "SPRING_GLOBAL_API_KEY"
}
},
"security": [
{
"API Key": []
}
],
"tags": [],
"x-ms-connector-metadata": [
{
"propertyName": "Website",
"propertyValue": "https://www.springglobal.com"
},
{
"propertyName": "Privacy policy",
"propertyValue": "https://www.springglobal.com/privacy-policy"
},
{
"propertyName": "Categories",
"propertyValue": "Productivity;Collaboration"
}
]
}

Просмотреть файл

@ -0,0 +1,36 @@
{
"properties": {
"connectionParameters": {
"baseurl": {
"type": "string",
"uiDefinition": {
"displayName": "Web API Base Url",
"description": "Web API Base Url",
"tooltip": "Provide Web API base url",
"constraints": {
"tabIndex": 1,
"clearText": true,
"required": "true"
}
}
},
"api_key": {
"type": "securestring",
"uiDefinition": {
"displayName": "API Key",
"description": "The API Key for this api",
"tooltip": "Provide your API Key",
"constraints": {
"tabIndex": 2,
"clearText": false,
"required": "true"
}
}
}
},
"iconBrandColor": "#fefefe",
"capabilities": [],
"publisher": "Spring Global",
"stackOwner": "Spring Global"
}
}

Просмотреть файл

@ -0,0 +1,29 @@
Spring Global is a leading provider of field sales tools for the Consumer Packaged Goods (CPG) industry. We enable users to serve with ease, monitor & control field execution, and leverage a single app with a 360° of the customer. We deliver a proven, flexible, enterprise-grade SaaS solution and our development team is continuously working on innovations to improve and expand the capabilities of our full-stack solution.
Current vertion of connector contains a trigger to handle surver execution events and methods get relevant information about survey execution and users
## Prerequisites
To use the Spring Global connector, you need to have trial or full license for Spring Global Survey. So, you must have portal URL and credentials (login and password) to create and configure a survey.
To configure the connector you should have Web API URL and API Key.
## How to get credentials
Contact our support team (sustaining.br@springglobal.com) for getting trial license and additional support.
## Getting started with your connector
1. Create a survey in the Spring Global Survey portal. Publish it.
2. Create a Power Automeate Flow
* The flow starts with trigger "On Survey Execution" of Spring Global connector
Use WebAPI Url and API key to configure connection
* Use "Get Survey Execution Data" to get details by survey execution id
3. Fill the survey as a user
4. Look the flow execution
## Supported Operations
The current version of connector supports the following operations:
* webhook trigger that fire on new surver execution
* method to get survey execution details
* method to get user details
## Deployment instructions
Please use [these instructions](https://docs.microsoft.com/en-us/connectors/custom-connectors/paconn-cli) to deploy this connector as custom connector in Microsoft Power Automate and Power Apps
Note: the connector contains code (script.csx file), so use --script (or -x) key to upload script file as well.

Просмотреть файл

@ -0,0 +1,192 @@
public class Script : ScriptBase
{
public override async Task<HttpResponseMessage> ExecuteAsync()
{
// Use the context to forward/send an HTTP request. Turn of caching
var cacheControlHeader = new CacheControlHeaderValue(){NoStore=true, NoCache=true};
this.Context.Request.Headers.CacheControl = cacheControlHeader;
HttpResponseMessage response = await this.Context.SendAsync(this.Context.Request, this.CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
string responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);
try
{
JObject surveyJson;
string newResponceContent = responseString;
bool contentChanged = false;
if (this.Context.OperationId == "GetSurveyPublicationSchema")
{
var arrayResponse = JArray.Parse(responseString);
surveyJson = arrayResponse.First as JObject;
newResponceContent = this.GetSurveySchema(surveyJson);
contentChanged = true;
}
else if (this.Context.OperationId == "GetExecutionById")
{
newResponceContent = this.GetSurveyData(responseString);
contentChanged = true;
}
else
{
//Don`t do any thing for other operations
}
if (contentChanged)
{
response.Content = CreateJsonContent(newResponceContent);
response.StatusCode = HttpStatusCode.OK;
}
}
catch
{
//Don`t to transformation
}
return response;
}
/// <summary>
/// The method transforms data from WebAPI to more plain structure, that suitable for Flows
/// </summary>
public string GetSurveyData(string surveyExecutionData)
{
JArray surveyExecutionArrayJson = JArray.Parse(surveyExecutionData);
JObject surveyExecutionJson = (JObject)surveyExecutionArrayJson.First();
JObject resultJson = new JObject();
resultJson["Id"] = surveyExecutionJson["id"];
resultJson["surveyId"] = surveyExecutionJson["surveyId"];
resultJson["SurveyName"] = (string)surveyExecutionJson.SelectToken("$.surveyPublication.survey.name");
resultJson["Date"] = surveyExecutionJson["executionDate"];
resultJson["userId"] = surveyExecutionJson["userId"];
List<JToken> questions = surveyExecutionJson.SelectTokens("$.pages..parameters[:10000]").ToList();
int i = 0;
foreach (JObject question in questions)
{
i++;
int order = i;
string questionText = question.Value<string>("name");
string questionType = (string)question.SelectToken("parameterType.code");
resultJson[$"Question{order}"] = questionText;
switch (questionType)
{
case "CHR":
case "NUM":
case "SCO":
case "RAD":
resultJson[$"Answer{order}"] = question["value"];
break;
case "CHK":
JObject selectedOptions = new JObject();
resultJson[$"Answer{order}"] = selectedOptions;
JArray optionsJson = (JArray)question["options"];
int optionNumber = 0;
foreach (JObject optionJson in optionsJson)
{
optionNumber++;
selectedOptions[$"Option{optionNumber}Text"] = optionJson["text"];
selectedOptions[$"Option{optionNumber}Checked"] = optionJson["checked"];
selectedOptions[$"Option{optionNumber}Id"] = optionJson["id"];
}
break;
//case "IMG":
default:
break;
}
}
string result = resultJson.ToString(); ;
return result;
}
/// <summary>
/// The method generate a schema of survey to support Flow Designer
/// </summary>
public string GetSurveySchema(JObject surveyJson)
{
JObject resultJson = new JObject();
JObject firstLevelJson = new JObject();
firstLevelJson["type"] = "object";
firstLevelJson["description"] = $"Survey execution (object)";
JObject resultBodyJson = new JObject();
SetSimpleProperty(resultBodyJson, "Id", "Execution Id", "Execution Id", "string", null);
SetSimpleProperty(resultBodyJson, "SurveyId", "Surver Id", "Surver Id", "string", null);
SetSimpleProperty(resultBodyJson, "SurveyName", "Survey name", "Survey name", "string", null);
SetSimpleProperty(resultBodyJson, "Date", "Execution date", "Execution date", "string", "date-time");
SetSimpleProperty(resultBodyJson, "UserId", "User Id", "User Id", "string", null);
List<JToken> questions = surveyJson.SelectTokens("$..parameters[:10000]").ToList();
int i = 0;
foreach (JObject question in questions)
{
i++;
int order = i;
string questionText = question.Value<string>("name");
string questionType = (string)question.SelectToken("parameterType.code");
SetSimpleProperty(resultBodyJson, $"Question{order}", $"Question {order} Text", questionText, "string", null);
switch (questionType)
{
case "CHR":
SetSimpleProperty(resultBodyJson, $"Answer{order}", $"Question {order} Answer (Text)", questionText, "string", null);
break;
case "NUM":
SetSimpleProperty(resultBodyJson, $"Answer{order}", $"Question {order} Answer (Numeric)", questionText, "number", null);
break;
case "SCO":
SetSimpleProperty(resultBodyJson, $"Answer{order}", $"Question {order} Answer (Scale)", questionText, "integer", null);
break;
case "RAD":
JObject answerJson1 = SetSimpleProperty(resultBodyJson, $"Answer{order}", $"Question {order} Answer (Single Choice)", questionText, "object", null);
JObject radJson = new JObject();
SetSimpleProperty(radJson, "id", $"Selected choice id", questionText, "string", null);
SetSimpleProperty(radJson, "text", $"Selected choice title", questionText, "string", null);
answerJson1["properties"] = radJson;
break;
case "CHK":
JObject answerJson2 = SetSimpleProperty(resultBodyJson, $"Answer{order}", $"Question {order} Answer (Checkbox)", questionText, "object", null);
JObject answerJson2Options = new JObject();
JArray optionsJson = (JArray)question["options"];
int optionNumber = 0;
foreach (JObject optionJson in optionsJson)
{
optionNumber++;
string optionText = optionJson.Value<string>("text");
SetSimpleProperty(answerJson2Options, $"Option{optionNumber}Text", $"Option {optionNumber} text", $"{optionText}{Environment.NewLine}{questionText}", "string", null);
SetSimpleProperty(answerJson2Options, $"Option{optionNumber}Checked", $"Option {optionNumber} is selected",$"Is selected '{optionText}'{Environment.NewLine}{questionText}", "boolean", null);
SetSimpleProperty(answerJson2Options, $"Option{optionNumber}Id", $"Option {optionNumber} id", $"Option {optionNumber} ID{Environment.NewLine}{questionText}", "boolean", null);
}
answerJson2["properties"] = answerJson2Options;
break;
//case "IMG":
default:
break;
}
}
firstLevelJson["properties"] = resultBodyJson;
resultJson["schemaDefinition"] = firstLevelJson;
return resultJson.ToString();
}
public JObject SetSimpleProperty(JObject parentObject, string paramName, string title, string description, string typeName, string format=null)
{
JObject jObject = new JObject();
jObject["type"] = typeName;
jObject["description"] = description;
if (string.IsNullOrEmpty(format)) { } else {jObject["format"] = format; }
if (string.IsNullOrEmpty(title)) { } else { jObject["title"] = title; }
parentObject[paramName] = jObject;
return jObject;
}
}