Skip to content

Commit

Permalink
Initial Commit v1
Browse files Browse the repository at this point in the history
  • Loading branch information
gscales committed Jan 11, 2019
0 parents commit b322428
Show file tree
Hide file tree
Showing 41 changed files with 18,131 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE.txt
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2017 Glen Scales

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
123 changes: 123 additions & 0 deletions Readme.md
@@ -0,0 +1,123 @@
# Microsoft Teams Group Calendar Tab sample

The following sample is a Microsoft Teams tab application that will show a Group Calendar by calling the Microsoft Graph API to get the members of a particular Team, then the getSchedule Graph operation to get the schedule of the users involved. The Display side of the application makes use of the [FullCalendar](https://fullcalendar.io/) JavaScript event calendar. The legend is built using the users photo which is downloaded from the Graph API also.

Screen Shots of the Tab application in Action

Month View

![](https://gscales.github.io/TeamsGroupCalendar/docs/gcScreen1.JPG)

Week View

![](https://gscales.github.io/TeamsGroupCalendar/docs/gcscren3.JPG)

Day View

![](https://gscales.github.io/TeamsGroupCalendar/docs/gcscren2.JPG)

List View

![](https://gscales.github.io/TeamsGroupCalendar/docs/gcscren4.JPG)

# User Permission requirements #

As this app runs as the currently logged on user that user must have a least the Calendar Details (Free/Busy time, subject, location) Freebusy permission to be able to view calendar events from Team members mailboxes.

# **Installation** #

**Prerequisites for using Teams Tab Applications**

To use a Teams Tab application application side loading must be enabled in the Office365 portal see the following page for how to modify the Teams Org setting [https://docs.microsoft.com/en-us/microsoftteams/admin-settings](https://docs.microsoft.com/en-us/microsoftteams/admin-settings).
> "Sideloading is how you add an app to Teams by uploading a zip file directly to a team. Side-loading lets you test an app as it's being developed. It also lets you build an app for internal use only and share it with your team without submitting it to the Teams app catalog in the Office Store. "
![](https://gscales.github.io/TeamsGroupCalendar/docs/Sideloading.JPG)

**Note**: Make sure you use the https://admin.microsoft.com/AdminPortal/Home#/Settings/ServicesAndAddIns and not the Teams Admin portal as you won't be able to finding this setting in the later.

# Testing this GitHub Instance #

The application files for a Teams Tab application needs to be hosted on a web server, for testing only you can use this hosted version on gitHub. To use this you would need to grant the following applicationId consent in your tenant using the following URL

[https://login.microsoftonline.com/common/adminconsent?client_id=71db5de8-6b7d-437c-b973-0e13f81619e8](https://login.microsoftonline.com/common/adminconsent?client_id=71db5de8-6b7d-437c-b973-0e13f81619e8)

You then need to download the Manifest Zip file from [https://github.com/gscales/gscales.github.io/raw/master/TeamsGroupCalendar/TabPackage/app.zip
](https://github.com/gscales/gscales.github.io/raw/master/TeamsGroupCalendar/TabPackage/app.zip)
then follow the Custom App installation process described below


# **Custom App Installation Process** #

Official documentation for installing Custom Apps can be found
[https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/apps/apps-upload](https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/apps/apps-upload)

Walk through

Choose the Microsoft Store Icon in the Team client (don't worry you not going to purchase anything)
![](https://gscales.github.io/TeamsGroupCalendar/docs/walkthrough1.JPG)

Then select "Upload Custom Application" & "For Me and My Teams"

![](https://gscales.github.io/TeamsGroupCalendar/docs/walkthrough2.JPG)

Select the Teams you want to install the app into

![](https://gscales.github.io/TeamsGroupCalendar/docs/walkthrough3.JPG)

Then select the Channel to install the Tab onto.

# Hosting the Application yourself #

Create an Application Registration that has the following grants

![](https://gscales.github.io/TeamsGroupCalendar/docs/grantsrequired.JPG)

Modify the manifest of the Application registration to enable the Implicit authentication flow

"logoutUrl": null,
"oauth2AllowImplicitFlow": true,
"oauth2AllowUrlPathMatching": false,

Change the tab application m** Manifest** (your version of [https://github.com/gscales/gscales.github.io/blob/master/TeamsGroupCalendar/TabPackage/manifest.json](https://github.com/gscales/gscales.github.io/blob/master/TeamsGroupCalendar/TabPackage/manifest.json))

You need to change the Id,PackageName and configurationURL setting in the manifest to your own unique ApplicationId and URL where the config.html page is hosted

"$schema": "https://statics.teams.microsoft.com/sdk/v1.2/manifest/MicrosoftTeams.schema.json",
"manifestVersion": "1.3",
"version": "1.0.0",
"id": "71db5de8-6b7d-437c-b973-0e13f81619e8",
"packageName": "TeamsGroupCalendar.io.github.gscales",
configurableTabs": [
{
"configurationUrl": "https://gscales.github.io/TeamsGroupCalendar/app/config.html",
"canUpdateConfiguration": true,
"scopes": [ "team" ]
}
],

Modify you hosted version of the https://github.com/gscales/gscales.github.io/blob/master/TeamsGroupCalendar/app/Config/appconfig.js file. Change the clientId to the applicationId from your application registration and the hostRoot to the root of your webhost.

const getConfig = () => {
var config = {
clientId : "71db5de8-6b7d-437c-b973-0e13f81619e8",
redirectUri : "/TeamsGroupCalendar/app/silent-end.html",
authwindow : "/TeamsGroupCalendar/app/auth.html",
hostRoot: "https://gscales.github.io",
};
return config;
}

Create a Zip file of all the files in the https://github.com/gscales/gscales.github.io/blob/master/TeamsGroupCalendar/TabPackage directory and then use that in the Custom App Installation process described above.













Binary file added TabPackage/Colour192.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TabPackage/Outline32.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added TabPackage/app.zip
Binary file not shown.
41 changes: 41 additions & 0 deletions TabPackage/manifest.json
@@ -0,0 +1,41 @@
{
"$schema": "https://statics.teams.microsoft.com/sdk/v1.2/manifest/MicrosoftTeams.schema.json",
"manifestVersion": "1.3",
"version": "1.0.0",
"id": "71db5de8-6b7d-437c-b973-0e13f81619e8",
"packageName": "TeamsGroupCalendar.io.github.gscales",
"developer": {
"name": "gscales@msgdevelop.com",
"websiteUrl": "https://gscales.github.io/TeamsGroupCalendar/app/todo.html",
"privacyUrl": "https://gscales.github.io/TeamsGroupCalendar/app/todo.html",
"termsOfUseUrl": "https://gscales.github.io/TeamsGroupCalendar/app/todo.html"
},
"name": {
"short": "Group Calendar",
"full": "Group Calendar"
},
"description": {
"short": "Tab for displaying an Group Calendar in Javascript Calendar Control",
"full": "Tab for displaying an Group Calendar in Javascript Calendar Control"
},
"icons": {
"outline": "Outline32.png",
"color": "Colour192.png"
},
"accentColor": "#333333",
"configurableTabs": [
{
"configurationUrl": "https://gscales.github.io/TeamsGroupCalendar/app/config.html",
"canUpdateConfiguration": true,
"scopes": [ "team" ]
}
],
"permissions": [
"identity",
"messageTeamMembers"
],
"validDomains": [
"gscales.github.io"

]
}
9 changes: 9 additions & 0 deletions app/Config/appconfig.js
@@ -0,0 +1,9 @@
const getConfig = () => {
var config = {
clientId : "71db5de8-6b7d-437c-b973-0e13f81619e8",
redirectUri : "/TeamsGroupCalendar/app/silent-end.html",
authwindow : "/TeamsGroupCalendar/app/auth.html",
hostRoot: "https://gscales.github.io",
};
return config;
}
70 changes: 70 additions & 0 deletions app/Modules/Authentication.js
@@ -0,0 +1,70 @@
const Authuser = (upn,appconfig) => {
return new Promise(
(resolve, reject) => {
let config = {
clientId: appConfig.clientId,
redirectUri: window.location.origin + appConfig.redirectUri, // This should be in the list of redirect uris for the AAD app
cacheLocation: "localStorage",
navigateToLoginRequestUrl: false,
endpoints: {
"https://graph.microsoft.com": "https://graph.microsoft.com"
}
};
if (upn) {
config.extraQueryParameters = "scope=openid+profile&login_hint=" + encodeURIComponent(upn);
} else {
config.extraQueryParameters = "scope=openid+profile";
}
let authContext = new AuthenticationContext(config);
let user = authContext.getCachedUser();
if (user) {
if (user.userName !== upn) {
// User doesn't match, clear the cache
authContext.clearCache();
}
}
// Get the id token (which is the access token for resource = clientId)
let token = authContext.getCachedToken(config.clientId);
if (token) {
authContext.acquireToken("https://graph.microsoft.com", function (error, idtoken) {
if (error || !idtoken) {
reject(error);
}
else
resolve(idtoken);
});
} else {
// No token, or token is expired
authContext._renewIdToken(function (err, idToken) {
if (err) {
console.log("Renewal failed: " + err);
microsoftTeams.authentication.authenticate({
url: window.location.origin + appConfig.authwindow,
width: 400,
height: 400,
successCallback: function (t) {
// Note: token is only good for one hour
token = t;
resolve(token);
},
failureCallback: function (err) {
reject(err);
}
});
} else {
authContext.acquireToken("https://graph.microsoft.com", function (error, idtoken) {
if (error || !idtoken) {
reject(error);
}
else
resolve(idtoken);
});
}
});
}



}
);
}
39 changes: 39 additions & 0 deletions app/Modules/Display.js
@@ -0,0 +1,39 @@
const buildScheduleTable = (Schedules,displayNameMap) => {
var JSONData = [];
for (index = 0; index < Schedules.value.length; ++index) {
var entry = Schedules.value[index].scheduleItems;
entry.forEach(function (CalendarEntry) {
calEntry ={};
calEntry.title = CalendarEntry.subject + " (" + displayNameMap[Schedules.value[index].scheduleId].initials + ")";
if(CalendarEntry.start.dateTime.slice(12,8) == "00:00:00"){
calEntry.start = CalendarEntry.start.dateTime.slice(0,11);
calEntry.end = CalendarEntry.end.dateTime.slice(0,11);
}else{
calEntry.start = CalendarEntry.start.dateTime;
calEntry.end = CalendarEntry.end.dateTime;
}
calEntry.color = displayNameMap[Schedules.value[index].scheduleId].colorEntry;
JSONData.push(calEntry);
});

}
return JSONData;
}

const buildLegend = (displayNameMap) => {
var html = "<div class=\"ms-Table\" style=\"border-collapse:collapse;border: 0px;table-layout: auto;width:100%;\;background-color:white;\"><div class=\"ms-Table-row\">";
html = html + "<span class=\"ms-Table-cell\" style=\"background-color:white;font-size: large;width:50px;font-weight:bolder;\"></span>";
html = html + "<span class=\"ms-Table-cell\" style=\"background-color:white;font-size: large;width:150px;font-weight:bolder;\">Member</span>";
html = html + "</div>";
for (var key in displayNameMap) {
if (displayNameMap.hasOwnProperty(key)) {
console.log(key);
console.log(displayNameMap[key].colorEntry);
html = html + "<div class=\"ms-Table-row\"><span class=\"ms-Table-cell\" style=\"width:50px;\"><img id=\"img" + key + "\" style=\"border: 2px solid " + displayNameMap[key].colorEntry + ";\" src=\"\" /></span>";
html = html + "<span class=\"ms-Table-cell ms-fontWeight-semibold\" style=\"vertical-align: middle;width:150px;background-color:" + displayNameMap[key].colorEntry + ";\">" + displayNameMap[key].displayName + "</span>";
html = html + "</div >";
}
}
html = html + "</div>";
return html;
}

0 comments on commit b322428

Please sign in to comment.