Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tribal/mszy/http requests #2755

Merged
merged 22 commits into from
Jun 29, 2023
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
2 changes: 2 additions & 0 deletions certified-connectors/Tribal/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ We provide the expertise, software and services required to underpin student suc

- `Delete a child entity`: Deletes an entity which is a child of another entity within a Tribal Edge module

- `HTTP Request`: Performs a custom request on a relative path for a Tribal Edge Edge module.

## Known Issues and Limitations


Expand Down
91 changes: 91 additions & 0 deletions certified-connectors/Tribal/Script.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
public class Script : ScriptBase
{
public override async Task<HttpResponseMessage> ExecuteAsync()
{
if (Context?.OperationId == "RawRequest")
{
return await HandleRawRequestAsync().ConfigureAwait(false);
}

return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = CreateJsonContent($"Unknown operation ID '{Context?.OperationId}'")
};
}

private async Task<HttpResponseMessage> HandleRawRequestAsync()
{
if (Context == null)
{
return new HttpResponseMessage(HttpStatusCode.InternalServerError)
{
Content = CreateJsonContent("Context not defined on request")
};
}

var request = Context.Request;
if (request?.Content == null)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = CreateJsonContent("Content not defined on request")
};
}
var content = await request.Content.ReadAsStringAsync().ConfigureAwait(false);

var obj = JObject.Parse(content);
var body = GetValue<string>(obj, "body");
var verb = GetValue<string>(obj, "verb");
var url = $"{request.RequestUri}{GetValue<string>(obj, "service")}/{GetValue<string>(obj, "relativeUrl")}";

if (!Uri.TryCreate(url, UriKind.Absolute, out _))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = CreateJsonContent($"Invalid Url Format '{url}'")
};
}

if (!string.IsNullOrEmpty(body))
{
request.Content = CreateJsonContent(body);
}

if (string.IsNullOrEmpty(verb))
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = CreateJsonContent("Verb must be provided")
};
}

request.Method = new HttpMethod(verb);
request.RequestUri = new Uri(url);

foreach (var token in GetValue<JArray>(obj, "headers") ?? new JArray())
{
var item = token.Value<JObject>();

var key = GetValue<string>(item, "key");
if (key == null)
{
return new HttpResponseMessage(HttpStatusCode.BadRequest)
{
Content = CreateJsonContent("Headers are invalid")
};
}
// Need to to add without validation because the etag causes it to fail
request.Headers.TryAddWithoutValidation(key, GetValue<string>(item, "value"));
}


return await Context.SendAsync(request, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
}

private static T? GetValue<T>(JObject? obj, string key) where T : class
{
return obj?.GetValue(key, StringComparison.InvariantCulture)?.Value<T>();
}


}
134 changes: 108 additions & 26 deletions certified-connectors/Tribal/apiDefinition.swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -836,7 +836,7 @@
}
]
},
"put": {
"put": {
"x-ms-visibility": "important",
"summary": "Replace an entity",
"description": "This replaces the contents of an entity. This will remove any properties from the entity that have not been included.",
Expand Down Expand Up @@ -887,7 +887,7 @@
"x-ms-url-encoding": "single",
"required": true,
"type": "string"
},
},
{
"name": "x-correlation-id",
"x-ms-summary": "Correlation Id",
Expand All @@ -903,7 +903,7 @@
"description": "ETag added in the If-Match header",
"in": "header",
"required": true,
"type": "string"
"type": "string"
},
{
"name": "body",
Expand Down Expand Up @@ -1059,14 +1059,12 @@
},
"/{service}/entities/{entityType}/{id}/uploaddocument": {
"post": {
"consumes": [
"multipart/form-data"
],
"consumes": ["multipart/form-data"],
"summary": "Upload a document to an entity",
"description": "Upload a document to an entity",
"operationId": "UploadDocument",
"x-ms-visibility": "important",
"parameters": [
"parameters": [
{
"name": "service",
"x-ms-summary": "Service",
Expand All @@ -1080,7 +1078,7 @@
"in": "path",
"required": true,
"type": "string"
},
},
{
"name": "entityType",
"x-ms-summary": "Entity",
Expand Down Expand Up @@ -1135,9 +1133,7 @@
"type": "string"
}
],
"produces": [
"application/json"
],
"produces": ["application/json"],
"responses": {
"200": {
"description": "Success"
Expand All @@ -1154,8 +1150,8 @@
"$ref": "#/definitions/ErrorResponse"
}
}
}
}
}
}
},
"/{service}/entities/children/{parentEntity}/{parentId}/{childEntity}": {
"post": {
Expand Down Expand Up @@ -1803,7 +1799,7 @@
"description": "ETag added in the If-Match header",
"in": "header",
"required": true,
"type": "string"
"type": "string"
},
{
"name": "body",
Expand Down Expand Up @@ -1889,16 +1885,14 @@
}
}
},
"/{service}/entities/children/{parentEntity}/{parentId}/{childEntity}/{childId}/uploadDocument":{
"/{service}/entities/children/{parentEntity}/{parentId}/{childEntity}/{childId}/uploadDocument": {
"post": {
"consumes": [
"multipart/form-data"
],
"consumes": ["multipart/form-data"],
"summary": "Upload a document to a child entity",
"description": "Upload a document to a child entity",
"operationId": "UploadChildDocument",
"x-ms-visibility": "important",
"parameters": [
"parameters": [
{
"name": "service",
"x-ms-summary": "Service",
Expand All @@ -1912,7 +1906,7 @@
"in": "path",
"required": true,
"type": "string"
},
},
{
"name": "parentEntity",
"x-ms-summary": "Parent Entity",
Expand Down Expand Up @@ -1974,7 +1968,7 @@
"x-ms-url-encoding": "single",
"required": true,
"type": "string"
},
},
{
"description": "Input file to perform the operation on.",
"in": "formData",
Expand All @@ -2000,9 +1994,7 @@
"type": "string"
}
],
"produces": [
"application/json"
],
"produces": ["application/json"],
"responses": {
"200": {
"description": "Success"
Expand All @@ -2019,7 +2011,7 @@
"$ref": "#/definitions/ErrorResponse"
}
}
}
}
}
},

Expand Down Expand Up @@ -3303,6 +3295,96 @@
}
}
}
},
"/": {
"post": {
"responses": {
"200": {
"description": "Success"
},
"201": {
"description": "Created"
},
"401": {
"description": "Unauthorized",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
},
"403": {
"description": "Forbidden",
"schema": {
"$ref": "#/definitions/ErrorResponse"
}
}
},
"summary": "HTTP Request",
"description": "Send an HTTP request to Edge",
"operationId": "RawRequest",
"x-ms-visibility": "important",
"parameters": [
{
"name": "body",
"in": "body",
"required": false,
"schema": {
"type": "object",
"properties": {
"service": {
"type": "string",
"x-ms-summary": "Service",
"description": "Service containing information",
"x-ms-dynamic-values": {
"operationId": "Services",
"value-path": "name",
"value-title": "description"
},
"x-ms-visibility": "important"
},
"headers": {
"type": "array",
"items": {
"type": "object",
"properties": {
"key": {
"type": "string",
"description": "key"
},
"value": {
"type": "string",
"description": "value"
}
}
},
"description": "Any additional headers",
"x-ms-summary": "Headers",
"x-ms-visibility": "important"
},
"verb": {
"type": "string",
"description": "HTTP Verb",
"x-ms-summary": "Verb",
"x-ms-visibility": "important",
"enum": ["GET", "POST", "PUT", "PATCH", "DELETE"]
},
"body": {
"type": "string",
"description": "Body of the request",
"x-ms-summary": "Body",
"x-ms-visibility": "important"
},
"relativeUrl": {
"type": "string",
"description": "Relative URL",
"x-ms-summary": "Relative URL e.g. /api/referenceData",
"x-ms-visibility": "important"
}
},
"required": ["verb", "relativeUrl"]
}
}
]
}
}
},
"definitions": {
Expand Down Expand Up @@ -3367,4 +3449,4 @@
}
}
}
}
}
17 changes: 15 additions & 2 deletions certified-connectors/Tribal/apiProperties.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"oAuthSettings": {
"identityProvider": "oauth2generic",
"clientId": "[DUMMY]",
"scopes": [ "web_hooks", "openid", "edge_identity", "offline_access", "edge", "EventsConnector.Endpoint", "ReferenceData.Api.Read" ],
"scopes": [ "web_hooks", "openid", "edge_identity", "offline_access", "edge", "EventsConnector.Endpoint", "ReferenceData.Api.Read", "Maytas.UI", "SITS.UI" ],
"redirectMode": "Global",
"redirectUrl": "https://global.consent.azure-apim.net/redirect",
"properties": {
Expand Down Expand Up @@ -88,9 +88,12 @@
"displayName": "Edge Tenant Id",
"tooltip": "Tenant Id for Tribal Edge"
}
}
}
},
"iconBrandColor": "#0077C4",
"scriptOperations": [
"RawRequest"
],
"capabilities": [],
"publisher": "Tribal Group",
"stackOwner": "Tribal Group",
Expand All @@ -102,6 +105,16 @@
"x-ms-apimTemplateParameter.urlTemplate": "https://api@connectionParameters('token:environment')/@connectionParameters('token:region')/"
}
},
{
"templateId": "setheader",
"title": "Tenant Header",
"parameters": {
"x-ms-apimTemplateParameter.name": "tenantId",
"x-ms-apimTemplateParameter.value": "@connectionParameters('token:tenantId')",
"x-ms-apimTemplateParameter.existsAction": "override",
"x-ms-apimTemplate-policySection": "Request"
}
},
{
"parameters": {
"x-ms-apimTemplate-operationName": ["CustomEvents"],
Expand Down