Skip to content

Commit 9b392cc

Browse files
garrytrinderwaldekmastykarz
authored andcommitted
Add samples
1 parent 11429d8 commit 9b392cc

File tree

9 files changed

+879
-0
lines changed

9 files changed

+879
-0
lines changed

samples/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
dist
2+
.parcel-cache
3+
env.js

samples/img/graph.png

23.2 KB
Loading

samples/img/samples.png

127 KB
Loading

samples/index.html

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
<html lang="en">
2+
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
6+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
7+
<title>Microsoft Graph Chaos Proxy</title>
8+
<link rel="stylesheet"
9+
href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css" />
10+
<link rel="stylesheet" href="https://unpkg.com/@n8d/[email protected]/dist/css/htwoo.min.css">
11+
<link rel="stylesheet" href="./style/theme.css">
12+
<script src="https://unpkg.com/@n8d/[email protected]/dist/js/umd/htwoo.min.js"></script>
13+
</head>
14+
15+
<body class="ms-Fabric" dir="ltr">
16+
<div class="hoo-splashscr">
17+
<div class="hoo-splashscr-content">
18+
<article class="hoo-splashcard">
19+
<header class="hoo-splashcard-header" role="presentation">
20+
<img src="img/graph.png" alt="Microsoft Graph" class="hoo-splashcard-img">
21+
</header>
22+
<h1 class="hoo-splashcard-title">
23+
Microsoft Graph Chaos Proxy
24+
</h1>
25+
<p class="hoo-splashcard-desc">
26+
Samples to use to test the Microsoft Graph Chaos Proxy functionality
27+
</p>
28+
<footer class="hoo-splashcard-footer">
29+
<button id="withsdk" class="hoo-button-primary">
30+
<span class="hoo-button-label">With SDK</span>
31+
</button>
32+
<button id="nosdk" class="hoo-button">
33+
<span class="hoo-button-label">Without SDK</span>
34+
</button>
35+
</article>
36+
</div>
37+
</div>
38+
<script>
39+
document.querySelector('button#withsdk').addEventListener('click', (e) => {
40+
e.preventDefault();
41+
window.location.href = 'withsdk.html';
42+
});
43+
44+
document.querySelector('button#nosdk').addEventListener('click', (e) => {
45+
e.preventDefault();
46+
window.location.href = 'nosdk.html';
47+
});
48+
</script>
49+
</body>
50+
51+
</html>

samples/nosdk.html

Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
<html lang="en">
2+
3+
<head>
4+
<meta charset="utf-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Microsoft Graph Chaos Proxy - No SDK Sample</title>
7+
<link rel="stylesheet"
8+
href="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-core/11.0.0/css/fabric.min.css" />
9+
<link rel="stylesheet" href="https://unpkg.com/@n8d/[email protected]/dist/css/htwoo.min.css">
10+
<link rel="stylesheet" href="./style/theme.css">
11+
<script src="https://alcdn.msauth.net/browser/2.28.3/js/msal-browser.min.js"></script>
12+
<script src="https://unpkg.com/@n8d/[email protected]/dist/js/umd/htwoo.min.js"></script>
13+
<script src="env.js"></script>
14+
<style>
15+
#content {
16+
display: flex;
17+
flex-flow: row wrap;
18+
justify-content: space-around;
19+
row-gap: 2em;
20+
column-gap: 2em;
21+
padding: 2em;
22+
align-items: stretch;
23+
}
24+
25+
</style>
26+
</head>
27+
28+
<body class="ms-Fabric" dir="ltr">
29+
<div id="content"></div>
30+
<div id="auth"></div>
31+
<script>
32+
((appId, msal) => {
33+
const msalClient = new msal.PublicClientApplication({
34+
auth: {
35+
clientId: appId
36+
}
37+
});
38+
39+
function render() {
40+
document.querySelector('div#content').innerHTML = "";
41+
document.querySelector('#auth').innerHTML = "";
42+
43+
const accounts = msalClient.getAllAccounts();
44+
45+
if (accounts.length === 0) {
46+
const element = `<div class="hoo-splashscr">
47+
<div class="hoo-splashscr-content">
48+
<article class="hoo-splashcard">
49+
<header class="hoo-splashcard-header" role="presentation">
50+
<img src="img/graph.png" class="hoo-splashcard-img">
51+
</header>
52+
<h1 class="hoo-splashcard-title">
53+
Microsoft Graph Chaos Proxy
54+
</h1>
55+
<p class="hoo-splashcard-desc">
56+
No SDK Sample
57+
</p>
58+
<footer class="hoo-splashcard-footer">
59+
<button id="login" class="hoo-button-primary">
60+
<span class="hoo-button-label">Login</span>
61+
</button>
62+
<button id="back" class="hoo-button">
63+
<span class="hoo-button-label">Back</span>
64+
</button>
65+
</article>
66+
</div>
67+
</div>`;
68+
69+
document.querySelector('#auth').innerHTML = element;
70+
71+
document.querySelector('button#login').addEventListener('click', login);
72+
document.querySelector('button#back').addEventListener('click', (e) => { e.preventDefault(); window.location.href = "index.html"; });
73+
}
74+
else {
75+
document.querySelector('#auth').innerHTML = `<div style="display:flex;column-gap:2em;padding:2em;">
76+
<button id="logout" class="hoo-button">
77+
<span class="hoo-button-label">Logout</span>
78+
</button>
79+
<button id="back" class="hoo-button">
80+
<span class="hoo-button-label">Back</span>
81+
</button>
82+
</div>`;
83+
document.querySelector('button#logout').addEventListener('click', logout);
84+
document.querySelector('button#back').addEventListener('click', (e) => { e.preventDefault(); window.location.href = "index.html"; });
85+
86+
getAccessToken(msalClient)
87+
.then(accessToken => callGraph(accessToken));
88+
}
89+
}
90+
91+
function login(e) {
92+
e.preventDefault();
93+
msalClient
94+
.loginPopup()
95+
.then(response => render());
96+
}
97+
98+
function logout(e) {
99+
e.preventDefault();
100+
101+
msalClient
102+
.logoutPopup()
103+
.then(response => render());
104+
}
105+
106+
function callMSGraph(endpoint, accessToken, binary = false) {
107+
const headers = new Headers();
108+
const bearer = `Bearer ${accessToken}`;
109+
110+
headers.append("Authorization", bearer);
111+
112+
const options = {
113+
method: "GET",
114+
headers: headers
115+
};
116+
117+
return fetch(endpoint, options)
118+
.then(response => binary ? response.blob() : response.json())
119+
}
120+
121+
function getAccessToken(msalClient) {
122+
const accounts = msalClient.getAllAccounts();
123+
124+
if (accounts.length > 0) {
125+
const accessTokenRequest = {
126+
scopes: [
127+
'https://graph.microsoft.com/User.Read.All',
128+
'https://graph.microsoft.com/Presence.Read.All'
129+
],
130+
account: accounts[0]
131+
};
132+
133+
return msalClient.acquireTokenSilent(accessTokenRequest)
134+
.then(response => response.accessToken)
135+
.catch(error => {
136+
console.log(error);
137+
console.log("silent token acquisition fails. acquiring token using redirect");
138+
if (error instanceof msal.InteractionRequiredAuthError) {
139+
return msalClient.acquireTokenRedirect(accessTokenRequest);
140+
}
141+
});
142+
}
143+
}
144+
145+
function callGraph(accessToken) {
146+
callMSGraph('https://graph.microsoft.com/v1.0/users', accessToken)
147+
.then((users) => {
148+
const usersWithPresence =
149+
users.value.map(
150+
profile =>
151+
callMSGraph(`https://graph.microsoft.com/v1.0/users/${profile.id}/presence`, accessToken)
152+
.then(presence => ({ profile, presence }))
153+
);
154+
return Promise.all(usersWithPresence)
155+
})
156+
.then((usersWithPresence) => {
157+
const usersWithPresenceAndPhoto =
158+
usersWithPresence.map(
159+
({ profile, presence }) =>
160+
callMSGraph(`https://graph.microsoft.com/v1.0/users/${profile.id}/photo/$value`, accessToken, true)
161+
.then(photo => ({ profile, presence, photo }))
162+
// .catch(e => ({ profile, presence, photo: null }))
163+
);
164+
return Promise.all(usersWithPresenceAndPhoto);
165+
})
166+
.then((usersWithPresenceAndPhoto) =>
167+
usersWithPresenceAndPhoto.map((user) => {
168+
const element = `<div class="hoo-persona-72">
169+
<div class="hoo-avatar-pres">
170+
<div class="hoo-avatar">
171+
<img src="${user.photo ? getImageUrl(user.photo) : null}" alt="${user.profile.displayName}" class="hoo-avatar-img" loading="lazy">
172+
</div>
173+
<div class="hoo-presence ${getHooClassFromAvailability(user.presence.availability)}" title="${user.presence.availability}"></div>
174+
</div>
175+
<div class="hoo-persona-data">
176+
<div class="hoo-persona-name">${user.profile.displayName}</div>
177+
<div class="hoo-persona-function">${user.profile.jobTitle ? user.profile.jobTitle : 'Chief Executive Officer'}</span></div>
178+
<div class="hoo-persona-statustext"><span>${user.presence.activity}</span></div>
179+
<div class="hoo-persona-available"><span>${user.presence.availability}</span></div>
180+
</div>
181+
</div>`;
182+
document.querySelector('div#content').innerHTML += element;
183+
}))
184+
}
185+
186+
function getImageUrl(data) {
187+
const url = window.URL || window.webkitURL;
188+
return url.createObjectURL(data);
189+
}
190+
191+
function getHooClassFromAvailability(status) {
192+
switch (status) {
193+
case 'Available':
194+
case 'AvailableIdle':
195+
return 'is-online';
196+
case 'Away':
197+
case 'BeRightBack':
198+
case 'PresenceIdle':
199+
return 'is-away';
200+
case 'Busy':
201+
case 'BusyIdle':
202+
case 'DoNotDisturb':
203+
return 'is-dnd';
204+
case 'Offline':
205+
case 'PresenceUnknown':
206+
return 'is-invisible';
207+
default:
208+
return 'is-invisible';
209+
}
210+
}
211+
212+
render();
213+
})(appId, msal)
214+
215+
</script>
216+
</body>
217+
218+
</html>

samples/readme.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# Samples
2+
3+
## Table of Contents
4+
5+
- [Pre-requisites](#prereqs)
6+
- [Configure Azure AD App Registration](#appreg)
7+
- [Script](#script)
8+
- [Manual](#manual)
9+
- [Launch Sample](#launch)
10+
11+
## <a id="prereqs">Pre-requisites</a>
12+
13+
All the samples have been designed with keeping dependencies to an absolute minimum, however there are a few things that you will need.
14+
15+
You will need a Microsoft 365 Tenant and be able to use an account that has permissions to create an Azure AD App Registrations in your tenant.
16+
17+
We highly recommend that you use a Microsoft 365 Developer Tenant with content packs installed when testing these samples, you can create a developer tenant by [signing up to the Microsoft 365 Developer Program](https://aka.ms/m365/).
18+
19+
## <a id="appreg">Configure Azure AD App Registration</a>
20+
21+
There are two ways which you can configur the App Registration required for the samples to work correctly, through automatation using a bash script or manually through Azure Portal.
22+
23+
### <a id="script">Script</a>
24+
25+
```shell
26+
$ > chmod +x /scripts/setup.sh
27+
$ > ./scripts/setup.sh
28+
```
29+
30+
Follow the prompts in the terminal.
31+
32+
> The script uses CLI for Microsoft 365 to authenticate with and create the app registration in your tenant, therefore requires nodejs, v8 or greater to be installed
33+
34+
## <a id="manual">Manual</a>
35+
36+
The following table provides details of how to configure your app registration.
37+
38+
| Property | Value |
39+
| ---- | ---- |
40+
| Name | Microsoft Graph Chaos Proxy Samples |
41+
| Platform type | Single-page application |
42+
| Redirect URIs | http://localhost:5500/withsdk.html <br> http://localhost:5500/nosdk.html |
43+
| API Permissions | Microsoft Graph <br> User.Read.All (Delegate) <br> Presence.Read.All |
44+
45+
After creating the app registation, create a file called `env.js` in the root of the `samples` directory with the following contents, replacing `<clientid>` with the value which can be copied from the portal.
46+
47+
```
48+
const appId = '<clientid>';
49+
```
50+
51+
## <a id="launch">Launch Sample</a>
52+
53+
Follow these instructions to launch the samples using the Visual Studio Code [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) extension.
54+
55+
> !!! IMPORTANT !!!
56+
> The default host name used by Live Server is `127.0.0.1`, therefore you will need to change the `liveServer.settings.host` setting to `localhost` for the samples to work correctly, as `127.0.0.1` is not a valid Redirect URI.
57+
58+
Open the `samples` directory in Visual Studio Code
59+
60+
```shell
61+
$ > cd samples
62+
$ > code .
63+
```
64+
65+
Start `Live Server`
66+
67+
![Samples](img/samples.png)

samples/scripts/setup.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
#!/usr/bin/env bash
2+
3+
# login
4+
echo "Sign in to Microsoft 365..."
5+
npx -p @pnp/cli-microsoft365 -- m365 login --authType browser
6+
7+
# create AAD app
8+
echo "Creating AAD app..."
9+
appId=$(npx -p @pnp/cli-microsoft365 -- m365 aad app add --name "Microsoft Graph Chaos Proxy Samples" --multitenant --redirectUris "http://localhost:5500/withsdk.html,http://localhost:5500/nosdk.html" --apisDelegated "https://graph.microsoft.com/User.Read.All,https://graph.microsoft.com/Presence.Read.All" --platform spa --query "appId" -o text)
10+
11+
# write app to env.js
12+
echo "Writing app to env.js..."
13+
echo "const appId = '$appId';" > env.js
14+
15+
# write app to env_esm.js
16+
echo "export const appId = '$appId';" > env_esm.js
17+
18+
echo "DONE"

0 commit comments

Comments
 (0)