├── .deployment
├── .gitignore
├── CODE_OF_CONDUCT.md
├── Deployment
└── azuredeploy.json
├── LICENSE
├── Manifest
├── color.png
├── manifest.json
└── outline.png
├── README.md
├── SECURITY.md
├── Source
├── GlobalSuppressions.cs
├── Microsoft.Teams.Apps.Celebration.Notification.Func
│ ├── EventNotificationFunction.cs
│ ├── MessageDeliveryFunction.cs
│ ├── Microsoft.Teams.Apps.Celebration.Notification.Func.csproj
│ ├── PreviewFunction.cs
│ ├── host.json
│ ├── settings.json
│ └── stylecop.json
├── Microsoft.Teams.Apps.Celebration.sln
├── Microsoft.Teams.Apps.Celebration
│ ├── .gitignore
│ ├── App_Start
│ │ ├── BundleConfig.cs
│ │ ├── FilterConfig.cs
│ │ ├── RouteConfig.cs
│ │ ├── Startup.Auth.cs
│ │ └── WebApiConfig.cs
│ ├── ApplicationConfig.cs
│ ├── ApplicationInsights.config
│ ├── CelebrationsAppModule.cs
│ ├── Connected Services
│ │ └── Application Insights
│ │ │ └── ConnectedService.json
│ ├── Content
│ │ ├── css
│ │ │ ├── button-themes.css
│ │ │ ├── datepicker-custom-theme.css
│ │ │ ├── datepicker.css
│ │ │ ├── spinner.css
│ │ │ ├── styles.css
│ │ │ └── tabStyles.css
│ │ └── images
│ │ │ ├── Celebrations-bot-image-new-event.jpg
│ │ │ ├── carousel
│ │ │ ├── 0.png
│ │ │ ├── 1.png
│ │ │ ├── 10.png
│ │ │ ├── 2.png
│ │ │ ├── 3.png
│ │ │ ├── 4.png
│ │ │ ├── 5.png
│ │ │ ├── 6.png
│ │ │ ├── 7.png
│ │ │ ├── 8.png
│ │ │ └── 9.png
│ │ │ ├── celebration_bot_full-color.png
│ │ │ ├── empty-state-celebrations.png
│ │ │ ├── welcome-card-image.png
│ │ │ └── welcome-dialog.png
│ ├── Controllers
│ │ ├── AuthController.cs
│ │ ├── EventNotificationController.cs
│ │ ├── MessageDeliveryController.cs
│ │ ├── MessagesController.cs
│ │ ├── PreviewController.cs
│ │ ├── SharedSecretAuthenticationAttribute.cs
│ │ ├── TabAuthController.cs
│ │ └── TabsController.cs
│ ├── Dialog
│ │ ├── DialogFactory.cs
│ │ ├── IgnoreEventShareDialog.cs
│ │ ├── RootDialog.cs
│ │ ├── ShareEventDialog.cs
│ │ └── SkipEventDialog.cs
│ ├── ErrorHandler
│ │ └── AiHandleErrorAttribute.cs
│ ├── Global.asax
│ ├── Global.asax.cs
│ ├── Helpers
│ │ ├── AdaptiveCardExtensions.cs
│ │ ├── ApplicationSettings.cs
│ │ ├── CelebrationCard.cs
│ │ ├── Common.cs
│ │ ├── ConnectorClientFactory.cs
│ │ ├── ConversationExtensions.cs
│ │ ├── DocumentQueryExtensions.cs
│ │ ├── EventDataProvider.cs
│ │ ├── IConnectorClientFactory.cs
│ │ ├── IEventDataProvider.cs
│ │ ├── IUserManagementHelper.cs
│ │ └── UserManagementHelper.cs
│ ├── Microsoft.Teams.Apps.Celebration.csproj
│ ├── Models
│ │ ├── BotScope.cs
│ │ ├── CelebrationEvent.cs
│ │ ├── EventMessage.cs
│ │ ├── EventNotificationData.cs
│ │ ├── EventOccurrence.cs
│ │ ├── EventStatus.cs
│ │ ├── EventTypes.cs
│ │ ├── EventsTabViewModel.cs
│ │ ├── ManageEventViewModel.cs
│ │ ├── MessageSendResult.cs
│ │ ├── MessageType.cs
│ │ ├── PreviewCardPayload.cs
│ │ ├── ShareEventPayload.cs
│ │ ├── SubmitActionPayload.cs
│ │ ├── Team.cs
│ │ ├── TimeZoneDisplayInfo.cs
│ │ ├── User.cs
│ │ └── UserTeamMembership.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Resources
│ │ ├── Strings.Designer.cs
│ │ └── Strings.resx
│ ├── Scripts
│ │ ├── bootstrap-datepicker.js
│ │ ├── custom-multiselect.js
│ │ ├── events.js
│ │ └── theme.js
│ ├── Startup.cs
│ ├── Views
│ │ ├── Shared
│ │ │ ├── Error.cshtml
│ │ │ ├── _Layout.cshtml
│ │ │ └── _Spinner.cshtml
│ │ ├── TabAuth
│ │ │ ├── Callback.cshtml
│ │ │ ├── Login.cshtml
│ │ │ └── Start.cshtml
│ │ ├── Tabs
│ │ │ ├── Events.cshtml
│ │ │ ├── EventsData.cshtml
│ │ │ ├── ManageEvent.cshtml
│ │ │ ├── ManageEventData.cshtml
│ │ │ └── Tour.cshtml
│ │ ├── _ViewStart.cshtml
│ │ └── web.config
│ ├── Web.Debug.config
│ ├── Web.Release.config
│ ├── Web.config
│ ├── default.htm
│ ├── libman.json
│ ├── packages.config
│ └── stylecop.json
├── Microsoft.Teams.Apps.Common
│ ├── Authentication
│ │ ├── ITokenValidator.cs
│ │ └── TokenValidator.cs
│ ├── CommonConfig.cs
│ ├── CommonConstant.cs
│ ├── Configuration
│ │ ├── IConfigProvider.cs
│ │ └── LocalConfigProvider.cs
│ ├── Exceptions
│ │ ├── SettingDeserializationException.cs
│ │ └── SettingNotFoundException.cs
│ ├── Extensions
│ │ ├── ClaimsPrincipalExtensions.cs
│ │ ├── ConfigurationExtensions.cs
│ │ ├── EncryptedConfigAttribute.cs
│ │ ├── LoggingExtensions.cs
│ │ └── TimeTracker.cs
│ ├── Http
│ │ ├── HttpClientWrapper.cs
│ │ └── IHttpClient.cs
│ ├── Logging
│ │ ├── AppInsightsLogProvider.cs
│ │ ├── ILogProvider.cs
│ │ └── LogLevel.cs
│ ├── Microsoft.Teams.Apps.Common.csproj
│ ├── Models
│ │ └── Token.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── Telemetry
│ │ ├── TelemetryEvent.cs
│ │ ├── TelemetryProperty.cs
│ │ └── UserTelemetryInitializer.cs
│ ├── app.config
│ └── packages.config
├── Settings.StyleCop
└── stylecop.json
├── deploy.app.cmd
├── deploy.cmd
├── deploy.function.cmd
└── global.json
/.deployment:
--------------------------------------------------------------------------------
1 | [config]
2 | command = deploy.cmd
3 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/Manifest/color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Manifest/color.png
--------------------------------------------------------------------------------
/Manifest/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.5/MicrosoftTeams.schema.json",
3 | "manifestVersion": "1.5",
4 | "version": "1.0.0",
5 | "id": "5c0b8ee0-d445-409b-9c19-ab9edc07a314",
6 | "packageName": "com.microsoft.teams.celebrations",
7 | "developer": {
8 | "name": "",
9 | "websiteUrl": "",
10 | "privacyUrl": "",
11 | "termsOfUseUrl": ""
12 | },
13 | "name": {
14 | "short": "Celebrations"
15 | },
16 | "description": {
17 | "short": "Celebrate birthdays, anniversaries and other events with your team",
18 | "full": "Celebrations helps members celebrate each others' birthdays, anniversaries, and other recurring events"
19 | },
20 | "icons": {
21 | "outline": "outline.png",
22 | "color": "color.png"
23 | },
24 | "accentColor": "#64A2CC",
25 | "staticTabs": [
26 | {
27 | "contentUrl": "https:///Tabs/Events?userObjectId={userObjectId}&theme={theme}&locale={locale}",
28 | "entityId": "EventsTab",
29 | "name": "Events",
30 | "scopes": [
31 | "personal"
32 | ]
33 | }
34 | ],
35 | "bots": [
36 | {
37 | "botId": "",
38 | "isNotificationOnly": false,
39 | "scopes": [ "team", "personal" ]
40 | }
41 | ],
42 | "permissions": [
43 | "identity",
44 | "messageTeamMembers"
45 | ],
46 | "validDomains": [
47 | ""
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/Manifest/outline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Manifest/outline.png
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | languages:
4 | - csharp
5 | products:
6 | - dotnet
7 | description: "Fun Teams app to celebrate special occasions in a team"
8 | ---
9 |
10 | # Celebrations App Template
11 |
12 | | [Documentation](https://github.com/OfficeDev/microsoft-teams-celebrations-app/wiki) | [Deployment guide](https://github.com/OfficeDev/microsoft-teams-celebrations-app/wiki/Deployment-guide) | [Architecture](https://github.com/OfficeDev/microsoft-teams-celebrations-app/wiki/Solution-overview) |
13 | | ---- | ---- | ---- |
14 |
15 | Celebrations is a Teams app that helps team members celebrate each others’ birthdays, anniversaries, and other recurring events. It remembers special occasions of all the team members and sends a friendly message in all the teams selected at the time of event creation, to make the team members feel special on their day.
16 |
17 | The app provides an easy interface for all the team members to personally add and view their events and also allows the user to select the teams in which the events gets shared.
18 |
19 | ## Get started
20 |
21 | Begin with the [Solution overview](https://github.com/OfficeDev/microsoft-teams-celebrations-app/wiki/Solution-overview) to read about what the app does and how it works.
22 |
23 | When you're ready to try out Celebrations, or to use it in your own organization, follow the steps in the [Deployment guide](https://github.com/OfficeDev/microsoft-teams-celebrations-app/wiki/Deployment-guide).
24 |
25 | ## Feedback
26 |
27 | Thoughts? Questions? Ideas? Share them with us on [Teams UserVoice](https://microsoftteams.uservoice.com/forums/555103-public)!
28 |
29 | Please report bugs and other code issues [here](https://github.com/OfficeDev/microsoft-teams-celebrations-app/issues/new).
30 |
31 | ## Legal notice
32 |
33 | This app template is provided under the [MIT License](https://github.com/OfficeDev/microsoft-teams-celebrations-app/blob/master/LICENSE) terms. In addition to these terms, by using this app template you agree to the following:
34 |
35 | - You, not Microsoft, will license the use of your app to users or organization.
36 |
37 | - This app template is not intended to substitute your own regulatory due diligence or make you or your app compliant with respect to any applicable regulations, including but not limited to privacy, healthcare, employment, or financial regulations.
38 |
39 | - You are responsible for complying with all applicable privacy and security regulations including those related to use, collection and handling of any personal data by your app. This includes complying with all internal privacy and security policies of your organization if your app is developed to be sideloaded internally within your organization. Where applicable, you may be responsible for data related incidents or data subject requests for data collected through your app.
40 |
41 | - Any trademarks or registered trademarks of Microsoft in the United States and/or other countries and logos included in this repository are the property of Microsoft, and the license for this project does not grant you rights to use any Microsoft names, logos or trademarks outside of this repository. Microsoft’s general trademark guidelines can be found [here](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general.aspx).
42 |
43 | - If the app template enables access to any Microsoft Internet-based services (e.g., Office365), use of those services will be subject to the separately-provided terms of use. In such cases, Microsoft may collect telemetry data related to app template usage and operation. Use and handling of telemetry data will be performed in accordance with such terms of use.
44 |
45 | - Use of this template does not guarantee acceptance of your app to the Teams app store. To make this app available in the Teams app store, you will have to comply with the [submission and validation process](https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/appsource/publish), and all associated requirements such as including your own privacy statement and terms of use for your app.
46 |
47 | ## Contributing
48 |
49 | This project welcomes contributions and suggestions. Most contributions require you to agree to a
50 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
51 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com.
52 |
53 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide
54 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions
55 | provided by the bot. You will only need to do this once across all repos using our CLA.
56 |
57 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
58 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
59 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
60 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets Microsoft's [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)) of a security vulnerability, please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Source/GlobalSuppressions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | // This file is used by Code Analysis to maintain SuppressMessage
6 | // attributes that are applied to this project.
7 | // Project-level suppressions either have no target or are given
8 | // a specific target and scoped to a namespace, type, member, etc.
9 |
10 | // Stylecop suppressions
11 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1629:Documentation text should end with a period", Justification = "Style choice")]
12 | [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.LayoutRules", "SA1512:SingleLineCommentsMustNotBeFollowedByBlankLine", Justification = "Style choice.")]
13 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/EventNotificationFunction.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace PreviewFunctionApp
6 | {
7 | using System;
8 | using System.Net.Http;
9 | using System.Threading.Tasks;
10 | using Microsoft.Azure.WebJobs;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.Logging;
13 |
14 | ///
15 | /// Send post request to celebration bot to send event card on the day of event
16 | ///
17 | public static class EventNotificationFunction
18 | {
19 | ///
20 | /// Timer triggered azure function that runs every hour and sends post request to bot to send the event card in teams on the day of event
21 | ///
22 | /// Timer instance
23 | /// ILogger instance
24 | /// ExecutionContext
25 | /// Tracking task
26 | [FunctionName("EventNotification")]
27 | public static async Task Run([TimerTrigger("0 0 * * * *")]TimerInfo myTimer, ILogger log, ExecutionContext context)
28 | {
29 | log.LogInformation($"Executing event notification function. Last run: {myTimer.ScheduleStatus.Last}");
30 |
31 | try
32 | {
33 | var config = new ConfigurationBuilder()
34 | .SetBasePath(context.FunctionAppDirectory)
35 | .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
36 | .AddEnvironmentVariables()
37 | .Build();
38 |
39 | var baseUri = config["AppBaseUri"];
40 | var endpointUri = $"{baseUri}/api/EventNotification?effectiveDateTime={DateTimeOffset.UtcNow.ToString("o")}";
41 |
42 | var httpClient = new HttpClient();
43 | httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("SharedSecret", config["AppApiKey"]);
44 |
45 | var response = await httpClient.PostAsync(endpointUri, new StringContent(string.Empty));
46 | log.LogInformation($"Posted event notification trigger to app. Status code: {response.StatusCode}");
47 | }
48 | catch (Exception ex)
49 | {
50 | log.LogError(ex, $"Error running event notification function: {ex.Message}");
51 | }
52 |
53 | log.LogInformation($"Finished event notification function. Next run: {myTimer.Schedule.GetNextOccurrence(DateTime.UtcNow)}");
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/MessageDeliveryFunction.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace ReliableDeliveryFunctionApp
6 | {
7 | using System;
8 | using System.Net.Http;
9 | using System.Threading.Tasks;
10 | using Microsoft.Azure.WebJobs;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.Logging;
13 |
14 | ///
15 | /// Send post request to celebration bot to send messages
16 | ///
17 | public static class MessageDeliveryFunction
18 | {
19 | ///
20 | /// Timer trigger azure function that runs in every 15 minutes and sends post request to bot to retry for failed messages
21 | ///
22 | /// Timer instance
23 | /// ILogger instance
24 | /// ExecutionContext
25 | /// Tracking task
26 | [FunctionName("MessageDelivery")]
27 | public static async Task Run([TimerTrigger("0 */15 * * * *")]TimerInfo myTimer, ILogger log, ExecutionContext context)
28 | {
29 | log.LogInformation($"Executing message delivery function. Last run: {myTimer.ScheduleStatus.Last}");
30 |
31 | try
32 | {
33 | var config = new ConfigurationBuilder()
34 | .SetBasePath(context.FunctionAppDirectory)
35 | .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
36 | .AddEnvironmentVariables()
37 | .Build();
38 |
39 | var baseUri = config["AppBaseUri"];
40 | var endpointUri = $"{baseUri}/api/MessageDelivery";
41 |
42 | var httpClient = new HttpClient();
43 | httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("SharedSecret", config["AppApiKey"]);
44 |
45 | var response = await httpClient.PostAsync(endpointUri, new StringContent(string.Empty));
46 | log.LogInformation($"Posted message delivery trigger to app. Status code: {response.StatusCode}");
47 | }
48 | catch (Exception ex)
49 | {
50 | log.LogError(ex, $"Error running message delivery function: {ex.Message}");
51 | }
52 |
53 | log.LogInformation($"Finished message delivery function. Next run: {myTimer.Schedule.GetNextOccurrence(DateTime.UtcNow)}");
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/Microsoft.Teams.Apps.Celebration.Notification.Func.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | netcoreapp2.1
4 | v2
5 | bin\Microsoft.Teams.Apps.Celebration.Notification.Func.xml
6 |
7 |
8 | bin\Release
9 |
10 |
11 | bin\Debug
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | all
23 | runtime; build; native; contentfiles; analyzers
24 |
25 |
26 |
27 |
28 | PreserveNewest
29 |
30 |
31 | PreserveNewest
32 |
33 |
34 | PreserveNewest
35 | Never
36 |
37 |
38 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/PreviewFunction.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace PreviewFunctionApp
6 | {
7 | using System;
8 | using System.Net.Http;
9 | using System.Threading.Tasks;
10 | using Microsoft.Azure.WebJobs;
11 | using Microsoft.Extensions.Configuration;
12 | using Microsoft.Extensions.Logging;
13 |
14 | ///
15 | /// Send post request to celebration bot to send the reminder of event
16 | ///
17 | public static class PreviewFunction
18 | {
19 | ///
20 | /// Timer trigger azure function that runs at 12 AM every day and sends post request to celebration app to process preview cards
21 | ///
22 | /// Timer instance
23 | /// ILogger instance
24 | /// ExecutionContext
25 | /// Tracking task
26 | [FunctionName("Preview")]
27 | public static async Task Run([TimerTrigger("0 0 0 * * *")]TimerInfo myTimer, ILogger log, ExecutionContext context)
28 | {
29 | log.LogInformation($"Executing preview function. Last run: {myTimer.ScheduleStatus.Last}");
30 |
31 | try
32 | {
33 | var config = new ConfigurationBuilder()
34 | .SetBasePath(context.FunctionAppDirectory)
35 | .AddJsonFile("local.settings.json", optional: true, reloadOnChange: true)
36 | .AddEnvironmentVariables()
37 | .Build();
38 |
39 | var baseUri = config["AppBaseUri"];
40 | var endpointUri = $"{baseUri}/api/Preview?effectiveDateTime={DateTimeOffset.UtcNow.ToString("o")}";
41 |
42 | var httpClient = new HttpClient();
43 | httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("SharedSecret", config["AppApiKey"]);
44 |
45 | var response = await httpClient.PostAsync(endpointUri, new StringContent(string.Empty));
46 | log.LogInformation($"Posted preview trigger to app. Status code: {response.StatusCode}");
47 | }
48 | catch (Exception ex)
49 | {
50 | log.LogError(ex, $"Error running preview function: {ex.Message}");
51 | }
52 |
53 | log.LogInformation($"Finished preview function. Next run: {myTimer.Schedule.GetNextOccurrence(DateTime.UtcNow)}");
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0"
3 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "AppBaseUri": "https://",
3 | "AppApiKey": "<>"
4 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.Notification.Func/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | // ACTION REQUIRED: This file was automatically added to your project, but it
3 | // will not take effect until additional steps are taken to enable it. See the
4 | // following page for additional information:
5 | //
6 | // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md
7 |
8 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
9 | "settings": {
10 | "documentationRules": {
11 | "companyName": "Microsoft"
12 | }
13 | }
14 | }
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28010.2036
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Teams.Apps.Celebration", "Microsoft.Teams.Apps.Celebration\Microsoft.Teams.Apps.Celebration.csproj", "{A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Teams.Apps.Common", "Microsoft.Teams.Apps.Common\Microsoft.Teams.Apps.Common.csproj", "{7FA2791F-E894-4876-8773-A5318631365C}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Teams.Apps.Celebration.Notification.Func", "Microsoft.Teams.Apps.Celebration.Notification.Func\Microsoft.Teams.Apps.Celebration.Notification.Func.csproj", "{2D93F294-E877-4988-B6FB-39F05ACFA38F}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|Any CPU = Debug|Any CPU
15 | Release|Any CPU = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
19 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
20 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
21 | {A8BA1066-5695-4D71-ABB4-65E5A5E0C3D4}.Release|Any CPU.Build.0 = Release|Any CPU
22 | {7FA2791F-E894-4876-8773-A5318631365C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
23 | {7FA2791F-E894-4876-8773-A5318631365C}.Debug|Any CPU.Build.0 = Debug|Any CPU
24 | {7FA2791F-E894-4876-8773-A5318631365C}.Release|Any CPU.ActiveCfg = Release|Any CPU
25 | {7FA2791F-E894-4876-8773-A5318631365C}.Release|Any CPU.Build.0 = Release|Any CPU
26 | {2D93F294-E877-4988-B6FB-39F05ACFA38F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
27 | {2D93F294-E877-4988-B6FB-39F05ACFA38F}.Debug|Any CPU.Build.0 = Debug|Any CPU
28 | {2D93F294-E877-4988-B6FB-39F05ACFA38F}.Release|Any CPU.ActiveCfg = Release|Any CPU
29 | {2D93F294-E877-4988-B6FB-39F05ACFA38F}.Release|Any CPU.Build.0 = Release|Any CPU
30 | EndGlobalSection
31 | GlobalSection(SolutionProperties) = preSolution
32 | HideSolutionNode = FALSE
33 | EndGlobalSection
34 | GlobalSection(ExtensibilityGlobals) = postSolution
35 | SolutionGuid = {3C10A400-912E-4E21-BBB1-5DD411367AA6}
36 | EndGlobalSection
37 | EndGlobal
38 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/.gitignore:
--------------------------------------------------------------------------------
1 | lib/
2 | Content/fontawesome/
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/App_Start/BundleConfig.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | using System.Web.Optimization;
8 |
9 | ///
10 | /// Configures bundles
11 | ///
12 | public class BundleConfig
13 | {
14 | ///
15 | /// Configures bundles.
16 | ///
17 | /// Bundle collection to configure
18 | // For more information on bundling, visit https://go.microsoft.com/fwlink/?LinkId=301862
19 | public static void RegisterBundles(BundleCollection bundles)
20 | {
21 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
22 | "~/lib/jquery/jquery.js"));
23 | bundles.Add(new ScriptBundle("~/bundles/jquery-validate").Include(
24 | "~/lib/jquery-validate/jquery.validate.js"));
25 | bundles.Add(new ScriptBundle("~/bundles/jquery-slimscroll").Include(
26 | "~/lib/jquery-slimscroll/jquery.slimscroll.js"));
27 |
28 | bundles.Add(new ScriptBundle("~/bundles/bootstrap3").Include(
29 | "~/lib/bootstrap3/dist/js/bootstrap.js"));
30 | bundles.Add(new ScriptBundle("~/bundles/bootstrap4").Include(
31 | "~/lib/bootstrap4/js/bootstrap.js"));
32 | bundles.Add(new ScriptBundle("~/bundles/bootstrap-multiselect").Include(
33 | "~/lib/bootstrap-multiselect/js/bootstrap-multiselect.js"));
34 | bundles.Add(new ScriptBundle("~/bundles/bootstrap-datepicker").Include(
35 | "~/Scripts/bootstrap-datepicker.js"));
36 |
37 | bundles.Add(new ScriptBundle("~/bundles/momentjs").Include(
38 | "~/lib/moment.js/moment.js"));
39 | bundles.Add(new ScriptBundle("~/bundles/adal-js").Include(
40 | "~/lib/adal-angular/dist/adal.min.js"));
41 | bundles.Add(new ScriptBundle("~/bundles/teams-js").Include(
42 | "~/lib/teams-js/dist/microsoftTeams.min.js"));
43 |
44 | bundles.Add(new StyleBundle("~/bundles/css").Include(
45 | "~/Content/css/styles.css",
46 | "~/Content/css/tabStyles.css",
47 | "~/Content/css/button-themes.css",
48 | "~/Content/css/spinner.css"));
49 |
50 | bundles.Add(new StyleBundle("~/bundles/bootstrap3-css").Include(
51 | "~/lib/bootstrap3/dist/css/bootstrap.css"));
52 | bundles.Add(new StyleBundle("~/bundles/bootstrap4-css").Include(
53 | "~/lib/bootstrap4/css/bootstrap.css"));
54 | bundles.Add(new StyleBundle("~/bundles/bootstrap-multiselect-css").Include(
55 | "~/lib/bootstrap-multiselect/css/bootstrap-multiselect.css"));
56 | bundles.Add(new StyleBundle("~/bundles/bootstrap-datepicker-css").Include(
57 | "~/Content/css/datepicker.css",
58 | "~/Content/css/datepicker-custom-theme.css"));
59 | bundles.Add(new StyleBundle("~/content/fontawesome/css/font-awesome").Include(
60 | "~/Content/fontawesome/css/font-awesome.css"));
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/App_Start/FilterConfig.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | using System.Web.Mvc;
8 |
9 | ///
10 | /// Filter configurator
11 | ///
12 | public class FilterConfig
13 | {
14 | ///
15 | /// Configures global filters
16 | ///
17 | /// The filters to configure
18 | public static void RegisterGlobalFilters(GlobalFilterCollection filters)
19 | {
20 | filters.Add(new HandleErrorAttribute());
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/App_Start/RouteConfig.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | using System.Web.Mvc;
8 | using System.Web.Routing;
9 |
10 | ///
11 | /// Route configurator
12 | ///
13 | public class RouteConfig
14 | {
15 | ///
16 | /// Registers routes with the
17 | ///
18 | /// The routes to configure
19 | public static void RegisterRoutes(RouteCollection routes)
20 | {
21 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
22 |
23 | routes.MapRoute(
24 | name: "Default",
25 | url: "{controller}/{action}/{id}",
26 | defaults: new { action = "Index", id = UrlParameter.Optional });
27 |
28 | // routes.MapMvcAttributeRoutes();
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/App_Start/Startup.Auth.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | using System;
8 | using global::Owin;
9 | using Microsoft.Owin.Security;
10 | using Microsoft.Owin.Security.Cookies;
11 | using Microsoft.Teams.Apps.Celebration.Controllers;
12 |
13 | ///
14 | /// OWIN startup class
15 | ///
16 | public partial class Startup
17 | {
18 | ///
19 | /// Configure authentication for the app
20 | ///
21 | /// App builder
22 | // For more information on configuring authentication, please visit https://go.microsoft.com/fwlink/?LinkId=301864
23 | public void ConfigureAuth(IAppBuilder app)
24 | {
25 | app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
26 |
27 | app.UseCookieAuthentication(new CookieAuthenticationOptions
28 | {
29 | AuthenticationMode = AuthenticationMode.Active,
30 | AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
31 | LoginPath = new Owin.PathString(TabAuthController.LoginPath),
32 | ExpireTimeSpan = TimeSpan.FromDays(1),
33 | SlidingExpiration = true,
34 | Provider = new CookieAuthenticationProvider
35 | {
36 | OnApplyRedirect = (context) =>
37 | {
38 | // Convert HTTP redirects to HTTPS
39 | var redirectUri = context.RedirectUri;
40 | if (!string.IsNullOrEmpty(redirectUri) && redirectUri.ToLowerInvariant().StartsWith("http://"))
41 | {
42 | redirectUri = "https://" + redirectUri.Substring(7);
43 | }
44 |
45 | context.Response.Redirect(redirectUri);
46 | },
47 | },
48 | });
49 | }
50 | }
51 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/App_Start/WebApiConfig.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | using System.Web.Http;
8 | using Autofac.Integration.WebApi;
9 | using Microsoft.Bot.Builder.Dialogs;
10 | using Newtonsoft.Json;
11 | using Newtonsoft.Json.Serialization;
12 |
13 | ///
14 | /// Web Api configurator
15 | ///
16 | public static class WebApiConfig
17 | {
18 | ///
19 | /// Register the routes and configuration settings.
20 | ///
21 | /// config.
22 | public static void Register(HttpConfiguration config)
23 | {
24 | // Json settings
25 | config.Formatters.JsonFormatter.SerializerSettings.NullValueHandling = NullValueHandling.Include;
26 | config.Formatters.JsonFormatter.SerializerSettings.Formatting = Formatting.Indented;
27 |
28 | config.Formatters.JsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
29 | JsonConvert.DefaultSettings = () => new JsonSerializerSettings()
30 | {
31 | Formatting = Formatting.Indented,
32 | NullValueHandling = NullValueHandling.Include,
33 | };
34 |
35 | // Web API configuration and services
36 | config.DependencyResolver = new AutofacWebApiDependencyResolver(Conversation.Container);
37 |
38 | // Web API routes
39 | config.MapHttpAttributeRoutes();
40 |
41 | config.Routes.MapHttpRoute(
42 | name: "DefaultApi",
43 | routeTemplate: "api/{controller}/{id}",
44 | defaults: new { id = RouteParameter.Optional });
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/ApplicationConfig.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | ///
8 | /// Application configuration keys
9 | ///
10 | public enum ApplicationConfig
11 | {
12 | ///
13 | /// Application base uri, without trailing slash
14 | ///
15 | BaseUrl,
16 |
17 | ///
18 | /// Cosmos DB endpoint url
19 | ///
20 | CosmosDBEndpointUrl,
21 |
22 | ///
23 | /// CosmosDB connection key
24 | ///
25 | CosmosDBKey,
26 |
27 | ///
28 | /// CosmosDB datbase name
29 | ///
30 | CosmosDBDatabaseName,
31 |
32 | ///
33 | /// Bot app id
34 | ///
35 | MicrosoftAppId,
36 |
37 | ///
38 | /// Bot app password
39 | ///
40 | MicrosoftAppPassword,
41 |
42 | ///
43 | /// Time to post the celebration in team
44 | ///
45 | TimeToPostCelebration,
46 |
47 | ///
48 | /// Maximum number of events per user
49 | ///
50 | MaxUserEventsCount,
51 |
52 | ///
53 | /// Number of days in advance to send the preview event notification
54 | ///
55 | DaysInAdvanceToSendEventPreview,
56 |
57 | ///
58 | /// Mininum time in hours to process event, otherwise the event will be skipped this year
59 | ///
60 | MinTimeToProcessEventInHours,
61 |
62 | ///
63 | /// Teams app ID
64 | ///
65 | ManifestAppId,
66 | }
67 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/CelebrationsAppModule.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration
6 | {
7 | using System;
8 | using Autofac;
9 | using Microsoft.ApplicationInsights;
10 | using Microsoft.ApplicationInsights.Extensibility;
11 | using Microsoft.Bot.Builder.Azure;
12 | using Microsoft.Bot.Builder.Dialogs.Internals;
13 | using Microsoft.Bot.Builder.Internals.Fibers;
14 | using Microsoft.Bot.Connector;
15 | using Microsoft.Teams.Apps.Celebration.Dialog;
16 | using Microsoft.Teams.Apps.Celebration.Helpers;
17 | using Microsoft.Teams.Apps.Common;
18 | using Microsoft.Teams.Apps.Common.Authentication;
19 | using Microsoft.Teams.Apps.Common.Configuration;
20 | using Microsoft.Teams.Apps.Common.Logging;
21 |
22 | ///
23 | /// Autofac Module
24 | ///
25 | public class CelebrationsAppModule : Module
26 | {
27 | ///
28 | protected override void Load(ContainerBuilder builder)
29 | {
30 | base.Load(builder);
31 |
32 | var configProvider = new LocalConfigProvider();
33 | builder.Register(c => configProvider)
34 | .Keyed(FiberModule.Key_DoNotSerialize)
35 | .AsImplementedInterfaces()
36 | .SingleInstance();
37 |
38 | builder.Register(c =>
39 | {
40 | return new TelemetryClient(new TelemetryConfiguration(configProvider.GetSetting(CommonConfig.ApplicationInsightsInstrumentationKey)));
41 | }).SingleInstance();
42 |
43 | builder.RegisterType()
44 | .Keyed(FiberModule.Key_DoNotSerialize)
45 | .AsImplementedInterfaces()
46 | .SingleInstance();
47 | builder.RegisterType()
48 | .Keyed(FiberModule.Key_DoNotSerialize)
49 | .AsImplementedInterfaces()
50 | .SingleInstance();
51 | builder.RegisterType()
52 | .Keyed(FiberModule.Key_DoNotSerialize)
53 | .AsImplementedInterfaces()
54 | .SingleInstance();
55 |
56 | // Override some Bot Framework registrations
57 | builder.Register(c => c.Resolve().MakeConnectorClient())
58 | .Keyed(FiberModule.Key_DoNotSerialize) // Tag IConnectorClient as DoNotSerialize
59 | .As()
60 | .ExternallyOwned();
61 |
62 | var appInsightsLogProvider = new AppInsightsLogProvider(configProvider);
63 | builder.Register(c => appInsightsLogProvider)
64 | .Keyed(FiberModule.Key_DoNotSerialize)
65 | .AsImplementedInterfaces()
66 | .SingleInstance();
67 |
68 | builder.Register(c => new TokenValidator(
69 | configProvider.GetSetting(CommonConfig.ActiveDirectoryClientId)))
70 | .AsImplementedInterfaces()
71 | .SingleInstance();
72 |
73 | // Use an in-memory store, as the bot does not currently use bot state storage.
74 | var store = new InMemoryDataStore();
75 | builder.Register(c => store)
76 | .As>()
77 | .AsSelf()
78 | .SingleInstance();
79 |
80 | // Register dialogs
81 | builder.RegisterType()
82 | .AsSelf()
83 | .InstancePerDependency();
84 |
85 | builder.RegisterType()
86 | .Keyed(FiberModule.Key_DoNotSerialize)
87 | .AsSelf()
88 | .InstancePerMatchingLifetimeScope(DialogModule.LifetimeScopeTag);
89 |
90 | builder.RegisterType()
91 | .AsSelf()
92 | .InstancePerDependency();
93 |
94 | builder.RegisterType()
95 | .AsSelf()
96 | .InstancePerDependency();
97 |
98 | builder.RegisterType()
99 | .AsSelf()
100 | .InstancePerDependency();
101 | }
102 | }
103 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Connected Services/Application Insights/ConnectedService.json:
--------------------------------------------------------------------------------
1 | {
2 | "ProviderId": "Microsoft.ApplicationInsights.ConnectedService.ConnectedServiceProvider",
3 | "Version": "9.1.611.1"
4 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/css/datepicker-custom-theme.css:
--------------------------------------------------------------------------------
1 | /*default rules*/
2 | .datepicker {
3 | height: 42%;
4 | width: 41%;
5 | font-size: small;
6 | box-shadow: 0 2px 4px 0 rgba(0,0,0,0.16),0 2px 10px 0 rgba(0,0,0,0.12) !important;
7 | }
8 |
9 | .datepicker .next {
10 | font-family: 'FontAwesome';
11 | content: '\f104' !important;
12 | }
13 |
14 | .datepicker .prev {
15 | font-family: 'FontAwesome';
16 | content: '\f105' !important;
17 | }
18 |
19 | .datepicker td.day {
20 | height:24px !important;
21 | }
22 |
23 | .datepicker .active {
24 | background: rgb(98, 100, 167) !important;
25 | }
26 |
27 |
28 | /*dark theme rules*/
29 | .theme-dark .datepicker {
30 | background: #2d2c2c;
31 | }
32 |
33 | .theme-dark .datepicker::after {
34 | border-bottom: #2d2c2c !important;
35 | }
36 |
37 | .theme-dark .dow {
38 | color: #fff;
39 | }
40 |
41 | .theme-dark .year,
42 | .theme-dark .month,
43 | .theme-dark .day {
44 | color: #fff;
45 | }
46 |
47 | .theme-dark .old,
48 | .theme-dark .new {
49 | color: #000;
50 | }
51 |
52 | .theme-dark .datepicker-years span:hover,
53 | .theme-dark .datepicker-years span:focus,
54 | .theme-dark .datepicker-months span:hover,
55 | .theme-dark .datepicker-months span:focus,
56 | .theme-dark .datepicker-days td:hover,
57 | .theme-dark .datepicker-days td:focus {
58 | background: #484644 !important;
59 | cursor: pointer;
60 | }
61 |
62 | .theme-dark .active {
63 | background: rgb(98, 100, 167) !important;
64 | }
65 |
66 | .theme-dark .datepicker .switch,
67 | .theme-dark .datepicker .prev,
68 | .theme-dark .datepicker .next {
69 | color: #fff;
70 | background-color: #2d2c2c;
71 | border-radius: 1%;
72 | }
73 |
74 | .theme-dark .datepicker .switch:hover,
75 | .theme-dark .datepicker .prev:hover,
76 | .theme-dark .datepicker .next:hover {
77 | color: #fff !important;
78 | background-color: #484644 !important;
79 | }
80 |
81 |
82 |
83 | /*high contrast theme rules*/
84 | .theme-highContrast .datepicker {
85 | background: #000;
86 | border: solid 1px #fff;
87 | }
88 |
89 | .theme-highContrast .datepicker::after {
90 | border-bottom: #000;
91 |
92 | }
93 |
94 | .theme-highContrast .dow {
95 | color: #fff;
96 | }
97 |
98 | .theme-highContrast .year,
99 | .theme-highContrast .month,
100 | .theme-highContrast .day {
101 | color: #fff;
102 | }
103 |
104 | .theme-highContrast .old,
105 | .theme-highContrast .new {
106 | color: #2d2c2c;
107 | }
108 |
109 | .theme-highContrast .datepicker-days td:hover,
110 | .theme-highContrast .datepicker-days td:focus,
111 | .theme-highContrast .datepicker-years span:hover,
112 | .theme-highContrast .datepicker-years span:focus,
113 | .theme-highContrast .datepicker-months span:hover,
114 | .theme-highContrast .datepicker-months span:focus {
115 | background-color: rgb(255, 255, 1) !important;
116 | color: #000;
117 | cursor: pointer;
118 | }
119 |
120 | .theme-highContrast .active {
121 | background: #1aebff !important;
122 | color: #000;
123 | }
124 |
125 | .theme-highContrast .datepicker .switch,
126 | .theme-highContrast .datepicker .prev,
127 | .theme-highContrast .datepicker .next {
128 | color: #fff;
129 | background-color: #000;
130 | border-radius: 5%;
131 | }
132 |
133 | .theme-highContrast .datepicker .switch:hover,
134 | .theme-highContrast .datepicker .prev:hover,
135 | .theme-highContrast .datepicker .next:hover {
136 | background-color: rgb(255, 255, 1) !important;
137 | color: #000;
138 | }
139 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/css/datepicker.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Datepicker for Bootstrap
3 | *
4 | * Copyright 2012 Stefan Petre
5 | * Licensed under the Apache License v2.0
6 | * http://www.apache.org/licenses/LICENSE-2.0
7 | *
8 | */
9 | .datepicker {
10 | top: 0;
11 | left: 0;
12 | padding: 4px;
13 | margin-top: 1px;
14 | -webkit-border-radius: 4px;
15 | -moz-border-radius: 4px;
16 | border-radius: 4px;
17 | /*.dow {
18 | border-top: 1px solid #ddd !important;
19 | }*/
20 |
21 | }
22 | .datepicker:before {
23 | content: '';
24 | display: inline-block;
25 | border-left: 7px solid transparent;
26 | border-right: 7px solid transparent;
27 | border-bottom: 7px solid #ccc;
28 | border-bottom-color: rgba(0, 0, 0, 0.2);
29 | position: absolute;
30 | top: -7px;
31 | left: 6px;
32 | }
33 | .datepicker:after {
34 | content: '';
35 | display: inline-block;
36 | border-left: 6px solid transparent;
37 | border-right: 6px solid transparent;
38 | border-bottom: 6px solid #ffffff;
39 | position: absolute;
40 | top: -6px;
41 | left: 7px;
42 | }
43 | .datepicker > div {
44 | display: none;
45 | }
46 | .datepicker table {
47 | width: 100%;
48 | margin: 0;
49 | }
50 | .datepicker td,
51 | .datepicker th {
52 | text-align: center;
53 | width: 20px;
54 | height: 20px;
55 | -webkit-border-radius: 4px;
56 | -moz-border-radius: 4px;
57 | border-radius: 4px;
58 | }
59 | .datepicker td.day:hover {
60 | background: #eeeeee;
61 | cursor: pointer;
62 | }
63 | .datepicker td.day.disabled {
64 | color: #eeeeee;
65 | }
66 | .datepicker td.old,
67 | .datepicker td.new {
68 | color: #999999;
69 | }
70 | .datepicker td.active,
71 | .datepicker td.active:hover {
72 | color: #ffffff;
73 | background-color: #006dcc;
74 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
75 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
76 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
77 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
78 | background-image: linear-gradient(to bottom, #0088cc, #0044cc);
79 | background-repeat: repeat-x;
80 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
81 | border-color: #0044cc #0044cc #002a80;
82 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
83 | *background-color: #0044cc;
84 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
85 |
86 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
87 | color: #fff;
88 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
89 | }
90 | .datepicker td.active:hover,
91 | .datepicker td.active:hover:hover,
92 | .datepicker td.active:focus,
93 | .datepicker td.active:hover:focus,
94 | .datepicker td.active:active,
95 | .datepicker td.active:hover:active,
96 | .datepicker td.active.active,
97 | .datepicker td.active:hover.active,
98 | .datepicker td.active.disabled,
99 | .datepicker td.active:hover.disabled,
100 | .datepicker td.active[disabled],
101 | .datepicker td.active:hover[disabled] {
102 | color: #ffffff;
103 | background-color: #0044cc;
104 | *background-color: #003bb3;
105 | }
106 | .datepicker td.active:active,
107 | .datepicker td.active:hover:active,
108 | .datepicker td.active.active,
109 | .datepicker td.active:hover.active {
110 | background-color: #003399 \9;
111 | }
112 | .datepicker td span {
113 | display: block;
114 | width: 47px;
115 | height: 54px;
116 | line-height: 54px;
117 | float: left;
118 | margin: 2px;
119 | cursor: pointer;
120 | -webkit-border-radius: 4px;
121 | -moz-border-radius: 4px;
122 | border-radius: 4px;
123 | }
124 | .datepicker td span:hover {
125 | background: #eeeeee;
126 | }
127 | .datepicker td span.active {
128 | color: #ffffff;
129 | background-color: #006dcc;
130 | background-image: -moz-linear-gradient(top, #0088cc, #0044cc);
131 | background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));
132 | background-image: -webkit-linear-gradient(top, #0088cc, #0044cc);
133 | background-image: -o-linear-gradient(top, #0088cc, #0044cc);
134 | background-image: linear-gradient(to bottom, #0088cc, #0044cc);
135 | background-repeat: repeat-x;
136 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);
137 | border-color: #0044cc #0044cc #002a80;
138 | border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
139 | *background-color: #0044cc;
140 | /* Darken IE7 buttons by default so they stand out more given they won't have borders */
141 |
142 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
143 | color: #fff;
144 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
145 | }
146 | .datepicker td span.active:hover,
147 | .datepicker td span.active:focus,
148 | .datepicker td span.active:active,
149 | .datepicker td span.active.active,
150 | .datepicker td span.active.disabled,
151 | .datepicker td span.active[disabled] {
152 | color: #ffffff;
153 | background-color: #0044cc;
154 | *background-color: #003bb3;
155 | }
156 | .datepicker td span.active:active,
157 | .datepicker td span.active.active {
158 | background-color: #003399 \9;
159 | }
160 | .datepicker td span.old {
161 | color: #999999;
162 | }
163 | .datepicker th.switch {
164 | width: 145px;
165 | }
166 | .datepicker th.next,
167 | .datepicker th.prev {
168 | font-size: 21px;
169 | }
170 | .datepicker thead tr:first-child th {
171 | cursor: pointer;
172 | }
173 | .datepicker thead tr:first-child th:hover {
174 | background: #eeeeee;
175 | }
176 | .input-append.date .add-on i,
177 | .input-prepend.date .add-on i {
178 | display: block;
179 | cursor: pointer;
180 | width: 16px;
181 | height: 16px;
182 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/css/spinner.css:
--------------------------------------------------------------------------------
1 | @-webkit-keyframes translate-small {
2 | to {
3 | -webkit-transform: translate3d(0, -144rem, 0);
4 | transform: translate3d(0, -144rem, 0);
5 | }
6 | }
7 |
8 | @keyframes translate-small {
9 | to {
10 | -webkit-transform: translate3d(0, -144rem, 0);
11 | transform: translate3d(0, -144rem, 0);
12 | }
13 | }
14 |
15 | @-webkit-keyframes translate-medium {
16 | to {
17 | -webkit-transform: translate3d(0, -216rem, 0);
18 | transform: translate3d(0, -216rem, 0);
19 | }
20 | }
21 |
22 | @keyframes translate-medium {
23 | to {
24 | -webkit-transform: translate3d(0, -216rem, 0);
25 | transform: translate3d(0, -216rem, 0);
26 | }
27 | }
28 |
29 | @-webkit-keyframes translate-large {
30 | to {
31 | -webkit-transform: translate3d(0, -432rem, 0);
32 | transform: translate3d(0, -432rem, 0);
33 | }
34 | }
35 |
36 | @keyframes translate-large {
37 | to {
38 | -webkit-transform: translate3d(0, -432rem, 0);
39 | transform: translate3d(0, -432rem, 0);
40 | }
41 | }
42 |
43 | @-webkit-keyframes fade-spinner-in {
44 | to {
45 | opacity: 1;
46 | }
47 | }
48 |
49 | @keyframes fade-spinner-in {
50 | to {
51 | opacity: 1;
52 | }
53 | }
54 |
55 | busy-animation {
56 | display: inline-block;
57 | }
58 |
59 | .ts-spinner-internal {
60 | overflow: hidden;
61 | }
62 |
63 | .ts-spinner-internal.size-1x {
64 | height: 2.4rem;
65 | width: 2.4rem;
66 | }
67 |
68 | .ts-spinner-internal.size-1x .spinner-animate {
69 | width: 2.4rem;
70 | height: 146.4rem;
71 | -webkit-animation: 2s steps(60) both infinite translate-small;
72 | animation: 2s steps(60) both infinite translate-small;
73 | }
74 |
75 | .ts-spinner-internal.size-2x {
76 | height: 3.6rem;
77 | width: 3.6rem;
78 | margin: auto;
79 | }
80 |
81 | .ts-spinner-internal.size-2x .spinner-animate {
82 | width: 3.6rem;
83 | height: 219.6rem;
84 | -webkit-animation: 2s steps(60) both infinite translate-medium;
85 | animation: 2s steps(60) both infinite translate-medium;
86 | }
87 |
88 | .ts-spinner-internal.size-3x {
89 | height: 7.2rem;
90 | width: 7.2rem;
91 | }
92 |
93 | .ts-spinner-internal.size-3x .spinner-animate {
94 | width: 7.2rem;
95 | height: 439.2rem;
96 | -webkit-animation: 2s steps(60) both infinite translate-large;
97 | animation: 2s steps(60) both infinite translate-large;
98 | }
99 |
100 | .ts-spinner-container {
101 | overflow: hidden;
102 | position: relative;
103 | }
104 |
105 | .loading {
106 | position: fixed;
107 | z-index: 999;
108 | height: 2em;
109 | width: 2em;
110 | overflow: visible;
111 | margin: auto;
112 | top: 0;
113 | left: 0;
114 | bottom: 0;
115 | right: 0;
116 | }
117 |
118 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/Celebrations-bot-image-new-event.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/Celebrations-bot-image-new-event.jpg
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/0.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/1.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/10.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/2.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/3.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/4.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/5.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/6.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/7.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/8.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/carousel/9.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/celebration_bot_full-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/celebration_bot_full-color.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/empty-state-celebrations.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/empty-state-celebrations.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/welcome-card-image.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/welcome-card-image.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Content/images/welcome-dialog.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OfficeDev/microsoft-teams-apps-celebrations/a65cb401bee628549fc54b96573206705e6ef731/Source/Microsoft.Teams.Apps.Celebration/Content/images/welcome-dialog.png
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Controllers/AuthController.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration.Controllers
6 | {
7 | using System;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Net.Http.Headers;
11 | using System.Security.Claims;
12 | using System.Threading.Tasks;
13 | using System.Web;
14 | using System.Web.Mvc;
15 | using Microsoft.Owin.Security.Cookies;
16 | using Microsoft.Teams.Apps.Common.Authentication;
17 |
18 | ///
19 | /// Authentication controller
20 | ///
21 | public class AuthController : Controller
22 | {
23 | ///
24 | /// Path to the login endpoint
25 | ///
26 | public const string TokenLoginEndpointPath = "/Auth/TokenLogin";
27 |
28 | private readonly ITokenValidator tokenValidator;
29 |
30 | ///
31 | /// Initializes a new instance of the class.
32 | ///
33 | /// The token validator
34 | public AuthController(ITokenValidator tokenValidator)
35 | {
36 | this.tokenValidator = tokenValidator;
37 | }
38 |
39 | ///
40 | /// Action to login using AAD ID token
41 | ///
42 | /// HTTP result
43 | // POST: TokenLogin
44 | [AllowAnonymous]
45 | [HttpPost]
46 | public async Task TokenLogin()
47 | {
48 | var headerString = this.Request.Headers?.GetValues("Authorization")?.FirstOrDefault();
49 | if (string.IsNullOrEmpty(headerString))
50 | {
51 | return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
52 | }
53 |
54 | try
55 | {
56 | var headerValue = AuthenticationHeaderValue.Parse(headerString);
57 | var claimsPrincipal = await this.tokenValidator.ValidateIdTokenAsync(headerValue.Parameter);
58 | var firstIdentity = claimsPrincipal.Identities.FirstOrDefault();
59 |
60 | var context = this.Request.GetOwinContext();
61 | context.Authentication.SignIn(new ClaimsIdentity(firstIdentity.Claims, CookieAuthenticationDefaults.AuthenticationType));
62 |
63 | return new HttpStatusCodeResult(HttpStatusCode.OK);
64 | }
65 | catch (Exception)
66 | {
67 | return new HttpStatusCodeResult(HttpStatusCode.Unauthorized);
68 | }
69 | }
70 |
71 | ///
72 | /// Logout.
73 | ///
74 | /// HTTP result
75 | // GET: Logout
76 | [HttpGet]
77 | public ActionResult Logout()
78 | {
79 | var context = this.Request.GetOwinContext();
80 | context.Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType);
81 |
82 | return new HttpStatusCodeResult(HttpStatusCode.OK);
83 | }
84 | }
85 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Controllers/SharedSecretAuthenticationAttribute.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration.Controllers
6 | {
7 | using System;
8 | using System.Configuration;
9 | using System.Net;
10 | using System.Net.Http;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 | using System.Web.Http.Controllers;
14 | using System.Web.Http.Filters;
15 |
16 | ///
17 | /// Action filter that authenticates an incoming request against a shared secret
18 | ///
19 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false)]
20 | public class SharedSecretAuthenticationAttribute : ActionFilterAttribute
21 | {
22 | ///
23 | /// Gets or sets the name of the setting that has the shared secret
24 | ///
25 | public string SharedSecretSettingName { get; set; }
26 |
27 | ///
28 | public override Task OnActionExecutingAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
29 | {
30 | var authHeader = actionContext.Request.Headers.Authorization;
31 | if (authHeader == null ||
32 | authHeader.Scheme != "SharedSecret" ||
33 | authHeader.Parameter != ConfigurationManager.AppSettings[this.SharedSecretSettingName])
34 | {
35 | actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
36 | return Task.CompletedTask;
37 | }
38 |
39 | return base.OnActionExecutingAsync(actionContext, cancellationToken);
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Controllers/TabAuthController.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration.Controllers
6 | {
7 | using System.Web.Mvc;
8 | using Microsoft.Teams.Apps.Common;
9 | using Microsoft.Teams.Apps.Common.Configuration;
10 |
11 | ///
12 | /// Tab authentication controller
13 | ///
14 | public class TabAuthController : Controller
15 | {
16 | ///
17 | /// Path to the tab login page
18 | ///
19 | public const string LoginPath = "/TabAuth/Login";
20 |
21 | private const string StartPath = "/TabAuth/Start";
22 | private const string RedirectUriPath = "/TabAuth/Callback";
23 |
24 | private readonly string tenantId;
25 | private readonly string clientId;
26 |
27 | ///
28 | /// Initializes a new instance of the class.
29 | ///
30 | /// The configuration provider to use
31 | public TabAuthController(IConfigProvider configProvider)
32 | {
33 | this.tenantId = configProvider.GetSetting(CommonConfig.ActiveDirectoryTenant);
34 | this.clientId = configProvider.GetSetting(CommonConfig.ActiveDirectoryClientId);
35 | }
36 |
37 | ///
38 | /// Tab authentication login page
39 | ///
40 | /// Destination path
41 | /// View
42 | // GET: Login
43 | [AllowAnonymous]
44 | public ActionResult Login(string returnUrl)
45 | {
46 | this.ViewBag.TenantId = this.tenantId;
47 | this.ViewBag.ClientId = this.clientId;
48 | this.ViewBag.StartPath = StartPath;
49 | this.ViewBag.RedirectUriPath = RedirectUriPath;
50 | this.ViewBag.DestinationPath = returnUrl;
51 | this.ViewBag.TokenLoginEndpointPath = AuthController.TokenLoginEndpointPath;
52 | return this.View();
53 | }
54 |
55 | ///
56 | /// Tab authentication flow start page
57 | ///
58 | /// View
59 | // GET: Start
60 | [AllowAnonymous]
61 | public ActionResult Start()
62 | {
63 | this.ViewBag.TenantId = this.tenantId;
64 | this.ViewBag.ClientId = this.clientId;
65 | this.ViewBag.RedirectUriPath = RedirectUriPath;
66 | return this.View();
67 | }
68 |
69 | ///
70 | /// Tab authentication flow callback page
71 | ///
72 | /// View
73 | // GET: Callback
74 | [AllowAnonymous]
75 | public ActionResult Callback()
76 | {
77 | this.ViewBag.TenantId = this.tenantId;
78 | this.ViewBag.ClientId = this.clientId;
79 | return this.View();
80 | }
81 | }
82 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Dialog/DialogFactory.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration.Dialog
6 | {
7 | using System;
8 | using Autofac;
9 | using Microsoft.Bot.Builder.Internals.Fibers;
10 |
11 | ///
12 | /// Factory to create dialogs
13 | ///
14 | [Serializable]
15 | public class DialogFactory
16 | {
17 | private readonly IComponentContext scope;
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | /// Lifetime scope
23 | public DialogFactory(IComponentContext scope)
24 | {
25 | SetField.NotNull(out this.scope, nameof(scope), scope);
26 | }
27 |
28 | ///
29 | /// Create a new instance of .
30 | ///
31 | /// New dialog instance
32 | public SkipEventDialog CreateSkipEventDialog()
33 | {
34 | return this.scope.Resolve();
35 | }
36 |
37 | ///
38 | /// Create a new instance of .
39 | ///
40 | /// New dialog instance
41 | public ShareEventDialog CreateShareEventDialog()
42 | {
43 | return this.scope.Resolve();
44 | }
45 |
46 | ///
47 | /// Create a new instance of .
48 | ///
49 | /// New dialog instance
50 | public IgnoreEventShareDialog CreateIgnoreEventShareDialog()
51 | {
52 | return this.scope.Resolve();
53 | }
54 | }
55 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/Dialog/IgnoreEventShareDialog.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Celebration.Dialog
6 | {
7 | using System;
8 | using System.Threading.Tasks;
9 | using Microsoft.Bot.Builder.Dialogs;
10 | using Microsoft.Bot.Connector;
11 | using Microsoft.Teams.Apps.Celebration.Helpers;
12 | using Microsoft.Teams.Apps.Celebration.Models;
13 | using Microsoft.Teams.Apps.Celebration.Resources;
14 | using Microsoft.Teams.Apps.Common.Logging;
15 | using Newtonsoft.Json.Linq;
16 |
17 | ///
18 | /// Ignore Event Sharing in team
19 | ///
20 | [Serializable]
21 | public class IgnoreEventShareDialog : IDialog
11 |
12 |
13 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/libman.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "1.0",
3 | "defaultProvider": "cdnjs",
4 | "libraries": [
5 | {
6 | "library": "twitter-bootstrap@4.3.1",
7 | "destination": "lib/bootstrap4/"
8 | },
9 | {
10 | "library": "bootstrap-datepicker@1.9.0",
11 | "destination": "lib/bootstrap-datepicker/"
12 | },
13 | {
14 | "library": "bootstrap-multiselect@0.9.15",
15 | "destination": "lib/bootstrap-multiselect/"
16 | },
17 | {
18 | "library": "jquery@3.4.1",
19 | "destination": "lib/jquery/"
20 | },
21 | {
22 | "library": "jQuery-slimScroll@1.3.8",
23 | "destination": "lib/jQuery-slimScroll/"
24 | },
25 | {
26 | "library": "jquery-validate@1.19.1",
27 | "destination": "lib/jquery-validate/"
28 | },
29 | {
30 | "library": "jquery-validation-unobtrusive@3.2.11",
31 | "destination": "lib/jquery-validation-unobtrusive/"
32 | },
33 | {
34 | "provider": "unpkg",
35 | "library": "@microsoft/teams-js@1.5.2",
36 | "destination": "lib/teams-js/",
37 | "files": [
38 | "dist/MicrosoftTeams.js",
39 | "dist/MicrosoftTeams.js.map",
40 | "dist/MicrosoftTeams.min.js"
41 | ]
42 | },
43 | {
44 | "provider": "unpkg",
45 | "library": "bootstrap@3.4.1",
46 | "destination": "lib/bootstrap3/",
47 | "files": [
48 | "dist/css/bootstrap-theme.css",
49 | "dist/css/bootstrap-theme.css.map",
50 | "dist/css/bootstrap-theme.min.css",
51 | "dist/css/bootstrap-theme.min.css.map",
52 | "dist/css/bootstrap.css",
53 | "dist/css/bootstrap.css.map",
54 | "dist/css/bootstrap.min.css",
55 | "dist/css/bootstrap.min.css.map",
56 | "dist/fonts/glyphicons-halflings-regular.eot",
57 | "dist/fonts/glyphicons-halflings-regular.svg",
58 | "dist/fonts/glyphicons-halflings-regular.ttf",
59 | "dist/fonts/glyphicons-halflings-regular.woff",
60 | "dist/fonts/glyphicons-halflings-regular.woff2",
61 | "dist/js/bootstrap.js",
62 | "dist/js/bootstrap.min.js",
63 | "dist/js/npm.js"
64 | ]
65 | },
66 | {
67 | "provider": "unpkg",
68 | "library": "adal-angular@1.0.17",
69 | "destination": "lib/adal-angular/",
70 | "files": [
71 | "lib/adal.js",
72 | "dist/adal.min.js"
73 | ]
74 | },
75 | {
76 | "provider": "unpkg",
77 | "library": "font-awesome@4.0.3",
78 | "destination": "Content/fontawesome/",
79 | "files": [
80 | "css/font-awesome.css",
81 | "css/font-awesome.min.css",
82 | "fonts/fontawesome-webfont.eot",
83 | "fonts/fontawesome-webfont.svg",
84 | "fonts/fontawesome-webfont.ttf",
85 | "fonts/fontawesome-webfont.woff",
86 | "fonts/FontAwesome.otf"
87 | ]
88 | },
89 | {
90 | "library": "moment.js@2.24.0",
91 | "destination": "lib/moment.js/"
92 | }
93 | ]
94 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Celebration/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | // ACTION REQUIRED: This file was automatically added to your project, but it
3 | // will not take effect until additional steps are taken to enable it. See the
4 | // following page for additional information:
5 | // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md
6 |
7 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
8 | "settings": {
9 | "documentationRules": {
10 | "companyName": "Microsoft"
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Authentication/ITokenValidator.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Authentication
6 | {
7 | using System.Security.Claims;
8 | using System.Threading.Tasks;
9 |
10 | ///
11 | /// Interface to validate tokens.
12 | ///
13 | public interface ITokenValidator
14 | {
15 | ///
16 | /// Validates a JWT token and extracts the claims principal and AAD objectId of the user.
17 | ///
18 | /// The token to validate.
19 | /// The claims principal or null if the token is not valid.
20 | Task ValidateIdTokenAsync(string token);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Authentication/TokenValidator.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Authentication
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Diagnostics;
10 | using System.IdentityModel.Tokens.Jwt;
11 | using System.Linq;
12 | using System.Net.Http;
13 | using System.Security.Claims;
14 | using System.Threading.Tasks;
15 | using Microsoft.IdentityModel.Protocols;
16 | using Microsoft.IdentityModel.Protocols.OpenIdConnect;
17 | using Microsoft.IdentityModel.Tokens;
18 | using Microsoft.Teams.Apps.Common.Configuration;
19 |
20 | ///
21 | /// The TokenValidator is an implementation of the interface.
22 | /// It uses AAD OAuth to validate a token and return the user's AAD objectId or an error.
23 | ///
24 | public class TokenValidator : ITokenValidator
25 | {
26 | private readonly string expectedAudience;
27 | private readonly ConfigurationManager openIdV1ConfigManager;
28 | private readonly ConfigurationManager openIdV2ConfigManager;
29 |
30 | ///
31 | /// Initializes a new instance of the class.
32 | ///
33 | /// The expected audience value.
34 | public TokenValidator(string expectedAudience)
35 | {
36 | Debug.Assert(!string.IsNullOrEmpty(expectedAudience), "expectedAudience is null or empty");
37 | this.expectedAudience = expectedAudience ?? throw new ArgumentException("expectedAudience is null or empty", nameof(expectedAudience));
38 |
39 | var httpClient = new HttpClient();
40 | this.openIdV1ConfigManager = new ConfigurationManager(
41 | "https://login.microsoftonline.com/common/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever(), httpClient);
42 | this.openIdV2ConfigManager = new ConfigurationManager(
43 | "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever(), httpClient);
44 | }
45 |
46 | ///
47 | public async Task ValidateIdTokenAsync(string token)
48 | {
49 | if (token == null)
50 | {
51 | return null;
52 | }
53 |
54 | var tokenPayload = this.ParseTokenPayload(token);
55 | if (tokenPayload == null)
56 | {
57 | return null;
58 | }
59 |
60 | var tidClaim = this.GetClaims(tokenPayload, "tid").FirstOrDefault();
61 | if (tidClaim == null)
62 | {
63 | return null;
64 | }
65 |
66 | var issClaim = this.GetClaims(tokenPayload, "iss").FirstOrDefault();
67 | if (issClaim == null)
68 | {
69 | return null;
70 | }
71 |
72 | // Test if the token is issued by the V2 AAD issuer
73 | var openIdConfig = await this.openIdV2ConfigManager.GetConfigurationAsync();
74 | var expectedIssuer = openIdConfig.Issuer.Replace("{tenantid}", tidClaim.Value);
75 | if (!issClaim.Value.Equals(expectedIssuer, StringComparison.InvariantCulture))
76 | {
77 | // If the token is not issued by the V2 AAD issuer, then try the V1 issuer.
78 | openIdConfig = await this.openIdV1ConfigManager.GetConfigurationAsync();
79 | expectedIssuer = openIdConfig.Issuer.Replace("{tenantid}", tidClaim.Value);
80 | }
81 |
82 | TokenValidationParameters validationParameters = new TokenValidationParameters
83 | {
84 | ValidateAudience = true,
85 | ValidateIssuer = true,
86 | ValidateLifetime = true,
87 | IssuerSigningKeys = openIdConfig.SigningKeys,
88 | ValidAudience = this.expectedAudience,
89 | ValidIssuer = expectedIssuer,
90 | };
91 |
92 | JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
93 | try
94 | {
95 | return tokenHandler.ValidateToken(token, validationParameters, out _);
96 | }
97 | catch (Exception)
98 | {
99 | return null;
100 | }
101 | }
102 |
103 | private JwtSecurityToken ParseTokenPayload(string token)
104 | {
105 | if (token == null)
106 | {
107 | throw new ArgumentNullException(nameof(token));
108 | }
109 |
110 | try
111 | {
112 | JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
113 | if (!tokenHandler.CanReadToken(token))
114 | {
115 | return null;
116 | }
117 |
118 | return tokenHandler.ReadJwtToken(token);
119 | }
120 | catch (Exception)
121 | {
122 | return null;
123 | }
124 | }
125 |
126 | private IEnumerable GetClaims(JwtSecurityToken token, string claimType)
127 | {
128 | return token.Claims.Where(c => c.Type.Equals(claimType, StringComparison.InvariantCultureIgnoreCase));
129 | }
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/CommonConfig.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common
6 | {
7 | ///
8 | /// Configurations that are used across multiple projects.
9 | ///
10 | public enum CommonConfig
11 | {
12 | ///
13 | /// Represents the current deployment environment.
14 | ///
15 | Environment,
16 |
17 | ///
18 | /// Represents an active directory audience.
19 | ///
20 | ActiveDirectoryAudience,
21 |
22 | ///
23 | /// Represents an active directory authority.
24 | ///
25 | ActiveDirectoryAuthority,
26 |
27 | ///
28 | /// Represents an active directory certificate location.
29 | ///
30 | ActiveDirectoryCertificateLocation,
31 |
32 | ///
33 | /// Represents an active directory certificate name.
34 | ///
35 | ActiveDirectoryCertificateName,
36 |
37 | ///
38 | /// Represents an active directory client identifier.
39 | ///
40 | ActiveDirectoryClientId,
41 |
42 | ///
43 | /// Represents an active directory tenant.
44 | ///
45 | ActiveDirectoryTenant,
46 |
47 | ///
48 | /// Represents an application insights instrumentation key.
49 | ///
50 | ApplicationInsightsInstrumentationKey,
51 |
52 | ///
53 | /// Represents an application insights log level.
54 | ///
55 | ApplicationInsightsLogLevel,
56 |
57 | ///
58 | /// Determines whether to use the key vault provider.
59 | ///
60 | UseKeyVault,
61 |
62 | ///
63 | /// Represents a key vault uri.
64 | ///
65 | KeyVaultUri,
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/CommonConstant.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common
6 | {
7 | using System;
8 | using System.Diagnostics.CodeAnalysis;
9 |
10 | ///
11 | /// Store common constants used in project.
12 | ///
13 | [ExcludeFromCodeCoverage]
14 | public static class CommonConstant
15 | {
16 | ///
17 | /// The correlation identifier.
18 | ///
19 | public const string CorrelationId = "CorrelationId";
20 |
21 | ///
22 | /// Azure storage partition key.
23 | ///
24 | public const string PartitionKey = "PartitionKey";
25 |
26 | ///
27 | /// Azure storage row key.
28 | ///
29 | public const string RowKey = "RowKey";
30 |
31 | ///
32 | /// The epoch value.
33 | ///
34 | public static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Configuration/IConfigProvider.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Configuration
6 | {
7 | using System;
8 |
9 | ///
10 | /// Interface for implementing get setting values.
11 | ///
12 | public interface IConfigProvider
13 | {
14 | ///
15 | /// Gets the setting value.
16 | ///
17 | /// The type of the configuration keys.
18 | /// The config key.
19 | /// The config value.
20 | string GetSetting(TConfigKeys key)
21 | where TConfigKeys : struct, IConvertible;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Configuration/LocalConfigProvider.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Configuration
6 | {
7 | using System;
8 | using System.Configuration;
9 | using Microsoft.Teams.Apps.Common.Exceptions;
10 |
11 | ///
12 | /// Provides configuration that are stored locally.
13 | ///
14 | ///
15 | [Serializable]
16 | public class LocalConfigProvider : IConfigProvider
17 | {
18 | ///
19 | /// Gets the setting value.
20 | ///
21 | /// The type of the configuration keys.
22 | /// The config key.
23 | /// The config value.
24 | ///
25 | /// Specific key configuration not found.
26 | ///
27 | public string GetSetting(TConfigKeys key)
28 | where TConfigKeys : struct, IConvertible
29 | {
30 | string value = ConfigurationManager.AppSettings[key.ToString()];
31 | if (value != null)
32 | {
33 | return value;
34 | }
35 |
36 | throw new SettingNotFoundException($"{key} configuration not found");
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Exceptions/SettingDeserializationException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Exceptions
6 | {
7 | using System;
8 | using System.Diagnostics.CodeAnalysis;
9 | using System.Runtime.Serialization;
10 |
11 | ///
12 | /// Exception for setting deserialization.
13 | ///
14 | ///
15 | [Serializable]
16 | [ExcludeFromCodeCoverage]
17 | public class SettingDeserializationException : System.Exception
18 | {
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | public SettingDeserializationException()
23 | {
24 | }
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// The message that describes the error.
30 | public SettingDeserializationException(string message)
31 | : base(message)
32 | {
33 | }
34 |
35 | ///
36 | /// Initializes a new instance of the class.
37 | ///
38 | /// The error message that explains the reason for the exception.
39 | ///
40 | /// The exception that is the cause of the current exception.
41 | /// If no inner exception is specified then returns null reference.
42 | ///
43 | public SettingDeserializationException(string message, System.Exception innerException)
44 | : base(message, innerException)
45 | {
46 | }
47 |
48 | ///
49 | /// Initializes a new instance of the class.
50 | ///
51 | /// The SerializationInfo that holds the serialized object data about the exception being thrown.
52 | /// The StreamingContext that contains contextual information about the source or destination.
53 | protected SettingDeserializationException(SerializationInfo info, StreamingContext context)
54 | : base(info, context)
55 | {
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Exceptions/SettingNotFoundException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Exceptions
6 | {
7 | using System;
8 | using System.Diagnostics.CodeAnalysis;
9 | using System.Runtime.Serialization;
10 |
11 | ///
12 | /// Exception for setting not found.
13 | ///
14 | ///
15 | [Serializable]
16 | [ExcludeFromCodeCoverage]
17 | public class SettingNotFoundException : Exception
18 | {
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | public SettingNotFoundException()
23 | {
24 | }
25 |
26 | ///
27 | /// Initializes a new instance of the class.
28 | ///
29 | /// The message that describes the error.
30 | public SettingNotFoundException(string message)
31 | : base(message)
32 | {
33 | }
34 |
35 | ///
36 | /// Initializes a new instance of the class.
37 | ///
38 | /// The error message that explains the reason for the exception.
39 | ///
40 | /// The exception that is the cause of the current exception.
41 | /// If no inner exception is specified then returns null reference.
42 | ///
43 | public SettingNotFoundException(string message, Exception innerException)
44 | : base(message, innerException)
45 | {
46 | // Add any type-specific logic for inner exceptions.
47 | }
48 |
49 | ///
50 | /// Initializes a new instance of the class.
51 | ///
52 | /// The SerializationInfo that holds the serialized object data about the exception being thrown.
53 | /// The StreamingContext that contains contextual information about the source or destination.
54 | protected SettingNotFoundException(SerializationInfo info, StreamingContext context)
55 | : base(info, context)
56 | {
57 | // Implement type-specific serialization constructor logic.
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Extensions/ClaimsPrincipalExtensions.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Extensions
6 | {
7 | using System.Linq;
8 | using System.Security.Claims;
9 |
10 | ///
11 | /// Extension methods for .
12 | ///
13 | public static class ClaimsPrincipalExtensions
14 | {
15 | ///
16 | /// Get the value of the user principal name claim.
17 | ///
18 | /// The claims principal instance
19 | /// The UPN claim, if present, or null otherwise
20 | public static string GetUserPrincipalName(this ClaimsPrincipal principal)
21 | {
22 | return principal.Claims?.FirstOrDefault(x => x.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/upn")?.Value;
23 | }
24 |
25 | ///
26 | /// Get the value of the user object identifier claim.
27 | ///
28 | /// The claims principal instance
29 | /// The objectidentifier claim, if present, or null otherwise
30 | public static string GetUserObjectId(this ClaimsPrincipal principal)
31 | {
32 | return principal.Claims?.FirstOrDefault(x => x.Type == "http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Extensions/EncryptedConfigAttribute.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Extensions
6 | {
7 | using System;
8 |
9 | ///
10 | /// The encrypted config attribute class.
11 | ///
12 | ///
13 | [AttributeUsage(AttributeTargets.All)]
14 | public sealed class EncryptedConfigAttribute : Attribute
15 | {
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Extensions/TimeTracker.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Extensions
6 | {
7 | using System;
8 | using System.Diagnostics;
9 | using Microsoft.Teams.Apps.Common.Logging;
10 |
11 | ///
12 | /// The time tracker class for logger.
13 | ///
14 | ///
15 | public sealed class TimeTracker : IDisposable
16 | {
17 | private readonly string commandName;
18 | private readonly string dependencyName;
19 | private readonly ILogProvider logger;
20 | private readonly DateTime startTime = DateTime.UtcNow;
21 | private readonly Stopwatch stopwatch = Stopwatch.StartNew();
22 |
23 | ///
24 | /// Initializes a new instance of the class.
25 | ///
26 | /// The logger object.
27 | /// Name of the dependency.
28 | /// Name of the command.
29 | private TimeTracker(ILogProvider logger, string dependencyName, string commandName)
30 | {
31 | this.logger = logger;
32 | this.dependencyName = dependencyName;
33 | this.commandName = commandName;
34 | }
35 |
36 | ///
37 | /// Creates the specified logger.
38 | ///
39 | /// The logger object.
40 | /// Name of the dependency.
41 | /// Name of the command.
42 | /// [Optional] Enable tracking with default value as true.
43 | /// Creates the time tracker for logger.
44 | public static TimeTracker Create(ILogProvider logger, string dependencyName, string commandName, bool enableTracking = true)
45 | {
46 | return enableTracking ? new TimeTracker(logger, dependencyName, commandName) : null;
47 | }
48 |
49 | ///
50 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
51 | ///
52 | public void Dispose()
53 | {
54 | this.stopwatch.Stop();
55 | this.logger.LogDependency(null, this.dependencyName, this.commandName, this.startTime, this.stopwatch.Elapsed, true);
56 | }
57 | }
58 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Http/HttpClientWrapper.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Http
6 | {
7 | using System;
8 | using System.Net.Http;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | ///
13 | /// Wrapper for that implements .
14 | ///
15 | public class HttpClientWrapper : IHttpClient
16 | {
17 | private readonly HttpClient httpClient;
18 |
19 | ///
20 | /// Initializes a new instance of the class.
21 | ///
22 | /// The instance to wrap
23 | public HttpClientWrapper(HttpClient httpClient)
24 | {
25 | this.httpClient = httpClient;
26 | }
27 |
28 | ///
29 | /// Initializes a new instance of the class.
30 | ///
31 | /// The message handler
32 | public HttpClientWrapper(HttpMessageHandler handler)
33 | : this(new HttpClient(handler))
34 | {
35 | }
36 |
37 | ///
38 | /// Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.
39 | ///
40 | /// The Uri the request is sent to.
41 | /// An HTTP completion option value that indicates when the operation should be considered completed.
42 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
43 | /// The task object representing the asynchronous operation.
44 | public Task GetAsync(Uri requestUri, HttpCompletionOption completionOption, CancellationToken cancellationToken)
45 | {
46 | #pragma warning disable SecurityIntelliSenseCS // This code is a pass-through wrapper around HttpClient
47 | return this.httpClient.GetAsync(requestUri, completionOption, cancellationToken);
48 | #pragma warning restore SecurityIntelliSenseCS
49 | }
50 |
51 | ///
52 | /// Send an HTTP request as an asynchronous operation.
53 | ///
54 | /// The HTTP request message to send.
55 | /// When the operation should complete (as soon as a response is available or after reading the whole response content)
56 | /// The cancellation token to cancel operation.
57 | /// The task object representing the asynchronous operation.
58 | public Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken cancellationToken)
59 | {
60 | return this.httpClient.SendAsync(request, completionOption, cancellationToken);
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Http/IHttpClient.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Http
6 | {
7 | using System;
8 | using System.Net.Http;
9 | using System.Threading;
10 | using System.Threading.Tasks;
11 |
12 | ///
13 | /// Interface for .
14 | ///
15 | public interface IHttpClient
16 | {
17 | ///
18 | /// Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.
19 | ///
20 | /// The Uri the request is sent to.
21 | /// An HTTP completion option value that indicates when the operation should be considered completed.
22 | /// A cancellation token that can be used by other objects or threads to receive notice of cancellation.
23 | /// The task object representing the asynchronous operation.
24 | Task GetAsync(Uri requestUri, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, CancellationToken cancellationToken = default(CancellationToken));
25 |
26 | ///
27 | /// Send an HTTP request as an asynchronous operation.
28 | ///
29 | /// The HTTP request message to send.
30 | /// When the operation should complete (as soon as a response is available or after reading the whole response content)
31 | /// The cancellation token to cancel operation.
32 | /// The task object representing the asynchronous operation.
33 | Task SendAsync(HttpRequestMessage request, HttpCompletionOption completionOption = HttpCompletionOption.ResponseContentRead, CancellationToken cancellationToken = default(CancellationToken));
34 | }
35 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Logging/ILogProvider.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Logging
6 | {
7 | using System;
8 | using System.Collections.Generic;
9 |
10 | ///
11 | /// Interface to implement different log information.
12 | ///
13 | public interface ILogProvider
14 | {
15 | ///
16 | /// Log a message of the given type.
17 | ///
18 | /// Type of log
19 | /// The debug message
20 | /// An exception to capture and correlate to the debug event
21 | /// A collection of properties that should be associated to the telemetry entry
22 | /// This is used for tracing a series of events.
23 | /// The source
24 | void Log(LogLevel logType, string message, Exception exception, Dictionary properties, Guid correlationId, Func source);
25 |
26 | ///
27 | /// Log a custom event.
28 | /// A custom event log provides insight to system administrators by logging information that may not be captured by other log levels.
29 | ///
30 | /// The information message
31 | /// A collection of properties that should be associated to the telemetry entry
32 | /// The metrics
33 | /// This is used for tracing a series of events.
34 | /// The source
35 | void LogEvent(string eventName, Dictionary properties, Dictionary metrics, Guid correlationId, Func source);
36 |
37 | ///
38 | /// Log a metric. Metrics are aggregated double values that can be processed for the system as a whole
39 | ///
40 | /// Metric Name
41 | /// The value that you are logging
42 | /// [Optional] A collection of properties that should be associated to the metric entry
43 | /// [Optional] The loglevel that this metric should be logged at
44 | void LogMetric(string name, double value, Dictionary properties = null, LogLevel logLevel = LogLevel.Metric);
45 |
46 | ///
47 | /// Log a dependency.
48 | ///
49 | /// External dependency type. Very low cardinality value for logical grouping and interpretation of fields. Examples are SQL, Azure table, and HTTP.
50 | /// Name of the command initiated with this dependency call. Low cardinality value. Examples are stored procedure name and URL path template.
51 | /// Command initiated by this dependency call. Examples are SQL statement and HTTP URL's with all query parameters.
52 | /// The time when the dependency was called.
53 | /// The time taken by the external dependency to handle the call.
54 | /// True if the dependency call was handled successfully.
55 | void LogDependency(string dependencyTypeName, string dependencyName, string data, DateTimeOffset startTime, TimeSpan duration, bool success);
56 | }
57 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Logging/LogLevel.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Logging
6 | {
7 | ///
8 | /// Types of log level.
9 | ///
10 | public enum LogLevel
11 | {
12 | ///
13 | /// Represents debug.
14 | ///
15 | Debug,
16 |
17 | ///
18 | /// Represents information.
19 | ///
20 | Info,
21 |
22 | ///
23 | /// Represents warning.
24 | ///
25 | Warning,
26 |
27 | ///
28 | /// Represents metric.
29 | ///
30 | Metric,
31 |
32 | ///
33 | /// Represents an event.
34 | ///
35 | Event,
36 |
37 | ///
38 | /// Represents an error.
39 | ///
40 | Error,
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Models/Token.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Models
6 | {
7 | using Newtonsoft.Json;
8 |
9 | ///
10 | /// Represents authentication token.
11 | ///
12 | public class Token
13 | {
14 | ///
15 | /// Gets or sets access token.
16 | ///
17 | [JsonProperty("access_token")]
18 | public string AccessToken { get; set; }
19 |
20 | ///
21 | /// Gets or sets type of token.
22 | ///
23 | [JsonProperty("token_type")]
24 | public string TokenType { get; set; }
25 |
26 | ///
27 | /// Gets or sets gets expire duration in milliseconds.
28 | ///
29 | [JsonProperty("expires_in")]
30 | public int ExpiresIn { get; set; }
31 |
32 | ///
33 | /// Gets or sets refresh token.
34 | ///
35 | [JsonProperty("refresh_token")]
36 | public string RefreshToken { get; set; }
37 | }
38 | }
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | using System.Reflection;
6 | using System.Runtime.InteropServices;
7 |
8 | // General Information about an assembly is controlled through the following
9 | // set of attributes. Change these attribute values to modify the information
10 | // associated with an assembly.
11 | [assembly: AssemblyTitle("Microsoft.Teams.Apps.Common")]
12 | [assembly: AssemblyDescription("")]
13 | [assembly: AssemblyConfiguration("")]
14 | [assembly: AssemblyCompany("HP Inc.")]
15 | [assembly: AssemblyProduct("Microsoft.Teams.Apps.Common")]
16 | [assembly: AssemblyCopyright("Copyright © HP Inc. 2019")]
17 | [assembly: AssemblyTrademark("")]
18 | [assembly: AssemblyCulture("")]
19 |
20 | // Setting ComVisible to false makes the types in this assembly not visible
21 | // to COM components. If you need to access a type in this assembly from
22 | // COM, set the ComVisible attribute to true on that type.
23 | [assembly: ComVisible(false)]
24 |
25 | // The following GUID is for the ID of the typelib if this project is exposed to COM
26 | [assembly: Guid("7fa2791f-e894-4876-8773-a5318631365c")]
27 |
28 | // Version information for an assembly consists of the following four values:
29 | //
30 | // Major Version
31 | // Minor Version
32 | // Build Number
33 | // Revision
34 | //
35 | // You can specify all the values or you can default the Build and Revision Numbers
36 | // by using the '*' as shown below:
37 | // [assembly: AssemblyVersion("1.0.*")]
38 | [assembly: AssemblyVersion("1.0.0.0")]
39 | [assembly: AssemblyFileVersion("1.0.0.0")]
40 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Telemetry/TelemetryEvent.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Telemetry
6 | {
7 | ///
8 | /// Event types
9 | ///
10 | public enum TelemetryEvent
11 | {
12 | ///
13 | /// Activity received by the bot
14 | ///
15 | UserActivity,
16 |
17 | ///
18 | /// Bot detected a command at the root dialog
19 | ///
20 | TopLevelCommand,
21 |
22 | ///
23 | /// User executed a command on a card
24 | ///
25 | CardCommand,
26 |
27 | ///
28 | /// Bot received input that it could not recognize
29 | ///
30 | UnrecognizedIntent,
31 |
32 | ///
33 | /// Events related to a dialog flow
34 | ///
35 | DialogEvent,
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Telemetry/TelemetryProperty.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Telemetry
6 | {
7 | ///
8 | /// Telemetry properties
9 | ///
10 | public enum TelemetryProperty
11 | {
12 | ///
13 | /// Type of incoming activity
14 | ///
15 | ActivityType,
16 |
17 | ///
18 | /// The activity id
19 | ///
20 | ActivityId,
21 |
22 | ///
23 | /// The Teams-specific event type
24 | ///
25 | TeamsEventType,
26 |
27 | ///
28 | /// The 29:xxx user id of the user
29 | ///
30 | UserId,
31 |
32 | ///
33 | /// The AAD object id of the user
34 | ///
35 | UserAadObjectId,
36 |
37 | ///
38 | /// The conversation id
39 | ///
40 | ConversationId,
41 |
42 | ///
43 | /// The conversation type
44 | ///
45 | ConversationType,
46 |
47 | ///
48 | /// The client platform
49 | ///
50 | Platform,
51 |
52 | ///
53 | /// The client locale
54 | ///
55 | Locale,
56 |
57 | ///
58 | /// The command that was invoked
59 | ///
60 | CommandName,
61 |
62 | ///
63 | /// The dialog id
64 | ///
65 | DialogId,
66 |
67 | ///
68 | /// The dialog instance id
69 | ///
70 | DialogInstanceId,
71 |
72 | ///
73 | /// [OperationStep] The event step in a multi-step process
74 | ///
75 | Step,
76 |
77 | ///
78 | /// [OperationResult] The result of a multi-step process
79 | ///
80 | Result,
81 |
82 | ///
83 | /// The status/error code
84 | ///
85 | StatusCode,
86 |
87 | ///
88 | /// The kind of card that was invoked
89 | ///
90 | CardType,
91 |
92 | ///
93 | /// The command on the card that was invoked
94 | ///
95 | CardCommand,
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/Telemetry/UserTelemetryInitializer.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Microsoft. All rights reserved.
3 | //
4 |
5 | namespace Microsoft.Teams.Apps.Common.Telemetry
6 | {
7 | using System;
8 | using System.Web;
9 | using Microsoft.ApplicationInsights.Channel;
10 | using Microsoft.ApplicationInsights.Extensibility;
11 |
12 | ///
13 | /// Initializes user property of telemetry
14 | ///
15 | public class UserTelemetryInitializer : ITelemetryInitializer
16 | {
17 | private const string TelemetryUserId = "TelemetryUserId";
18 |
19 | ///
20 | /// Set the user id in the platform HTTP context.
21 | ///
22 | /// The HTTP context
23 | /// The user id
24 | public static void SetTelemetryUserId(HttpContext platformContext, string userId)
25 | {
26 | platformContext.Items[TelemetryUserId] = userId;
27 | }
28 |
29 | ///
30 | public void Initialize(ITelemetry telemetry)
31 | {
32 | try
33 | {
34 | var platformContext = HttpContext.Current;
35 | if ((platformContext != null) &&
36 | platformContext.Items[TelemetryUserId] is string userId)
37 | {
38 | telemetry.Context.User.Id = userId;
39 | }
40 | }
41 | catch (Exception)
42 | {
43 | // Ignore failure to add user id
44 | }
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/app.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Source/Microsoft.Teams.Apps.Common/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Source/Settings.StyleCop:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | preprocessor,pre-processor
5 | shortlived,short-lived
6 |
7 |
8 |
9 |
10 |
11 |
12 | \.g\.cs$
13 | \.generated\.cs$
14 | \.g\.i\.cs$
15 | TemporaryGeneratedFile_.*\.cs$
16 | AssemblyInfo.*\.cs$
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | False
27 |
28 |
29 |
30 |
31 |
32 | as
33 | do
34 | id
35 | if
36 | in
37 | ip
38 | is
39 | mx
40 | my
41 | no
42 | on
43 | to
44 | ui
45 | vs
46 | x
47 | y
48 | z
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | False
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/Source/stylecop.json:
--------------------------------------------------------------------------------
1 | {
2 | // ACTION REQUIRED: This file was automatically added to your project, but it
3 | // will not take effect until additional steps are taken to enable it. See the
4 | // following page for additional information:
5 | //
6 | // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md
7 |
8 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
9 | "settings": {
10 | "documentationRules": {
11 | "companyName": "Microsoft"
12 | }
13 | }
14 | }
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/deploy.app.cmd:
--------------------------------------------------------------------------------
1 | @if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off
2 |
3 | :: ----------------------
4 | :: KUDU Deployment Script
5 | :: Version: 1.0.17
6 | :: ----------------------
7 |
8 | :: Prerequisites
9 | :: -------------
10 |
11 | :: Verify node.js installed
12 | where node 2>nul >nul
13 | IF %ERRORLEVEL% NEQ 0 (
14 | echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
15 | goto error
16 | )
17 |
18 | :: Setup
19 | :: -----
20 |
21 | setlocal enabledelayedexpansion
22 |
23 | SET ARTIFACTS=%~dp0%..\artifacts
24 |
25 | IF NOT DEFINED DEPLOYMENT_SOURCE (
26 | SET DEPLOYMENT_SOURCE=%~dp0%.
27 | )
28 |
29 | IF NOT DEFINED DEPLOYMENT_TARGET (
30 | SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
31 | )
32 |
33 | IF NOT DEFINED NEXT_MANIFEST_PATH (
34 | SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest
35 |
36 | IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
37 | SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
38 | )
39 | )
40 |
41 | IF NOT DEFINED KUDU_SYNC_CMD (
42 | :: Install kudu sync
43 | echo Installing Kudu Sync
44 | call npm install kudusync -g --silent
45 | IF !ERRORLEVEL! NEQ 0 goto error
46 |
47 | :: Locally just running "kuduSync" would also work
48 | SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
49 | )
50 | IF NOT DEFINED DEPLOYMENT_TEMP (
51 | SET DEPLOYMENT_TEMP=%temp%\___deployTemp%random%
52 | SET CLEAN_LOCAL_DEPLOYMENT_TEMP=true
53 | )
54 |
55 | IF DEFINED CLEAN_LOCAL_DEPLOYMENT_TEMP (
56 | IF EXIST "%DEPLOYMENT_TEMP%" rd /s /q "%DEPLOYMENT_TEMP%"
57 | mkdir "%DEPLOYMENT_TEMP%"
58 | )
59 |
60 | SET MSBUILD_PATH=%MSBUILD_15_DIR%\MSBuild.exe
61 |
62 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
63 | :: Deployment
64 | :: ----------
65 |
66 | echo Handling .NET Web Application deployment.
67 |
68 | :: 1. Restore NuGet packages
69 | IF /I "Source\Microsoft.Teams.Apps.FAQPlusPlus.sln" NEQ "" (
70 | call :ExecuteCmd nuget restore "%DEPLOYMENT_SOURCE%\Source\Microsoft.Teams.Apps.Celebration.sln" -MSBuildPath "%MSBUILD_15_DIR%"
71 | IF !ERRORLEVEL! NEQ 0 goto error
72 | )
73 |
74 | :: 2. Build to the temporary path
75 | IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
76 | call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\Source\Microsoft.Teams.Apps.Celebration\Microsoft.Teams.Apps.Celebration.csproj" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="%DEPLOYMENT_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\Source\\" %SCM_BUILD_ARGS%
77 | ) ELSE (
78 | call :ExecuteCmd "%MSBUILD_PATH%" "%DEPLOYMENT_SOURCE%\Source\Microsoft.Teams.Apps.Celebration\Microsoft.Teams.Apps.Celebration.csproj" /nologo /verbosity:m /t:Build /p:AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release;UseSharedCompilation=false /p:SolutionDir="%DEPLOYMENT_SOURCE%\Source\\" %SCM_BUILD_ARGS%
79 | )
80 |
81 | IF !ERRORLEVEL! NEQ 0 goto error
82 |
83 | :: 3. KuduSync
84 | IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
85 | call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
86 | IF !ERRORLEVEL! NEQ 0 goto error
87 | )
88 |
89 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
90 | goto end
91 |
92 | :: Execute command routine that will echo out when error
93 | :ExecuteCmd
94 | setlocal
95 | set _CMD_=%*
96 | call %_CMD_%
97 | if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
98 | exit /b %ERRORLEVEL%
99 |
100 | :error
101 | endlocal
102 | echo An error has occurred during web site deployment.
103 | call :exitSetErrorLevel
104 | call :exitFromFunction 2>nul
105 |
106 | :exitSetErrorLevel
107 | exit /b 1
108 |
109 | :exitFromFunction
110 | ()
111 |
112 | :end
113 | endlocal
114 | echo Finished successfully.
115 |
--------------------------------------------------------------------------------
/deploy.cmd:
--------------------------------------------------------------------------------
1 | @if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off
2 |
3 | IF "%SITE_ROLE%" == "app" (
4 | deploy.app.cmd
5 | ) ELSE (
6 | IF "%SITE_ROLE%" == "function" (
7 | deploy.function.cmd
8 | ) ELSE (
9 | echo You have to set SITE_ROLE setting to either "app" or "function"
10 | exit /b 1
11 | )
12 | )
--------------------------------------------------------------------------------
/deploy.function.cmd:
--------------------------------------------------------------------------------
1 | @if "%SCM_TRACE_LEVEL%" NEQ "4" @echo off
2 |
3 | :: ----------------------
4 | :: KUDU Deployment Script
5 | :: Version: 1.0.17
6 | :: ----------------------
7 |
8 | :: Prerequisites
9 | :: -------------
10 |
11 | :: Verify node.js installed
12 | where node 2>nul >nul
13 | IF %ERRORLEVEL% NEQ 0 (
14 | echo Missing node.js executable, please install node.js, if already installed make sure it can be reached from current environment.
15 | goto error
16 | )
17 |
18 | :: Setup
19 | :: -----
20 |
21 | setlocal enabledelayedexpansion
22 |
23 | SET ARTIFACTS=%~dp0%..\artifacts
24 |
25 | IF NOT DEFINED DEPLOYMENT_SOURCE (
26 | SET DEPLOYMENT_SOURCE=%~dp0%.
27 | )
28 |
29 | IF NOT DEFINED DEPLOYMENT_TARGET (
30 | SET DEPLOYMENT_TARGET=%ARTIFACTS%\wwwroot
31 | )
32 |
33 | IF NOT DEFINED NEXT_MANIFEST_PATH (
34 | SET NEXT_MANIFEST_PATH=%ARTIFACTS%\manifest
35 |
36 | IF NOT DEFINED PREVIOUS_MANIFEST_PATH (
37 | SET PREVIOUS_MANIFEST_PATH=%ARTIFACTS%\manifest
38 | )
39 | )
40 |
41 | IF NOT DEFINED KUDU_SYNC_CMD (
42 | :: Install kudu sync
43 | echo Installing Kudu Sync
44 | call npm install kudusync -g --silent
45 | IF !ERRORLEVEL! NEQ 0 goto error
46 |
47 | :: Locally just running "kuduSync" would also work
48 | SET KUDU_SYNC_CMD=%appdata%\npm\kuduSync.cmd
49 | )
50 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
51 | :: Deployment
52 | :: ----------
53 | echo Handling function App deployment with Msbuild.
54 |
55 | :: 1. Restore nuget packages
56 | call :ExecuteCmd nuget.exe restore "%DEPLOYMENT_SOURCE%\Source\Microsoft.Teams.Apps.Celebration.sln" -MSBuildPath "%MSBUILD_15_DIR%"
57 | IF !ERRORLEVEL! NEQ 0 goto error
58 |
59 | :: 2. Build and publish
60 | call :ExecuteCmd "%MSBUILD_15_DIR%\MSBuild.exe" "%DEPLOYMENT_SOURCE%\Source\Microsoft.Teams.Apps.Celebration.Notification.Func\Microsoft.Teams.Apps.Celebration.Notification.Func.csproj" /p:DeployOnBuild=true /p:configuration=Release /p:publishurl="%DEPLOYMENT_TEMP%" %SCM_BUILD_ARGS%
61 | IF !ERRORLEVEL! NEQ 0 goto error
62 |
63 | :: 3. KuduSync
64 | IF /I "%IN_PLACE_DEPLOYMENT%" NEQ "1" (
65 | call :ExecuteCmd "%KUDU_SYNC_CMD%" -v 50 -f "%DEPLOYMENT_TEMP%" -t "%DEPLOYMENT_TARGET%" -n "%NEXT_MANIFEST_PATH%" -p "%PREVIOUS_MANIFEST_PATH%" -i ".git;.hg;.deployment;deploy.cmd"
66 | IF !ERRORLEVEL! NEQ 0 goto error
67 | )
68 |
69 | ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
70 | goto end
71 |
72 | :: Execute command routine that will echo out when error
73 | :ExecuteCmd
74 | setlocal
75 | set _CMD_=%*
76 | call %_CMD_%
77 | if "%ERRORLEVEL%" NEQ "0" echo Failed exitCode=%ERRORLEVEL%, command=%_CMD_%
78 | exit /b %ERRORLEVEL%
79 |
80 | :error
81 | endlocal
82 | echo An error has occurred during web site deployment.
83 | call :exitSetErrorLevel
84 | call :exitFromFunction 2>nul
85 |
86 | :exitSetErrorLevel
87 | exit /b 1
88 |
89 | :exitFromFunction
90 | ()
91 |
92 | :end
93 | endlocal
94 | echo Finished successfully.
95 |
--------------------------------------------------------------------------------
/global.json:
--------------------------------------------------------------------------------
1 | {
2 | "sdk": {
3 | "version": "2.1.515"
4 | }
5 | }
--------------------------------------------------------------------------------