@mindline/sync 1.0.18 → 1.0.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/configs.json +1 -1
- package/hybridspa.ts +159 -0
- package/index.test.ts +16 -0
- package/{index.js → index.ts} +53 -3
- package/package.json +2 -1
- package/sync.d.ts +2 -1
- package/index.test.js +0 -12
package/configs.json
CHANGED
package/hybridspa.ts
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// Select DOM elements to work with
|
|
2
|
+
const welcomeDiv = document.getElementById("welcomeMessage");
|
|
3
|
+
const cardDiv = document.getElementById("card-div");
|
|
4
|
+
const profileButton = document.getElementById("seeProfile");
|
|
5
|
+
const profileDiv = document.getElementById("profile-div");
|
|
6
|
+
|
|
7
|
+
// Add here the endpoints for MS Graph API services you would like to use.
|
|
8
|
+
const graphConfig = {
|
|
9
|
+
graphMeEndpoint: "https://graph.microsoft.com/v1.0/me",
|
|
10
|
+
graphMailEndpoint: "https://graph.microsoft.com/v1.0/me/messages",
|
|
11
|
+
graphTenantEndpoint:
|
|
12
|
+
"https://graph.microsoft.com/beta/tenantRelationships/findTenantInformationByTenantId",
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function updateUI(data, endpoint) {
|
|
16
|
+
console.log("Graph API responded at: " + new Date().toString());
|
|
17
|
+
|
|
18
|
+
if (endpoint === graphConfig.graphMeEndpoint) {
|
|
19
|
+
profileDiv.innerHTML = "";
|
|
20
|
+
const title = document.createElement("p");
|
|
21
|
+
title.innerHTML = "<strong>Title: </strong>" + data.jobTitle;
|
|
22
|
+
console.log(data.jobTitle);
|
|
23
|
+
const email = document.createElement("p");
|
|
24
|
+
email.innerHTML = "<strong>Mail: </strong>" + data.mail;
|
|
25
|
+
console.log(data.mail);
|
|
26
|
+
const phone = document.createElement("p");
|
|
27
|
+
phone.innerHTML = "<strong>Phone: </strong>" + data.businessPhones[0];
|
|
28
|
+
console.log(data.businessPhones[0]);
|
|
29
|
+
const address = document.createElement("p");
|
|
30
|
+
address.innerHTML = "<strong>Location: </strong>" + data.officeLocation;
|
|
31
|
+
console.log(data.officeLocation);
|
|
32
|
+
profileDiv.appendChild(title);
|
|
33
|
+
profileDiv.appendChild(email);
|
|
34
|
+
profileDiv.appendChild(phone);
|
|
35
|
+
profileDiv.appendChild(address);
|
|
36
|
+
} else if (endpoint === graphConfig.graphMailEndpoint) {
|
|
37
|
+
if (data.value.length < 1) {
|
|
38
|
+
alert("Your mailbox is empty!");
|
|
39
|
+
} else {
|
|
40
|
+
console.log("Displaying Emails for the signed in user.");
|
|
41
|
+
const tabList = document.getElementById("list-tab");
|
|
42
|
+
tabList.innerHTML = ""; // clear tabList at each readMail call
|
|
43
|
+
const tabContent = document.getElementById("nav-tabContent");
|
|
44
|
+
|
|
45
|
+
data.value.map((d, i) => {
|
|
46
|
+
// Keeping it simple
|
|
47
|
+
if (i < 10) {
|
|
48
|
+
const listItem = document.createElement("a");
|
|
49
|
+
listItem.setAttribute(
|
|
50
|
+
"class",
|
|
51
|
+
"list-group-item list-group-item-action"
|
|
52
|
+
);
|
|
53
|
+
listItem.setAttribute("id", "list" + i + "list");
|
|
54
|
+
listItem.setAttribute("data-toggle", "list");
|
|
55
|
+
listItem.setAttribute("href", "#list" + i);
|
|
56
|
+
listItem.setAttribute("role", "tab");
|
|
57
|
+
listItem.setAttribute("aria-controls", i);
|
|
58
|
+
listItem.innerHTML = d.subject;
|
|
59
|
+
tabList.appendChild(listItem);
|
|
60
|
+
const contentItem = document.createElement("div");
|
|
61
|
+
contentItem.setAttribute("class", "tab-pane fade");
|
|
62
|
+
contentItem.setAttribute("id", "list" + i);
|
|
63
|
+
contentItem.setAttribute("role", "tabpanel");
|
|
64
|
+
contentItem.setAttribute("aria-labelledby", "list" + i + "list");
|
|
65
|
+
contentItem.innerHTML =
|
|
66
|
+
"<strong> from: " + d.from.emailAddress.address + "</strong>";
|
|
67
|
+
tabContent.appendChild(contentItem);
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Helper function to call MS Graph API endpoint
|
|
75
|
+
// using authorization bearer token scheme
|
|
76
|
+
function callMSGraph(endpoint, token, callback) {
|
|
77
|
+
const headers = new Headers();
|
|
78
|
+
const bearer = `Bearer ${token}`;
|
|
79
|
+
headers.append("Authorization", bearer);
|
|
80
|
+
|
|
81
|
+
const options = {
|
|
82
|
+
method: "GET",
|
|
83
|
+
headers: headers,
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
console.log("request made to Graph API at: " + new Date().toString());
|
|
87
|
+
|
|
88
|
+
fetch(endpoint, options)
|
|
89
|
+
.then((response) => response.json())
|
|
90
|
+
.then((response) => callback(response, endpoint))
|
|
91
|
+
.then((result) => {
|
|
92
|
+
console.log("Successfully Fetched Data from Graph API:", result);
|
|
93
|
+
})
|
|
94
|
+
.catch((error) => console.log(error));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
///get Token
|
|
98
|
+
function getTokenByCode(spaCode) {
|
|
99
|
+
var code = spaCode;
|
|
100
|
+
const scopes = ["user.read"];
|
|
101
|
+
|
|
102
|
+
console.log("MSAL: acquireTokenByCode hybrid parameters present");
|
|
103
|
+
|
|
104
|
+
var authResult = msalInstance.acquireTokenByCode({
|
|
105
|
+
code,
|
|
106
|
+
scopes,
|
|
107
|
+
});
|
|
108
|
+
console.log(authResult);
|
|
109
|
+
|
|
110
|
+
return authResult;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
//See Profile
|
|
114
|
+
function seeProfile(spaCode) {
|
|
115
|
+
getTokenByCode(spaCode)
|
|
116
|
+
.then((response) => {
|
|
117
|
+
callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI);
|
|
118
|
+
})
|
|
119
|
+
.catch((error) => {
|
|
120
|
+
console.log(error);
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//Get Tenant Info
|
|
125
|
+
async function getTenantInfo(user: User, instance: IPublicClientApplication) {
|
|
126
|
+
var authResult = await instance
|
|
127
|
+
.acquireTokenByCode({ code: user.spacode })
|
|
128
|
+
.catch((e: any) => {
|
|
129
|
+
console.log(e);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
const headers = new Headers();
|
|
133
|
+
const bearer = `Bearer ${authResult.accessToken}`;
|
|
134
|
+
headers.append("Authorization", bearer);
|
|
135
|
+
|
|
136
|
+
const options = {
|
|
137
|
+
method: "GET",
|
|
138
|
+
headers: headers,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
var tenantEndpoint = graphConfig.graphTenantEndpoint;
|
|
142
|
+
tenantEndpoint += "(tenantId='";
|
|
143
|
+
tenantEndpoint += user.tid;
|
|
144
|
+
tenantEndpoint += "')";
|
|
145
|
+
|
|
146
|
+
console.log(
|
|
147
|
+
"request made to Graph API tenant endpoint at: " + new Date().toString()
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
fetch(tenantEndpoint, options)
|
|
151
|
+
.then((response) => response.json())
|
|
152
|
+
.then((response) => {
|
|
153
|
+
console.log("Successfully Fetched Data from Graph API:", response);
|
|
154
|
+
})
|
|
155
|
+
.catch((error) => console.log(error));
|
|
156
|
+
|
|
157
|
+
user.companyName = response.displayName;
|
|
158
|
+
user.companyDomain = response.defaultDomainName;
|
|
159
|
+
}
|
package/index.test.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import {sum, User, InitInfo, InitGet } from "index";
|
|
2
|
+
import {test, expect} from "vitest";
|
|
3
|
+
|
|
4
|
+
test("adds 1 + 2 to equal 3", () => {
|
|
5
|
+
expect(sum(1, 2)).toBe(3);
|
|
6
|
+
});
|
|
7
|
+
test("loads config based on a user and expects function to return true", () => {
|
|
8
|
+
let ii = new InitInfo();
|
|
9
|
+
let bResult:boolean = false;
|
|
10
|
+
InitGet(ii, null)
|
|
11
|
+
.then((response) => bResult = response)
|
|
12
|
+
.catch((e: any) => {
|
|
13
|
+
console.log(e);
|
|
14
|
+
});
|
|
15
|
+
expect(bResult);
|
|
16
|
+
});
|
package/{index.js → index.ts}
RENAMED
|
@@ -22,6 +22,7 @@ export class User {
|
|
|
22
22
|
this.associatedWorkspaces = {};
|
|
23
23
|
this.workspaceIDs = "";
|
|
24
24
|
this.session = "";
|
|
25
|
+
this.spacode = "";
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
@@ -118,15 +119,15 @@ export class InitInfo {
|
|
|
118
119
|
}
|
|
119
120
|
|
|
120
121
|
import { deserializeArray } from 'class-transformer';
|
|
122
|
+
import { IPublicClientApplication } from '@azure/msal-browser';
|
|
121
123
|
import users from "./users.json";
|
|
122
124
|
import targets from "./targets.json";
|
|
123
125
|
import configs from "./configs.json";
|
|
124
126
|
import workspaces from "./workspaces.json";
|
|
125
127
|
|
|
126
|
-
//
|
|
127
|
-
|
|
128
|
+
// get hardcoded data from JSON
|
|
129
|
+
function DummyInit(ii)
|
|
128
130
|
{
|
|
129
|
-
// for now, just get hardcoded data from JSON
|
|
130
131
|
var usersString = JSON.stringify(users);
|
|
131
132
|
var targetsString = JSON.stringify(targets);
|
|
132
133
|
var configsString = JSON.stringify(configs);
|
|
@@ -143,6 +144,55 @@ export function InitGet(user, ii)
|
|
|
143
144
|
}
|
|
144
145
|
return true;
|
|
145
146
|
}
|
|
147
|
+
// retrieve Workspace(s), User(s), Target(s), Config(s) given logged in user
|
|
148
|
+
// three InitGet scenarios
|
|
149
|
+
// scenario 1: empty user array, read defaults
|
|
150
|
+
// scenario 2: user array with dummy user at end, return without doing anything
|
|
151
|
+
// scenario 3: user array with non-dummy user at end, call back end Init
|
|
152
|
+
// (1) TODO: Azure AD: lookup companyDomain and companyName
|
|
153
|
+
// look up tenant name
|
|
154
|
+
// look up tenant domain
|
|
155
|
+
// TODO: Mindline: post complete user to init endpoint
|
|
156
|
+
// create and push partial tenant at end of target array
|
|
157
|
+
// post user and partial tenant to InitInfo
|
|
158
|
+
// Return: success return value, need to query for associations
|
|
159
|
+
// (2) Sync NPM: ii.ws: once InitInfo completes, retrieve workspaces for the new user
|
|
160
|
+
// TODO: Mindline: retrieve associated workspaces
|
|
161
|
+
// Returns: associated workspaces
|
|
162
|
+
// (3) Sync NPM:
|
|
163
|
+
// TODO: Mindline: retrieve associated admins, targets for each workspace
|
|
164
|
+
// ii.us / ii.ts / ii.cs: query components of each associated workspaces
|
|
165
|
+
// Returns: users, targets, configs for each workspace
|
|
166
|
+
export async function InitGet(ii, instance)
|
|
167
|
+
{
|
|
168
|
+
// if empty user array, retrieve dummy data from JSON to populate UI
|
|
169
|
+
let l = ii.us.length;
|
|
170
|
+
if(l === 0) return DummyInit(ii);
|
|
171
|
+
|
|
172
|
+
// if last user is a dummy user, then we have nothing
|
|
173
|
+
let user:User = ii.us[l-1];
|
|
174
|
+
if(user.oid === "1") return true;
|
|
175
|
+
|
|
176
|
+
// have real user: remove dummy user, target, config, workspace if they exist
|
|
177
|
+
let dummyIndex = ii.us.findIndex((u) => u.oid === "1");
|
|
178
|
+
ii.us.splice(dummyIndex, 1);
|
|
179
|
+
dummyIndex = ii.ts.findIndex((u) => u.oid === "1");
|
|
180
|
+
ii.ts.splice(dummyIndex, 1);
|
|
181
|
+
dummyIndex = ii.cs.findIndex((u) => u.oid === "1");
|
|
182
|
+
ii.cs.splice(dummyIndex, 1);
|
|
183
|
+
dummyIndex = ii.ws.findIndex((u) => u.oid === "1");
|
|
184
|
+
ii.ws.splice(dummyIndex, 1);
|
|
185
|
+
|
|
186
|
+
// why would instance be null here? investigate!
|
|
187
|
+
if(instance===null) {
|
|
188
|
+
debugger;
|
|
189
|
+
return false;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// valid user, query AAD for associated company name and domain
|
|
193
|
+
getTenantInfo(user, instance);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
146
196
|
|
|
147
197
|
export function AddTarget()
|
|
148
198
|
{
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindline/sync",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.19",
|
|
5
5
|
"description": "sync is a node.js package encapsulating javscript classes required for configuring Mindline sync service.",
|
|
6
6
|
"exports": "./index.js",
|
|
7
7
|
"scripts": {
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
"vitest": "^0.29.8"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
+
"@azure/msal-browser": "^2.37.0",
|
|
18
19
|
"class-transformer": "^0.5.1",
|
|
19
20
|
"reflect-metadata": "^0.1.13"
|
|
20
21
|
},
|
package/sync.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ declare module "@mindline/sync" {
|
|
|
14
14
|
associatedWorkspaces: string[];
|
|
15
15
|
workspaceIDs: string;
|
|
16
16
|
session: string;
|
|
17
|
+
spacode: string;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
20
|
// target (Azure AD tenant, AD domain, Google workspace)
|
|
@@ -61,7 +62,7 @@ declare module "@mindline/sync" {
|
|
|
61
62
|
tagWithWorkspaces(): boolean;
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
export function InitGet(
|
|
65
|
+
export function InitGet(ii: InitInfo, instance: IPublicClientApplication): boolean;
|
|
65
66
|
export function AddTarget(): boolean;
|
|
66
67
|
export function CompleteTarget(): boolean;
|
|
67
68
|
export function AddUser(): boolean;
|
package/index.test.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import {sum, User, InitInfo, InitGet } from "./index.js";
|
|
2
|
-
import {test, expect} from "vitest";
|
|
3
|
-
|
|
4
|
-
test("adds 1 + 2 to equal 3", () => {
|
|
5
|
-
expect(sum(1, 2)).toBe(3);
|
|
6
|
-
});
|
|
7
|
-
test("loads config based on a user and expects function to return true", () => {
|
|
8
|
-
let u = new User();
|
|
9
|
-
let ii = new InitInfo();
|
|
10
|
-
expect(InitGet(u, ii)).toBe(true);
|
|
11
|
-
expect(ii.us.length).toBe(6);
|
|
12
|
-
});
|