@mindline/sync 1.0.19 → 1.0.21
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/README.md +4 -0
- package/hybridspa.ts +21 -51
- package/{sync.d.ts → index.d.ts} +4 -3
- package/index.test.ts +3 -7
- package/index.ts +83 -39
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -10,6 +10,10 @@ https://nodejs.org/en/download
|
|
|
10
10
|
npm install class-transformer --save
|
|
11
11
|
npm install reflect-metadata --save
|
|
12
12
|
```
|
|
13
|
+
## install @azure/msal-browser
|
|
14
|
+
``` js
|
|
15
|
+
npm install @azure/msal-browser --save
|
|
16
|
+
```
|
|
13
17
|
# 2. Latest releases
|
|
14
18
|
# 3. API references
|
|
15
19
|
# 4. Unit Test
|
package/hybridspa.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
const cardDiv = document.getElementById("card-div");
|
|
4
|
-
const profileButton = document.getElementById("seeProfile");
|
|
5
|
-
const profileDiv = document.getElementById("profile-div");
|
|
1
|
+
import { IPublicClientApplication, AuthenticationResult } from '@azure/msal-browser';
|
|
2
|
+
import { User } from '@mindline/sync';
|
|
6
3
|
|
|
7
4
|
// Add here the endpoints for MS Graph API services you would like to use.
|
|
8
5
|
const graphConfig = {
|
|
@@ -16,55 +13,21 @@ function updateUI(data, endpoint) {
|
|
|
16
13
|
console.log("Graph API responded at: " + new Date().toString());
|
|
17
14
|
|
|
18
15
|
if (endpoint === graphConfig.graphMeEndpoint) {
|
|
19
|
-
profileDiv.innerHTML = "";
|
|
20
|
-
const title = document.createElement("p");
|
|
21
|
-
title.innerHTML = "<strong>Title: </strong>" + data.jobTitle;
|
|
22
16
|
console.log(data.jobTitle);
|
|
23
|
-
const email = document.createElement("p");
|
|
24
|
-
email.innerHTML = "<strong>Mail: </strong>" + data.mail;
|
|
25
17
|
console.log(data.mail);
|
|
26
|
-
const phone = document.createElement("p");
|
|
27
|
-
phone.innerHTML = "<strong>Phone: </strong>" + data.businessPhones[0];
|
|
28
18
|
console.log(data.businessPhones[0]);
|
|
29
|
-
const address = document.createElement("p");
|
|
30
|
-
address.innerHTML = "<strong>Location: </strong>" + data.officeLocation;
|
|
31
19
|
console.log(data.officeLocation);
|
|
32
|
-
profileDiv.appendChild(title);
|
|
33
|
-
profileDiv.appendChild(email);
|
|
34
|
-
profileDiv.appendChild(phone);
|
|
35
|
-
profileDiv.appendChild(address);
|
|
36
20
|
} else if (endpoint === graphConfig.graphMailEndpoint) {
|
|
37
21
|
if (data.value.length < 1) {
|
|
38
22
|
alert("Your mailbox is empty!");
|
|
39
23
|
} else {
|
|
40
24
|
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
25
|
data.value.map((d, i) => {
|
|
46
26
|
// Keeping it simple
|
|
47
27
|
if (i < 10) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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);
|
|
28
|
+
console.log(data.officeLocation);
|
|
29
|
+
console.log(d.subject);
|
|
30
|
+
console.log(d.from.emailAddress.address);
|
|
68
31
|
}
|
|
69
32
|
});
|
|
70
33
|
}
|
|
@@ -95,13 +58,13 @@ function callMSGraph(endpoint, token, callback) {
|
|
|
95
58
|
}
|
|
96
59
|
|
|
97
60
|
///get Token
|
|
98
|
-
function getTokenByCode(spaCode) {
|
|
61
|
+
function getTokenByCode(spaCode: string, instance: IPublicClientApplication) {
|
|
99
62
|
var code = spaCode;
|
|
100
63
|
const scopes = ["user.read"];
|
|
101
64
|
|
|
102
65
|
console.log("MSAL: acquireTokenByCode hybrid parameters present");
|
|
103
66
|
|
|
104
|
-
var authResult =
|
|
67
|
+
var authResult = instance.acquireTokenByCode({
|
|
105
68
|
code,
|
|
106
69
|
scopes,
|
|
107
70
|
});
|
|
@@ -111,8 +74,8 @@ function getTokenByCode(spaCode) {
|
|
|
111
74
|
}
|
|
112
75
|
|
|
113
76
|
//See Profile
|
|
114
|
-
function seeProfile(spaCode) {
|
|
115
|
-
getTokenByCode(spaCode)
|
|
77
|
+
function seeProfile(spaCode: string, instance: IPublicClientApplication) {
|
|
78
|
+
getTokenByCode(spaCode, instance)
|
|
116
79
|
.then((response) => {
|
|
117
80
|
callMSGraph(graphConfig.graphMeEndpoint, response.accessToken, updateUI);
|
|
118
81
|
})
|
|
@@ -122,13 +85,16 @@ function seeProfile(spaCode) {
|
|
|
122
85
|
}
|
|
123
86
|
|
|
124
87
|
//Get Tenant Info
|
|
125
|
-
|
|
126
|
-
|
|
88
|
+
export function getTenantInfo(user: User, instance: IPublicClientApplication) {
|
|
89
|
+
debugger;
|
|
90
|
+
|
|
91
|
+
let authResult: AuthenticationResult;
|
|
92
|
+
instance
|
|
127
93
|
.acquireTokenByCode({ code: user.spacode })
|
|
94
|
+
.then((result) => (authResult = result))
|
|
128
95
|
.catch((e: any) => {
|
|
129
96
|
console.log(e);
|
|
130
97
|
});
|
|
131
|
-
|
|
132
98
|
const headers = new Headers();
|
|
133
99
|
const bearer = `Bearer ${authResult.accessToken}`;
|
|
134
100
|
headers.append("Authorization", bearer);
|
|
@@ -147,13 +113,17 @@ async function getTenantInfo(user: User, instance: IPublicClientApplication) {
|
|
|
147
113
|
"request made to Graph API tenant endpoint at: " + new Date().toString()
|
|
148
114
|
);
|
|
149
115
|
|
|
116
|
+
let r = null;
|
|
150
117
|
fetch(tenantEndpoint, options)
|
|
151
118
|
.then((response) => response.json())
|
|
152
119
|
.then((response) => {
|
|
120
|
+
r = response;
|
|
153
121
|
console.log("Successfully Fetched Data from Graph API:", response);
|
|
154
122
|
})
|
|
155
123
|
.catch((error) => console.log(error));
|
|
156
124
|
|
|
157
|
-
|
|
158
|
-
user.
|
|
125
|
+
if(r!==null) {
|
|
126
|
+
user.companyName = r.displayName;
|
|
127
|
+
user.companyDomain = r.defaultDomainName;
|
|
128
|
+
}
|
|
159
129
|
}
|
package/{sync.d.ts → index.d.ts}
RENAMED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { IPublicClientApplication } from "@azure/msal-browser/dist";
|
|
2
|
+
|
|
1
3
|
declare module "@mindline/sync" {
|
|
2
4
|
export function sum(a: number, b: number): number;
|
|
3
5
|
export function helloNpm(): string;
|
|
@@ -18,12 +20,11 @@ declare module "@mindline/sync" {
|
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
// target (Azure AD tenant, AD domain, Google workspace)
|
|
21
|
-
enum TargetType { AAD = 1, AD, Google }
|
|
22
23
|
export class Target {
|
|
23
24
|
tid: string; // from AAD ID token
|
|
24
25
|
name: string; // findTenantInformationByTenantId
|
|
25
26
|
domain: string; // findTenantInformationByTenantId
|
|
26
|
-
type:
|
|
27
|
+
type: string; // always AAD=1 for now
|
|
27
28
|
authority: string; // from AAD ID auth response
|
|
28
29
|
readServicePrincipal: string; // from AAD consent
|
|
29
30
|
writeServicePrincipal: string; // from AAD consent
|
|
@@ -33,7 +34,7 @@ declare module "@mindline/sync" {
|
|
|
33
34
|
// config
|
|
34
35
|
export class TargetConfigInfo {
|
|
35
36
|
tid: string; // target identifier
|
|
36
|
-
sourceGroups: string[]; // source groups - we can
|
|
37
|
+
sourceGroups: string[]; // source groups - we can configure multiple source groups for reading (*may* slow things down, but less work for admin)
|
|
37
38
|
targetGroup: string; // target group - we only write users to a single target group (complex to fiugure out which users get written to which groups)
|
|
38
39
|
}
|
|
39
40
|
export class Config {
|
package/index.test.ts
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
|
-
import {sum,
|
|
1
|
+
import {sum, InitInfo, InitGet} from "./index";
|
|
2
2
|
import {test, expect} from "vitest";
|
|
3
|
+
import {stubbedPublicClientApplication} from "@azure/msal-browser/dist";
|
|
3
4
|
|
|
4
5
|
test("adds 1 + 2 to equal 3", () => {
|
|
5
6
|
expect(sum(1, 2)).toBe(3);
|
|
6
7
|
});
|
|
7
8
|
test("loads config based on a user and expects function to return true", () => {
|
|
8
9
|
let ii = new InitInfo();
|
|
9
|
-
let bResult:boolean =
|
|
10
|
-
InitGet(ii, null)
|
|
11
|
-
.then((response) => bResult = response)
|
|
12
|
-
.catch((e: any) => {
|
|
13
|
-
console.log(e);
|
|
14
|
-
});
|
|
10
|
+
let bResult:boolean = InitGet(ii, stubbedPublicClientApplication);
|
|
15
11
|
expect(bResult);
|
|
16
12
|
});
|
package/index.ts
CHANGED
|
@@ -1,17 +1,36 @@
|
|
|
1
1
|
//index.js
|
|
2
2
|
|
|
3
|
+
import { deserializeArray } from 'class-transformer';
|
|
4
|
+
import { IPublicClientApplication } from '@azure/msal-browser';
|
|
5
|
+
import { getTenantInfo } from './hybridspa';
|
|
6
|
+
import users from "./users.json";
|
|
7
|
+
import targets from "./targets.json";
|
|
8
|
+
import configs from "./configs.json";
|
|
9
|
+
import workspaces from "./workspaces.json";
|
|
10
|
+
|
|
11
|
+
const FILTER_FIELD = "workspaceIDs";
|
|
12
|
+
|
|
3
13
|
// called by unit tests
|
|
4
|
-
export function sum(a, b) {
|
|
14
|
+
export function sum(a: number, b: number): number {
|
|
5
15
|
return a + b;
|
|
6
16
|
}
|
|
7
|
-
export function helloNpm() {
|
|
17
|
+
export function helloNpm() : string {
|
|
8
18
|
return "hello NPM";
|
|
9
19
|
}
|
|
10
20
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
21
|
+
class User {
|
|
22
|
+
oid: string;
|
|
23
|
+
name: string;
|
|
24
|
+
mail: string;
|
|
25
|
+
authority: string;
|
|
26
|
+
tid: string;
|
|
27
|
+
companyName: string;
|
|
28
|
+
companyDomain: string;
|
|
29
|
+
associatedWorkspaces: string[];
|
|
30
|
+
workspaceIDs: string;
|
|
31
|
+
session: string;
|
|
32
|
+
spacode: string;
|
|
33
|
+
constructor() {
|
|
15
34
|
this.oid = "";
|
|
16
35
|
this.name = "";
|
|
17
36
|
this.mail = "";
|
|
@@ -19,14 +38,22 @@ export class User {
|
|
|
19
38
|
this.tid = "";
|
|
20
39
|
this.companyName = "";
|
|
21
40
|
this.companyDomain = "";
|
|
22
|
-
this.associatedWorkspaces =
|
|
41
|
+
this.associatedWorkspaces = new Array();
|
|
23
42
|
this.workspaceIDs = "";
|
|
24
43
|
this.session = "";
|
|
25
44
|
this.spacode = "";
|
|
26
45
|
}
|
|
27
46
|
}
|
|
28
47
|
|
|
29
|
-
|
|
48
|
+
class Target {
|
|
49
|
+
tid: string;
|
|
50
|
+
name: string;
|
|
51
|
+
domain: string;
|
|
52
|
+
type: string;
|
|
53
|
+
authority: string;
|
|
54
|
+
readServicePrincipal: string;
|
|
55
|
+
writeServicePrincipal: string;
|
|
56
|
+
workspaceIDs: string;
|
|
30
57
|
constructor(){
|
|
31
58
|
this.tid = "";
|
|
32
59
|
this.name = "";
|
|
@@ -39,35 +66,57 @@ export class Target {
|
|
|
39
66
|
}
|
|
40
67
|
}
|
|
41
68
|
|
|
42
|
-
|
|
69
|
+
class TargetConfigInfo {
|
|
70
|
+
tid: string;
|
|
71
|
+
sourceGroups: string[];
|
|
72
|
+
targetGroup: string;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
class Config {
|
|
76
|
+
id: string;
|
|
77
|
+
name: string;
|
|
78
|
+
description: string;
|
|
79
|
+
targetConfigs: TargetConfigInfo[];
|
|
80
|
+
enabled: boolean;
|
|
81
|
+
workspaceIDs: string;
|
|
43
82
|
constructor(){
|
|
44
83
|
this.id = "";
|
|
45
84
|
this.name = "";
|
|
46
85
|
this.description = "";
|
|
47
|
-
this.targetConfigs =
|
|
86
|
+
this.targetConfigs = new Array();
|
|
48
87
|
this.enabled = false;
|
|
49
88
|
this.workspaceIDs = "";
|
|
50
89
|
}
|
|
51
90
|
}
|
|
52
91
|
|
|
53
|
-
|
|
92
|
+
class Workspace {
|
|
93
|
+
id: string;
|
|
94
|
+
name: string;
|
|
95
|
+
associatedUsers: string[];
|
|
96
|
+
associatedTargets: string[];
|
|
97
|
+
associatedConfigs: string[];
|
|
54
98
|
constructor(){
|
|
55
99
|
this.id = "";
|
|
56
100
|
this.name = "";
|
|
57
|
-
this.associatedUsers =
|
|
58
|
-
this.associatedTargets =
|
|
59
|
-
this.associatedConfigs =
|
|
101
|
+
this.associatedUsers = new Array();
|
|
102
|
+
this.associatedTargets = new Array();
|
|
103
|
+
this.associatedConfigs = new Array();
|
|
60
104
|
}
|
|
61
105
|
}
|
|
62
106
|
|
|
63
107
|
export class InitInfo {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
108
|
+
us: User[];
|
|
109
|
+
ts: Target[];
|
|
110
|
+
cs: Config[];
|
|
111
|
+
ws: Workspace[];
|
|
112
|
+
constructor(){
|
|
113
|
+
debugger;
|
|
114
|
+
this.us = new Array();
|
|
115
|
+
this.ts = new Array();
|
|
116
|
+
this.cs = new Array();
|
|
117
|
+
this.ws = new Array();
|
|
69
118
|
}
|
|
70
|
-
|
|
119
|
+
tagWithWorkspaces(): boolean {
|
|
71
120
|
// for each Workspace tag associated User, Target, Config with Workspace.id
|
|
72
121
|
for (let workspace of this.ws) {
|
|
73
122
|
// find matching Users to tag with this workspace
|
|
@@ -118,15 +167,8 @@ export class InitInfo {
|
|
|
118
167
|
}
|
|
119
168
|
}
|
|
120
169
|
|
|
121
|
-
import { deserializeArray } from 'class-transformer';
|
|
122
|
-
import { IPublicClientApplication } from '@azure/msal-browser';
|
|
123
|
-
import users from "./users.json";
|
|
124
|
-
import targets from "./targets.json";
|
|
125
|
-
import configs from "./configs.json";
|
|
126
|
-
import workspaces from "./workspaces.json";
|
|
127
|
-
|
|
128
170
|
// get hardcoded data from JSON
|
|
129
|
-
function DummyInit(ii)
|
|
171
|
+
function DummyInit(ii: InitInfo)
|
|
130
172
|
{
|
|
131
173
|
var usersString = JSON.stringify(users);
|
|
132
174
|
var targetsString = JSON.stringify(targets);
|
|
@@ -137,7 +179,7 @@ function DummyInit(ii)
|
|
|
137
179
|
ii.ts = deserializeArray(Target, targetsString);
|
|
138
180
|
ii.cs = deserializeArray(Config, configsString);
|
|
139
181
|
ii.ws = deserializeArray(Workspace, workspacesString);
|
|
140
|
-
if(!ii.
|
|
182
|
+
if(!ii.tagWithWorkspaces()) return false;
|
|
141
183
|
} catch (e) {
|
|
142
184
|
debugger;
|
|
143
185
|
return false;
|
|
@@ -163,8 +205,10 @@ function DummyInit(ii)
|
|
|
163
205
|
// TODO: Mindline: retrieve associated admins, targets for each workspace
|
|
164
206
|
// ii.us / ii.ts / ii.cs: query components of each associated workspaces
|
|
165
207
|
// Returns: users, targets, configs for each workspace
|
|
166
|
-
export
|
|
208
|
+
export function InitGet(ii: InitInfo, instance: IPublicClientApplication): boolean
|
|
167
209
|
{
|
|
210
|
+
debugger;
|
|
211
|
+
|
|
168
212
|
// if empty user array, retrieve dummy data from JSON to populate UI
|
|
169
213
|
let l = ii.us.length;
|
|
170
214
|
if(l === 0) return DummyInit(ii);
|
|
@@ -176,11 +220,11 @@ export async function InitGet(ii, instance)
|
|
|
176
220
|
// have real user: remove dummy user, target, config, workspace if they exist
|
|
177
221
|
let dummyIndex = ii.us.findIndex((u) => u.oid === "1");
|
|
178
222
|
ii.us.splice(dummyIndex, 1);
|
|
179
|
-
dummyIndex = ii.ts.findIndex((u) => u.
|
|
223
|
+
dummyIndex = ii.ts.findIndex((u) => u.tid === "1");
|
|
180
224
|
ii.ts.splice(dummyIndex, 1);
|
|
181
|
-
dummyIndex = ii.cs.findIndex((u) => u.
|
|
225
|
+
dummyIndex = ii.cs.findIndex((u) => u.id === "1");
|
|
182
226
|
ii.cs.splice(dummyIndex, 1);
|
|
183
|
-
dummyIndex = ii.ws.findIndex((u) => u.
|
|
227
|
+
dummyIndex = ii.ws.findIndex((u) => u.id === "1");
|
|
184
228
|
ii.ws.splice(dummyIndex, 1);
|
|
185
229
|
|
|
186
230
|
// why would instance be null here? investigate!
|
|
@@ -191,30 +235,30 @@ export async function InitGet(ii, instance)
|
|
|
191
235
|
|
|
192
236
|
// valid user, query AAD for associated company name and domain
|
|
193
237
|
getTenantInfo(user, instance);
|
|
194
|
-
return;
|
|
238
|
+
return true;
|
|
195
239
|
}
|
|
196
240
|
|
|
197
|
-
|
|
241
|
+
function AddTarget(): boolean
|
|
198
242
|
{
|
|
199
243
|
return true;
|
|
200
244
|
}
|
|
201
245
|
|
|
202
|
-
|
|
246
|
+
function CompleteTarget(): boolean
|
|
203
247
|
{
|
|
204
248
|
return true;
|
|
205
249
|
}
|
|
206
250
|
|
|
207
|
-
|
|
251
|
+
function AddUser(): boolean
|
|
208
252
|
{
|
|
209
253
|
return true;
|
|
210
254
|
}
|
|
211
255
|
|
|
212
|
-
|
|
256
|
+
function CompleteUser(): boolean
|
|
213
257
|
{
|
|
214
258
|
return true;
|
|
215
259
|
}
|
|
216
260
|
|
|
217
|
-
|
|
261
|
+
function CreateConfig(): boolean
|
|
218
262
|
{
|
|
219
263
|
return true;
|
|
220
264
|
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindline/sync",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.21",
|
|
5
|
+
"types": "index.d.ts",
|
|
6
|
+
"exports": "./index.ts",
|
|
5
7
|
"description": "sync is a node.js package encapsulating javscript classes required for configuring Mindline sync service.",
|
|
6
|
-
"exports": "./index.js",
|
|
7
8
|
"scripts": {
|
|
8
9
|
"test": "vitest",
|
|
9
10
|
"coverage": "vitest run --coverage"
|
|
@@ -18,6 +19,5 @@
|
|
|
18
19
|
"@azure/msal-browser": "^2.37.0",
|
|
19
20
|
"class-transformer": "^0.5.1",
|
|
20
21
|
"reflect-metadata": "^0.1.13"
|
|
21
|
-
}
|
|
22
|
-
"typings": "sync.d.ts"
|
|
22
|
+
}
|
|
23
23
|
}
|