├── ngrok.bat
├── OneDriveWebhooks
├── Views
│ ├── _ViewStart.cshtml
│ ├── Home
│ │ ├── About.cshtml
│ │ ├── Contact.cshtml
│ │ └── Index.cshtml
│ ├── Shared
│ │ ├── Error.cshtml
│ │ └── _Layout.cshtml
│ ├── Subscription
│ │ ├── Index.cshtml
│ │ └── Subscription.cshtml
│ ├── Web.config
│ └── Notification
│ │ └── Notification.cshtml
├── favicon.ico
├── Global.asax
├── Scripts
│ ├── _references.js
│ ├── respond.min.js
│ ├── jquery.validate.unobtrusive.min.js
│ ├── respond.js
│ ├── jquery.validate.min.js
│ └── jquery.validate.unobtrusive.js
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.ttf
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
├── SignalR
│ ├── NotificationHub.cs
│ └── NotificationService.cs
├── App_Start
│ ├── FilterConfig.cs
│ ├── RouteConfig.cs
│ └── BundleConfig.cs
├── Startup.cs
├── Content
│ ├── Site.css
│ ├── bootstrap-theme.min.css
│ └── bootstrap-theme.css
├── Global.asax.cs
├── Controllers
│ ├── HomeController.cs
│ ├── AccountController.cs
│ ├── NotificationController.cs
│ └── SubscriptionController.cs
├── Web.Debug.config
├── Web.Release.config
├── Properties
│ └── AssemblyInfo.cs
├── Models
│ ├── OneDriveUserManager.cs
│ ├── OneDriveNotification.cs
│ ├── OneDriveSubscription.cs
│ ├── OneDriveAccountServiceProvider.cs
│ └── OneDriveUser.cs
├── packages.config
├── Auth
│ ├── QueryStringBuilder.cs
│ └── AuthHelper.cs
├── Web.config
└── OneDriveWebhooks.csproj
├── readme-images
├── Page2.png
├── Page3.png
├── Page4.png
├── Page5.png
├── Page6.png
├── ngrok1.png
├── ngrok2.png
└── PortNumber.png
├── LICENSE.md
├── onedrive-webhooks-aspnet.sln
├── .gitignore
└── README.md
/ngrok.bat:
--------------------------------------------------------------------------------
1 | @echo off
2 | c:\ngrok\ngrok http 52026 -host-header localhost:52026
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/_ViewStart.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | Layout = "~/Views/Shared/_Layout.cshtml";
3 | }
4 |
--------------------------------------------------------------------------------
/readme-images/Page2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/Page2.png
--------------------------------------------------------------------------------
/readme-images/Page3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/Page3.png
--------------------------------------------------------------------------------
/readme-images/Page4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/Page4.png
--------------------------------------------------------------------------------
/readme-images/Page5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/Page5.png
--------------------------------------------------------------------------------
/readme-images/Page6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/Page6.png
--------------------------------------------------------------------------------
/readme-images/ngrok1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/ngrok1.png
--------------------------------------------------------------------------------
/readme-images/ngrok2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/ngrok2.png
--------------------------------------------------------------------------------
/OneDriveWebhooks/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/OneDriveWebhooks/favicon.ico
--------------------------------------------------------------------------------
/readme-images/PortNumber.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/readme-images/PortNumber.png
--------------------------------------------------------------------------------
/OneDriveWebhooks/Global.asax:
--------------------------------------------------------------------------------
1 | <%@ Application Codebehind="Global.asax.cs" Inherits="OneDriveWebhookTranslator.MvcApplication" Language="C#" %>
2 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Scripts/_references.js:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/OneDriveWebhooks/Scripts/_references.js
--------------------------------------------------------------------------------
/OneDriveWebhooks/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/OneDriveWebhooks/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/OneDriveWebhooks/fonts/glyphicons-halflings-regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/OneDriveWebhooks/fonts/glyphicons-halflings-regular.ttf
--------------------------------------------------------------------------------
/OneDriveWebhooks/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/OneDriveWebhooks/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/OneDriveWebhooks/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OneDrive/onedrive-webhooks-aspnet/HEAD/OneDriveWebhooks/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Home/About.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "About";
3 | }
4 |
@ViewBag.Title.
5 | @ViewBag.Message
6 |
7 | Use this area to provide additional information.
8 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/SignalR/NotificationHub.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using Microsoft.AspNet.SignalR;
7 | using Microsoft.AspNet.SignalR.Hubs;
8 |
9 | namespace OneDriveWebhookTranslator.SignalR
10 | {
11 | [HubName("NotificationHub")]
12 | public class NotificationHub : Hub
13 | {
14 |
15 | }
16 | }
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Shared/Error.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Error
6 |
7 |
8 |
9 | Error.
10 | An error occurred while processing your request.
11 |
12 | @ViewBag.Message
13 | @if (!string.IsNullOrEmpty(ViewBag.Debug))
14 | {
15 | @ViewBag.Debug
16 | }
17 |
18 |
19 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Home/Contact.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "Contact";
3 | }
4 | @ViewBag.Title.
5 | @ViewBag.Message
6 |
7 |
8 | One Microsoft Way
9 | Redmond, WA 98052-6399
10 | P:
11 | 425.555.0100
12 |
13 |
14 |
15 | Support: Support@example.com
16 | Marketing: Marketing@example.com
17 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/App_Start/FilterConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System.Web;
7 | using System.Web.Mvc;
8 |
9 | namespace OneDriveWebhookTranslator
10 | {
11 | public class FilterConfig
12 | {
13 | public static void RegisterGlobalFilters(GlobalFilterCollection filters)
14 | {
15 | filters.Add(new HandleErrorAttribute());
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Startup.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using Owin;
7 | using Microsoft.Owin;
8 | [assembly: OwinStartup(typeof(OneDriveWebhookTranslator.Startup))]
9 | namespace OneDriveWebhookTranslator
10 | {
11 | public class Startup
12 | {
13 | public void Configuration(IAppBuilder app)
14 | {
15 | // Any connection or hub wire up and configuration should go here
16 | app.MapSignalR();
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/OneDriveWebhooks/Content/Site.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 50px;
3 | padding-bottom: 20px;
4 | }
5 |
6 | /* Set padding to keep content from hitting the edges */
7 | .body-content {
8 | padding-left: 15px;
9 | padding-right: 15px;
10 | }
11 |
12 | /* Override the default bootstrap behavior where horizontal description lists
13 | will truncate terms that are too long to fit in the left column
14 | */
15 | .dl-horizontal dt {
16 | white-space: normal;
17 | }
18 |
19 | /* Set width on the form input elements since they're 100% wide by default */
20 | input,
21 | select,
22 | textarea {
23 | max-width: 280px;
24 | }
25 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Subscription/Index.cshtml:
--------------------------------------------------------------------------------
1 |
2 | @{
3 | ViewBag.Title = "Webhook Subscriptions";
4 | }
5 |
6 | OneDrive Webhooks
7 |
8 |
9 |
You can subscribe to webhooks for a user's OneDrive and get notifications when changes are made to the drive.
10 |
This sample creates a subscription for the signed in user's drive. An example request looks like this:
11 |
12 |
See the docs for more information about creating webhooks for OneDrive.
13 | @using (Html.BeginForm("CreateSubscription", "Subscription"))
14 | {
15 |
Create subscription
16 | }
17 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Global.asax.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Web;
10 | using System.Web.Mvc;
11 | using System.Web.Optimization;
12 | using System.Web.Routing;
13 |
14 | namespace OneDriveWebhookTranslator
15 | {
16 | public class MvcApplication : System.Web.HttpApplication
17 | {
18 | protected void Application_Start()
19 | {
20 | AreaRegistration.RegisterAllAreas();
21 | FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
22 | RouteConfig.RegisterRoutes(RouteTable.Routes);
23 | BundleConfig.RegisterBundles(BundleTable.Bundles);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/App_Start/RouteConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Web;
10 | using System.Web.Mvc;
11 | using System.Web.Routing;
12 |
13 | namespace OneDriveWebhookTranslator
14 | {
15 | public class RouteConfig
16 | {
17 | public static void RegisterRoutes(RouteCollection routes)
18 | {
19 | routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
20 |
21 | routes.MapRoute(
22 | name: "Default",
23 | url: "{controller}/{action}/{id}",
24 | defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
25 | );
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Home/Index.cshtml:
--------------------------------------------------------------------------------
1 | @{
2 | ViewBag.Title = "Home Page";
3 | }
4 |
5 |
6 |
OneDrive Webhooks
7 |
This sample provides an example of using OneDrive webhooks to receive real time notifications when content is changed.
8 | To get started, sign in with your account below.
9 |
10 | @if (ViewBag.Message != null)
11 | {
12 |
@ViewBag.Message
13 | }
14 |
15 | @if (ViewBag.ShowSignInButtons)
16 | {
17 |
18 | OneDrive Personal
19 | OneDrive for Business
20 |
21 | }
22 | else
23 | {
24 |
25 | Sign Out
26 |
27 | }
28 |
29 |
30 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016 Microsoft Corporation
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Controllers/HomeController.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using OneDriveWebhookTranslator.Models;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Web;
11 | using System.Web.Mvc;
12 |
13 | namespace OneDriveWebhookTranslator.Controllers
14 | {
15 | public class HomeController : Controller
16 | {
17 | public ActionResult Index()
18 | {
19 | OneDriveUser user = OneDriveUser.UserForRequest(this.Request);
20 | ViewBag.ShowSignInButtons = (user == null);
21 |
22 | return View();
23 | }
24 |
25 | public ActionResult About()
26 | {
27 | ViewBag.Message = "Your application description page.";
28 |
29 | return View();
30 | }
31 |
32 | public ActionResult Contact()
33 | {
34 | ViewBag.Message = "Your contact page.";
35 |
36 | return View();
37 | }
38 | }
39 | }
--------------------------------------------------------------------------------
/onedrive-webhooks-aspnet.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OneDriveWebhooks", "OneDriveWebhooks\OneDriveWebhooks.csproj", "{8728D262-D20E-45AE-AA9B-306F0DA8CBC5}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{5FBB7F40-1739-415E-86CD-91D1F6DCEDBB}"
9 | ProjectSection(SolutionItems) = preProject
10 | LICENSE.md = LICENSE.md
11 | README.md = README.md
12 | EndProjectSection
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {8728D262-D20E-45AE-AA9B-306F0DA8CBC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {8728D262-D20E-45AE-AA9B-306F0DA8CBC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {8728D262-D20E-45AE-AA9B-306F0DA8CBC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {8728D262-D20E-45AE-AA9B-306F0DA8CBC5}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | EndGlobal
29 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Web.Debug.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Web.Release.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
17 |
18 |
19 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("OneDriveWebhookTranslator")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("OneDriveWebhookTranslator")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3f9b9d3d-496d-45cd-aed8-10427cdd3685")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Revision and Build Numbers
33 | // by using the '*' as shown below:
34 | [assembly: AssemblyVersion("1.0.0.0")]
35 | [assembly: AssemblyFileVersion("1.0.0.0")]
36 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Subscription/Subscription.cshtml:
--------------------------------------------------------------------------------
1 | @model OneDriveWebhookTranslator.Models.SubscriptionViewModel
2 | @{
3 | ViewBag.Title = "Subscription Results";
4 | }
5 |
6 | New Subscription
7 |
8 |
9 |
10 |
11 |
12 | @Html.LabelFor(m => m.Subscription.Resource, htmlAttributes: new { @class = "control-label col-md-2" })
13 |
14 |
15 | @Model.Subscription.Resource
16 |
17 |
18 |
19 |
20 | @Html.LabelFor(m => m.Subscription.ClientState, htmlAttributes: new { @class = "control-label col-md-2" })
21 |
22 |
23 | @Model.Subscription.ClientState
24 |
25 |
26 |
27 |
28 | @Html.LabelFor(m => m.Subscription.SubscriptionId, htmlAttributes: new { @class = "control-label col-md-2" })
29 |
30 |
31 | @Model.Subscription.SubscriptionId
32 |
33 |
34 |
35 |
36 | @Html.LabelFor(m => m.Subscription.SubscriptionExpirationDateTime, htmlAttributes: new { @class = "control-label col-md-2" })
37 |
38 |
39 | @Model.Subscription.SubscriptionExpirationDateTime
40 |
41 |
42 |
43 |
44 |
45 | @using (Html.BeginForm("LoadView", "Notification"))
46 | {
47 | Watch for notifications
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/App_Start/BundleConfig.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System.Web;
7 | using System.Web.Optimization;
8 |
9 | namespace OneDriveWebhookTranslator
10 | {
11 | public class BundleConfig
12 | {
13 | // For more information on bundling, visit http://go.microsoft.com/fwlink/?LinkId=301862
14 | public static void RegisterBundles(BundleCollection bundles)
15 | {
16 | bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
17 | "~/Scripts/jquery-{version}.js"));
18 |
19 | bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
20 | "~/Scripts/jquery.validate*"));
21 |
22 | // Use the development version of Modernizr to develop with and learn from. Then, when you're
23 | // ready for production, use the build tool at http://modernizr.com to pick only the tests you need.
24 | bundles.Add(new ScriptBundle("~/bundles/modernizr").Include(
25 | "~/Scripts/modernizr-*"));
26 |
27 | bundles.Add(new ScriptBundle("~/bundles/bootstrap").Include(
28 | "~/Scripts/bootstrap.js",
29 | "~/Scripts/respond.js"));
30 |
31 | bundles.Add(new StyleBundle("~/Content/css").Include(
32 | "~/Content/bootstrap.css",
33 | "~/Content/site.css"));
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Shared/_Layout.cshtml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | @ViewBag.Title - OneDrive Webhook Sample
7 | @Styles.Render("~/Content/css")
8 | @Scripts.Render("~/bundles/modernizr")
9 |
10 |
11 |
12 |
13 |
21 |
22 |
23 | @Html.ActionLink("Home", "Index", "Home")
24 | @Html.ActionLink("About", "About", "Home")
25 | @Html.ActionLink("Webhooks", "Index", "Subscription")
26 |
27 |
28 |
29 |
30 |
31 | @RenderBody()
32 |
33 |
34 | @Scripts.Render("~/bundles/jquery")
35 | @Scripts.Render("~/bundles/bootstrap")
36 | @RenderSection("scripts", required: false)
37 |
38 |
39 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Models/OneDriveUserManager.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace OneDriveWebhookTranslator.Models
13 | {
14 | ///
15 | /// This class manages an in-memory set of users. In a production serivce this class would
16 | /// be provided by a backend database that could manage the state of users securely across
17 | /// multiple server instances.
18 | ///
19 | class OneDriveUserManager
20 | {
21 | private static Dictionary KnownUsers = new Dictionary();
22 |
23 | public static OneDriveUser LookupUserById(string userGuid)
24 | {
25 | OneDriveUser user;
26 | if (KnownUsers.TryGetValue(userGuid, out user))
27 | return user;
28 |
29 | throw new InvalidOperationException("Unknown user.");
30 | }
31 |
32 | public static void RegisterUser(string userGuid, OneDriveUser user)
33 | {
34 | KnownUsers[userGuid] = user;
35 | }
36 |
37 | public static OneDriveUser LookupUserForSubscriptionId(string subscriptionId)
38 | {
39 | var query = from u in KnownUsers.Values
40 | where u.SubscriptionId == subscriptionId
41 | select u;
42 |
43 | return query.FirstOrDefault();
44 | }
45 |
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/SignalR/NotificationService.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System.Collections.Generic;
7 | using System.Threading.Tasks;
8 | using Microsoft.AspNet.SignalR;
9 | using System.Linq;
10 |
11 | namespace OneDriveWebhookTranslator.SignalR
12 | {
13 | public class NotificationService : PersistentConnection
14 | {
15 | public void SendNotificationToClient(List items)
16 | {
17 | var hubContext = GlobalHost.ConnectionManager.GetHubContext();
18 | if (hubContext != null)
19 | {
20 | hubContext.Clients.All.showNotification(items);
21 | }
22 | }
23 |
24 | public void SendFileChangeNotification(List filenames)
25 | {
26 | if (null == filenames || !filenames.Any())
27 | return;
28 |
29 |
30 | var hubContext = GlobalHost.ConnectionManager.GetHubContext();
31 | if (null != hubContext)
32 | {
33 | hubContext.Clients.All.filesChanged(filenames);
34 | }
35 | }
36 |
37 | protected override Task OnConnected(IRequest request, string connectionId)
38 | {
39 | return Connection.Send(connectionId, "Connected");
40 | }
41 |
42 | protected override Task OnReceived(IRequest request, string connectionId, string data)
43 | {
44 | return Connection.Broadcast(data);
45 | }
46 | }
47 |
48 | }
--------------------------------------------------------------------------------
/OneDriveWebhooks/Models/OneDriveNotification.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using Newtonsoft.Json;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Web;
11 |
12 | namespace OneDriveWebhookTranslator.Models
13 | {
14 | public class OneDriveWebhookNotification
15 | {
16 | // The client state used to verify that the notification is from Microsoft Graph. Compare the value received with the notification to the value you sent with the subscription request.
17 | [JsonProperty("clientState")]
18 | public string ClientState { get; set; }
19 |
20 | // The endpoint of the resource that changed. For example, a message uses the format ../Users/{user-id}/Messages/{message-id}
21 | [JsonProperty("resource")]
22 | public string Resource { get; set; }
23 |
24 | // The date and time when the webhooks subscription expires.
25 | // The time is in UTC, and can be up to three days from the time of subscription creation.
26 | [JsonProperty("subscriptionExpirationDateTime")]
27 | public string SubscriptionExpirationDateTime { get; set; }
28 |
29 | // The unique identifier for the webhooks subscription.
30 | [JsonProperty("subscriptionId")]
31 | public string SubscriptionId { get; set; }
32 |
33 | [JsonProperty("receivedDateTime", DefaultValueHandling = DefaultValueHandling.Ignore)]
34 | public DateTime ReceivedDateTime { get; set; }
35 |
36 | public OneDriveWebhookNotification()
37 | {
38 | this.ReceivedDateTime = DateTime.UtcNow;
39 | }
40 |
41 | }
42 |
43 | public class OneDriveNotificationCollection
44 | {
45 | [JsonProperty("value")]
46 | public OneDriveWebhookNotification[] Notifications { get; set; }
47 |
48 | }
49 | }
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Models/OneDriveSubscription.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using Newtonsoft.Json;
8 |
9 | namespace OneDriveWebhookTranslator.Models
10 | {
11 | public class OneDriveSubscription
12 | {
13 | // The string that MS Graph should send with each notification. Maximum length is 255 characters.
14 | // To verify that the notification is from MS Graph, compare the value received with the notification to the value you sent with the subscription request.
15 | [JsonProperty("clientState", DefaultValueHandling = DefaultValueHandling.Ignore)]
16 | public string ClientState { get; set; }
17 |
18 | // The URL of the endpoint that receives the subscription response and notifications. Requires https.
19 | [JsonProperty("notificationUrl", DefaultValueHandling = DefaultValueHandling.Ignore)]
20 | public string NotificationUrl { get; set; }
21 |
22 | // The resource to monitor for changes.
23 | [JsonProperty("resource", DefaultValueHandling = DefaultValueHandling.Ignore)]
24 | public string Resource { get; set; }
25 |
26 | // The date and time when the webhooks subscription expires.
27 | // The time is in UTC, and can be up to three days from the time of subscription creation.
28 | [JsonProperty("expirationDateTime", DefaultValueHandling = DefaultValueHandling.Ignore)]
29 | public DateTimeOffset SubscriptionExpirationDateTime { get; set; }
30 |
31 | // The unique identifier for the webhooks subscription.
32 | [JsonProperty("id", DefaultValueHandling = DefaultValueHandling.Ignore)]
33 | public string SubscriptionId { get; set; }
34 |
35 | // OneDrive Personal requires scenarios to be passed currently. This requirement will be removed in the future
36 | [JsonProperty("scenarios", DefaultValueHandling = DefaultValueHandling.Ignore)]
37 | public string[] Scenarios { get; set; }
38 |
39 | public OneDriveSubscription()
40 | {
41 | this.Scenarios = new string[] { "Webhook" };
42 | }
43 | }
44 |
45 | public class SubscriptionViewModel
46 | {
47 | public OneDriveSubscription Subscription { get; set; }
48 | }
49 | }
--------------------------------------------------------------------------------
/OneDriveWebhooks/Views/Notification/Notification.cshtml:
--------------------------------------------------------------------------------
1 |
3 |
4 | @{
5 | ViewBag.Title = "Notification";
6 | }
7 |
8 | @section Scripts {
9 | @Scripts.Render("~/Scripts/jquery.signalR-2.2.0.min.js");
10 | @Scripts.Render("~/signalr/hubs");
11 |
12 |
50 | }
51 | Webhook Notifications
52 | You'll get a near-real time notification when a signed in user adds, deletes, or modifies a file. The raw notifications display below.
53 | Subscription ID: @ViewBag.SubscriptionId
54 |
55 |
56 |
57 | @using (Html.BeginForm("DeleteSubscription", "Subscription"))
58 | {
59 | Delete subscription and sign out
60 | }
61 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Auth/QueryStringBuilder.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace OneDriveWebhookTranslator.Auth
13 | {
14 | public class QueryStringBuilder
15 | {
16 | private readonly Dictionary parameters = new Dictionary();
17 | public QueryStringBuilder()
18 | {
19 | StartCharacter = '?';
20 | SeperatorCharacter = '&';
21 | KeyValueJoinCharacter = '=';
22 | }
23 |
24 | public QueryStringBuilder(string key, string value)
25 | {
26 | this[key] = value;
27 | }
28 |
29 | public void Clear()
30 | {
31 | parameters.Clear();
32 | }
33 |
34 | public bool HasKeys
35 | {
36 | get { return parameters.Count > 0; }
37 | }
38 |
39 | public char? StartCharacter { get; set; }
40 |
41 | public char SeperatorCharacter { get; set; }
42 |
43 | public char KeyValueJoinCharacter { get; set; }
44 |
45 | public string this[string key]
46 | {
47 | get
48 | {
49 | if (parameters.ContainsKey(key))
50 | return parameters[key];
51 | else
52 | return null;
53 | }
54 | set
55 | {
56 | parameters[key] = value;
57 | }
58 | }
59 |
60 | public bool ContainsKey(string key)
61 | {
62 | return parameters.ContainsKey(key);
63 | }
64 |
65 | public string[] Keys
66 | {
67 | get { return parameters.Keys.ToArray(); }
68 | }
69 |
70 | public void Add(string key, string value)
71 | {
72 | if (string.IsNullOrEmpty(value))
73 | throw new ArgumentNullException("value");
74 |
75 | parameters[key] = value;
76 | }
77 |
78 | public void AddIfNotNullOrEmpty(string key, string value)
79 | {
80 | if (!string.IsNullOrEmpty(value))
81 | parameters[key] = value;
82 | }
83 |
84 | public void Remove(string key)
85 | {
86 | parameters.Remove(key);
87 | }
88 |
89 | public override string ToString()
90 | {
91 | var sb = new StringBuilder();
92 | foreach (var param in parameters)
93 | {
94 | if ((sb.Length == 0) && (null != StartCharacter))
95 | sb.Append(StartCharacter);
96 | if ((sb.Length > 0) && (sb[sb.Length - 1] != StartCharacter))
97 | sb.Append(SeperatorCharacter);
98 |
99 | sb.Append(param.Key);
100 | sb.Append('=');
101 | sb.Append(Uri.EscapeDataString(param.Value));
102 | }
103 | return sb.ToString();
104 | }
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Controllers/AccountController.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Configuration;
9 | using System.Linq;
10 | using System.Web;
11 | using System.Web.Mvc;
12 | using OneDriveWebhookTranslator.Auth;
13 | using System.Threading.Tasks;
14 | using OneDriveWebhookTranslator.Models;
15 |
16 | namespace OneDriveWebhookTranslator.Controllers
17 | {
18 | public class AccountController : Controller
19 | {
20 | private string RedirectUri
21 | {
22 | get
23 | {
24 | return Url.Action("Redirect", "Account", null, this.Request.Url.Scheme);
25 | }
26 | }
27 |
28 | public ActionResult SignInBusiness()
29 | {
30 | QueryStringBuilder builder = new QueryStringBuilder();
31 | builder.Add("client_id", ConfigurationManager.AppSettings["ida:AADAppId"]);
32 | builder.Add("response_type", "code");
33 | builder.Add("redirect_uri", this.RedirectUri);
34 | builder.Add("state", "business");
35 |
36 | string targetUrl = ConfigurationManager.AppSettings["ida:AADAuthService"] + builder.ToString();
37 | return Redirect(targetUrl);
38 | }
39 |
40 | public ActionResult SignInPersonal()
41 | {
42 |
43 | QueryStringBuilder builder = new QueryStringBuilder();
44 | builder.Add("client_id", ConfigurationManager.AppSettings["ida:MSAAppId"]);
45 | builder.Add("response_type", "code");
46 | builder.Add("redirect_uri", this.RedirectUri);
47 | builder.Add("state", "personal");
48 | builder.Add("scope", ConfigurationManager.AppSettings["ida:MSAScopes"]);
49 |
50 | string targetUrl = ConfigurationManager.AppSettings["ida:MSAAuthService"] + builder.ToString();
51 | return Redirect(targetUrl);
52 | }
53 |
54 | public ActionResult SignOut()
55 | {
56 | OneDriveUser.ClearResponseCookie(this.Response);
57 | return Redirect(Url.Action("Index", "Home"));
58 | }
59 |
60 | public async Task Redirect(string code, string state)
61 | {
62 | OAuthHelper helper;
63 | try {
64 | helper = OAuthHelper.HelperForService(state, this.RedirectUri);
65 | }
66 | catch (ArgumentException ex)
67 | {
68 | ViewBag.Message = ex.Message;
69 | return View("Error");
70 | }
71 |
72 | string discoveryResource = "https://api.office.com/discovery/";
73 | var token = await helper.RedeemAuthorizationCodeAsync(code, discoveryResource);
74 | if (null == token)
75 | {
76 | ViewBag.Message = "Invalid response from token service. Unable to login. Try again later.";
77 | return View("Error");
78 | }
79 |
80 | OneDriveUser user = new OneDriveUser(token, helper, discoveryResource);
81 | user.SetResponseCookie(this.Response);
82 |
83 | return Redirect(Url.Action("Index", "Subscription"));
84 | }
85 |
86 |
87 | }
88 | }
--------------------------------------------------------------------------------
/OneDriveWebhooks/Models/OneDriveAccountServiceProvider.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Net.Http;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using Microsoft.OneDrive.Sdk;
13 |
14 | namespace OneDriveWebhookTranslator.Models
15 | {
16 | class OneDriveAccountServiceProvider : Microsoft.OneDrive.Sdk.IServiceInfoProvider
17 | {
18 | private readonly OneDriveUser user;
19 | private readonly DelegateAuthenticationProvider authProvider;
20 | private readonly string resource;
21 |
22 | public OneDriveAccountServiceProvider(OneDriveUser user)
23 | {
24 | this.user = user;
25 |
26 | Uri baseUrl;
27 | if (!Uri.TryCreate(user.OneDriveBaseUrl, UriKind.Absolute, out baseUrl))
28 | {
29 | throw new InvalidOperationException("Unable to parse base URL: " + user.OneDriveBaseUrl);
30 | }
31 |
32 | this.resource = string.Concat(baseUrl.Scheme, "://", baseUrl.Host);
33 | this.authProvider = new DelegateAuthenticationProvider(new DelegateAuthenticationProvider.ProviderAuthHeaderDelegate(async req =>
34 | {
35 | req.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", await this.user.GetAccessTokenAsync(this.resource));
36 | }));
37 | }
38 |
39 | public IAuthenticationProvider AuthenticationProvider
40 | {
41 | get { return this.authProvider; }
42 | }
43 |
44 | public Task GetServiceInfo(AppConfig appConfig, CredentialCache credentialCache, IHttpProvider httpProvider, ClientType clientType)
45 | {
46 | var info = new ServiceInfo
47 | {
48 | AccountType = AccountType.None,
49 | AuthenticationProvider = this.authProvider,
50 | CredentialCache = credentialCache ?? new CredentialCache(),
51 | HttpProvider = httpProvider ?? new HttpProvider(),
52 | BaseUrl = this.user.OneDriveBaseUrl
53 | };
54 | return Task.FromResult(info);
55 | }
56 | }
57 |
58 | class DelegateAuthenticationProvider : IAuthenticationProvider
59 | {
60 | public delegate Task ProviderAuthHeaderDelegate(HttpRequestMessage request);
61 |
62 | private readonly ProviderAuthHeaderDelegate methodDelegate;
63 |
64 | public DelegateAuthenticationProvider(ProviderAuthHeaderDelegate method)
65 | {
66 | this.methodDelegate = method;
67 | this.CurrentAccountSession = new AccountSession();
68 | }
69 |
70 |
71 | public AccountSession CurrentAccountSession { get; set; }
72 |
73 | public async Task AppendAuthHeaderAsync(HttpRequestMessage request)
74 | {
75 | await this.methodDelegate(request);
76 | }
77 |
78 | public Task AuthenticateAsync()
79 | {
80 | return Task.FromResult(this.CurrentAccountSession);
81 | }
82 |
83 | public Task SignOutAsync()
84 | {
85 | return Task.FromResult(false);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Models/OneDriveUser.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using OneDriveWebhookTranslator.Auth;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Threading.Tasks;
10 | using System.Web;
11 |
12 | namespace OneDriveWebhookTranslator.Models
13 | {
14 | public class OneDriveUser
15 | {
16 | private Dictionary TokenCache = new Dictionary();
17 | private readonly string UserId;
18 | private string RefreshToken { get; set; }
19 | private OAuthHelper AuthHelper { get; set; }
20 |
21 | public string OneDriveBaseUrl { get; set; }
22 |
23 | public string SubscriptionId { get; set; }
24 |
25 | public string DeltaToken { get; set; }
26 |
27 | public Microsoft.OneDrive.Sdk.ClientType ClientType { get; set; }
28 |
29 | public Dictionary FileNameAndETag { get; set; }
30 |
31 | public OneDriveUser(OAuthToken token, OAuthHelper helper, string resource = null)
32 | {
33 | this.UserId = Guid.NewGuid().ToString();
34 | this.AuthHelper = helper;
35 | this.ClientType = helper.IsConsumerService ? Microsoft.OneDrive.Sdk.ClientType.Consumer : Microsoft.OneDrive.Sdk.ClientType.Business;
36 | this.FileNameAndETag = new Dictionary();
37 | if (!string.IsNullOrEmpty(token.RefreshToken))
38 | {
39 | this.RefreshToken = token.RefreshToken;
40 | }
41 |
42 | if (!string.IsNullOrEmpty(resource))
43 | {
44 | TokenCache[resource] = token;
45 | }
46 |
47 |
48 | OneDriveUserManager.RegisterUser(this.UserId, this);
49 | }
50 |
51 | public async Task GetAccessTokenAsync(string resource)
52 | {
53 | // Return a cached access token if we still have a valid one for this resource
54 | OAuthToken token;
55 | if (TokenCache.TryGetValue(resource, out token))
56 | {
57 | if (!string.IsNullOrEmpty(token.AccessToken) &&
58 | token.CreatedDateTime.AddSeconds(token.AccessTokenExpirationDuration) > DateTimeOffset.UtcNow.AddMinutes(5))
59 | {
60 | return token.AccessToken;
61 | }
62 | }
63 |
64 | // Otherwise, we need to redeem the refresh token
65 | token = await this.AuthHelper.RedeemRefreshTokenAsync(this.RefreshToken, resource);
66 | TokenCache[resource] = token;
67 |
68 | return token.AccessToken;
69 | }
70 |
71 | internal void SetResponseCookie(HttpResponseBase response)
72 | {
73 | HttpCookie cookie = new HttpCookie("oneDriveUser", this.UserId);
74 | cookie.HttpOnly = true;
75 |
76 | response.SetCookie(cookie);
77 | }
78 |
79 | internal static OneDriveUser UserForRequest(HttpRequestBase request)
80 | {
81 | try
82 | {
83 | string userGuid = request.Cookies["oneDriveUser"].Value;
84 | return OneDriveUserManager.LookupUserById(userGuid);
85 | }
86 | catch { }
87 |
88 | return null;
89 | }
90 |
91 | internal static void ClearResponseCookie(HttpResponseBase response)
92 | {
93 | HttpCookie cookie = new HttpCookie("oneDriveUser", null);
94 | cookie.HttpOnly = true;
95 | response.SetCookie(cookie);
96 | }
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Web.config:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Scripts/respond.min.js:
--------------------------------------------------------------------------------
1 | /* NUGET: BEGIN LICENSE TEXT
2 | *
3 | * Microsoft grants you the right to use these script files for the sole
4 | * purpose of either: (i) interacting through your browser with the Microsoft
5 | * website or online service, subject to the applicable licensing or use
6 | * terms; or (ii) using the files as included with a Microsoft product subject
7 | * to that product's license terms. Microsoft reserves all other rights to the
8 | * files not expressly granted by Microsoft, whether by implication, estoppel
9 | * or otherwise. Insofar as a script file is dual licensed under GPL,
10 | * Microsoft neither took the code under GPL nor distributes it thereunder but
11 | * under the terms set out in this paragraph. All notices and licenses
12 | * below are for informational purposes only.
13 | *
14 | * NUGET: END LICENSE TEXT */
15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
17 | window.matchMedia=window.matchMedia||(function(e,f){var c,a=e.documentElement,b=a.firstElementChild||a.firstChild,d=e.createElement("body"),g=e.createElement("div");g.id="mq-test-1";g.style.cssText="position:absolute;top:-100em";d.style.background="none";d.appendChild(g);return function(h){g.innerHTML='';a.insertBefore(d,b);c=g.offsetWidth==42;a.removeChild(d);return{matches:c,media:h}}})(document);
18 |
19 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
20 | (function(e){e.respond={};respond.update=function(){};respond.mediaQueriesSupported=e.matchMedia&&e.matchMedia("only all").matches;if(respond.mediaQueriesSupported){return}var w=e.document,s=w.documentElement,i=[],k=[],q=[],o={},h=30,f=w.getElementsByTagName("head")[0]||s,g=w.getElementsByTagName("base")[0],b=f.getElementsByTagName("link"),d=[],a=function(){var D=b,y=D.length,B=0,A,z,C,x;for(;B-1,minw:F.match(/\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:F.match(/\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}}j()},l,r,v=function(){var z,A=w.createElement("div"),x=w.body,y=false;A.style.cssText="position:absolute;font-size:1em;width:1em";if(!x){x=y=w.createElement("body");x.style.background="none"}x.appendChild(A);s.insertBefore(x,s.firstChild);z=A.offsetWidth;if(y){s.removeChild(x)}else{x.removeChild(A)}z=p=parseFloat(z);return z},p,j=function(I){var x="clientWidth",B=s[x],H=w.compatMode==="CSS1Compat"&&B||w.body[x]||B,D={},G=b[b.length-1],z=(new Date()).getTime();if(I&&l&&z-l-1?(p||v()):1)}if(!!J){J=parseFloat(J)*(J.indexOf(y)>-1?(p||v()):1)}if(!K.hasquery||(!A||!L)&&(A||H>=C)&&(L||H<=J)){if(!D[K.media]){D[K.media]=[]}D[K.media].push(k[K.rules])}}for(var E in q){if(q[E]&&q[E].parentNode===f){f.removeChild(q[E])}}for(var E in D){var M=w.createElement("style"),F=D[E].join("\n");M.type="text/css";M.media=E;f.insertBefore(M,G.nextSibling);if(M.styleSheet){M.styleSheet.cssText=F}else{M.appendChild(w.createTextNode(F))}q.push(M)}},n=function(x,z){var y=c();if(!y){return}y.open("GET",x,true);y.onreadystatechange=function(){if(y.readyState!=4||y.status!=200&&y.status!=304){return}z(y.responseText)};if(y.readyState==4){return}y.send(null)},c=(function(){var x=false;try{x=new XMLHttpRequest()}catch(y){x=new ActiveXObject("Microsoft.XMLHTTP")}return function(){return x}})();a();respond.update=a;function t(){j(true)}if(e.addEventListener){e.addEventListener("resize",t,false)}else{if(e.attachEvent){e.attachEvent("onresize",t)}}})(this);
--------------------------------------------------------------------------------
/OneDriveWebhooks/Controllers/NotificationController.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using Newtonsoft.Json;
7 | using OneDriveWebhookTranslator.Models;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Threading.Tasks;
11 | using System.Web.Mvc;
12 |
13 |
14 | namespace OneDriveWebhookTranslator.Controllers
15 | {
16 | public class NotificationController : Controller
17 | {
18 | public ActionResult LoadView(string subscriptionId)
19 | {
20 | ViewBag.SubscriptionId = subscriptionId;
21 | return View("Notification");
22 | }
23 |
24 | ///
25 | /// Parse JSON from webhook message
26 | ///
27 | ///
28 | private async Task ParseIncomingNotificationAsync()
29 | {
30 | try
31 | {
32 | using (var inputStream = new System.IO.StreamReader(Request.InputStream))
33 | {
34 | var collection = JsonConvert.DeserializeObject(await inputStream.ReadToEndAsync());
35 | if (collection != null && collection.Notifications != null)
36 | {
37 | return collection.Notifications;
38 | }
39 | }
40 | }
41 | catch { }
42 | return null;
43 | }
44 |
45 | public async Task Listen()
46 | {
47 | #region Validation new subscriptions
48 | // Respond to validation requests from the service by sending the token
49 | // back to the service. This response is required for each subscription.
50 | const string ValidationTokenKey = "validationToken";
51 | if (Request.QueryString[ValidationTokenKey] != null)
52 | {
53 | string token = Request.QueryString[ValidationTokenKey];
54 | return Content(token, "text/plain");
55 | }
56 | #endregion
57 |
58 | var notifications = await ParseIncomingNotificationAsync();
59 | if (null != notifications && notifications.Any())
60 | {
61 | await ProcessNotificationsAsync(notifications);
62 | }
63 |
64 | // Return a 200 so the service doesn't resend the notification.
65 | return new HttpStatusCodeResult(200);
66 | }
67 |
68 | ///
69 | /// Enumerate the changes detected by this notification
70 | ///
71 | ///
72 | ///
73 | private async Task ProcessNotificationsAsync(Models.OneDriveWebhookNotification[] notifications)
74 | {
75 | SignalR.NotificationService service = new SignalR.NotificationService();
76 | service.SendNotificationToClient(notifications.ToList());
77 |
78 | // In a production service, you should store notifications into a queue and process them on a WebJob or
79 | // other background service runner
80 | foreach (var notification in notifications)
81 | {
82 | var user = OneDriveUserManager.LookupUserForSubscriptionId(notification.SubscriptionId);
83 | if (null != user)
84 | {
85 | await ProcessChangesToUserFolder(user, service);
86 | }
87 | }
88 | }
89 |
90 | private async Task ProcessChangesToUserFolder(OneDriveUser user, SignalR.NotificationService notificationService)
91 | {
92 | var client = await SubscriptionController.GetOneDriveClientAsync(user);
93 |
94 | List filesChanged = new List();
95 |
96 | var knownFiles = user.FileNameAndETag;
97 | var request = client.Drive.Special["approot"].Children.Request();
98 | while (request != null)
99 | {
100 | var items = await request.GetAsync();
101 | // Pull out the changes we're interested in
102 |
103 | foreach (var item in items)
104 | {
105 | string etag;
106 | if (knownFiles.TryGetValue(item.Name, out etag))
107 | {
108 | if (etag == item.ETag)
109 | continue;
110 | }
111 | knownFiles[item.Name] = item.ETag;
112 | filesChanged.Add(item.Name);
113 | }
114 | request = items.NextPageRequest;
115 | }
116 |
117 | notificationService.SendFileChangeNotification(filesChanged);
118 | }
119 |
120 |
121 |
122 | }
123 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | artifacts/
46 |
47 | *_i.c
48 | *_p.c
49 | *_i.h
50 | *.ilk
51 | *.meta
52 | *.obj
53 | *.pch
54 | *.pdb
55 | *.pgc
56 | *.pgd
57 | *.rsp
58 | *.sbr
59 | *.tlb
60 | *.tli
61 | *.tlh
62 | *.tmp
63 | *.tmp_proj
64 | *.log
65 | *.vspscc
66 | *.vssscc
67 | .builds
68 | *.pidb
69 | *.svclog
70 | *.scc
71 |
72 | # Chutzpah Test files
73 | _Chutzpah*
74 |
75 | # Visual C++ cache files
76 | ipch/
77 | *.aps
78 | *.ncb
79 | *.opendb
80 | *.opensdf
81 | *.sdf
82 | *.cachefile
83 |
84 | # Visual Studio profiler
85 | *.psess
86 | *.vsp
87 | *.vspx
88 | *.sap
89 |
90 | # TFS 2012 Local Workspace
91 | $tf/
92 |
93 | # Guidance Automation Toolkit
94 | *.gpState
95 |
96 | # ReSharper is a .NET coding add-in
97 | _ReSharper*/
98 | *.[Rr]e[Ss]harper
99 | *.DotSettings.user
100 |
101 | # JustCode is a .NET coding add-in
102 | .JustCode
103 |
104 | # TeamCity is a build add-in
105 | _TeamCity*
106 |
107 | # DotCover is a Code Coverage Tool
108 | *.dotCover
109 |
110 | # NCrunch
111 | _NCrunch_*
112 | .*crunch*.local.xml
113 | nCrunchTemp_*
114 |
115 | # MightyMoose
116 | *.mm.*
117 | AutoTest.Net/
118 |
119 | # Web workbench (sass)
120 | .sass-cache/
121 |
122 | # Installshield output folder
123 | [Ee]xpress/
124 |
125 | # DocProject is a documentation generator add-in
126 | DocProject/buildhelp/
127 | DocProject/Help/*.HxT
128 | DocProject/Help/*.HxC
129 | DocProject/Help/*.hhc
130 | DocProject/Help/*.hhk
131 | DocProject/Help/*.hhp
132 | DocProject/Help/Html2
133 | DocProject/Help/html
134 |
135 | # Click-Once directory
136 | publish/
137 |
138 | # Publish Web Output
139 | *.[Pp]ublish.xml
140 | *.azurePubxml
141 | # TODO: Comment the next line if you want to checkin your web deploy settings
142 | # but database connection strings (with potential passwords) will be unencrypted
143 | *.pubxml
144 | *.publishproj
145 |
146 | # NuGet Packages
147 | *.nupkg
148 | # The packages folder can be ignored because of Package Restore
149 | **/packages/*
150 | # except build/, which is used as an MSBuild target.
151 | !**/packages/build/
152 | # Uncomment if necessary however generally it will be regenerated when needed
153 | #!**/packages/repositories.config
154 | # NuGet v3's project.json files produces more ignoreable files
155 | *.nuget.props
156 | *.nuget.targets
157 |
158 | # Microsoft Azure Build Output
159 | csx/
160 | *.build.csdef
161 |
162 | # Microsoft Azure Emulator
163 | ecf/
164 | rcf/
165 |
166 | # Windows Store app package directories and files
167 | AppPackages/
168 | BundleArtifacts/
169 | Package.StoreAssociation.xml
170 | _pkginfo.txt
171 |
172 | # Visual Studio cache files
173 | # files ending in .cache can be ignored
174 | *.[Cc]ache
175 | # but keep track of directories ending in .cache
176 | !*.[Cc]ache/
177 |
178 | # Others
179 | ClientBin/
180 | ~$*
181 | *~
182 | *.dbmdl
183 | *.dbproj.schemaview
184 | *.pfx
185 | *.publishsettings
186 | node_modules/
187 | orleans.codegen.cs
188 |
189 | # Since there are multiple workflows, uncomment next line to ignore bower_components
190 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
191 | #bower_components/
192 |
193 | # RIA/Silverlight projects
194 | Generated_Code/
195 |
196 | # Backup & report files from converting an old project file
197 | # to a newer Visual Studio version. Backup files are not needed,
198 | # because we have git ;-)
199 | _UpgradeReport_Files/
200 | Backup*/
201 | UpgradeLog*.XML
202 | UpgradeLog*.htm
203 |
204 | # SQL Server files
205 | *.mdf
206 | *.ldf
207 |
208 | # Business Intelligence projects
209 | *.rdl.data
210 | *.bim.layout
211 | *.bim_*.settings
212 |
213 | # Microsoft Fakes
214 | FakesAssemblies/
215 |
216 | # GhostDoc plugin setting file
217 | *.GhostDoc.xml
218 |
219 | # Node.js Tools for Visual Studio
220 | .ntvs_analysis.dat
221 |
222 | # Visual Studio 6 build log
223 | *.plg
224 |
225 | # Visual Studio 6 workspace options file
226 | *.opt
227 |
228 | # Visual Studio LightSwitch build output
229 | **/*.HTMLClient/GeneratedArtifacts
230 | **/*.DesktopClient/GeneratedArtifacts
231 | **/*.DesktopClient/ModelManifest.xml
232 | **/*.Server/GeneratedArtifacts
233 | **/*.Server/ModelManifest.xml
234 | _Pvt_Extensions
235 |
236 | # Paket dependency manager
237 | .paket/paket.exe
238 | paket-files/
239 |
240 | # FAKE - F# Make
241 | .fake/
242 |
243 | # JetBrains Rider
244 | .idea/
245 | *.sln.iml
--------------------------------------------------------------------------------
/OneDriveWebhooks/Scripts/jquery.validate.unobtrusive.min.js:
--------------------------------------------------------------------------------
1 | /* NUGET: BEGIN LICENSE TEXT
2 | *
3 | * Microsoft grants you the right to use these script files for the sole
4 | * purpose of either: (i) interacting through your browser with the Microsoft
5 | * website or online service, subject to the applicable licensing or use
6 | * terms; or (ii) using the files as included with a Microsoft product subject
7 | * to that product's license terms. Microsoft reserves all other rights to the
8 | * files not expressly granted by Microsoft, whether by implication, estoppel
9 | * or otherwise. Insofar as a script file is dual licensed under GPL,
10 | * Microsoft neither took the code under GPL nor distributes it thereunder but
11 | * under the terms set out in this paragraph. All notices and licenses
12 | * below are for informational purposes only.
13 | *
14 | * NUGET: END LICENSE TEXT */
15 | /*
16 | ** Unobtrusive validation support library for jQuery and jQuery Validate
17 | ** Copyright (C) Microsoft Corporation. All rights reserved.
18 | */
19 | (function(a){var d=a.validator,b,e="unobtrusiveValidation";function c(a,b,c){a.rules[b]=c;if(a.message)a.messages[b]=a.message}function j(a){return a.replace(/^\s+|\s+$/g,"").split(/\s*,\s*/g)}function f(a){return a.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g,"\\$1")}function h(a){return a.substr(0,a.lastIndexOf(".")+1)}function g(a,b){if(a.indexOf("*.")===0)a=a.replace("*.",b);return a}function m(c,e){var b=a(this).find("[data-valmsg-for='"+f(e[0].name)+"']"),d=b.attr("data-valmsg-replace"),g=d?a.parseJSON(d)!==false:null;b.removeClass("field-validation-valid").addClass("field-validation-error");c.data("unobtrusiveContainer",b);if(g){b.empty();c.removeClass("input-validation-error").appendTo(b)}else c.hide()}function l(e,d){var c=a(this).find("[data-valmsg-summary=true]"),b=c.find("ul");if(b&&b.length&&d.errorList.length){b.empty();c.addClass("validation-summary-errors").removeClass("validation-summary-valid");a.each(d.errorList,function(){a(" ").html(this.message).appendTo(b)})}}function k(d){var b=d.data("unobtrusiveContainer"),c=b.attr("data-valmsg-replace"),e=c?a.parseJSON(c):null;if(b){b.addClass("field-validation-valid").removeClass("field-validation-error");d.removeData("unobtrusiveContainer");e&&b.empty()}}function n(){var b=a(this),c="__jquery_unobtrusive_validation_form_reset";if(b.data(c))return;b.data(c,true);try{b.data("validator").resetForm()}finally{b.removeData(c)}b.find(".validation-summary-errors").addClass("validation-summary-valid").removeClass("validation-summary-errors");b.find(".field-validation-error").addClass("field-validation-valid").removeClass("field-validation-error").removeData("unobtrusiveContainer").find(">*").removeData("unobtrusiveContainer")}function i(b){var c=a(b),f=c.data(e),i=a.proxy(n,b),g=d.unobtrusive.options||{},h=function(e,d){var c=g[e];c&&a.isFunction(c)&&c.apply(b,d)};if(!f){f={options:{errorClass:g.errorClass||"input-validation-error",errorElement:g.errorElement||"span",errorPlacement:function(){m.apply(b,arguments);h("errorPlacement",arguments)},invalidHandler:function(){l.apply(b,arguments);h("invalidHandler",arguments)},messages:{},rules:{},success:function(){k.apply(b,arguments);h("success",arguments)}},attachValidation:function(){c.off("reset."+e,i).on("reset."+e,i).validate(this.options)},validate:function(){c.validate();return c.valid()}};c.data(e,f)}return f}d.unobtrusive={adapters:[],parseElement:function(b,h){var d=a(b),f=d.parents("form")[0],c,e,g;if(!f)return;c=i(f);c.options.rules[b.name]=e={};c.options.messages[b.name]=g={};a.each(this.adapters,function(){var c="data-val-"+this.name,i=d.attr(c),h={};if(i!==undefined){c+="-";a.each(this.params,function(){h[this]=d.attr(c+this)});this.adapt({element:b,form:f,message:i,params:h,rules:e,messages:g})}});a.extend(e,{__dummy__:true});!h&&c.attachValidation()},parse:function(c){var b=a(c),e=b.parents().addBack().filter("form").add(b.find("form")).has("[data-val=true]");b.find("[data-val=true]").each(function(){d.unobtrusive.parseElement(this,true)});e.each(function(){var a=i(this);a&&a.attachValidation()})}};b=d.unobtrusive.adapters;b.add=function(c,a,b){if(!b){b=a;a=[]}this.push({name:c,params:a,adapt:b});return this};b.addBool=function(a,b){return this.add(a,function(d){c(d,b||a,true)})};b.addMinMax=function(e,g,f,a,d,b){return this.add(e,[d||"min",b||"max"],function(b){var e=b.params.min,d=b.params.max;if(e&&d)c(b,a,[e,d]);else if(e)c(b,g,e);else d&&c(b,f,d)})};b.addSingleVal=function(a,b,d){return this.add(a,[b||"val"],function(e){c(e,d||a,e.params[b])})};d.addMethod("__dummy__",function(){return true});d.addMethod("regex",function(b,c,d){var a;if(this.optional(c))return true;a=(new RegExp(d)).exec(b);return a&&a.index===0&&a[0].length===b.length});d.addMethod("nonalphamin",function(c,d,b){var a;if(b){a=c.match(/\W/g);a=a&&a.length>=b}return a});if(d.methods.extension){b.addSingleVal("accept","mimtype");b.addSingleVal("extension","extension")}else b.addSingleVal("extension","extension","accept");b.addSingleVal("regex","pattern");b.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");b.addMinMax("length","minlength","maxlength","rangelength").addMinMax("range","min","max","range");b.addMinMax("minlength","minlength").addMinMax("maxlength","minlength","maxlength");b.add("equalto",["other"],function(b){var i=h(b.element.name),j=b.params.other,d=g(j,i),e=a(b.form).find(":input").filter("[name='"+f(d)+"']")[0];c(b,"equalTo",e)});b.add("required",function(a){(a.element.tagName.toUpperCase()!=="INPUT"||a.element.type.toUpperCase()!=="CHECKBOX")&&c(a,"required",true)});b.add("remote",["url","type","additionalfields"],function(b){var d={url:b.params.url,type:b.params.type||"GET",data:{}},e=h(b.element.name);a.each(j(b.params.additionalfields||b.element.name),function(i,h){var c=g(h,e);d.data[c]=function(){var d=a(b.form).find(":input").filter("[name='"+f(c)+"']");return d.is(":checkbox")?d.filter(":checked").val()||d.filter(":hidden").val()||"":d.is(":radio")?d.filter(":checked").val()||"":d.val()}});c(b,"remote",d)});b.add("password",["min","nonalphamin","regex"],function(a){a.params.min&&c(a,"minlength",a.params.min);a.params.nonalphamin&&c(a,"nonalphamin",a.params.nonalphamin);a.params.regex&&c(a,"regex",a.params.regex)});a(function(){d.unobtrusive.parse(document)})})(jQuery);
--------------------------------------------------------------------------------
/OneDriveWebhooks/Auth/AuthHelper.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using Newtonsoft.Json;
7 | using System;
8 | using System.Configuration;
9 | using System.IO;
10 | using System.Net;
11 | using System.Threading.Tasks;
12 |
13 | namespace OneDriveWebhookTranslator.Auth
14 | {
15 | public class OAuthHelper
16 | {
17 | public string ClientId { get; set; }
18 | public string ClientSecret { get; set; }
19 | public string RedirectUri { get; set; }
20 | public Uri TokenService { get; set; }
21 | public bool IsConsumerService { get; set; }
22 |
23 |
24 | public OAuthHelper(string tokenService, string clientId, string clientSecret = null, string redirectUri = null)
25 | {
26 | this.TokenService = new Uri(tokenService);
27 | this.ClientId = clientId;
28 | this.ClientSecret = clientSecret;
29 | this.RedirectUri = redirectUri;
30 | }
31 |
32 | public async Task RedeemRefreshTokenAsync(string refreshToken, string resource)
33 | {
34 | var queryBuilder = new QueryStringBuilder { StartCharacter = null };
35 |
36 | queryBuilder.Add("grant_type", "refresh_token");
37 | queryBuilder.Add("refresh_token", refreshToken);
38 | queryBuilder.Add("client_id", this.ClientId);
39 | if (!string.IsNullOrEmpty(resource))
40 | queryBuilder.Add("resource", resource);
41 |
42 | if (!string.IsNullOrEmpty(this.RedirectUri))
43 | {
44 | queryBuilder.Add("redirect_uri", this.RedirectUri);
45 | }
46 | if (!string.IsNullOrEmpty(this.ClientSecret))
47 | {
48 | queryBuilder.Add("client_secret", this.ClientSecret);
49 | }
50 |
51 | return await PostToTokenEndPoint(queryBuilder);
52 | }
53 |
54 | public async Task RedeemAuthorizationCodeAsync(string authCode, string resource)
55 | {
56 | var queryBuilder = new QueryStringBuilder { StartCharacter = null };
57 |
58 | queryBuilder.Add("grant_type", "authorization_code");
59 | queryBuilder.Add("code", authCode);
60 | queryBuilder.Add("client_id", this.ClientId);
61 |
62 | if (!string.IsNullOrEmpty(this.RedirectUri))
63 | {
64 | queryBuilder.Add("redirect_uri", this.RedirectUri);
65 | }
66 | if (!string.IsNullOrEmpty(this.ClientSecret))
67 | {
68 | queryBuilder.Add("client_secret", this.ClientSecret);
69 | }
70 | if (!string.IsNullOrEmpty(resource))
71 | {
72 | queryBuilder.Add("resource", resource);
73 | }
74 |
75 | return await PostToTokenEndPoint(queryBuilder);
76 | }
77 |
78 | private async Task PostToTokenEndPoint(QueryStringBuilder queryBuilder)
79 | {
80 | HttpWebRequest request = WebRequest.CreateHttp(this.TokenService);
81 | request.Method = "POST";
82 | request.ContentType = "application/x-www-form-urlencoded";
83 |
84 | using (StreamWriter requestWriter = new StreamWriter(await request.GetRequestStreamAsync()))
85 | {
86 | await requestWriter.WriteAsync(queryBuilder.ToString());
87 | await requestWriter.FlushAsync();
88 | }
89 |
90 | HttpWebResponse httpResponse;
91 | try
92 | {
93 | var response = await request.GetResponseAsync();
94 | httpResponse = response as HttpWebResponse;
95 | }
96 | catch (WebException webex)
97 | {
98 | httpResponse = webex.Response as HttpWebResponse;
99 | }
100 | catch (Exception)
101 | {
102 | return null;
103 | }
104 |
105 | if (httpResponse == null)
106 | {
107 | return null;
108 | }
109 |
110 | try
111 | {
112 | if (httpResponse.StatusCode != HttpStatusCode.OK)
113 | {
114 | return null;
115 | }
116 |
117 | using (var responseBodyStreamReader = new StreamReader(httpResponse.GetResponseStream()))
118 | {
119 | var responseBody = await responseBodyStreamReader.ReadToEndAsync();
120 | var tokenResult = Newtonsoft.Json.JsonConvert.DeserializeObject(responseBody);
121 |
122 | httpResponse.Dispose();
123 | return tokenResult;
124 | }
125 | }
126 | catch (Exception)
127 | {
128 | return null;
129 | }
130 | finally
131 | {
132 | httpResponse.Dispose();
133 | }
134 | }
135 |
136 | internal static OAuthHelper HelperForService(string service, string redirectUri)
137 | {
138 | if (service == "business")
139 | {
140 | return new OAuthHelper(ConfigurationManager.AppSettings["ida:AADTokenService"],
141 | ConfigurationManager.AppSettings["ida:AADAppId"],
142 | ConfigurationManager.AppSettings["ida:AADAppSecret"],
143 | redirectUri)
144 | {
145 | IsConsumerService = false
146 | };
147 | }
148 | else if (service == "personal")
149 | {
150 | return new OAuthHelper(ConfigurationManager.AppSettings["ida:MSATokenService"],
151 | ConfigurationManager.AppSettings["ida:MSAAppId"],
152 | ConfigurationManager.AppSettings["ida:MSAAppSecret"],
153 | redirectUri)
154 | {
155 | IsConsumerService = true
156 | };
157 | }
158 |
159 | throw new ArgumentException("Invalid service: " + service);
160 | }
161 |
162 | }
163 |
164 | public class OAuthToken
165 | {
166 | [JsonProperty("token_type")]
167 | public string TokenType { get; set; }
168 |
169 | [JsonProperty("access_token")]
170 | public string AccessToken { get; set; }
171 |
172 | [JsonProperty("expires_in")]
173 | public int AccessTokenExpirationDuration { get; set; }
174 |
175 | [JsonProperty("refresh_token")]
176 | public string RefreshToken { get; set; }
177 |
178 | [JsonProperty("scope")]
179 | public string Scopes { get; set; }
180 |
181 | [JsonProperty("authentication_token")]
182 | public string AuthenticationToken { get; set; }
183 |
184 | public DateTimeOffset CreatedDateTime { get; set; }
185 |
186 | public OAuthToken()
187 | {
188 | CreatedDateTime = DateTimeOffset.UtcNow;
189 | }
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Controllers/SubscriptionController.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license.
3 | * See LICENSE in the source repository root for complete license information.
4 | */
5 |
6 | using System;
7 | using System.Configuration;
8 | using System.Linq;
9 | using System.Threading.Tasks;
10 | using System.Web.Mvc;
11 | using Microsoft.OneDrive.Sdk;
12 | using OneDriveWebhookTranslator.Models;
13 | using System.Net.Http;
14 | using Newtonsoft.Json;
15 |
16 | namespace OneDriveWebhookTranslator.Controllers
17 | {
18 | public class SubscriptionController : Controller
19 | {
20 | // GET: Subscription
21 | public ActionResult Index()
22 | {
23 | return View();
24 | }
25 |
26 | // Create webhook subscription
27 | public async Task CreateSubscription()
28 | {
29 | #region Create OneDriveClient for current user
30 | OneDriveUser user = OneDriveUser.UserForRequest(this.Request);
31 | if (null == user)
32 | {
33 | return Redirect(Url.Action("Index", "Home"));
34 | }
35 | var client = await GetOneDriveClientAsync(user);
36 | #endregion
37 |
38 | // Ensure the app folder is created first
39 | var appFolder = await client.Drive.Special["approot"].Request().GetAsync();
40 |
41 | // Create a subscription on the drive
42 | var notificationUrl = ConfigurationManager.AppSettings["ida:NotificationUrl"];
43 |
44 | Models.OneDriveSubscription subscription = new OneDriveSubscription
45 | {
46 | NotificationUrl = notificationUrl,
47 | ClientState = "my client state"
48 | };
49 | FixPPESubscriptionBug(user, subscription);
50 |
51 | // Because the OneDrive SDK does not support OneDrive subscriptions natively yet,
52 | // we use BaseRequest to generate a request the SDK can understand. You could also use HttpClient
53 | var request = new BaseRequest(client.BaseUrl + "/drive/root/subscriptions", client)
54 | {
55 | Method = "POST",
56 | ContentType = "application/json"
57 | };
58 |
59 | try
60 | {
61 | var subscriptionResponse = await request.SendAsync(subscription);
62 | if (null != subscriptionResponse)
63 | {
64 | // Store the subscription ID so we can keep track of which subscriptions are tied to which users
65 | user.SubscriptionId = subscriptionResponse.SubscriptionId;
66 |
67 | Models.SubscriptionViewModel viewModel = new Models.SubscriptionViewModel { Subscription = subscriptionResponse };
68 | return View("Subscription", viewModel);
69 | }
70 | }
71 | catch (Exception ex)
72 | {
73 | ViewBag.Message = ex.Message;
74 | }
75 |
76 | return View("Error");
77 | }
78 |
79 | private static void FixPPESubscriptionBug(OneDriveUser user, OneDriveSubscription subscription)
80 | {
81 | if (user.ClientType == ClientType.Business)
82 | {
83 | subscription.Scenarios = null;
84 |
85 | }
86 | else
87 | {
88 | subscription.SubscriptionExpirationDateTime = DateTime.Now.AddDays(3);
89 | subscription.ClientState = null;
90 | }
91 | }
92 |
93 | ///
94 | /// Delete the user's active subscription and then redirect to logout
95 | ///
96 | ///
97 | public async Task DeleteSubscription()
98 | {
99 | OneDriveUser user = OneDriveUser.UserForRequest(this.Request);
100 | if (null == user)
101 | {
102 | return Redirect(Url.Action("Index", "Home"));
103 | }
104 |
105 | if (!string.IsNullOrEmpty(user.SubscriptionId))
106 | {
107 | var client = await GetOneDriveClientAsync(user);
108 |
109 | // Because the OneDrive SDK does not support OneDrive subscriptions natively yet,
110 | // we use BaseRequest to generate a request the SDK can understand
111 | var request = new BaseRequest(client.BaseUrl + "/drive/root/subscriptions/" + user.SubscriptionId, client) { Method = "DELETE" };
112 |
113 | try
114 | {
115 | var response = await request.SendRequestAsync(null);
116 | if (!response.IsSuccessStatusCode)
117 | {
118 | ViewBag.Message = response.ReasonPhrase;
119 | return View("Error");
120 | }
121 | else
122 | {
123 | user.SubscriptionId = null;
124 | }
125 | }
126 | catch (Exception ex)
127 | {
128 | ViewBag.Message = ex.Message;
129 | return View("Error");
130 | }
131 | }
132 | return RedirectToAction("SignOut", "Account");
133 | }
134 |
135 | #region SDK helper methods
136 |
137 | ///
138 | /// Create a new instance of the OneDriveClient for the signed in user.
139 | ///
140 | ///
141 | ///
142 | internal static async Task GetOneDriveClientAsync(OneDriveUser user)
143 | {
144 | if (string.IsNullOrEmpty(user.OneDriveBaseUrl))
145 | {
146 | // Resolve the API URL for this user
147 | user.OneDriveBaseUrl = await LookupOneDriveUrl(user);
148 | }
149 |
150 | var client = new OneDriveClient(new AppConfig(), null, null, new OneDriveAccountServiceProvider(user), user.ClientType);
151 | await client.AuthenticateAsync();
152 |
153 | return client;
154 | }
155 |
156 |
157 | ///
158 | /// Use the discovery API to resolve the base URL for the OneDrive API
159 | ///
160 | ///
161 | ///
162 | internal static async Task LookupOneDriveUrl(OneDriveUser user)
163 | {
164 | if (user.ClientType == ClientType.Consumer)
165 | {
166 | return "https://api.onedrive.com/v1.0";
167 | }
168 | var accessToken = await user.GetAccessTokenAsync("https://api.office.com/discovery/");
169 |
170 | HttpClient client = new HttpClient();
171 | HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "https://api.office.com/discovery/v2.0/me/services");
172 | request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
173 | request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
174 |
175 | var response = await client.SendAsync(request);
176 | if (!response.IsSuccessStatusCode)
177 | {
178 | throw new InvalidOperationException("Unable to determine OneDrive URL: " + response.ReasonPhrase);
179 | }
180 |
181 | var services = JsonConvert.DeserializeObject(await response.Content.ReadAsStringAsync());
182 |
183 | var query = from s in services.Value
184 | where s.Capability == "MyFiles" && s.ServiceApiVersion == "v2.0"
185 | select s.ServiceEndpointUri;
186 |
187 | return query.FirstOrDefault();
188 | }
189 | #endregion
190 | }
191 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ---
2 | page_type: sample
3 | products:
4 | - office-onedrive
5 | languages:
6 | - javascript
7 | extensions:
8 | contentType: samples
9 | createdDate: 3/14/2016 10:52:16 AM
10 | ---
11 | # OneDrive Webhooks ASP.NET Sample
12 |
13 | This ASP.NET MVC sample shows how to receive notifications from OneDrive
14 | and OneDrive for Business when changes occur to files. The following are common
15 | tasks that a web application performs with OneDrive webhooks.
16 |
17 | * Sign-in your users with their Microsoft account, or a work or school account to get an access token.
18 | * Use the access token to create a webhook subscription.
19 | * Send back a validation token to confirm the notification URL.
20 | * Listen for notifications from OneDrive.
21 | * Request for more information using data in the notification.
22 |
23 | This sample subscribes to notification on the signed in user's OneDrive and
24 | displays the name of the files that were added, modified, or deleted when a
25 | notification is received.
26 |
27 | **Note:** Webhooks are still being enabled as a _preview only_ on OneDrive for Business. Webhooks functionality may not be available for your tenant yet. You can use a OneDrive Personal account to test functionality if this is the case.
28 |
29 | ## Prerequisites
30 |
31 | To use the OneDrive Webhooks sample, you need the following:
32 |
33 | * Visual Studio 2015 with Update 1 installed on your development computer.
34 |
35 | * A public HTTPS endpoint to receive and send HTTP requests. You can use
36 | Microsoft Azure or another service to host your endpoint. If you prefer, you
37 | can use ngrok (or a similar tool) while testing to temporarily allow messages
38 | from Microsoft Graph to tunnel to a port on your local computer.
39 | [Instructions for setting up ngrok](#set-up-the-ngrok-proxy-optional-) are included below.
40 |
41 | * A client ID and key for two applications:
42 | * To enable OneDrive Personal support, you need to register an application at the [Microsoft registration portal](account.live.com/developers/applications).
43 | * To enable OneDrive for Business support, you need to register an application
44 | through a Microsoft Azure Active Directory tenant. You can use the
45 | [Office 365 app registration tool](https://dev.office.com/app-registration),
46 | which simplifies the process. Use the following parameters:
47 |
48 | | Parameter | Value |
49 | |:----------------|:------------------------|
50 | | App type | Web App |
51 | | Sign on URL | http://localhost:52026/ |
52 | | Redirect URI | http://localhost:52026/ |
53 | | App permissions | Files.ReadWrite |
54 |
55 | Copy and store the returned **Client ID** and **Client Secret** values.
56 |
57 | ### Set up the ngrok proxy (optional)
58 |
59 | You must expose a public HTTPS endpoint to create a subscription and receive
60 | notifications from OneDrive. While testing, you can use ngrok to
61 | temporarily allow messages from OneDrive to tunnel to a *localhost* port
62 | on your computer. To learn more about using ngrok, see the [ngrok website](https://ngrok.com/).
63 |
64 | 1. In Solution Explorer, select the **OneDriveWebhooks** project.
65 |
66 | 2. Copy the **URL** port number from the **Properties** window. If the **Properties** window isn't showing, choose **View/Properties Window**.
67 |
68 | 
69 |
70 | 3. [Download ngrok](https://ngrok.com/download) for Windows.
71 |
72 | 4. Unzip the package and run ngrok.exe.
73 |
74 | 5. Replace the two ** placeholder values in the following command with the port number you copied, and then run the command in the ngrok console.
75 |
76 | ```
77 | ngrok http -host-header=localhost:
78 | ```
79 |
80 | 
81 |
82 | 6. Copy the HTTPS URL that's shown in the console.
83 |
84 | 
85 |
86 | >Keep the console open while testing. If you close it, the tunnel also closes
87 | >and you'll need to generate a new URL and update the sample.
88 |
89 | ## Configure and run the sample
90 |
91 | 1. Create a public HTTPS notification endpoint. It can run on a service such as
92 | Microsoft Azure, or you can create a proxy web server by [using ngrok](#ngrok)
93 | or a similar tool.
94 |
95 | 2. Open **onedrive-webhooks-aspnet.sln** in the sample files.
96 |
97 | 3. In Solution Explorer, open the **Web.config** file in the root directory of the project.
98 | a. Enter the values for your registered applications client ID into **ida:AppId**.
99 | b. Enter the values for your registered applications client secret / password into **ida:AppSecret**.
100 | c. For the **ida:NotificationUrl** key, replace *ENTER_YOUR_URL* with your
101 | HTTPS URL. Keep the */notification/listen* portion. If you're using ngrok, the
102 | value will look something like this:
103 |
104 | ```xml
105 |
106 | ```
107 |
108 | 4. Make sure that the ngrok console is still running, then press F5 to build and
109 | run the solution in debug mode.
110 |
111 |
112 | ### Use the app
113 |
114 | 1. Sign in with your Office 365 work or school account.
115 |
116 | 2. Choose the **Create subscription** button. The **Subscription** page loads
117 | with information about the subscription.
118 |
119 | 
120 |
121 | 3. Choose the **Watch for notifications** button.
122 |
123 | 4. Add or modify a file in your OneDrive account. The **Notification** page
124 | displays some message properties. It may take several seconds for the page to update.
125 |
126 | 
127 |
128 | 5. Choose the **Delete subscription and sign out** button.
129 |
130 |
131 | ## Key components of the sample
132 |
133 | The following files contain code that shows how to work with OneDrive webhooks.
134 |
135 | **Controllers**
136 | - [`NotificationController.cs`](OneDriveWebhooks/Controllers/NotificationController.cs) Receives notifications.
137 | - [`SubscriptionContoller.cs`](OneDriveWebhooks/Controllers/SubscriptionController.cs) Creates and receives webhook subscriptions.
138 |
139 | **Models**
140 | - [`OneDriveNotification.cs`](OneDriveWebhooks/Models/OneDriveNotification.cs) Represents a change notification.
141 | - [`OneDriveSubscription.cs`](OneDriveWebhooks/Models/OneDriveSubscription.cs) Represents a webhook subscription. Also defines the **SubscriptionViewModel** that represents the data displayed in the Subscription view.
142 |
143 | **Views**
144 | - [`Notification/Notification.cshtml`](OneDriveWebhooks/Views/Notification/Notification.cshtml) Displays information about received messages, and contains the **Delete subscription and sign out** button.
145 | - [`Subscription/Index.cshtml`](OneDriveWebhooks/Views/Subscription/Index.cshtml) Landing page that contains the **Create subscription** button.
146 | - [`Subscription/CreateSubscription.cshtml```](OneDriveWebhooks/Views/Subscription/Subscription.cshtml) Displays subscription properties, and contains the **Watch for notifications** button.
147 |
148 | **Other**
149 | - [`Web.config`](OneDriveWebhooks/Web.config) Contains values used for authentication and authorization.
150 | - [`Startup.cs`](OneDriveWebhooks/App_Start/Startup.cs) Contains code used for authentication and authorization when the app starts. The sample uses [OpenID Connect](https://msdn.microsoft.com/en-us/library/azure/jj573266.aspx) to authenticate and authorize the user.
151 |
152 | ## Troubleshooting
153 |
154 | | Issue | Resolution |
155 | |:--------------------------------------------------------------------------------------------------|:------------------------------------------------------------------------------------------------|
156 | | The app opens to a *Server Error in '/' Application. The resource cannot be found.* browser page. | Make sure that a CSHTML view file isn't the active tab when you run the app from Visual Studio. |
157 |
158 |
159 | ## Questions and comments
160 |
161 | We'd love to get your feedback about OneDrive Webhooks ASP.NET
162 | sample. You can send your questions and suggestions to us in the [Issues](https://github.com/OneDrive/onedrive-webhooks-aspnet)
163 | section of this repository.
164 |
165 | Questions about OneDrive or Office 365 in general should be posted to [Stack Overflow](http://stackoverflow.com/questions/tagged/OneDrive+Office365).
166 | Make sure that your questions or comments are tagged with *OneDrive* or *Office365*.
167 |
168 | You can suggest changes for OneDrive on [UserVoice](onedrive.uservoice.com/forums/262982-onedrive/category/89523-developer).
169 |
170 |
171 | ## Additional resources
172 |
173 | * [OneDrive API Reference](https://dev.onedrive.com/README.htm)
174 | * [Office 365 Developer Portal](https://dev.office.com)
175 |
176 | ## License
177 |
178 | See [LICENSE](LICENSE.md) for the license for this sample code.
179 |
180 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
181 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Scripts/respond.js:
--------------------------------------------------------------------------------
1 | /* NUGET: BEGIN LICENSE TEXT
2 | *
3 | * Microsoft grants you the right to use these script files for the sole
4 | * purpose of either: (i) interacting through your browser with the Microsoft
5 | * website or online service, subject to the applicable licensing or use
6 | * terms; or (ii) using the files as included with a Microsoft product subject
7 | * to that product's license terms. Microsoft reserves all other rights to the
8 | * files not expressly granted by Microsoft, whether by implication, estoppel
9 | * or otherwise. Insofar as a script file is dual licensed under GPL,
10 | * Microsoft neither took the code under GPL nor distributes it thereunder but
11 | * under the terms set out in this paragraph. All notices and licenses
12 | * below are for informational purposes only.
13 | *
14 | * NUGET: END LICENSE TEXT */
15 | /*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */
16 | /*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */
17 | window.matchMedia = window.matchMedia || (function(doc, undefined){
18 |
19 | var bool,
20 | docElem = doc.documentElement,
21 | refNode = docElem.firstElementChild || docElem.firstChild,
22 | // fakeBody required for
23 | fakeBody = doc.createElement('body'),
24 | div = doc.createElement('div');
25 |
26 | div.id = 'mq-test-1';
27 | div.style.cssText = "position:absolute;top:-100em";
28 | fakeBody.style.background = "none";
29 | fakeBody.appendChild(div);
30 |
31 | return function(q){
32 |
33 | div.innerHTML = '';
34 |
35 | docElem.insertBefore(fakeBody, refNode);
36 | bool = div.offsetWidth == 42;
37 | docElem.removeChild(fakeBody);
38 |
39 | return { matches: bool, media: q };
40 | };
41 |
42 | })(document);
43 |
44 |
45 |
46 |
47 | /*! Respond.js v1.2.0: min/max-width media query polyfill. (c) Scott Jehl. MIT/GPLv2 Lic. j.mp/respondjs */
48 | (function( win ){
49 | //exposed namespace
50 | win.respond = {};
51 |
52 | //define update even in native-mq-supporting browsers, to avoid errors
53 | respond.update = function(){};
54 |
55 | //expose media query support flag for external use
56 | respond.mediaQueriesSupported = win.matchMedia && win.matchMedia( "only all" ).matches;
57 |
58 | //if media queries are supported, exit here
59 | if( respond.mediaQueriesSupported ){ return; }
60 |
61 | //define vars
62 | var doc = win.document,
63 | docElem = doc.documentElement,
64 | mediastyles = [],
65 | rules = [],
66 | appendedEls = [],
67 | parsedSheets = {},
68 | resizeThrottle = 30,
69 | head = doc.getElementsByTagName( "head" )[0] || docElem,
70 | base = doc.getElementsByTagName( "base" )[0],
71 | links = head.getElementsByTagName( "link" ),
72 | requestQueue = [],
73 |
74 | //loop stylesheets, send text content to translate
75 | ripCSS = function(){
76 | var sheets = links,
77 | sl = sheets.length,
78 | i = 0,
79 | //vars for loop:
80 | sheet, href, media, isCSS;
81 |
82 | for( ; i < sl; i++ ){
83 | sheet = sheets[ i ],
84 | href = sheet.href,
85 | media = sheet.media,
86 | isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet";
87 |
88 | //only links plz and prevent re-parsing
89 | if( !!href && isCSS && !parsedSheets[ href ] ){
90 | // selectivizr exposes css through the rawCssText expando
91 | if (sheet.styleSheet && sheet.styleSheet.rawCssText) {
92 | translate( sheet.styleSheet.rawCssText, href, media );
93 | parsedSheets[ href ] = true;
94 | } else {
95 | if( (!/^([a-zA-Z:]*\/\/)/.test( href ) && !base)
96 | || href.replace( RegExp.$1, "" ).split( "/" )[0] === win.location.host ){
97 | requestQueue.push( {
98 | href: href,
99 | media: media
100 | } );
101 | }
102 | }
103 | }
104 | }
105 | makeRequests();
106 | },
107 |
108 | //recurse through request queue, get css text
109 | makeRequests = function(){
110 | if( requestQueue.length ){
111 | var thisRequest = requestQueue.shift();
112 |
113 | ajax( thisRequest.href, function( styles ){
114 | translate( styles, thisRequest.href, thisRequest.media );
115 | parsedSheets[ thisRequest.href ] = true;
116 | makeRequests();
117 | } );
118 | }
119 | },
120 |
121 | //find media blocks in css text, convert to style blocks
122 | translate = function( styles, href, media ){
123 | var qs = styles.match( /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi ),
124 | ql = qs && qs.length || 0,
125 | //try to get CSS path
126 | href = href.substring( 0, href.lastIndexOf( "/" )),
127 | repUrls = function( css ){
128 | return css.replace( /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, "$1" + href + "$2$3" );
129 | },
130 | useMedia = !ql && media,
131 | //vars used in loop
132 | i = 0,
133 | j, fullq, thisq, eachq, eql;
134 |
135 | //if path exists, tack on trailing slash
136 | if( href.length ){ href += "/"; }
137 |
138 | //if no internal queries exist, but media attr does, use that
139 | //note: this currently lacks support for situations where a media attr is specified on a link AND
140 | //its associated stylesheet has internal CSS media queries.
141 | //In those cases, the media attribute will currently be ignored.
142 | if( useMedia ){
143 | ql = 1;
144 | }
145 |
146 |
147 | for( ; i < ql; i++ ){
148 | j = 0;
149 |
150 | //media attr
151 | if( useMedia ){
152 | fullq = media;
153 | rules.push( repUrls( styles ) );
154 | }
155 | //parse for styles
156 | else{
157 | fullq = qs[ i ].match( /@media *([^\{]+)\{([\S\s]+?)$/ ) && RegExp.$1;
158 | rules.push( RegExp.$2 && repUrls( RegExp.$2 ) );
159 | }
160 |
161 | eachq = fullq.split( "," );
162 | eql = eachq.length;
163 |
164 | for( ; j < eql; j++ ){
165 | thisq = eachq[ j ];
166 | mediastyles.push( {
167 | media : thisq.split( "(" )[ 0 ].match( /(only\s+)?([a-zA-Z]+)\s?/ ) && RegExp.$2 || "all",
168 | rules : rules.length - 1,
169 | hasquery: thisq.indexOf("(") > -1,
170 | minw : thisq.match( /\(min\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" ),
171 | maxw : thisq.match( /\(max\-width:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ ) && parseFloat( RegExp.$1 ) + ( RegExp.$2 || "" )
172 | } );
173 | }
174 | }
175 |
176 | applyMedia();
177 | },
178 |
179 | lastCall,
180 |
181 | resizeDefer,
182 |
183 | // returns the value of 1em in pixels
184 | getEmValue = function() {
185 | var ret,
186 | div = doc.createElement('div'),
187 | body = doc.body,
188 | fakeUsed = false;
189 |
190 | div.style.cssText = "position:absolute;font-size:1em;width:1em";
191 |
192 | if( !body ){
193 | body = fakeUsed = doc.createElement( "body" );
194 | body.style.background = "none";
195 | }
196 |
197 | body.appendChild( div );
198 |
199 | docElem.insertBefore( body, docElem.firstChild );
200 |
201 | ret = div.offsetWidth;
202 |
203 | if( fakeUsed ){
204 | docElem.removeChild( body );
205 | }
206 | else {
207 | body.removeChild( div );
208 | }
209 |
210 | //also update eminpx before returning
211 | ret = eminpx = parseFloat(ret);
212 |
213 | return ret;
214 | },
215 |
216 | //cached container for 1em value, populated the first time it's needed
217 | eminpx,
218 |
219 | //enable/disable styles
220 | applyMedia = function( fromResize ){
221 | var name = "clientWidth",
222 | docElemProp = docElem[ name ],
223 | currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[ name ] || docElemProp,
224 | styleBlocks = {},
225 | lastLink = links[ links.length-1 ],
226 | now = (new Date()).getTime();
227 |
228 | //throttle resize calls
229 | if( fromResize && lastCall && now - lastCall < resizeThrottle ){
230 | clearTimeout( resizeDefer );
231 | resizeDefer = setTimeout( applyMedia, resizeThrottle );
232 | return;
233 | }
234 | else {
235 | lastCall = now;
236 | }
237 |
238 | for( var i in mediastyles ){
239 | var thisstyle = mediastyles[ i ],
240 | min = thisstyle.minw,
241 | max = thisstyle.maxw,
242 | minnull = min === null,
243 | maxnull = max === null,
244 | em = "em";
245 |
246 | if( !!min ){
247 | min = parseFloat( min ) * ( min.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
248 | }
249 | if( !!max ){
250 | max = parseFloat( max ) * ( max.indexOf( em ) > -1 ? ( eminpx || getEmValue() ) : 1 );
251 | }
252 |
253 | // if there's no media query at all (the () part), or min or max is not null, and if either is present, they're true
254 | if( !thisstyle.hasquery || ( !minnull || !maxnull ) && ( minnull || currWidth >= min ) && ( maxnull || currWidth <= max ) ){
255 | if( !styleBlocks[ thisstyle.media ] ){
256 | styleBlocks[ thisstyle.media ] = [];
257 | }
258 | styleBlocks[ thisstyle.media ].push( rules[ thisstyle.rules ] );
259 | }
260 | }
261 |
262 | //remove any existing respond style element(s)
263 | for( var i in appendedEls ){
264 | if( appendedEls[ i ] && appendedEls[ i ].parentNode === head ){
265 | head.removeChild( appendedEls[ i ] );
266 | }
267 | }
268 |
269 | //inject active styles, grouped by media type
270 | for( var i in styleBlocks ){
271 | var ss = doc.createElement( "style" ),
272 | css = styleBlocks[ i ].join( "\n" );
273 |
274 | ss.type = "text/css";
275 | ss.media = i;
276 |
277 | //originally, ss was appended to a documentFragment and sheets were appended in bulk.
278 | //this caused crashes in IE in a number of circumstances, such as when the HTML element had a bg image set, so appending beforehand seems best. Thanks to @dvelyk for the initial research on this one!
279 | head.insertBefore( ss, lastLink.nextSibling );
280 |
281 | if ( ss.styleSheet ){
282 | ss.styleSheet.cssText = css;
283 | }
284 | else {
285 | ss.appendChild( doc.createTextNode( css ) );
286 | }
287 |
288 | //push to appendedEls to track for later removal
289 | appendedEls.push( ss );
290 | }
291 | },
292 | //tweaked Ajax functions from Quirksmode
293 | ajax = function( url, callback ) {
294 | var req = xmlHttp();
295 | if (!req){
296 | return;
297 | }
298 | req.open( "GET", url, true );
299 | req.onreadystatechange = function () {
300 | if ( req.readyState != 4 || req.status != 200 && req.status != 304 ){
301 | return;
302 | }
303 | callback( req.responseText );
304 | }
305 | if ( req.readyState == 4 ){
306 | return;
307 | }
308 | req.send( null );
309 | },
310 | //define ajax obj
311 | xmlHttp = (function() {
312 | var xmlhttpmethod = false;
313 | try {
314 | xmlhttpmethod = new XMLHttpRequest();
315 | }
316 | catch( e ){
317 | xmlhttpmethod = new ActiveXObject( "Microsoft.XMLHTTP" );
318 | }
319 | return function(){
320 | return xmlhttpmethod;
321 | };
322 | })();
323 |
324 | //translate CSS
325 | ripCSS();
326 |
327 | //expose update for re-running respond later on
328 | respond.update = ripCSS;
329 |
330 | //adjust on resize
331 | function callMedia(){
332 | applyMedia( true );
333 | }
334 | if( win.addEventListener ){
335 | win.addEventListener( "resize", callMedia, false );
336 | }
337 | else if( win.attachEvent ){
338 | win.attachEvent( "onresize", callMedia );
339 | }
340 | })(this);
341 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/OneDriveWebhooks.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | Debug
8 | AnyCPU
9 |
10 |
11 | 2.0
12 | {8728D262-D20E-45AE-AA9B-306F0DA8CBC5}
13 | {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc}
14 | Library
15 | Properties
16 | OneDriveWebhookTranslator
17 | OneDriveWebhookTranslator
18 | v4.5.2
19 | false
20 | true
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 | true
32 | full
33 | false
34 | bin\
35 | DEBUG;TRACE
36 | prompt
37 | 4
38 |
39 |
40 | pdbonly
41 | true
42 | bin\
43 | TRACE
44 | prompt
45 | 4
46 |
47 |
48 |
49 | ..\packages\Microsoft.AspNet.SignalR.Core.2.2.0\lib\net45\Microsoft.AspNet.SignalR.Core.dll
50 | True
51 |
52 |
53 | ..\packages\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.1.0.0\lib\net45\Microsoft.CodeDom.Providers.DotNetCompilerPlatform.dll
54 | True
55 |
56 |
57 |
58 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.19.208020213\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
59 | True
60 |
61 |
62 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.2.19.208020213\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.WindowsForms.dll
63 | True
64 |
65 |
66 | ..\packages\Microsoft.Owin.3.0.1\lib\net45\Microsoft.Owin.dll
67 | True
68 |
69 |
70 | ..\packages\Microsoft.Owin.Host.SystemWeb.3.0.1\lib\net45\Microsoft.Owin.Host.SystemWeb.dll
71 | True
72 |
73 |
74 | ..\packages\Microsoft.Owin.Security.2.1.0\lib\net45\Microsoft.Owin.Security.dll
75 | True
76 |
77 |
78 | ..\packages\Newtonsoft.Json.7.0.1\lib\net45\Newtonsoft.Json.dll
79 | True
80 |
81 |
82 | ..\packages\Microsoft.OneDriveSDK.1.1.29\lib\net451\OneDriveSdk.dll
83 | True
84 |
85 |
86 | ..\packages\Microsoft.OneDriveSDK.1.1.29\lib\net451\OneDriveSdk.WindowsForms.dll
87 | True
88 |
89 |
90 | ..\packages\Owin.1.0\lib\net40\Owin.dll
91 | True
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 | True
113 | ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll
114 |
115 |
116 |
117 |
118 |
119 |
120 | True
121 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.Helpers.dll
122 |
123 |
124 | True
125 | ..\packages\Microsoft.AspNet.Mvc.5.2.3\lib\net45\System.Web.Mvc.dll
126 |
127 |
128 | ..\packages\Microsoft.AspNet.Web.Optimization.1.1.3\lib\net40\System.Web.Optimization.dll
129 |
130 |
131 | True
132 | ..\packages\Microsoft.AspNet.Razor.3.2.3\lib\net45\System.Web.Razor.dll
133 |
134 |
135 | True
136 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.dll
137 |
138 |
139 | True
140 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Deployment.dll
141 |
142 |
143 | True
144 | ..\packages\Microsoft.AspNet.WebPages.3.2.3\lib\net45\System.Web.WebPages.Razor.dll
145 |
146 |
147 | True
148 | ..\packages\WebGrease.1.5.2\lib\WebGrease.dll
149 |
150 |
151 | True
152 | ..\packages\Antlr.3.4.1.9004\lib\Antlr3.Runtime.dll
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 | Global.asax
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 | Designer
210 |
211 |
212 | Web.config
213 |
214 |
215 | Web.config
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 | 10.0
241 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
251 |
252 |
253 | True
254 | True
255 | 52026
256 | /
257 | http://localhost:52026/
258 | False
259 | False
260 |
261 |
262 | False
263 |
264 |
265 |
266 |
267 |
268 |
269 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.
270 |
271 |
272 |
273 |
274 |
280 |
--------------------------------------------------------------------------------
/OneDriveWebhooks/Scripts/jquery.validate.min.js:
--------------------------------------------------------------------------------
1 | /* NUGET: BEGIN LICENSE TEXT
2 | *
3 | * Microsoft grants you the right to use these script files for the sole
4 | * purpose of either: (i) interacting through your browser with the Microsoft
5 | * website or online service, subject to the applicable licensing or use
6 | * terms; or (ii) using the files as included with a Microsoft product subject
7 | * to that product's license terms. Microsoft reserves all other rights to the
8 | * files not expressly granted by Microsoft, whether by implication, estoppel
9 | * or otherwise. Insofar as a script file is dual licensed under GPL,
10 | * Microsoft neither took the code under GPL nor distributes it thereunder but
11 | * under the terms set out in this paragraph. All notices and licenses
12 | * below are for informational purposes only.
13 | *
14 | * NUGET: END LICENSE TEXT */
15 | /*! jQuery Validation Plugin - v1.11.1 - 3/22/2013\n* https://github.com/jzaefferer/jquery-validation
16 | * Copyright (c) 2013 Jörn Zaefferer; Licensed MIT */(function(t){t.extend(t.fn,{validate:function(e){if(!this.length)return e&&e.debug&&window.console&&console.warn("Nothing selected, can't validate, returning nothing."),void 0;var i=t.data(this[0],"validator");return i?i:(this.attr("novalidate","novalidate"),i=new t.validator(e,this[0]),t.data(this[0],"validator",i),i.settings.onsubmit&&(this.validateDelegate(":submit","click",function(e){i.settings.submitHandler&&(i.submitButton=e.target),t(e.target).hasClass("cancel")&&(i.cancelSubmit=!0),void 0!==t(e.target).attr("formnovalidate")&&(i.cancelSubmit=!0)}),this.submit(function(e){function s(){var s;return i.settings.submitHandler?(i.submitButton&&(s=t(" ").attr("name",i.submitButton.name).val(t(i.submitButton).val()).appendTo(i.currentForm)),i.settings.submitHandler.call(i,i.currentForm,e),i.submitButton&&s.remove(),!1):!0}return i.settings.debug&&e.preventDefault(),i.cancelSubmit?(i.cancelSubmit=!1,s()):i.form()?i.pendingRequest?(i.formSubmitted=!0,!1):s():(i.focusInvalid(),!1)})),i)},valid:function(){if(t(this[0]).is("form"))return this.validate().form();var e=!0,i=t(this[0].form).validate();return this.each(function(){e=e&&i.element(this)}),e},removeAttrs:function(e){var i={},s=this;return t.each(e.split(/\s/),function(t,e){i[e]=s.attr(e),s.removeAttr(e)}),i},rules:function(e,i){var s=this[0];if(e){var r=t.data(s.form,"validator").settings,n=r.rules,a=t.validator.staticRules(s);switch(e){case"add":t.extend(a,t.validator.normalizeRule(i)),delete a.messages,n[s.name]=a,i.messages&&(r.messages[s.name]=t.extend(r.messages[s.name],i.messages));break;case"remove":if(!i)return delete n[s.name],a;var u={};return t.each(i.split(/\s/),function(t,e){u[e]=a[e],delete a[e]}),u}}var o=t.validator.normalizeRules(t.extend({},t.validator.classRules(s),t.validator.attributeRules(s),t.validator.dataRules(s),t.validator.staticRules(s)),s);if(o.required){var l=o.required;delete o.required,o=t.extend({required:l},o)}return o}}),t.extend(t.expr[":"],{blank:function(e){return!t.trim(""+t(e).val())},filled:function(e){return!!t.trim(""+t(e).val())},unchecked:function(e){return!t(e).prop("checked")}}),t.validator=function(e,i){this.settings=t.extend(!0,{},t.validator.defaults,e),this.currentForm=i,this.init()},t.validator.format=function(e,i){return 1===arguments.length?function(){var i=t.makeArray(arguments);return i.unshift(e),t.validator.format.apply(this,i)}:(arguments.length>2&&i.constructor!==Array&&(i=t.makeArray(arguments).slice(1)),i.constructor!==Array&&(i=[i]),t.each(i,function(t,i){e=e.replace(RegExp("\\{"+t+"\\}","g"),function(){return i})}),e)},t.extend(t.validator,{defaults:{messages:{},groups:{},rules:{},errorClass:"error",validClass:"valid",errorElement:"label",focusInvalid:!0,errorContainer:t([]),errorLabelContainer:t([]),onsubmit:!0,ignore:":hidden",ignoreTitle:!1,onfocusin:function(t){this.lastActive=t,this.settings.focusCleanup&&!this.blockFocusCleanup&&(this.settings.unhighlight&&this.settings.unhighlight.call(this,t,this.settings.errorClass,this.settings.validClass),this.addWrapper(this.errorsFor(t)).hide())},onfocusout:function(t){this.checkable(t)||!(t.name in this.submitted)&&this.optional(t)||this.element(t)},onkeyup:function(t,e){(9!==e.which||""!==this.elementValue(t))&&(t.name in this.submitted||t===this.lastElement)&&this.element(t)},onclick:function(t){t.name in this.submitted?this.element(t):t.parentNode.name in this.submitted&&this.element(t.parentNode)},highlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).addClass(i).removeClass(s):t(e).addClass(i).removeClass(s)},unhighlight:function(e,i,s){"radio"===e.type?this.findByName(e.name).removeClass(i).addClass(s):t(e).removeClass(i).addClass(s)}},setDefaults:function(e){t.extend(t.validator.defaults,e)},messages:{required:"This field is required.",remote:"Please fix this field.",email:"Please enter a valid email address.",url:"Please enter a valid URL.",date:"Please enter a valid date.",dateISO:"Please enter a valid date (ISO).",number:"Please enter a valid number.",digits:"Please enter only digits.",creditcard:"Please enter a valid credit card number.",equalTo:"Please enter the same value again.",maxlength:t.validator.format("Please enter no more than {0} characters."),minlength:t.validator.format("Please enter at least {0} characters."),rangelength:t.validator.format("Please enter a value between {0} and {1} characters long."),range:t.validator.format("Please enter a value between {0} and {1}."),max:t.validator.format("Please enter a value less than or equal to {0}."),min:t.validator.format("Please enter a value greater than or equal to {0}.")},autoCreateRanges:!1,prototype:{init:function(){function e(e){var i=t.data(this[0].form,"validator"),s="on"+e.type.replace(/^validate/,"");i.settings[s]&&i.settings[s].call(i,this[0],e)}this.labelContainer=t(this.settings.errorLabelContainer),this.errorContext=this.labelContainer.length&&this.labelContainer||t(this.currentForm),this.containers=t(this.settings.errorContainer).add(this.settings.errorLabelContainer),this.submitted={},this.valueCache={},this.pendingRequest=0,this.pending={},this.invalid={},this.reset();var i=this.groups={};t.each(this.settings.groups,function(e,s){"string"==typeof s&&(s=s.split(/\s/)),t.each(s,function(t,s){i[s]=e})});var s=this.settings.rules;t.each(s,function(e,i){s[e]=t.validator.normalizeRule(i)}),t(this.currentForm).validateDelegate(":text, [type='password'], [type='file'], select, textarea, [type='number'], [type='search'] ,[type='tel'], [type='url'], [type='email'], [type='datetime'], [type='date'], [type='month'], [type='week'], [type='time'], [type='datetime-local'], [type='range'], [type='color'] ","focusin focusout keyup",e).validateDelegate("[type='radio'], [type='checkbox'], select, option","click",e),this.settings.invalidHandler&&t(this.currentForm).bind("invalid-form.validate",this.settings.invalidHandler)},form:function(){return this.checkForm(),t.extend(this.submitted,this.errorMap),this.invalid=t.extend({},this.errorMap),this.valid()||t(this.currentForm).triggerHandler("invalid-form",[this]),this.showErrors(),this.valid()},checkForm:function(){this.prepareForm();for(var t=0,e=this.currentElements=this.elements();e[t];t++)this.check(e[t]);return this.valid()},element:function(e){e=this.validationTargetFor(this.clean(e)),this.lastElement=e,this.prepareElement(e),this.currentElements=t(e);var i=this.check(e)!==!1;return i?delete this.invalid[e.name]:this.invalid[e.name]=!0,this.numberOfInvalids()||(this.toHide=this.toHide.add(this.containers)),this.showErrors(),i},showErrors:function(e){if(e){t.extend(this.errorMap,e),this.errorList=[];for(var i in e)this.errorList.push({message:e[i],element:this.findByName(i)[0]});this.successList=t.grep(this.successList,function(t){return!(t.name in e)})}this.settings.showErrors?this.settings.showErrors.call(this,this.errorMap,this.errorList):this.defaultShowErrors()},resetForm:function(){t.fn.resetForm&&t(this.currentForm).resetForm(),this.submitted={},this.lastElement=null,this.prepareForm(),this.hideErrors(),this.elements().removeClass(this.settings.errorClass).removeData("previousValue")},numberOfInvalids:function(){return this.objectLength(this.invalid)},objectLength:function(t){var e=0;for(var i in t)e++;return e},hideErrors:function(){this.addWrapper(this.toHide).hide()},valid:function(){return 0===this.size()},size:function(){return this.errorList.length},focusInvalid:function(){if(this.settings.focusInvalid)try{t(this.findLastActive()||this.errorList.length&&this.errorList[0].element||[]).filter(":visible").focus().trigger("focusin")}catch(e){}},findLastActive:function(){var e=this.lastActive;return e&&1===t.grep(this.errorList,function(t){return t.element.name===e.name}).length&&e},elements:function(){var e=this,i={};return t(this.currentForm).find("input, select, textarea").not(":submit, :reset, :image, [disabled]").not(this.settings.ignore).filter(function(){return!this.name&&e.settings.debug&&window.console&&console.error("%o has no name assigned",this),this.name in i||!e.objectLength(t(this).rules())?!1:(i[this.name]=!0,!0)})},clean:function(e){return t(e)[0]},errors:function(){var e=this.settings.errorClass.replace(" ",".");return t(this.settings.errorElement+"."+e,this.errorContext)},reset:function(){this.successList=[],this.errorList=[],this.errorMap={},this.toShow=t([]),this.toHide=t([]),this.currentElements=t([])},prepareForm:function(){this.reset(),this.toHide=this.errors().add(this.containers)},prepareElement:function(t){this.reset(),this.toHide=this.errorsFor(t)},elementValue:function(e){var i=t(e).attr("type"),s=t(e).val();return"radio"===i||"checkbox"===i?t("input[name='"+t(e).attr("name")+"']:checked").val():"string"==typeof s?s.replace(/\r/g,""):s},check:function(e){e=this.validationTargetFor(this.clean(e));var i,s=t(e).rules(),r=!1,n=this.elementValue(e);for(var a in s){var u={method:a,parameters:s[a]};try{if(i=t.validator.methods[a].call(this,n,e,u.parameters),"dependency-mismatch"===i){r=!0;continue}if(r=!1,"pending"===i)return this.toHide=this.toHide.not(this.errorsFor(e)),void 0;if(!i)return this.formatAndAdd(e,u),!1}catch(o){throw this.settings.debug&&window.console&&console.log("Exception occurred when checking element "+e.id+", check the '"+u.method+"' method.",o),o}}return r?void 0:(this.objectLength(s)&&this.successList.push(e),!0)},customDataMessage:function(e,i){return t(e).data("msg-"+i.toLowerCase())||e.attributes&&t(e).attr("data-msg-"+i.toLowerCase())},customMessage:function(t,e){var i=this.settings.messages[t];return i&&(i.constructor===String?i:i[e])},findDefined:function(){for(var t=0;arguments.length>t;t++)if(void 0!==arguments[t])return arguments[t];return void 0},defaultMessage:function(e,i){return this.findDefined(this.customMessage(e.name,i),this.customDataMessage(e,i),!this.settings.ignoreTitle&&e.title||void 0,t.validator.messages[i],"Warning: No message defined for "+e.name+" ")},formatAndAdd:function(e,i){var s=this.defaultMessage(e,i.method),r=/\$?\{(\d+)\}/g;"function"==typeof s?s=s.call(this,i.parameters,e):r.test(s)&&(s=t.validator.format(s.replace(r,"{$1}"),i.parameters)),this.errorList.push({message:s,element:e}),this.errorMap[e.name]=s,this.submitted[e.name]=s},addWrapper:function(t){return this.settings.wrapper&&(t=t.add(t.parent(this.settings.wrapper))),t},defaultShowErrors:function(){var t,e;for(t=0;this.errorList[t];t++){var i=this.errorList[t];this.settings.highlight&&this.settings.highlight.call(this,i.element,this.settings.errorClass,this.settings.validClass),this.showLabel(i.element,i.message)}if(this.errorList.length&&(this.toShow=this.toShow.add(this.containers)),this.settings.success)for(t=0;this.successList[t];t++)this.showLabel(this.successList[t]);if(this.settings.unhighlight)for(t=0,e=this.validElements();e[t];t++)this.settings.unhighlight.call(this,e[t],this.settings.errorClass,this.settings.validClass);this.toHide=this.toHide.not(this.toShow),this.hideErrors(),this.addWrapper(this.toShow).show()},validElements:function(){return this.currentElements.not(this.invalidElements())},invalidElements:function(){return t(this.errorList).map(function(){return this.element})},showLabel:function(e,i){var s=this.errorsFor(e);s.length?(s.removeClass(this.settings.validClass).addClass(this.settings.errorClass),s.html(i)):(s=t("<"+this.settings.errorElement+">").attr("for",this.idOrName(e)).addClass(this.settings.errorClass).html(i||""),this.settings.wrapper&&(s=s.hide().show().wrap("<"+this.settings.wrapper+"/>").parent()),this.labelContainer.append(s).length||(this.settings.errorPlacement?this.settings.errorPlacement(s,t(e)):s.insertAfter(e))),!i&&this.settings.success&&(s.text(""),"string"==typeof this.settings.success?s.addClass(this.settings.success):this.settings.success(s,e)),this.toShow=this.toShow.add(s)},errorsFor:function(e){var i=this.idOrName(e);return this.errors().filter(function(){return t(this).attr("for")===i})},idOrName:function(t){return this.groups[t.name]||(this.checkable(t)?t.name:t.id||t.name)},validationTargetFor:function(t){return this.checkable(t)&&(t=this.findByName(t.name).not(this.settings.ignore)[0]),t},checkable:function(t){return/radio|checkbox/i.test(t.type)},findByName:function(e){return t(this.currentForm).find("[name='"+e+"']")},getLength:function(e,i){switch(i.nodeName.toLowerCase()){case"select":return t("option:selected",i).length;case"input":if(this.checkable(i))return this.findByName(i.name).filter(":checked").length}return e.length},depend:function(t,e){return this.dependTypes[typeof t]?this.dependTypes[typeof t](t,e):!0},dependTypes:{"boolean":function(t){return t},string:function(e,i){return!!t(e,i.form).length},"function":function(t,e){return t(e)}},optional:function(e){var i=this.elementValue(e);return!t.validator.methods.required.call(this,i,e)&&"dependency-mismatch"},startRequest:function(t){this.pending[t.name]||(this.pendingRequest++,this.pending[t.name]=!0)},stopRequest:function(e,i){this.pendingRequest--,0>this.pendingRequest&&(this.pendingRequest=0),delete this.pending[e.name],i&&0===this.pendingRequest&&this.formSubmitted&&this.form()?(t(this.currentForm).submit(),this.formSubmitted=!1):!i&&0===this.pendingRequest&&this.formSubmitted&&(t(this.currentForm).triggerHandler("invalid-form",[this]),this.formSubmitted=!1)},previousValue:function(e){return t.data(e,"previousValue")||t.data(e,"previousValue",{old:null,valid:!0,message:this.defaultMessage(e,"remote")})}},classRuleSettings:{required:{required:!0},email:{email:!0},url:{url:!0},date:{date:!0},dateISO:{dateISO:!0},number:{number:!0},digits:{digits:!0},creditcard:{creditcard:!0}},addClassRules:function(e,i){e.constructor===String?this.classRuleSettings[e]=i:t.extend(this.classRuleSettings,e)},classRules:function(e){var i={},s=t(e).attr("class");return s&&t.each(s.split(" "),function(){this in t.validator.classRuleSettings&&t.extend(i,t.validator.classRuleSettings[this])}),i},attributeRules:function(e){var i={},s=t(e),r=s[0].getAttribute("type");for(var n in t.validator.methods){var a;"required"===n?(a=s.get(0).getAttribute(n),""===a&&(a=!0),a=!!a):a=s.attr(n),/min|max/.test(n)&&(null===r||/number|range|text/.test(r))&&(a=Number(a)),a?i[n]=a:r===n&&"range"!==r&&(i[n]=!0)}return i.maxlength&&/-1|2147483647|524288/.test(i.maxlength)&&delete i.maxlength,i},dataRules:function(e){var i,s,r={},n=t(e);for(i in t.validator.methods)s=n.data("rule-"+i.toLowerCase()),void 0!==s&&(r[i]=s);return r},staticRules:function(e){var i={},s=t.data(e.form,"validator");return s.settings.rules&&(i=t.validator.normalizeRule(s.settings.rules[e.name])||{}),i},normalizeRules:function(e,i){return t.each(e,function(s,r){if(r===!1)return delete e[s],void 0;if(r.param||r.depends){var n=!0;switch(typeof r.depends){case"string":n=!!t(r.depends,i.form).length;break;case"function":n=r.depends.call(i,i)}n?e[s]=void 0!==r.param?r.param:!0:delete e[s]}}),t.each(e,function(s,r){e[s]=t.isFunction(r)?r(i):r}),t.each(["minlength","maxlength"],function(){e[this]&&(e[this]=Number(e[this]))}),t.each(["rangelength","range"],function(){var i;e[this]&&(t.isArray(e[this])?e[this]=[Number(e[this][0]),Number(e[this][1])]:"string"==typeof e[this]&&(i=e[this].split(/[\s,]+/),e[this]=[Number(i[0]),Number(i[1])]))}),t.validator.autoCreateRanges&&(e.min&&e.max&&(e.range=[e.min,e.max],delete e.min,delete e.max),e.minlength&&e.maxlength&&(e.rangelength=[e.minlength,e.maxlength],delete e.minlength,delete e.maxlength)),e},normalizeRule:function(e){if("string"==typeof e){var i={};t.each(e.split(/\s/),function(){i[this]=!0}),e=i}return e},addMethod:function(e,i,s){t.validator.methods[e]=i,t.validator.messages[e]=void 0!==s?s:t.validator.messages[e],3>i.length&&t.validator.addClassRules(e,t.validator.normalizeRule(e))},methods:{required:function(e,i,s){if(!this.depend(s,i))return"dependency-mismatch";if("select"===i.nodeName.toLowerCase()){var r=t(i).val();return r&&r.length>0}return this.checkable(i)?this.getLength(e,i)>0:t.trim(e).length>0},email:function(t,e){return this.optional(e)||/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(t)},url:function(t,e){return this.optional(e)||/^(https?|s?ftp):\/\/(((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(t)},date:function(t,e){return this.optional(e)||!/Invalid|NaN/.test(""+new Date(t))},dateISO:function(t,e){return this.optional(e)||/^\d{4}[\/\-]\d{1,2}[\/\-]\d{1,2}$/.test(t)},number:function(t,e){return this.optional(e)||/^-?(?:\d+|\d{1,3}(?:,\d{3})+)?(?:\.\d+)?$/.test(t)},digits:function(t,e){return this.optional(e)||/^\d+$/.test(t)},creditcard:function(t,e){if(this.optional(e))return"dependency-mismatch";if(/[^0-9 \-]+/.test(t))return!1;var i=0,s=0,r=!1;t=t.replace(/\D/g,"");for(var n=t.length-1;n>=0;n--){var a=t.charAt(n);s=parseInt(a,10),r&&(s*=2)>9&&(s-=9),i+=s,r=!r}return 0===i%10},minlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s},maxlength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||s>=r},rangelength:function(e,i,s){var r=t.isArray(e)?e.length:this.getLength(t.trim(e),i);return this.optional(i)||r>=s[0]&&s[1]>=r},min:function(t,e,i){return this.optional(e)||t>=i},max:function(t,e,i){return this.optional(e)||i>=t},range:function(t,e,i){return this.optional(e)||t>=i[0]&&i[1]>=t},equalTo:function(e,i,s){var r=t(s);return this.settings.onfocusout&&r.unbind(".validate-equalTo").bind("blur.validate-equalTo",function(){t(i).valid()}),e===r.val()},remote:function(e,i,s){if(this.optional(i))return"dependency-mismatch";var r=this.previousValue(i);if(this.settings.messages[i.name]||(this.settings.messages[i.name]={}),r.originalMessage=this.settings.messages[i.name].remote,this.settings.messages[i.name].remote=r.message,s="string"==typeof s&&{url:s}||s,r.old===e)return r.valid;r.old=e;var n=this;this.startRequest(i);var a={};return a[i.name]=e,t.ajax(t.extend(!0,{url:s,mode:"abort",port:"validate"+i.name,dataType:"json",data:a,success:function(s){n.settings.messages[i.name].remote=r.originalMessage;var a=s===!0||"true"===s;if(a){var u=n.formSubmitted;n.prepareElement(i),n.formSubmitted=u,n.successList.push(i),delete n.invalid[i.name],n.showErrors()}else{var o={},l=s||n.defaultMessage(i,"remote");o[i.name]=r.message=t.isFunction(l)?l(e):l,n.invalid[i.name]=!0,n.showErrors(o)}r.valid=a,n.stopRequest(i,a)}},s)),"pending"}}}),t.format=t.validator.format})(jQuery),function(t){var e={};if(t.ajaxPrefilter)t.ajaxPrefilter(function(t,i,s){var r=t.port;"abort"===t.mode&&(e[r]&&e[r].abort(),e[r]=s)});else{var i=t.ajax;t.ajax=function(s){var r=("mode"in s?s:t.ajaxSettings).mode,n=("port"in s?s:t.ajaxSettings).port;return"abort"===r?(e[n]&&e[n].abort(),e[n]=i.apply(this,arguments),e[n]):i.apply(this,arguments)}}}(jQuery),function(t){t.extend(t.fn,{validateDelegate:function(e,i,s){return this.bind(i,function(i){var r=t(i.target);return r.is(e)?s.apply(r,arguments):void 0})}})}(jQuery);
--------------------------------------------------------------------------------
/OneDriveWebhooks/Scripts/jquery.validate.unobtrusive.js:
--------------------------------------------------------------------------------
1 | /* NUGET: BEGIN LICENSE TEXT
2 | *
3 | * Microsoft grants you the right to use these script files for the sole
4 | * purpose of either: (i) interacting through your browser with the Microsoft
5 | * website or online service, subject to the applicable licensing or use
6 | * terms; or (ii) using the files as included with a Microsoft product subject
7 | * to that product's license terms. Microsoft reserves all other rights to the
8 | * files not expressly granted by Microsoft, whether by implication, estoppel
9 | * or otherwise. Insofar as a script file is dual licensed under GPL,
10 | * Microsoft neither took the code under GPL nor distributes it thereunder but
11 | * under the terms set out in this paragraph. All notices and licenses
12 | * below are for informational purposes only.
13 | *
14 | * NUGET: END LICENSE TEXT */
15 | /*!
16 | ** Unobtrusive validation support library for jQuery and jQuery Validate
17 | ** Copyright (C) Microsoft Corporation. All rights reserved.
18 | */
19 |
20 | /*jslint white: true, browser: true, onevar: true, undef: true, nomen: true, eqeqeq: true, plusplus: true, bitwise: true, regexp: true, newcap: true, immed: true, strict: false */
21 | /*global document: false, jQuery: false */
22 |
23 | (function ($) {
24 | var $jQval = $.validator,
25 | adapters,
26 | data_validation = "unobtrusiveValidation";
27 |
28 | function setValidationValues(options, ruleName, value) {
29 | options.rules[ruleName] = value;
30 | if (options.message) {
31 | options.messages[ruleName] = options.message;
32 | }
33 | }
34 |
35 | function splitAndTrim(value) {
36 | return value.replace(/^\s+|\s+$/g, "").split(/\s*,\s*/g);
37 | }
38 |
39 | function escapeAttributeValue(value) {
40 | // As mentioned on http://api.jquery.com/category/selectors/
41 | return value.replace(/([!"#$%&'()*+,./:;<=>?@\[\\\]^`{|}~])/g, "\\$1");
42 | }
43 |
44 | function getModelPrefix(fieldName) {
45 | return fieldName.substr(0, fieldName.lastIndexOf(".") + 1);
46 | }
47 |
48 | function appendModelPrefix(value, prefix) {
49 | if (value.indexOf("*.") === 0) {
50 | value = value.replace("*.", prefix);
51 | }
52 | return value;
53 | }
54 |
55 | function onError(error, inputElement) { // 'this' is the form element
56 | var container = $(this).find("[data-valmsg-for='" + escapeAttributeValue(inputElement[0].name) + "']"),
57 | replaceAttrValue = container.attr("data-valmsg-replace"),
58 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) !== false : null;
59 |
60 | container.removeClass("field-validation-valid").addClass("field-validation-error");
61 | error.data("unobtrusiveContainer", container);
62 |
63 | if (replace) {
64 | container.empty();
65 | error.removeClass("input-validation-error").appendTo(container);
66 | }
67 | else {
68 | error.hide();
69 | }
70 | }
71 |
72 | function onErrors(event, validator) { // 'this' is the form element
73 | var container = $(this).find("[data-valmsg-summary=true]"),
74 | list = container.find("ul");
75 |
76 | if (list && list.length && validator.errorList.length) {
77 | list.empty();
78 | container.addClass("validation-summary-errors").removeClass("validation-summary-valid");
79 |
80 | $.each(validator.errorList, function () {
81 | $(" ").html(this.message).appendTo(list);
82 | });
83 | }
84 | }
85 |
86 | function onSuccess(error) { // 'this' is the form element
87 | var container = error.data("unobtrusiveContainer"),
88 | replaceAttrValue = container.attr("data-valmsg-replace"),
89 | replace = replaceAttrValue ? $.parseJSON(replaceAttrValue) : null;
90 |
91 | if (container) {
92 | container.addClass("field-validation-valid").removeClass("field-validation-error");
93 | error.removeData("unobtrusiveContainer");
94 |
95 | if (replace) {
96 | container.empty();
97 | }
98 | }
99 | }
100 |
101 | function onReset(event) { // 'this' is the form element
102 | var $form = $(this),
103 | key = '__jquery_unobtrusive_validation_form_reset';
104 | if ($form.data(key)) {
105 | return;
106 | }
107 | // Set a flag that indicates we're currently resetting the form.
108 | $form.data(key, true);
109 | try {
110 | $form.data("validator").resetForm();
111 | } finally {
112 | $form.removeData(key);
113 | }
114 |
115 | $form.find(".validation-summary-errors")
116 | .addClass("validation-summary-valid")
117 | .removeClass("validation-summary-errors");
118 | $form.find(".field-validation-error")
119 | .addClass("field-validation-valid")
120 | .removeClass("field-validation-error")
121 | .removeData("unobtrusiveContainer")
122 | .find(">*") // If we were using valmsg-replace, get the underlying error
123 | .removeData("unobtrusiveContainer");
124 | }
125 |
126 | function validationInfo(form) {
127 | var $form = $(form),
128 | result = $form.data(data_validation),
129 | onResetProxy = $.proxy(onReset, form),
130 | defaultOptions = $jQval.unobtrusive.options || {},
131 | execInContext = function (name, args) {
132 | var func = defaultOptions[name];
133 | func && $.isFunction(func) && func.apply(form, args);
134 | }
135 |
136 | if (!result) {
137 | result = {
138 | options: { // options structure passed to jQuery Validate's validate() method
139 | errorClass: defaultOptions.errorClass || "input-validation-error",
140 | errorElement: defaultOptions.errorElement || "span",
141 | errorPlacement: function () {
142 | onError.apply(form, arguments);
143 | execInContext("errorPlacement", arguments);
144 | },
145 | invalidHandler: function () {
146 | onErrors.apply(form, arguments);
147 | execInContext("invalidHandler", arguments);
148 | },
149 | messages: {},
150 | rules: {},
151 | success: function () {
152 | onSuccess.apply(form, arguments);
153 | execInContext("success", arguments);
154 | }
155 | },
156 | attachValidation: function () {
157 | $form
158 | .off("reset." + data_validation, onResetProxy)
159 | .on("reset." + data_validation, onResetProxy)
160 | .validate(this.options);
161 | },
162 | validate: function () { // a validation function that is called by unobtrusive Ajax
163 | $form.validate();
164 | return $form.valid();
165 | }
166 | };
167 | $form.data(data_validation, result);
168 | }
169 |
170 | return result;
171 | }
172 |
173 | $jQval.unobtrusive = {
174 | adapters: [],
175 |
176 | parseElement: function (element, skipAttach) {
177 | ///
178 | /// Parses a single HTML element for unobtrusive validation attributes.
179 | ///
180 | /// The HTML element to be parsed.
181 | /// [Optional] true to skip attaching the
182 | /// validation to the form. If parsing just this single element, you should specify true.
183 | /// If parsing several elements, you should specify false, and manually attach the validation
184 | /// to the form when you are finished. The default is false.
185 | var $element = $(element),
186 | form = $element.parents("form")[0],
187 | valInfo, rules, messages;
188 |
189 | if (!form) { // Cannot do client-side validation without a form
190 | return;
191 | }
192 |
193 | valInfo = validationInfo(form);
194 | valInfo.options.rules[element.name] = rules = {};
195 | valInfo.options.messages[element.name] = messages = {};
196 |
197 | $.each(this.adapters, function () {
198 | var prefix = "data-val-" + this.name,
199 | message = $element.attr(prefix),
200 | paramValues = {};
201 |
202 | if (message !== undefined) { // Compare against undefined, because an empty message is legal (and falsy)
203 | prefix += "-";
204 |
205 | $.each(this.params, function () {
206 | paramValues[this] = $element.attr(prefix + this);
207 | });
208 |
209 | this.adapt({
210 | element: element,
211 | form: form,
212 | message: message,
213 | params: paramValues,
214 | rules: rules,
215 | messages: messages
216 | });
217 | }
218 | });
219 |
220 | $.extend(rules, { "__dummy__": true });
221 |
222 | if (!skipAttach) {
223 | valInfo.attachValidation();
224 | }
225 | },
226 |
227 | parse: function (selector) {
228 | ///
229 | /// Parses all the HTML elements in the specified selector. It looks for input elements decorated
230 | /// with the [data-val=true] attribute value and enables validation according to the data-val-*
231 | /// attribute values.
232 | ///
233 | /// Any valid jQuery selector.
234 |
235 | // $forms includes all forms in selector's DOM hierarchy (parent, children and self) that have at least one
236 | // element with data-val=true
237 | var $selector = $(selector),
238 | $forms = $selector.parents()
239 | .addBack()
240 | .filter("form")
241 | .add($selector.find("form"))
242 | .has("[data-val=true]");
243 |
244 | $selector.find("[data-val=true]").each(function () {
245 | $jQval.unobtrusive.parseElement(this, true);
246 | });
247 |
248 | $forms.each(function () {
249 | var info = validationInfo(this);
250 | if (info) {
251 | info.attachValidation();
252 | }
253 | });
254 | }
255 | };
256 |
257 | adapters = $jQval.unobtrusive.adapters;
258 |
259 | adapters.add = function (adapterName, params, fn) {
260 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation.
261 | /// The name of the adapter to be added. This matches the name used
262 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
263 | /// [Optional] An array of parameter names (strings) that will
264 | /// be extracted from the data-val-nnnn-mmmm HTML attributes (where nnnn is the adapter name, and
265 | /// mmmm is the parameter name).
266 | /// The function to call, which adapts the values from the HTML
267 | /// attributes into jQuery Validate rules and/or messages.
268 | ///
269 | if (!fn) { // Called with no params, just a function
270 | fn = params;
271 | params = [];
272 | }
273 | this.push({ name: adapterName, params: params, adapt: fn });
274 | return this;
275 | };
276 |
277 | adapters.addBool = function (adapterName, ruleName) {
278 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
279 | /// the jQuery Validate validation rule has no parameter values.
280 | /// The name of the adapter to be added. This matches the name used
281 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
282 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
283 | /// of adapterName will be used instead.
284 | ///
285 | return this.add(adapterName, function (options) {
286 | setValidationValues(options, ruleName || adapterName, true);
287 | });
288 | };
289 |
290 | adapters.addMinMax = function (adapterName, minRuleName, maxRuleName, minMaxRuleName, minAttribute, maxAttribute) {
291 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
292 | /// the jQuery Validate validation has three potential rules (one for min-only, one for max-only, and
293 | /// one for min-and-max). The HTML parameters are expected to be named -min and -max.
294 | /// The name of the adapter to be added. This matches the name used
295 | /// in the data-val-nnnn HTML attribute (where nnnn is the adapter name).
296 | /// The name of the jQuery Validate rule to be used when you only
297 | /// have a minimum value.
298 | /// The name of the jQuery Validate rule to be used when you only
299 | /// have a maximum value.
300 | /// The name of the jQuery Validate rule to be used when you
301 | /// have both a minimum and maximum value.
302 | /// [Optional] The name of the HTML attribute that
303 | /// contains the minimum value. The default is "min".
304 | /// [Optional] The name of the HTML attribute that
305 | /// contains the maximum value. The default is "max".
306 | ///
307 | return this.add(adapterName, [minAttribute || "min", maxAttribute || "max"], function (options) {
308 | var min = options.params.min,
309 | max = options.params.max;
310 |
311 | if (min && max) {
312 | setValidationValues(options, minMaxRuleName, [min, max]);
313 | }
314 | else if (min) {
315 | setValidationValues(options, minRuleName, min);
316 | }
317 | else if (max) {
318 | setValidationValues(options, maxRuleName, max);
319 | }
320 | });
321 | };
322 |
323 | adapters.addSingleVal = function (adapterName, attribute, ruleName) {
324 | /// Adds a new adapter to convert unobtrusive HTML into a jQuery Validate validation, where
325 | /// the jQuery Validate validation rule has a single value.
326 | /// The name of the adapter to be added. This matches the name used
327 | /// in the data-val-nnnn HTML attribute(where nnnn is the adapter name).
328 | /// [Optional] The name of the HTML attribute that contains the value.
329 | /// The default is "val".
330 | /// [Optional] The name of the jQuery Validate rule. If not provided, the value
331 | /// of adapterName will be used instead.
332 | ///
333 | return this.add(adapterName, [attribute || "val"], function (options) {
334 | setValidationValues(options, ruleName || adapterName, options.params[attribute]);
335 | });
336 | };
337 |
338 | $jQval.addMethod("__dummy__", function (value, element, params) {
339 | return true;
340 | });
341 |
342 | $jQval.addMethod("regex", function (value, element, params) {
343 | var match;
344 | if (this.optional(element)) {
345 | return true;
346 | }
347 |
348 | match = new RegExp(params).exec(value);
349 | return (match && (match.index === 0) && (match[0].length === value.length));
350 | });
351 |
352 | $jQval.addMethod("nonalphamin", function (value, element, nonalphamin) {
353 | var match;
354 | if (nonalphamin) {
355 | match = value.match(/\W/g);
356 | match = match && match.length >= nonalphamin;
357 | }
358 | return match;
359 | });
360 |
361 | if ($jQval.methods.extension) {
362 | adapters.addSingleVal("accept", "mimtype");
363 | adapters.addSingleVal("extension", "extension");
364 | } else {
365 | // for backward compatibility, when the 'extension' validation method does not exist, such as with versions
366 | // of JQuery Validation plugin prior to 1.10, we should use the 'accept' method for
367 | // validating the extension, and ignore mime-type validations as they are not supported.
368 | adapters.addSingleVal("extension", "extension", "accept");
369 | }
370 |
371 | adapters.addSingleVal("regex", "pattern");
372 | adapters.addBool("creditcard").addBool("date").addBool("digits").addBool("email").addBool("number").addBool("url");
373 | adapters.addMinMax("length", "minlength", "maxlength", "rangelength").addMinMax("range", "min", "max", "range");
374 | adapters.addMinMax("minlength", "minlength").addMinMax("maxlength", "minlength", "maxlength");
375 | adapters.add("equalto", ["other"], function (options) {
376 | var prefix = getModelPrefix(options.element.name),
377 | other = options.params.other,
378 | fullOtherName = appendModelPrefix(other, prefix),
379 | element = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(fullOtherName) + "']")[0];
380 |
381 | setValidationValues(options, "equalTo", element);
382 | });
383 | adapters.add("required", function (options) {
384 | // jQuery Validate equates "required" with "mandatory" for checkbox elements
385 | if (options.element.tagName.toUpperCase() !== "INPUT" || options.element.type.toUpperCase() !== "CHECKBOX") {
386 | setValidationValues(options, "required", true);
387 | }
388 | });
389 | adapters.add("remote", ["url", "type", "additionalfields"], function (options) {
390 | var value = {
391 | url: options.params.url,
392 | type: options.params.type || "GET",
393 | data: {}
394 | },
395 | prefix = getModelPrefix(options.element.name);
396 |
397 | $.each(splitAndTrim(options.params.additionalfields || options.element.name), function (i, fieldName) {
398 | var paramName = appendModelPrefix(fieldName, prefix);
399 | value.data[paramName] = function () {
400 | var field = $(options.form).find(":input").filter("[name='" + escapeAttributeValue(paramName) + "']");
401 | // For checkboxes and radio buttons, only pick up values from checked fields.
402 | if (field.is(":checkbox")) {
403 | return field.filter(":checked").val() || field.filter(":hidden").val() || '';
404 | }
405 | else if (field.is(":radio")) {
406 | return field.filter(":checked").val() || '';
407 | }
408 | return field.val();
409 | };
410 | });
411 |
412 | setValidationValues(options, "remote", value);
413 | });
414 | adapters.add("password", ["min", "nonalphamin", "regex"], function (options) {
415 | if (options.params.min) {
416 | setValidationValues(options, "minlength", options.params.min);
417 | }
418 | if (options.params.nonalphamin) {
419 | setValidationValues(options, "nonalphamin", options.params.nonalphamin);
420 | }
421 | if (options.params.regex) {
422 | setValidationValues(options, "regex", options.params.regex);
423 | }
424 | });
425 |
426 | $(function () {
427 | $jQval.unobtrusive.parse(document);
428 | });
429 | }(jQuery));
--------------------------------------------------------------------------------
/OneDriveWebhooks/Content/bootstrap-theme.min.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.4.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;text-shadow:0 1px 0 #fff;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x;background-color:#e8e8e8}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x;background-color:#2e6da4}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)}
6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */
--------------------------------------------------------------------------------
/OneDriveWebhooks/Content/bootstrap-theme.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap v3.4.1 (https://getbootstrap.com/)
3 | * Copyright 2011-2019 Twitter, Inc.
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
5 | */
6 | .btn-default,
7 | .btn-primary,
8 | .btn-success,
9 | .btn-info,
10 | .btn-warning,
11 | .btn-danger {
12 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.2);
13 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
14 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
15 | }
16 | .btn-default:active,
17 | .btn-primary:active,
18 | .btn-success:active,
19 | .btn-info:active,
20 | .btn-warning:active,
21 | .btn-danger:active,
22 | .btn-default.active,
23 | .btn-primary.active,
24 | .btn-success.active,
25 | .btn-info.active,
26 | .btn-warning.active,
27 | .btn-danger.active {
28 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
29 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, 0.125);
30 | }
31 | .btn-default.disabled,
32 | .btn-primary.disabled,
33 | .btn-success.disabled,
34 | .btn-info.disabled,
35 | .btn-warning.disabled,
36 | .btn-danger.disabled,
37 | .btn-default[disabled],
38 | .btn-primary[disabled],
39 | .btn-success[disabled],
40 | .btn-info[disabled],
41 | .btn-warning[disabled],
42 | .btn-danger[disabled],
43 | fieldset[disabled] .btn-default,
44 | fieldset[disabled] .btn-primary,
45 | fieldset[disabled] .btn-success,
46 | fieldset[disabled] .btn-info,
47 | fieldset[disabled] .btn-warning,
48 | fieldset[disabled] .btn-danger {
49 | -webkit-box-shadow: none;
50 | box-shadow: none;
51 | }
52 | .btn-default .badge,
53 | .btn-primary .badge,
54 | .btn-success .badge,
55 | .btn-info .badge,
56 | .btn-warning .badge,
57 | .btn-danger .badge {
58 | text-shadow: none;
59 | }
60 | .btn:active,
61 | .btn.active {
62 | background-image: none;
63 | }
64 | .btn-default {
65 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%);
66 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%);
67 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0));
68 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%);
69 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);
70 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
71 | background-repeat: repeat-x;
72 | border-color: #dbdbdb;
73 | text-shadow: 0 1px 0 #fff;
74 | border-color: #ccc;
75 | }
76 | .btn-default:hover,
77 | .btn-default:focus {
78 | background-color: #e0e0e0;
79 | background-position: 0 -15px;
80 | }
81 | .btn-default:active,
82 | .btn-default.active {
83 | background-color: #e0e0e0;
84 | border-color: #dbdbdb;
85 | }
86 | .btn-default.disabled,
87 | .btn-default[disabled],
88 | fieldset[disabled] .btn-default,
89 | .btn-default.disabled:hover,
90 | .btn-default[disabled]:hover,
91 | fieldset[disabled] .btn-default:hover,
92 | .btn-default.disabled:focus,
93 | .btn-default[disabled]:focus,
94 | fieldset[disabled] .btn-default:focus,
95 | .btn-default.disabled.focus,
96 | .btn-default[disabled].focus,
97 | fieldset[disabled] .btn-default.focus,
98 | .btn-default.disabled:active,
99 | .btn-default[disabled]:active,
100 | fieldset[disabled] .btn-default:active,
101 | .btn-default.disabled.active,
102 | .btn-default[disabled].active,
103 | fieldset[disabled] .btn-default.active {
104 | background-color: #e0e0e0;
105 | background-image: none;
106 | }
107 | .btn-primary {
108 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%);
109 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%);
110 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88));
111 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%);
112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);
113 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
114 | background-repeat: repeat-x;
115 | border-color: #245580;
116 | }
117 | .btn-primary:hover,
118 | .btn-primary:focus {
119 | background-color: #265a88;
120 | background-position: 0 -15px;
121 | }
122 | .btn-primary:active,
123 | .btn-primary.active {
124 | background-color: #265a88;
125 | border-color: #245580;
126 | }
127 | .btn-primary.disabled,
128 | .btn-primary[disabled],
129 | fieldset[disabled] .btn-primary,
130 | .btn-primary.disabled:hover,
131 | .btn-primary[disabled]:hover,
132 | fieldset[disabled] .btn-primary:hover,
133 | .btn-primary.disabled:focus,
134 | .btn-primary[disabled]:focus,
135 | fieldset[disabled] .btn-primary:focus,
136 | .btn-primary.disabled.focus,
137 | .btn-primary[disabled].focus,
138 | fieldset[disabled] .btn-primary.focus,
139 | .btn-primary.disabled:active,
140 | .btn-primary[disabled]:active,
141 | fieldset[disabled] .btn-primary:active,
142 | .btn-primary.disabled.active,
143 | .btn-primary[disabled].active,
144 | fieldset[disabled] .btn-primary.active {
145 | background-color: #265a88;
146 | background-image: none;
147 | }
148 | .btn-success {
149 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%);
150 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%);
151 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641));
152 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%);
153 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);
154 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
155 | background-repeat: repeat-x;
156 | border-color: #3e8f3e;
157 | }
158 | .btn-success:hover,
159 | .btn-success:focus {
160 | background-color: #419641;
161 | background-position: 0 -15px;
162 | }
163 | .btn-success:active,
164 | .btn-success.active {
165 | background-color: #419641;
166 | border-color: #3e8f3e;
167 | }
168 | .btn-success.disabled,
169 | .btn-success[disabled],
170 | fieldset[disabled] .btn-success,
171 | .btn-success.disabled:hover,
172 | .btn-success[disabled]:hover,
173 | fieldset[disabled] .btn-success:hover,
174 | .btn-success.disabled:focus,
175 | .btn-success[disabled]:focus,
176 | fieldset[disabled] .btn-success:focus,
177 | .btn-success.disabled.focus,
178 | .btn-success[disabled].focus,
179 | fieldset[disabled] .btn-success.focus,
180 | .btn-success.disabled:active,
181 | .btn-success[disabled]:active,
182 | fieldset[disabled] .btn-success:active,
183 | .btn-success.disabled.active,
184 | .btn-success[disabled].active,
185 | fieldset[disabled] .btn-success.active {
186 | background-color: #419641;
187 | background-image: none;
188 | }
189 | .btn-info {
190 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
191 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%);
192 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2));
193 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%);
194 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);
195 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
196 | background-repeat: repeat-x;
197 | border-color: #28a4c9;
198 | }
199 | .btn-info:hover,
200 | .btn-info:focus {
201 | background-color: #2aabd2;
202 | background-position: 0 -15px;
203 | }
204 | .btn-info:active,
205 | .btn-info.active {
206 | background-color: #2aabd2;
207 | border-color: #28a4c9;
208 | }
209 | .btn-info.disabled,
210 | .btn-info[disabled],
211 | fieldset[disabled] .btn-info,
212 | .btn-info.disabled:hover,
213 | .btn-info[disabled]:hover,
214 | fieldset[disabled] .btn-info:hover,
215 | .btn-info.disabled:focus,
216 | .btn-info[disabled]:focus,
217 | fieldset[disabled] .btn-info:focus,
218 | .btn-info.disabled.focus,
219 | .btn-info[disabled].focus,
220 | fieldset[disabled] .btn-info.focus,
221 | .btn-info.disabled:active,
222 | .btn-info[disabled]:active,
223 | fieldset[disabled] .btn-info:active,
224 | .btn-info.disabled.active,
225 | .btn-info[disabled].active,
226 | fieldset[disabled] .btn-info.active {
227 | background-color: #2aabd2;
228 | background-image: none;
229 | }
230 | .btn-warning {
231 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
232 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%);
233 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316));
234 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%);
235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);
236 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
237 | background-repeat: repeat-x;
238 | border-color: #e38d13;
239 | }
240 | .btn-warning:hover,
241 | .btn-warning:focus {
242 | background-color: #eb9316;
243 | background-position: 0 -15px;
244 | }
245 | .btn-warning:active,
246 | .btn-warning.active {
247 | background-color: #eb9316;
248 | border-color: #e38d13;
249 | }
250 | .btn-warning.disabled,
251 | .btn-warning[disabled],
252 | fieldset[disabled] .btn-warning,
253 | .btn-warning.disabled:hover,
254 | .btn-warning[disabled]:hover,
255 | fieldset[disabled] .btn-warning:hover,
256 | .btn-warning.disabled:focus,
257 | .btn-warning[disabled]:focus,
258 | fieldset[disabled] .btn-warning:focus,
259 | .btn-warning.disabled.focus,
260 | .btn-warning[disabled].focus,
261 | fieldset[disabled] .btn-warning.focus,
262 | .btn-warning.disabled:active,
263 | .btn-warning[disabled]:active,
264 | fieldset[disabled] .btn-warning:active,
265 | .btn-warning.disabled.active,
266 | .btn-warning[disabled].active,
267 | fieldset[disabled] .btn-warning.active {
268 | background-color: #eb9316;
269 | background-image: none;
270 | }
271 | .btn-danger {
272 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
273 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%);
274 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a));
275 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%);
276 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);
277 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
278 | background-repeat: repeat-x;
279 | border-color: #b92c28;
280 | }
281 | .btn-danger:hover,
282 | .btn-danger:focus {
283 | background-color: #c12e2a;
284 | background-position: 0 -15px;
285 | }
286 | .btn-danger:active,
287 | .btn-danger.active {
288 | background-color: #c12e2a;
289 | border-color: #b92c28;
290 | }
291 | .btn-danger.disabled,
292 | .btn-danger[disabled],
293 | fieldset[disabled] .btn-danger,
294 | .btn-danger.disabled:hover,
295 | .btn-danger[disabled]:hover,
296 | fieldset[disabled] .btn-danger:hover,
297 | .btn-danger.disabled:focus,
298 | .btn-danger[disabled]:focus,
299 | fieldset[disabled] .btn-danger:focus,
300 | .btn-danger.disabled.focus,
301 | .btn-danger[disabled].focus,
302 | fieldset[disabled] .btn-danger.focus,
303 | .btn-danger.disabled:active,
304 | .btn-danger[disabled]:active,
305 | fieldset[disabled] .btn-danger:active,
306 | .btn-danger.disabled.active,
307 | .btn-danger[disabled].active,
308 | fieldset[disabled] .btn-danger.active {
309 | background-color: #c12e2a;
310 | background-image: none;
311 | }
312 | .thumbnail,
313 | .img-thumbnail {
314 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
315 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
316 | }
317 | .dropdown-menu > li > a:hover,
318 | .dropdown-menu > li > a:focus {
319 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
320 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
321 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
322 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
323 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
324 | background-repeat: repeat-x;
325 | background-color: #e8e8e8;
326 | }
327 | .dropdown-menu > .active > a,
328 | .dropdown-menu > .active > a:hover,
329 | .dropdown-menu > .active > a:focus {
330 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
331 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
332 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
333 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
334 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
335 | background-repeat: repeat-x;
336 | background-color: #2e6da4;
337 | }
338 | .navbar-default {
339 | background-image: -webkit-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
340 | background-image: -o-linear-gradient(top, #ffffff 0%, #f8f8f8 100%);
341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8));
342 | background-image: linear-gradient(to bottom, #ffffff 0%, #f8f8f8 100%);
343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);
344 | background-repeat: repeat-x;
345 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
346 | border-radius: 4px;
347 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
348 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 5px rgba(0, 0, 0, 0.075);
349 | }
350 | .navbar-default .navbar-nav > .open > a,
351 | .navbar-default .navbar-nav > .active > a {
352 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
353 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%);
354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2));
355 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%);
356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);
357 | background-repeat: repeat-x;
358 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
359 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.075);
360 | }
361 | .navbar-brand,
362 | .navbar-nav > li > a {
363 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.25);
364 | }
365 | .navbar-inverse {
366 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%);
367 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%);
368 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222));
369 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%);
370 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);
371 | background-repeat: repeat-x;
372 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
373 | border-radius: 4px;
374 | }
375 | .navbar-inverse .navbar-nav > .open > a,
376 | .navbar-inverse .navbar-nav > .active > a {
377 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%);
378 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%);
379 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f));
380 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%);
381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);
382 | background-repeat: repeat-x;
383 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
384 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, 0.25);
385 | }
386 | .navbar-inverse .navbar-brand,
387 | .navbar-inverse .navbar-nav > li > a {
388 | text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
389 | }
390 | .navbar-static-top,
391 | .navbar-fixed-top,
392 | .navbar-fixed-bottom {
393 | border-radius: 0;
394 | }
395 | @media (max-width: 767px) {
396 | .navbar .navbar-nav .open .dropdown-menu > .active > a,
397 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover,
398 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus {
399 | color: #fff;
400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
405 | background-repeat: repeat-x;
406 | }
407 | }
408 | .alert {
409 | text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2);
410 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
411 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25), 0 1px 2px rgba(0, 0, 0, 0.05);
412 | }
413 | .alert-success {
414 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
415 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%);
416 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc));
417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%);
418 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);
419 | background-repeat: repeat-x;
420 | border-color: #b2dba1;
421 | }
422 | .alert-info {
423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%);
425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0));
426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%);
427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);
428 | background-repeat: repeat-x;
429 | border-color: #9acfea;
430 | }
431 | .alert-warning {
432 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
433 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%);
434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0));
435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%);
436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);
437 | background-repeat: repeat-x;
438 | border-color: #f5e79e;
439 | }
440 | .alert-danger {
441 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
442 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%);
443 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3));
444 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%);
445 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);
446 | background-repeat: repeat-x;
447 | border-color: #dca7a7;
448 | }
449 | .progress {
450 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
451 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%);
452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5));
453 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%);
454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);
455 | background-repeat: repeat-x;
456 | }
457 | .progress-bar {
458 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%);
459 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%);
460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090));
461 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%);
462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);
463 | background-repeat: repeat-x;
464 | }
465 | .progress-bar-success {
466 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%);
467 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%);
468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44));
469 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%);
470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);
471 | background-repeat: repeat-x;
472 | }
473 | .progress-bar-info {
474 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
475 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%);
476 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5));
477 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%);
478 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);
479 | background-repeat: repeat-x;
480 | }
481 | .progress-bar-warning {
482 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
483 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%);
484 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f));
485 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%);
486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);
487 | background-repeat: repeat-x;
488 | }
489 | .progress-bar-danger {
490 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%);
491 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%);
492 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c));
493 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%);
494 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);
495 | background-repeat: repeat-x;
496 | }
497 | .progress-bar-striped {
498 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
499 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
500 | background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
501 | }
502 | .list-group {
503 | border-radius: 4px;
504 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
505 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.075);
506 | }
507 | .list-group-item.active,
508 | .list-group-item.active:hover,
509 | .list-group-item.active:focus {
510 | text-shadow: 0 -1px 0 #286090;
511 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%);
512 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%);
513 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a));
514 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%);
515 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);
516 | background-repeat: repeat-x;
517 | border-color: #2b669a;
518 | }
519 | .list-group-item.active .badge,
520 | .list-group-item.active:hover .badge,
521 | .list-group-item.active:focus .badge {
522 | text-shadow: none;
523 | }
524 | .panel {
525 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
526 | box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
527 | }
528 | .panel-default > .panel-heading {
529 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
530 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%);
531 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8));
532 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%);
533 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);
534 | background-repeat: repeat-x;
535 | }
536 | .panel-primary > .panel-heading {
537 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
538 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%);
539 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4));
540 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%);
541 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);
542 | background-repeat: repeat-x;
543 | }
544 | .panel-success > .panel-heading {
545 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
546 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%);
547 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6));
548 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%);
549 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);
550 | background-repeat: repeat-x;
551 | }
552 | .panel-info > .panel-heading {
553 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
554 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%);
555 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3));
556 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%);
557 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);
558 | background-repeat: repeat-x;
559 | }
560 | .panel-warning > .panel-heading {
561 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
562 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%);
563 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc));
564 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%);
565 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);
566 | background-repeat: repeat-x;
567 | }
568 | .panel-danger > .panel-heading {
569 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
570 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%);
571 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc));
572 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%);
573 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);
574 | background-repeat: repeat-x;
575 | }
576 | .well {
577 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
578 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%);
579 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5));
580 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%);
581 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);
582 | background-repeat: repeat-x;
583 | border-color: #dcdcdc;
584 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
585 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.05), 0 1px 0 rgba(255, 255, 255, 0.1);
586 | }
587 | /*# sourceMappingURL=bootstrap-theme.css.map */
--------------------------------------------------------------------------------