├── shopping-client-ng ├── client │ ├── src │ │ ├── assets │ │ │ ├── .gitkeep │ │ │ └── logo.svg │ │ ├── cordova.js │ │ ├── modules │ │ │ └── app │ │ │ │ ├── components │ │ │ │ ├── home │ │ │ │ │ ├── home.html │ │ │ │ │ ├── home.scss │ │ │ │ │ └── home.ts │ │ │ │ ├── list │ │ │ │ │ ├── orderList.scss │ │ │ │ │ ├── orderList.ts │ │ │ │ │ └── orderList.html │ │ │ │ ├── root │ │ │ │ │ ├── root.scss │ │ │ │ │ ├── root.html │ │ │ │ │ └── root.ts │ │ │ │ ├── menu │ │ │ │ │ ├── menu.html │ │ │ │ │ └── menu.ts │ │ │ │ ├── header │ │ │ │ │ ├── header.html │ │ │ │ │ ├── header.scss │ │ │ │ │ └── header.ts │ │ │ │ └── login │ │ │ │ │ ├── login.html │ │ │ │ │ ├── login.ts │ │ │ │ │ └── login.scss │ │ │ │ ├── models │ │ │ │ ├── product.ts │ │ │ │ ├── signalRConnectionInformation.ts │ │ │ │ ├── order.ts │ │ │ │ └── orderWithItems.ts │ │ │ │ ├── services │ │ │ │ ├── windowRef.ts │ │ │ │ ├── desktopIntegrationService.ts │ │ │ │ ├── platformService.ts │ │ │ │ ├── authInterceptor.ts │ │ │ │ └── ordersService.ts │ │ │ │ ├── routes.ts │ │ │ │ ├── guards │ │ │ │ └── isAuthenticated.ts │ │ │ │ └── module.ts │ │ ├── styles │ │ │ ├── _utilities.scss │ │ │ ├── _links.scss │ │ │ ├── _backdrop.scss │ │ │ ├── _variables.scss │ │ │ ├── _table.scss │ │ │ ├── global.scss │ │ │ ├── _menu.scss │ │ │ └── _loader.scss │ │ ├── favicon.ico │ │ ├── tsconfig.app.json │ │ ├── index.html │ │ ├── hmr.ts │ │ ├── environments │ │ │ ├── environment.hmr.ts │ │ │ ├── environment.ts │ │ │ └── environment.prod.ts │ │ ├── main.ts │ │ └── polyfills.ts │ ├── README.md │ ├── buildAssets │ │ ├── desktop │ │ │ ├── icon.png │ │ │ ├── package.json │ │ │ └── index.js │ │ ├── resources │ │ │ ├── icon.icns │ │ │ ├── icon.ico │ │ │ ├── icon.png │ │ │ └── splash.png │ │ └── mobile │ │ │ └── config.xml │ ├── .editorconfig │ ├── tsconfig.json │ ├── LICENSE │ └── tslint.json └── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── products-service-dotnet ├── .dockerignore ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── host.json ├── Functions │ └── AppSettings.cs ├── DTOs │ ├── Product.cs │ └── ProductDetails.cs ├── env_functions ├── Dockerfile ├── Startup.cs ├── Entities │ └── ProductDetailsEntity.cs ├── products-service-dotnet.sln ├── Directory.Build.targets └── products-service-dotnet.csproj ├── orders-service-dotnet ├── starthost.sh ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── curl_with_timing_get_orders.txt ├── DTOs │ ├── OrderItem.cs │ └── Order.cs ├── Entities │ ├── OrderItem.cs │ └── Order.cs ├── host.json ├── Messages │ └── NewOrderMessage.cs ├── Client HTTP Scripts │ ├── RetrieveToken.http │ ├── GetAllOrders.http │ └── SumbitNewOrder.http ├── Dockerfile ├── Functions │ ├── Infrastructure │ │ ├── KeepItWarm.cs │ │ ├── HealthCheck.cs │ │ └── LetsEncrypt.cs │ ├── GetOrders.cs │ ├── CreateNewOrder.cs │ └── SubmitNewOrder.cs ├── Pipeline │ └── ModelBinding.cs └── orders-service.csproj ├── products-service-js ├── starthost.sh ├── HealthCheck │ ├── sample.dat │ ├── index.js │ └── function.json ├── .vscode │ ├── extensions.json │ ├── settings.json │ ├── launch.json │ └── tasks.json ├── host.json ├── KeepItWarm │ ├── index.js │ └── function.json ├── .gitignore ├── ListProducts │ ├── index.js │ └── function.json ├── package.json ├── LetsEncrypt │ ├── function.json │ └── index.js ├── SearchProducts │ ├── function.json │ └── index.js ├── GetProduct │ ├── index.js │ └── function.json └── extensions.csproj ├── invoice-scanner-dotnet ├── host.json ├── For local debugging.txt ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── Functions │ ├── KeepItWarm.cs │ └── UploadDocument.cs ├── Directory.Build.targets ├── Startup.cs ├── invoice-scanner.csproj └── Services │ └── OcrClient.cs ├── loadtest.txt ├── shipping-service-dotnet ├── host.json ├── starthost.sh ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── Messages │ ├── NewOrderMessage.cs │ ├── DTOs │ │ ├── OrderItem.cs │ │ └── Order.cs │ └── ShippingCreatedMessage.cs ├── Functions │ ├── KeepItWarm.cs │ └── CreateShipment.cs └── shipping-service.csproj ├── shipping-service-ts ├── host.json ├── .funcignore ├── proxies.json ├── Messages │ ├── DTOs │ │ ├── orderItem.ts │ │ └── order.ts │ ├── newOrderMessage.ts │ └── shippingCreatedMessage.ts ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── tsconfig.json ├── KeepItWarm │ ├── function.json │ ├── index.ts │ └── readme.md ├── HealthCheck │ ├── index.ts │ └── function.json ├── extensions.csproj ├── CreateShipment │ ├── function.json │ └── index.ts ├── package.json ├── package-lock.json └── .gitignore ├── shipping-service-java ├── host.json ├── .settings │ ├── org.eclipse.jdt.apt.core.prefs │ ├── org.eclipse.core.resources.prefs │ ├── org.eclipse.m2e.core.prefs │ └── org.eclipse.jdt.core.prefs ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── src │ └── main │ │ └── java │ │ └── com │ │ └── thinktecture │ │ └── serverless │ │ ├── messages │ │ ├── dtos │ │ │ ├── OrderItem.java │ │ │ └── Order.java │ │ ├── NewOrderMessage.java │ │ └── ShippingCreatedMessage.java │ │ └── functions │ │ ├── HealthCheck.java │ │ ├── KeepItWarm.java │ │ └── CreateShipment.java ├── extensions.csproj ├── .gitignore ├── .project └── .classpath ├── identity-service-dotnet ├── Views │ ├── _ViewStart.cshtml │ ├── _ViewImports.cshtml │ ├── Device │ │ ├── Success.cshtml │ │ └── UserCodeCapture.cshtml │ ├── Shared │ │ ├── _ValidationSummary.cshtml │ │ ├── Redirect.cshtml │ │ ├── _ScopeListItem.cshtml │ │ ├── Error.cshtml │ │ └── _Layout.cshtml │ ├── Account │ │ ├── Logout.cshtml │ │ └── LoggedOut.cshtml │ ├── Diagnostics │ │ └── Index.cshtml │ └── Home │ │ └── Index.cshtml ├── wwwroot │ ├── icon.jpg │ ├── icon.png │ ├── js │ │ ├── signin-redirect.js │ │ └── signout-redirect.js │ ├── favicon.ico │ ├── lib │ │ └── bootstrap │ │ │ └── fonts │ │ │ ├── glyphicons-halflings-regular.eot │ │ │ ├── glyphicons-halflings-regular.ttf │ │ │ ├── glyphicons-halflings-regular.woff │ │ │ └── glyphicons-halflings-regular.woff2 │ └── css │ │ ├── site.min.css │ │ ├── site.css │ │ └── site.less ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── host.json ├── Binaries │ └── S-Innovations.Azure.TableStorageRepository.dll ├── appsettings.json ├── Quickstart │ ├── Account │ │ ├── LogoutInputModel.cs │ │ ├── RedirectViewModel.cs │ │ ├── LogoutViewModel.cs │ │ ├── ExternalProvider.cs │ │ ├── LoginInputModel.cs │ │ ├── LoggedOutViewModel.cs │ │ ├── LoginViewModel.cs │ │ └── AccountOptions.cs │ ├── Home │ │ ├── ErrorViewModel.cs │ │ └── HomeController.cs │ ├── Device │ │ ├── DeviceAuthorizationInputModel.cs │ │ └── DeviceAuthorizationViewModel.cs │ ├── Consent │ │ ├── ConsentInputModel.cs │ │ ├── ScopeViewModel.cs │ │ ├── ProcessConsentResult.cs │ │ ├── ConsentViewModel.cs │ │ └── ConsentOptions.cs │ ├── Extensions.cs │ ├── Grants │ │ └── GrantsViewModel.cs │ ├── Diagnostics │ │ ├── DiagnosticsController.cs │ │ └── DiagnosticsViewModel.cs │ ├── TestUsers.cs │ └── SecurityHeadersAttribute.cs ├── Functions │ └── Infrastructure │ │ ├── KeepItWarm.cs │ │ └── LetsEncrypt.cs ├── Stores │ ├── PersistedGrantContext.cs │ └── TableStoragePersistedGrantStore.cs └── Program.cs ├── notification-service-dotnet ├── .vscode │ ├── extensions.json │ ├── launch.json │ ├── settings.json │ └── tasks.json ├── host.json ├── Functions │ ├── Messages │ │ └── ShippingCreatedMessage.cs │ ├── Infrastructure │ │ ├── KeepItWarm.cs │ │ ├── HealthCheck.cs │ │ ├── LetsEncrypt.cs │ │ └── GetSignalRConfguration.cs │ └── NotifyClientsAboutOrderShipment.cs └── notification-service.csproj ├── README.md ├── LICENSE └── serverless-microservices.code-workspace /shopping-client-ng/client/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /products-service-dotnet/.dockerignore: -------------------------------------------------------------------------------- 1 | local.settings.json -------------------------------------------------------------------------------- /orders-service-dotnet/starthost.sh: -------------------------------------------------------------------------------- 1 | func host start --build 2 | -------------------------------------------------------------------------------- /products-service-js/starthost.sh: -------------------------------------------------------------------------------- 1 | func host start --build 2 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0" 3 | } -------------------------------------------------------------------------------- /loadtest.txt: -------------------------------------------------------------------------------- 1 | wrk -t12 -c400 -d180s http://localhost:7073/api/products -------------------------------------------------------------------------------- /shipping-service-dotnet/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0" 3 | } -------------------------------------------------------------------------------- /shipping-service-dotnet/starthost.sh: -------------------------------------------------------------------------------- 1 | func host start --build 2 | -------------------------------------------------------------------------------- /shipping-service-ts/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0" 3 | } 4 | -------------------------------------------------------------------------------- /shipping-service-java/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0" 3 | } 4 | -------------------------------------------------------------------------------- /products-service-js/HealthCheck/sample.dat: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure" 3 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Views/_ViewStart.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | Layout = "_Layout"; 3 | } 4 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/cordova.js: -------------------------------------------------------------------------------- 1 | /* This file is intentionally here as a placeholder */ -------------------------------------------------------------------------------- /invoice-scanner-dotnet/For local debugging.txt: -------------------------------------------------------------------------------- 1 | ssh -R :80:localhost:7071 serveo.net -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/home/home.html: -------------------------------------------------------------------------------- 1 |

Home

2 | 3 |

MyShopping - welcome!
-------------------------------------------------------------------------------- /shipping-service-ts/.funcignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | *.ts 3 | .git* 4 | .vscode 5 | local.settings.json 6 | test 7 | tsconfig.json -------------------------------------------------------------------------------- /shipping-service-ts/proxies.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/proxies", 3 | "proxies": {} 4 | } 5 | -------------------------------------------------------------------------------- /shipping-service-ts/Messages/DTOs/orderItem.ts: -------------------------------------------------------------------------------- 1 | declare interface OrderItem { 2 | Id: string; 3 | Quantity: number; 4 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/README.md: -------------------------------------------------------------------------------- 1 | # Simple Orders monitoring application - for Azure Serverless Microservices demo scenario -------------------------------------------------------------------------------- /identity-service-dotnet/Views/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using IdentityServer 2 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers 3 | -------------------------------------------------------------------------------- /products-service-js/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /shipping-service-java/.settings/org.eclipse.jdt.apt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.apt.aptEnabled=false 3 | -------------------------------------------------------------------------------- /shipping-service-ts/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /shipping-service-ts/Messages/newOrderMessage.ts: -------------------------------------------------------------------------------- 1 | declare interface NewOrderMessage { 2 | Order: Order; 3 | UserId: string; 4 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/models/product.ts: -------------------------------------------------------------------------------- 1 | export interface Product { 2 | id: string; 3 | name: string; 4 | } 5 | -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/icon.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/icon.jpg -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/icon.png -------------------------------------------------------------------------------- /products-service-js/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensions": { 4 | "http": { 5 | "routePrefix": "" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_utilities.scss: -------------------------------------------------------------------------------- 1 | @import '_variables'; 2 | // For Breakpoints 3 | @import '~include-media/dist/_include-media'; 4 | -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/js/signin-redirect.js: -------------------------------------------------------------------------------- 1 | window.location.href = document.querySelector("meta[http-equiv=refresh]").getAttribute("data-url"); 2 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/shopping-client-ng/client/src/favicon.ico -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/favicon.ico -------------------------------------------------------------------------------- /shipping-service-java/.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding//src/main/java=UTF-8 3 | encoding/=UTF-8 4 | -------------------------------------------------------------------------------- /shipping-service-java/.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /shopping-client-ng/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/list/orderList.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../styles/_utilities'; 2 | 3 | :host { 4 | overflow: scroll 5 | } 6 | -------------------------------------------------------------------------------- /identity-service-dotnet/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /orders-service-dotnet/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /products-service-dotnet/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /shipping-service-dotnet/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /identity-service-dotnet/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensions": { 4 | "http": { 5 | "routePrefix": "" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /notification-service-dotnet/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "ms-vscode.csharp" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/services/windowRef.ts: -------------------------------------------------------------------------------- 1 | export class WindowRef { 2 | public get nativeWindow(): Window { 3 | return window; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microservices architectures with Serverless Azure 2 | Sample implementations for a Microservices/Nanoservices architecture based on Azure Serverless technologies. 3 | -------------------------------------------------------------------------------- /products-service-dotnet/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensions": { 4 | "http": { 5 | "routePrefix": "" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /shipping-service-java/.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "ms-azuretools.vscode-azurefunctions", 4 | "vscjava.vscode-java-debug" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /shipping-service-ts/Messages/DTOs/order.ts: -------------------------------------------------------------------------------- 1 | declare interface Order { 2 | Id: string; 3 | Description: string; 4 | Created: string; 5 | Items: OrderItem[]; 6 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/home/home.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../styles/_utilities'; 2 | 3 | :host { 4 | padding-bottom: $menu-height + 5px; 5 | } 6 | -------------------------------------------------------------------------------- /notification-service-dotnet/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "extensions": { 4 | "http": { 5 | "routePrefix": "" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/desktop/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/shopping-client-ng/client/buildAssets/desktop/icon.png -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/resources/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/shopping-client-ng/client/buildAssets/resources/icon.icns -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/resources/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/shopping-client-ng/client/buildAssets/resources/icon.ico -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/shopping-client-ng/client/buildAssets/resources/icon.png -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/models/signalRConnectionInformation.ts: -------------------------------------------------------------------------------- 1 | export interface SignalRConnectionInformation { 2 | url: string; 3 | accessToken: string; 4 | } 5 | -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/resources/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/shopping-client-ng/client/buildAssets/resources/splash.png -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_links.scss: -------------------------------------------------------------------------------- 1 | @import '_variables.scss'; 2 | 3 | router-outlet + * { 4 | a { 5 | color: $primary-color; 6 | text-decoration: none; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/desktop/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "CrossPlatformDemo", 3 | "productName": "Cross-Platform Demo", 4 | "version": "1.0.0", 5 | "main": "index.js" 6 | } 7 | -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Device/Success.cshtml: -------------------------------------------------------------------------------- 1 |

-------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/models/order.ts: -------------------------------------------------------------------------------- 1 | export interface Order { 2 | id: string; 3 | description: string; 4 | items: { id: string, quantity: number }[]; 5 | created: string; 6 | } 7 | -------------------------------------------------------------------------------- /orders-service-dotnet/curl_with_timing_get_orders.txt: -------------------------------------------------------------------------------- 1 | curl -o /dev/null -s -w 'Establish Connection: %{time_connect}s\nTTFB: %{time_starttransfer}s\nTotal: %{time_total}s\n' https://orders.serverlessmicroservices.net/api/orders -------------------------------------------------------------------------------- /identity-service-dotnet/Binaries/S-Innovations.Azure.TableStorageRepository.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/Binaries/S-Innovations.Azure.TableStorageRepository.dll -------------------------------------------------------------------------------- /products-service-js/KeepItWarm/index.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (context, timer) { 2 | var timeStamp = new Date().toISOString(); 3 | 4 | context.log('JavaScript timer trigger function ran.', timeStamp); 5 | }; -------------------------------------------------------------------------------- /shipping-service-dotnet/Messages/NewOrderMessage.cs: -------------------------------------------------------------------------------- 1 | namespace Serverless 2 | { 3 | public class NewOrderMessage 4 | { 5 | public Order Order { get; set; } 6 | public string UserId { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /shipping-service-ts/Messages/shippingCreatedMessage.ts: -------------------------------------------------------------------------------- 1 | import { Guid } from "guid-typescript"; 2 | 3 | export class ShippingCreatedMessage { 4 | Id: Guid; 5 | Created: string; 6 | OrderId: string; 7 | UserId: string; 8 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/root/root.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../styles/_variables'; 2 | 3 | :host { 4 | display: flex; 5 | flex: 1; 6 | flex-direction: column; 7 | 8 | padding: $gap; 9 | } 10 | -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/js/signout-redirect.js: -------------------------------------------------------------------------------- 1 | window.addEventListener("load", function () { 2 | var a = document.querySelector("a.PostLogoutRedirectUri"); 3 | if (a) { 4 | window.location = a.href; 5 | } 6 | }); 7 | -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/thinktecture/serverless-microservices/HEAD/identity-service-dotnet/wwwroot/lib/bootstrap/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /orders-service-dotnet/DTOs/OrderItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Serverless.DTOs 4 | { 5 | public class OrderItem 6 | { 7 | public Guid Id { get; set; } 8 | public int Quantity { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /shipping-service-ts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es6", 5 | "outDir": "dist", 6 | "rootDir": ".", 7 | "sourceMap": true, 8 | "strict": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /shipping-service-dotnet/Messages/DTOs/OrderItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Serverless 4 | { 5 | public class OrderItem 6 | { 7 | public Guid Id { get; set; } 8 | public int Quantity { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/root/root.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /orders-service-dotnet/Entities/OrderItem.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Serverless.Entities 4 | { 5 | public class OrderItem 6 | { 7 | public Guid Id { get; set; } 8 | public int Quantity { get; set; } 9 | } 10 | } -------------------------------------------------------------------------------- /products-service-js/HealthCheck/index.js: -------------------------------------------------------------------------------- 1 | module.exports = async function (context, req) { 2 | context.log('JavaScript Ping trigger function processed a request.'); 3 | 4 | context.res = { 5 | status: 200, 6 | body: "OK" 7 | }; 8 | }; -------------------------------------------------------------------------------- /orders-service-dotnet/host.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0", 3 | "cosmosDB": { 4 | "connectionMode": "Direct", 5 | "protocol": "Tcp" 6 | }, 7 | "extensions": { 8 | "http": { 9 | "routePrefix": "" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /products-service-js/KeepItWarm/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "name": "timer", 6 | "type": "timerTrigger", 7 | "direction": "in", 8 | "schedule": "0 */9 * * * *" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/messages/dtos/OrderItem.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.messages.dtos; 2 | 3 | import java.util.UUID; 4 | 5 | public class OrderItem { 6 | public UUID Id; 7 | public Integer Quantity; 8 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Shared/_ValidationSummary.cshtml: -------------------------------------------------------------------------------- 1 | @if (ViewContext.ModelState.IsValid == false) 2 | { 3 |
4 | Error 5 |
6 |
7 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/home/home.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'app-home', 5 | templateUrl: 'home.html', 6 | styleUrls: ['home.scss'] 7 | }) 8 | export class HomeComponent { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /orders-service-dotnet/Messages/NewOrderMessage.cs: -------------------------------------------------------------------------------- 1 | using Serverless.Entities; 2 | 3 | namespace Serverless.Messages 4 | { 5 | public class NewOrderMessage 6 | { 7 | public Order Order { get; set; } 8 | public string UserId { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /shipping-service-ts/KeepItWarm/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "name": "timer", 5 | "type": "timerTrigger", 6 | "direction": "in", 7 | "schedule": "0 */9 * * * *" 8 | } 9 | ], 10 | "scriptFile": "../dist/KeepItWarm/index.js" 11 | } 12 | -------------------------------------------------------------------------------- /products-service-js/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "JavaScript", 4 | "azureFunctions.templateFilter": "Verified", 5 | "azureFunctions.deploySubpath": ".", 6 | "azureFunctions.preDeployTask": "installExtensions" 7 | } 8 | -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/messages/NewOrderMessage.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.messages; 2 | 3 | import com.thinktecture.serverless.messages.dtos.Order; 4 | 5 | public class NewOrderMessage { 6 | public Order Order; 7 | public String UserId; 8 | } -------------------------------------------------------------------------------- /invoice-scanner-dotnet/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to C# Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /orders-service-dotnet/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to C# Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /shopping-client-ng/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to .NET Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /identity-service-dotnet/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to C# Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /products-service-dotnet/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to C# Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /shipping-service-dotnet/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to C# Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /shipping-service-ts/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Node Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 9229, 9 | "preLaunchTask": "func: host start" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /notification-service-dotnet/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to .NET Functions", 6 | "type": "coreclr", 7 | "request": "attach", 8 | "processId": "${command:azureFunctions.pickProcess}" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /orders-service-dotnet/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.templateFilter": "Verified", 5 | "azureFunctions.deploySubpath": "bin/Release/netstandard2.0/publish", 6 | "azureFunctions.preDeployTask": "publish" 7 | } 8 | -------------------------------------------------------------------------------- /products-service-dotnet/Functions/AppSettings.cs: -------------------------------------------------------------------------------- 1 | using Aliencube.AzureFunctions.Extensions.OpenApi.Configurations; 2 | 3 | namespace Serverless 4 | { 5 | public class AppSettings : OpenApiAppSettingsBase 6 | { 7 | public AppSettings() : base() 8 | { 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /products-service-js/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to JavaScript Functions", 6 | "type": "node", 7 | "request": "attach", 8 | "port": 5858, 9 | "preLaunchTask": "runFunctionsHost" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /shipping-service-dotnet/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.templateFilter": "Verified", 5 | "azureFunctions.deploySubpath": "bin/Release/netstandard2.0/publish", 6 | "azureFunctions.preDeployTask": "publish" 7 | } 8 | -------------------------------------------------------------------------------- /notification-service-dotnet/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp2.1/publish", 5 | "azureFunctions.preDeployTask": "publish", 6 | "debug.internalConsoleOptions": "neverOpen" 7 | } 8 | -------------------------------------------------------------------------------- /shopping-client-ng/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.deploySubpath": "functions/bin/Release/netcoreapp2.1/publish", 5 | "azureFunctions.preDeployTask": "publish", 6 | "debug.internalConsoleOptions": "neverOpen" 7 | } 8 | -------------------------------------------------------------------------------- /products-service-js/.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | obj 3 | csx 4 | .vs 5 | edge 6 | Publish 7 | 8 | *.user 9 | *.suo 10 | *.cscfg 11 | *.Cache 12 | project.lock.json 13 | 14 | /packages 15 | /TestResults 16 | 17 | /tools/NuGet.exe 18 | /App_Data 19 | /secrets 20 | /data 21 | .secrets 22 | appsettings.json 23 | local.settings.json 24 | -------------------------------------------------------------------------------- /orders-service-dotnet/Client HTTP Scripts/RetrieveToken.http: -------------------------------------------------------------------------------- 1 | POST https://tt-identityserver4-demo.azurewebsites.net/connect/token 2 | Content-Type: application/x-www-form-urlencoded 3 | 4 | client_id=resourceowner 5 | &client_secret=no-really-a-secret 6 | &grant_type=password 7 | &username=bob 8 | &password=bob 9 | &scope=openid profile api -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/models/orderWithItems.ts: -------------------------------------------------------------------------------- 1 | import { Order } from "./order"; 2 | import { Product } from "./product"; 3 | import { Observable } from "rxjs"; 4 | 5 | export interface OrderWithItems { 6 | order: Order; 7 | items: Observable[]; 8 | shipped$: Observable; 9 | } 10 | -------------------------------------------------------------------------------- /identity-service-dotnet/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "KeyVault": { 3 | "BaseUrl": "https://cw-serverless-ms.vault.azure.net/", 4 | "ClientId": "cfe10a94-9b22-4ace-b47c-3001cc487f85", 5 | "ClientSecret": "#NAU:HAV7}V@Rrw;L%NN*c;AIQQj(Q+=5yci#b9?UQNA8CPLbG2RML*;:lG", 6 | "CertName": "IdSrvSigningCert" 7 | } 8 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Shared/Redirect.cshtml: -------------------------------------------------------------------------------- 1 | @model RedirectViewModel 2 | 3 |

You are now being returned to the application.

4 |

Once complete, you may close this tab

5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /products-service-js/ListProducts/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (context, req) { 2 | context.log('Start ListProducts...'); 3 | 4 | // TODO: Dude - what about paging!? 5 | context.res.status(200).json(context.bindings.products 6 | .map(p => { 7 | return { id: p.RowKey, name: p.Name } 8 | })); 9 | }; -------------------------------------------------------------------------------- /shopping-client-ng/client/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /shipping-service-java/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Attach to Java Functions", 6 | "type": "java", 7 | "request": "attach", 8 | "hostName": "127.0.0.1", 9 | "port": 5005, 10 | "preLaunchTask": "func: host start" 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /products-service-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "products-service", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "request": "^2.88.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /identity-service-dotnet/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.templateFilter": "Verified", 5 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp2.1/publish", 6 | "azureFunctions.preDeployTask": "publish", 7 | "debug.internalConsoleOptions": "neverOpen" 8 | } 9 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.templateFilter": "Verified", 5 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp2.1/publish", 6 | "azureFunctions.preDeployTask": "publish", 7 | "debug.internalConsoleOptions": "neverOpen" 8 | } 9 | -------------------------------------------------------------------------------- /products-service-dotnet/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "C#", 4 | "azureFunctions.templateFilter": "Verified", 5 | "azureFunctions.deploySubpath": "bin/Debug/netcoreapp2.1/publish", 6 | "azureFunctions.preDeployTask": "publish", 7 | "debug.internalConsoleOptions": "neverOpen" 8 | } 9 | -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/messages/ShippingCreatedMessage.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.messages; 2 | 3 | import java.util.Date; 4 | import java.util.UUID; 5 | 6 | public class ShippingCreatedMessage { 7 | public UUID Id; 8 | public Date Created; 9 | public UUID OrderId; 10 | public String UserId; 11 | } -------------------------------------------------------------------------------- /shipping-service-dotnet/Messages/ShippingCreatedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Serverless 4 | { 5 | public class ShippingCreatedMessage 6 | { 7 | public Guid Id { get; set; } 8 | public DateTime Created { get; set; } 9 | public Guid OrderId { get; set; } 10 | public string UserId { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /shipping-service-ts/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "TypeScript", 4 | "azureFunctions.deploySubpath": ".", 5 | "azureFunctions.preDeployTask": "npm prune", 6 | "files.exclude": { 7 | "obj": true, 8 | "bin": true 9 | }, 10 | "debug.internalConsoleOptions": "neverOpen" 11 | } 12 | -------------------------------------------------------------------------------- /shipping-service-ts/KeepItWarm/index.ts: -------------------------------------------------------------------------------- 1 | import { AzureFunction, Context } from "@azure/functions" 2 | 3 | const timerTrigger: AzureFunction = async function (context: Context, timer: any): Promise { 4 | var timeStamp = new Date().toISOString(); 5 | context.log('TS timer trigger function ran.', timeStamp); 6 | }; 7 | 8 | export default timerTrigger; 9 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_backdrop.scss: -------------------------------------------------------------------------------- 1 | @import '_utilities'; 2 | 3 | .backdrop { 4 | position: fixed; 5 | top: $header-height; 6 | left: 0; 7 | right: 0; 8 | bottom: 0; 9 | background-color: black; 10 | pointer-events: none; 11 | 12 | opacity: 0; 13 | 14 | will-change: opacity; 15 | transition: opacity $transition-duration; 16 | } 17 | -------------------------------------------------------------------------------- /products-service-dotnet/DTOs/Product.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MessagePack; 3 | using Microsoft.WindowsAzure.Storage.Table; 4 | 5 | namespace Serverless 6 | { 7 | [MessagePackObject] 8 | public class Product 9 | { 10 | [Key(0)] 11 | public Guid Id { get; set; } 12 | [Key(1)] 13 | public string Name { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /orders-service-dotnet/DTOs/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Serverless.DTOs 5 | { 6 | public class Order 7 | { 8 | public Guid Id { get; set; } 9 | public string Description { get; set; } 10 | public DateTime Created { get; set; } 11 | public List Items { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /shipping-service-dotnet/Messages/DTOs/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Serverless 5 | { 6 | public class Order 7 | { 8 | public Guid Id { get; set; } 9 | public string Description { get; set; } 10 | public DateTime Created { get; set; } 11 | public List Items { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/messages/dtos/Order.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.messages.dtos; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | import java.util.UUID; 6 | 7 | public class Order { 8 | public UUID Id; 9 | public String Description; 10 | public Date Created; 11 | public List Items; 12 | } -------------------------------------------------------------------------------- /notification-service-dotnet/Functions/Messages/ShippingCreatedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Serverless.Messages 4 | { 5 | public class ShippingCreatedMessage 6 | { 7 | public Guid Id { get; set; } 8 | public DateTime Created { get; set; } 9 | public Guid OrderId { get; set; } 10 | public string UserId { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /orders-service-dotnet/Entities/Order.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace Serverless.Entities 5 | { 6 | public class Order 7 | { 8 | public Guid Id { get; set; } 9 | public string Description { get; set; } 10 | public DateTime Created { get; set; } 11 | public List Items { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_variables.scss: -------------------------------------------------------------------------------- 1 | $primary-color: #FF584F; 2 | $background-color: #F9F8F6; 3 | $alternative-background-color: #868686; 4 | 5 | $header-height: 50px; 6 | 7 | $gap: 25px; 8 | 9 | $border-radius: 6px; 10 | 11 | $menu-width: 80px; 12 | $submenu-width: 200px; 13 | 14 | $menu-height: 65px; 15 | $submenu-height: 180px; 16 | 17 | $transition-duration: 0.3s; 18 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/LogoutInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class LogoutInputModel 8 | { 9 | public string LogoutId { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/RedirectViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | 6 | namespace IdentityServer 7 | { 8 | public class RedirectViewModel 9 | { 10 | public string RedirectUrl { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /shipping-service-ts/HealthCheck/index.ts: -------------------------------------------------------------------------------- 1 | import { AzureFunction, Context, HttpRequest } from "@azure/functions" 2 | 3 | const httpTrigger: AzureFunction = async function (context: Context, req: HttpRequest): Promise { 4 | context.log('Ping HTTP trigger function processed a request.'); 5 | 6 | context.res = { 7 | body: "OK" 8 | }; 9 | }; 10 | 11 | export default httpTrigger; 12 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/menu/menu.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": [ 5 | "es2016", 6 | "dom" 7 | ], 8 | "outDir": "../out-tsc/app", 9 | "target": "es5", 10 | "module": "es2015", 11 | "baseUrl": "" 12 | }, 13 | "types":[ 14 | "signalr" 15 | ], 16 | "exclude": [ 17 | "test.ts", 18 | "**/*.spec.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/LogoutViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class LogoutViewModel : LogoutInputModel 8 | { 9 | public bool ShowLogoutPrompt { get; set; } = true; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Home/ErrorViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Models; 6 | 7 | namespace IdentityServer 8 | { 9 | public class ErrorViewModel 10 | { 11 | public ErrorMessage Error { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Device/UserCodeCapture.cshtml: -------------------------------------------------------------------------------- 1 | @model string 2 | 3 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/menu/menu.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | import { WindowRef } from "../../services/windowRef"; 3 | 4 | @Component({ 5 | selector: "app-menu", 6 | templateUrl: "menu.html", 7 | styleUrls: ["menu.scss"] 8 | }) 9 | export class MenuComponent { 10 | private readonly _bodyCssClass = "show-menu"; 11 | 12 | constructor(private _windowRef: WindowRef) {} 13 | } 14 | -------------------------------------------------------------------------------- /products-service-js/HealthCheck/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "anonymous", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": [ 9 | "get", 10 | "post" 11 | ], 12 | "route": "api/ping" 13 | }, 14 | { 15 | "type": "http", 16 | "direction": "out", 17 | "name": "res" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Device/DeviceAuthorizationInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer.Device 6 | { 7 | public class DeviceAuthorizationInputModel : ConsentInputModel 8 | { 9 | public string UserCode { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /orders-service-dotnet/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.1-sdk AS installer-env 2 | 3 | COPY . /src/dotnet-function-app 4 | RUN cd /src/dotnet-function-app && \ 5 | mkdir -p /home/site/wwwroot && \ 6 | dotnet publish *.csproj --output /home/site/wwwroot 7 | 8 | FROM mcr.microsoft.com/azure-functions/dotnet:2.0 9 | ENV AzureWebJobsScriptRoot=/home/site/wwwroot 10 | 11 | COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"] -------------------------------------------------------------------------------- /shipping-service-java/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "azureFunctions.projectRuntime": "~2", 3 | "azureFunctions.projectLanguage": "Java", 4 | "azureFunctions.templateFilter": "Verified", 5 | "debug.internalConsoleOptions": "neverOpen", 6 | "java.configuration.updateBuildConfiguration": "interactive", 7 | "azureFunctions.deploySubpath": "target/azure-functions/shipping-service-java/", 8 | "azureFunctions.preDeployTask": "package" 9 | } 10 | -------------------------------------------------------------------------------- /products-service-dotnet/env_functions: -------------------------------------------------------------------------------- 1 | AzureWebJobsStorage=DefaultEndpointsProtocol=https;AccountName=cwserverlessmsproductsex;AccountKey=ycpM2P9CsWN8h0WlffmCSe3CWxiAgh01E8i+ObmyF1zr7Vq0u8RfktTq6HvysziJAL2SgaBuIK6DSlDUvBpgtQ== 2 | products=DefaultEndpointsProtocol=https;AccountName=cwserverlessmsproducts;AccountKey=6DEfaUY1LDhEIMxa36n0jlRvl87Sjf7h0F4g77lh5P80xxbe1umGGKJyMA8n2XLhbP4ojfkpNTIvfWjIM4mPLg==;EndpointSuffix=core.windows.net 3 | FUNCTIONS_WORKER_RUNTIME=dotnet -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/ExternalProvider.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class ExternalProvider 8 | { 9 | public string DisplayName { get; set; } 10 | public string AuthenticationScheme { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /shipping-service-ts/HealthCheck/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "authLevel": "anonymous", 5 | "type": "httpTrigger", 6 | "direction": "in", 7 | "name": "req", 8 | "methods": [ 9 | "get", 10 | "post" 11 | ], 12 | "route": "ping" 13 | }, 14 | { 15 | "type": "http", 16 | "direction": "out", 17 | "name": "res" 18 | } 19 | ], 20 | "scriptFile": "../dist/HealthCheck/index.js" 21 | } 22 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/header/header.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | MyShopping 4 | 5 | 6 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /products-service-js/LetsEncrypt/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "anonymous", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": [ 10 | "get", 11 | "post" 12 | ], 13 | "route": ".well-known/acme-challenge/{code}" 14 | }, 15 | { 16 | "type": "http", 17 | "direction": "out", 18 | "name": "res" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Device/DeviceAuthorizationViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer.Device 6 | { 7 | public class DeviceAuthorizationViewModel : ConsentViewModel 8 | { 9 | public string UserCode { get; set; } 10 | public bool ConfirmUserCode { get; set; } 11 | } 12 | } -------------------------------------------------------------------------------- /products-service-js/SearchProducts/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": true, 3 | "bindings": [ 4 | { 5 | "authLevel": "anonymous", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": [ 10 | "get" 11 | ], 12 | "route": "api/productssearch/{*searchterm}" 13 | }, 14 | { 15 | "type": "http", 16 | "direction": "out", 17 | "name": "res" 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /products-service-dotnet/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.2-sdk AS installer-env 2 | 3 | COPY . /src/dotnet-function-app 4 | RUN cd /src/dotnet-function-app && \ 5 | mkdir -p /home/site/wwwroot && \ 6 | dotnet publish *.csproj --output /home/site/wwwroot 7 | 8 | FROM mcr.microsoft.com/azure-functions/dotnet:2.0 9 | ENV AzureWebJobsScriptRoot=/home/site/wwwroot \ 10 | AzureFunctionsJobHost__Logging__Console__IsEnabled=true 11 | 12 | COPY --from=installer-env ["/home/site/wwwroot", "/home/site/wwwroot"] -------------------------------------------------------------------------------- /products-service-dotnet/DTOs/ProductDetails.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MessagePack; 3 | using Microsoft.WindowsAzure.Storage.Table; 4 | 5 | namespace Serverless 6 | { 7 | [MessagePackObject] 8 | public class ProductDetails 9 | { 10 | [Key(0)] 11 | public Guid Id { get; set; } 12 | [Key(1)] 13 | public string Name { get; set; } 14 | [Key(2)] 15 | public string Description { get; set; } 16 | [Key(3)] 17 | public bool OnStock { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /products-service-js/GetProduct/index.js: -------------------------------------------------------------------------------- 1 | module.exports = function (context, req) { 2 | context.log('Start GetProduct...'); 3 | 4 | var product = context.bindings.product; 5 | 6 | if(product) { 7 | var result = { 8 | id: product.RowKey, name: product.Name, description: product.Description, onStock: product.OnStock 9 | }; 10 | 11 | context.res.status(200).json(result); 12 | } else { 13 | context.res.status(404); 14 | context.done(); 15 | } 16 | }; -------------------------------------------------------------------------------- /products-service-js/extensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | ** 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /shipping-service-java/extensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | ** 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /shipping-service-ts/extensions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | 5 | ** 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /shipping-service-java/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "func", 6 | "command": "host start", 7 | "problemMatcher": "$func-watch", 8 | "isBackground": true, 9 | "options": { 10 | "cwd": "${workspaceFolder}/target/azure-functions/shipping-service-java/" 11 | }, 12 | "dependsOn": "package" 13 | }, 14 | { 15 | "label": "package", 16 | "command": "mvn clean package", 17 | "type": "shell" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /shipping-service-ts/CreateShipment/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "bindings": [ 3 | { 4 | "name": "message", 5 | "type": "serviceBusTrigger", 6 | "direction": "in", 7 | "queueName": "ordersforshipping", 8 | "connection": "ServiceBus" 9 | }, 10 | { 11 | "name": "outQueue", 12 | "type": "serviceBus", 13 | "direction": "out", 14 | "queueName": "shippingsinitiated", 15 | "connection": "ServiceBus" 16 | } 17 | ], 18 | "scriptFile": "../dist/CreateShipment/index.js" 19 | } 20 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | MyShopping 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 |
16 |
17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /shipping-service-java/.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled 5 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 6 | org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore 7 | org.eclipse.jdt.core.compiler.processAnnotations=disabled 8 | org.eclipse.jdt.core.compiler.release=disabled 9 | org.eclipse.jdt.core.compiler.source=1.8 10 | -------------------------------------------------------------------------------- /shopping-client-ng/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "exclude": [ 4 | "node_modules" 5 | ], 6 | "compilerOptions": { 7 | "typeRoots": [ 8 | "node_modules/@types" 9 | ], 10 | "outDir": "./dist/out-tsc", 11 | "sourceMap": true, 12 | "declaration": false, 13 | "moduleResolution": "node", 14 | "emitDecoratorMetadata": true, 15 | "experimentalDecorators": true, 16 | "target": "es5", 17 | "lib": [ 18 | "es2016", 19 | "dom" 20 | ], 21 | "module": "es2015", 22 | "baseUrl": "./" 23 | } 24 | } -------------------------------------------------------------------------------- /shipping-service-java/.gitignore: -------------------------------------------------------------------------------- 1 | # Build output 2 | target/ 3 | *.class 4 | 5 | # Log file 6 | *.log 7 | 8 | # BlueJ files 9 | *.ctxt 10 | 11 | # Mobile Tools for Java (J2ME) 12 | .mtj.tmp/ 13 | 14 | # Package Files # 15 | *.jar 16 | *.war 17 | *.ear 18 | *.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | 25 | # IDE 26 | .idea/ 27 | *.iml 28 | 29 | # macOS 30 | .DS_Store 31 | 32 | # Azure Functions 33 | local.settings.json 34 | bin/ 35 | obj/ 36 | -------------------------------------------------------------------------------- /shipping-service-dotnet/Functions/KeepItWarm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Host; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Serverless 7 | { 8 | public static class KeepItWarm 9 | { 10 | [FunctionName("KeepItWarm")] 11 | public static void Run( 12 | [TimerTrigger("0 */9 * * * *")] 13 | TimerInfo myTimer, 14 | ILogger log) 15 | { 16 | log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /products-service-js/ListProducts/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "type": "httpTrigger", 6 | "authLevel": "anonymous", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["get"], 10 | "route": "api/products" 11 | }, 12 | { 13 | "type": "http", 14 | "direction": "out", 15 | "name": "res" 16 | }, 17 | { 18 | "type": "table", 19 | "name": "products", 20 | "tableName": "products", 21 | "partitionKey": "products", 22 | "direction": "in" 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Consent/ConsentInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace IdentityServer 8 | { 9 | public class ConsentInputModel 10 | { 11 | public string Button { get; set; } 12 | public IEnumerable ScopesConsented { get; set; } 13 | public bool RememberConsent { get; set; } 14 | public string ReturnUrl { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Functions/Infrastructure/KeepItWarm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Host; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Serverless 7 | { 8 | public static class KeepItWarm 9 | { 10 | [FunctionName("KeepItWarm")] 11 | public static void Run( 12 | [TimerTrigger("0 */9 * * * *")] 13 | TimerInfo timer, ILogger log) 14 | { 15 | log.LogInformation($"KeepItWarm Timer trigger function executed at: {DateTime.Now}"); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/Functions/KeepItWarm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Host; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Serverless 7 | { 8 | public static class KeepItWarm 9 | { 10 | [FunctionName("KeepItWarm")] 11 | public static void Run( 12 | [TimerTrigger("0 */9 * * * *", RunOnStartup = true)] 13 | TimerInfo timer, 14 | ILogger log) 15 | { 16 | log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Consent/ScopeViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class ScopeViewModel 8 | { 9 | public string Name { get; set; } 10 | public string DisplayName { get; set; } 11 | public string Description { get; set; } 12 | public bool Emphasize { get; set; } 13 | public bool Required { get; set; } 14 | public bool Checked { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /notification-service-dotnet/Functions/Infrastructure/KeepItWarm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Host; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Serverless 7 | { 8 | public class KeepItWarm 9 | { 10 | [FunctionName("KeepItWarm")] 11 | public void Run( 12 | [TimerTrigger("0 */9 * * * *", RunOnStartup = true)] 13 | TimerInfo myTimer, 14 | ILogger log) 15 | { 16 | log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/LoginInputModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.ComponentModel.DataAnnotations; 6 | 7 | namespace IdentityServer 8 | { 9 | public class LoginInputModel 10 | { 11 | [Required] 12 | public string Username { get; set; } 13 | [Required] 14 | public string Password { get; set; } 15 | public bool RememberLogin { get; set; } 16 | public string ReturnUrl { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/hmr.ts: -------------------------------------------------------------------------------- 1 | import {ApplicationRef, NgModuleRef} from '@angular/core'; 2 | import {createNewHosts} from '@angularclass/hmr'; 3 | 4 | export const hmrBootstrap = (module: any, bootstrap: () => Promise>) => { 5 | let ngModule: NgModuleRef; 6 | module.hot.accept(); 7 | bootstrap().then(mod => ngModule = mod); 8 | module.hot.dispose(() => { 9 | const appRef: ApplicationRef = ngModule.injector.get(ApplicationRef); 10 | const elements = appRef.components.map(c => c.location.nativeElement); 11 | const makeVisible = createNewHosts(elements); 12 | ngModule.destroy(); 13 | makeVisible(); 14 | }); 15 | }; 16 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_table.scss: -------------------------------------------------------------------------------- 1 | @import '_variables'; 2 | 3 | .table { 4 | width: 100%; 5 | 6 | border: 0; 7 | border-spacing: 0; 8 | 9 | td, th { 10 | padding: $gap/4; 11 | } 12 | 13 | thead { 14 | tr { 15 | background-color: $primary-color; 16 | 17 | th { 18 | text-align: left; 19 | color: white; 20 | font-weight: bold; 21 | 22 | &:first-child { 23 | width: 20%; 24 | } 25 | } 26 | } 27 | } 28 | 29 | tbody { 30 | tr { 31 | &:nth-child(even) { 32 | background-color: darken($background-color, 3%); 33 | } 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /orders-service-dotnet/Functions/Infrastructure/KeepItWarm.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Host; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Serverless 7 | { 8 | public static class KeepItWarm 9 | { 10 | /* 11 | [FunctionName("KeepItWarm")] 12 | public static void Run( 13 | [TimerTrigger("0 *9 * * * *", RunOnStartup = true)] 14 | TimerInfo myTimer, 15 | ILogger log) 16 | { 17 | log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); 18 | } 19 | */ 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /products-service-js/GetProduct/function.json: -------------------------------------------------------------------------------- 1 | { 2 | "disabled": false, 3 | "bindings": [ 4 | { 5 | "authLevel": "anonymous", 6 | "type": "httpTrigger", 7 | "direction": "in", 8 | "name": "req", 9 | "methods": ["get"], 10 | "route": "api/products/{productId}" 11 | }, 12 | { 13 | "type": "http", 14 | "direction": "out", 15 | "name": "res" 16 | }, 17 | { 18 | "name": "product", 19 | "type": "table", 20 | "tableName": "products", 21 | "partitionKey": "products", 22 | "rowKey": "{productId}", 23 | "direction": "in" 24 | } 25 | ] 26 | } -------------------------------------------------------------------------------- /shipping-service-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shipping-service-ts", 3 | "description": "", 4 | "version": "0.1.0", 5 | "scripts": { 6 | "build": "tsc", 7 | "watch": "tsc -w", 8 | "prestart": "npm run build && func extensions install", 9 | "start:host": "func start", 10 | "start": "npm run start:host & npm run watch", 11 | "build:production": "npm run prestart && npm prune --production", 12 | "test": "echo \"No tests yet...\"" 13 | }, 14 | "dependencies": { 15 | "guid-typescript": "^1.0.9", 16 | "uuid": "^3.3.2" 17 | }, 18 | "devDependencies": { 19 | "@azure/functions": "^1.0.1-beta2", 20 | "typescript": "^3.3.3" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/environments/environment.hmr.ts: -------------------------------------------------------------------------------- 1 | import { AuthConfig } from "angular-oauth2-oidc"; 2 | 3 | export const environment = { 4 | production: false, 5 | hmr: true, 6 | 7 | loginRoute: "/login", 8 | notificationsServiceBaseUrl: "http://localhost:7074/api/", 9 | ordersApiBaseUrl: "http://localhost:7071/api/", 10 | productsApiBaseUrl: "http://localhost:7073/api/" 11 | }; 12 | 13 | export const resourceOwnerConfig: AuthConfig = { 14 | issuer: "https://cw-serverless-microservices-identity.azurewebsites.net", 15 | clientId: "resourceowner", 16 | dummyClientSecret: "no-really-a-secret", 17 | scope: "openid profile email api", 18 | oidc: false 19 | }; 20 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/login/login.html: -------------------------------------------------------------------------------- 1 | 15 | -------------------------------------------------------------------------------- /products-service-dotnet/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.WebJobs; 2 | using Microsoft.Azure.WebJobs.Hosting; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Serverless; 5 | using Willezone.Azure.WebJobs.Extensions.DependencyInjection; 6 | 7 | [assembly: WebJobsStartup(typeof(Startup))] 8 | 9 | namespace Serverless 10 | { 11 | internal class Startup : IWebJobsStartup 12 | { 13 | public void Configure(IWebJobsBuilder builder) => 14 | builder.AddDependencyInjection(ConfigureServices); 15 | 16 | private void ConfigureServices(IServiceCollection services) 17 | { 18 | services.AddDistributedMemoryCache(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | import { AuthConfig } from "angular-oauth2-oidc"; 2 | 3 | export const environment = { 4 | production: false, 5 | hmr: false, 6 | 7 | loginRoute: "/login", 8 | notificationsServiceBaseUrl: "http://localhost:7074/api/", 9 | ordersApiBaseUrl: "http://localhost:7071/api/", 10 | productsApiBaseUrl: "http://localhost:7073/api/" 11 | }; 12 | 13 | export const resourceOwnerConfig: AuthConfig = { 14 | issuer: "http://localhost:7075", 15 | clientId: "resourceowner", 16 | dummyClientSecret: "no-really-a-secret", 17 | scope: "openid profile email api", 18 | oidc: false, 19 | strictDiscoveryDocumentValidation: false, 20 | requireHttps: false 21 | }; 22 | -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Account/Logout.cshtml: -------------------------------------------------------------------------------- 1 | @model LogoutViewModel 2 | 3 |
4 | 7 | 8 |
9 |
10 |

Would you like to logout of IdentityServer?

11 |
12 | 13 |
14 |
15 | 16 |
17 |
18 |
19 |
20 |
21 |
-------------------------------------------------------------------------------- /identity-service-dotnet/Views/Diagnostics/Index.cshtml: -------------------------------------------------------------------------------- 1 | @model DiagnosticsViewModel 2 | 3 |

Authentication cookie

4 | 5 |

Claims

6 |
7 | @foreach (var claim in Model.AuthenticateResult.Principal.Claims) 8 | { 9 |
@claim.Type
10 |
@claim.Value
11 | } 12 |
13 | 14 |

Properties

15 |
16 | @foreach (var prop in Model.AuthenticateResult.Properties.Items) 17 | { 18 |
@prop.Key
19 |
@prop.Value
20 | } 21 |
22 | 23 | @if (Model.Clients.Any()) 24 | { 25 |

Clients

26 |
    27 | @foreach (var client in Model.Clients) 28 | { 29 |
  • @client
  • 30 | } 31 |
32 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/global.scss: -------------------------------------------------------------------------------- 1 | @import '_variables.scss'; 2 | @import '_menu.scss'; 3 | @import '_backdrop.scss'; 4 | @import '_table.scss'; 5 | @import '_links.scss'; 6 | @import '_loader.scss'; 7 | 8 | * { 9 | box-sizing: border-box; 10 | } 11 | 12 | body { 13 | overflow-x: hidden; 14 | -webkit-overflow-scrolling: touch; 15 | max-width: 100vw; 16 | max-height: 100vh; 17 | display: flex; 18 | min-width: 100vw; 19 | min-height: 100vh; 20 | margin: 0; 21 | padding: $header-height 0 0; 22 | 23 | font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Roboto", "Helvetica Neue", Arial, sans-serif; 24 | background-color: $background-color; 25 | user-select: none; 26 | line-height: 1.5; 27 | } 28 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | import { AuthConfig } from "angular-oauth2-oidc"; 2 | 3 | export const environment = { 4 | production: true, 5 | hmr: false, 6 | 7 | loginRoute: "/login", 8 | notificationsServiceBaseUrl: "https://notifications.serverlessmicroservices.net/api/", 9 | ordersApiBaseUrl: "https://orders.serverlessmicroservices.net/api/", 10 | productsApiBaseUrl: "https://products.serverlessmicroservices.net/api/" 11 | }; 12 | 13 | export const resourceOwnerConfig: AuthConfig = { 14 | issuer: "https://cw-serverless-microservices-identity.azurewebsites.net", 15 | clientId: "resourceowner", 16 | dummyClientSecret: "no-really-a-secret", 17 | scope: "openid profile email api", 18 | oidc: false 19 | }; 20 | -------------------------------------------------------------------------------- /products-service-dotnet/Entities/ProductDetailsEntity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.WindowsAzure.Storage.Table; 3 | 4 | namespace Serverless 5 | { 6 | public class ProductDetailsEntity : TableEntity 7 | { 8 | public Guid Id { get; set; } 9 | public string Name { get; set; } 10 | public string Description { get; set; } 11 | public bool OnStock { get; set; } 12 | 13 | public ProductDetails ToProductDetails() 14 | { 15 | return new ProductDetails 16 | { 17 | Id = Guid.Parse(this.RowKey), 18 | Name = this.Name, 19 | Description = this.Description, 20 | OnStock = this.OnStock 21 | }; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Consent/ProcessConsentResult.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class ProcessConsentResult 8 | { 9 | public bool IsRedirect => RedirectUri != null; 10 | public string RedirectUri { get; set; } 11 | public string ClientId { get; set; } 12 | 13 | public bool ShowView => ViewModel != null; 14 | public ConsentViewModel ViewModel { get; set; } 15 | 16 | public bool HasValidationError => ValidationError != null; 17 | public string ValidationError { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Consent/ConsentViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Collections.Generic; 6 | 7 | namespace IdentityServer 8 | { 9 | public class ConsentViewModel : ConsentInputModel 10 | { 11 | public string ClientName { get; set; } 12 | public string ClientUrl { get; set; } 13 | public string ClientLogoUrl { get; set; } 14 | public bool AllowRememberConsent { get; set; } 15 | 16 | public IEnumerable IdentityScopes { get; set; } 17 | public IEnumerable ResourceScopes { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/functions/HealthCheck.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.functions; 2 | 3 | import java.util.*; 4 | import com.microsoft.azure.functions.annotation.*; 5 | import com.microsoft.azure.functions.*; 6 | 7 | public class HealthCheck { 8 | @FunctionName("Ping") 9 | public HttpResponseMessage run( 10 | @HttpTrigger(name = "req", route = "ping", methods = { HttpMethod.GET }, authLevel = AuthorizationLevel.ANONYMOUS) 11 | HttpRequestMessage> request, 12 | final ExecutionContext context) { 13 | context.getLogger().info("Ping HTTP trigger processed a request."); 14 | 15 | return request.createResponseBuilder(HttpStatus.OK).body("OK").build(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/LoggedOutViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class LoggedOutViewModel 8 | { 9 | public string PostLogoutRedirectUri { get; set; } 10 | public string ClientName { get; set; } 11 | public string SignOutIframeUrl { get; set; } 12 | 13 | public bool AutomaticRedirectAfterSignOut { get; set; } = false; 14 | 15 | public string LogoutId { get; set; } 16 | public bool TriggerExternalSignout => ExternalAuthenticationScheme != null; 17 | public string ExternalAuthenticationScheme { get; set; } 18 | } 19 | } -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/functions/KeepItWarm.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.functions; 2 | 3 | import java.time.*; 4 | import com.microsoft.azure.functions.annotation.*; 5 | import com.microsoft.azure.functions.*; 6 | 7 | /** 8 | * Azure Functions with Timer trigger. 9 | */ 10 | public class KeepItWarm { 11 | /** 12 | * This function will be invoked periodically according to the specified schedule. 13 | */ 14 | @FunctionName("KeepItWarm") 15 | public void run( 16 | @TimerTrigger(name = "timerInfo", schedule = "0 */9 * * * *") 17 | String timerInfo, 18 | final ExecutionContext context 19 | ) { 20 | context.getLogger().info("Java Timer trigger function executed at: " + LocalDateTime.now()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Consent/ConsentOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | namespace IdentityServer 6 | { 7 | public class ConsentOptions 8 | { 9 | public static bool EnableOfflineAccess = true; 10 | public static string OfflineAccessDisplayName = "Offline Access"; 11 | public static string OfflineAccessDescription = "Access to your applications and resources, even when you are offline"; 12 | 13 | public static readonly string MustChooseOneErrorMessage = "You must pick at least one permission"; 14 | public static readonly string InvalidSelectionErrorMessage = "Invalid selection"; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /shipping-service-ts/KeepItWarm/readme.md: -------------------------------------------------------------------------------- 1 | # TimerTrigger - TypeScript 2 | 3 | The `TimerTrigger` makes it incredibly easy to have your functions executed on a schedule. This sample demonstrates a simple use case of calling your function every 5 minutes. 4 | 5 | ## How it works 6 | 7 | For a `TimerTrigger` to work, you provide a schedule in the form of a [cron expression](https://en.wikipedia.org/wiki/Cron#CRON_expression)(See the link for full details). A cron expression is a string with 6 separate expressions which represent a given schedule via patterns. The pattern we use to represent every 5 minutes is `0 */5 * * * *`. This, in plain text, means: "When seconds is equal to 0, minutes is divisible by 5, for any hour, day of the month, month, day of the week, or year". 8 | 9 | ## Learn more 10 | 11 | Documentation -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/services/desktopIntegrationService.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, NgZone } from "@angular/core"; 2 | import { ElectronService } from "ngx-electron"; 3 | import { Router } from "@angular/router"; 4 | import { PlatformService } from "./platformService"; 5 | 6 | @Injectable() 7 | export class DesktopIntegrationService { 8 | constructor( 9 | private _platform: PlatformService, 10 | private _electronService: ElectronService, 11 | private _zone: NgZone, 12 | private _router: Router 13 | ) {} 14 | 15 | public register() { 16 | if (this._platform.isElectron) { 17 | this._electronService.ipcRenderer.on("navigateTo", (event, data) => { 18 | this._zone.run(() => { 19 | this._router.navigate([data]); 20 | }); 21 | }); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/routes.ts: -------------------------------------------------------------------------------- 1 | import {Routes} from '@angular/router'; 2 | import {HomeComponent} from './components/home/home'; 3 | import {LoginComponent} from './components/login/login'; 4 | import {IsAuthenticated} from './guards/isAuthenticated'; 5 | import {OrderListComponent} from './components/list/orderList'; 6 | 7 | export const ROUTES: Routes = [ 8 | { 9 | path: 'login', 10 | component: LoginComponent 11 | }, 12 | { 13 | path: '', 14 | pathMatch: 'full', 15 | redirectTo: '/home' 16 | }, 17 | { 18 | path: 'home', 19 | component: HomeComponent 20 | }, 21 | { 22 | path: 'orders', 23 | canActivate: [IsAuthenticated], 24 | children: [ 25 | { 26 | path: 'list', 27 | component: OrderListComponent 28 | } 29 | ] 30 | } 31 | ]; 32 | -------------------------------------------------------------------------------- /products-service-js/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Run Functions Host", 6 | "identifier": "runFunctionsHost", 7 | "type": "shell", 8 | "command": "func host start", 9 | "isBackground": true, 10 | "presentation": { 11 | "reveal": "always" 12 | }, 13 | "problemMatcher": "$func-watch", 14 | "options": { 15 | "env": { 16 | "languageWorkers__node__arguments": "--inspect=5858" 17 | } 18 | }, 19 | "dependsOn": "installExtensions" 20 | }, 21 | { 22 | "label": "installExtensions", 23 | "identifier": "installExtensions", 24 | "command": "func extensions install", 25 | "type": "shell", 26 | "presentation": { 27 | "reveal": "always" 28 | } 29 | } 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /shipping-service-ts/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "func", 6 | "command": "host start", 7 | "problemMatcher": "$func-watch", 8 | "isBackground": true, 9 | "dependsOn": "npm build" 10 | }, 11 | { 12 | "type": "shell", 13 | "label": "npm build", 14 | "command": "npm run build", 15 | "dependsOn": [ 16 | "func: extensions install", 17 | "npm install" 18 | ], 19 | "problemMatcher": "$tsc" 20 | }, 21 | { 22 | "type": "shell", 23 | "label": "npm install", 24 | "command": "npm install" 25 | }, 26 | { 27 | "type": "shell", 28 | "label": "npm prune", 29 | "command": "npm prune --production", 30 | "dependsOn": "npm build", 31 | "problemMatcher": [] 32 | } 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /shipping-service-dotnet/shipping-service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | v2 5 | shipping_service 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | PreserveNewest 14 | 15 | 16 | PreserveNewest 17 | Never 18 | 19 | 20 | -------------------------------------------------------------------------------- /notification-service-dotnet/Functions/Infrastructure/HealthCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Newtonsoft.Json; 10 | 11 | namespace Serverless 12 | { 13 | public class HealthCheck 14 | { 15 | [FunctionName("Ping")] 16 | public async Task Run( 17 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "api/ping")] 18 | HttpRequest req, 19 | ILogger log) 20 | { 21 | log.LogInformation("C# Ping trigger function processed a request."); 22 | 23 | return new OkObjectResult("OK"); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /orders-service-dotnet/Pipeline/ModelBinding.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Microsoft.AspNetCore.Http; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace Serverless 7 | { 8 | public static class ModelBinding 9 | { 10 | public static T Deserialize(this HttpRequest request) 11 | { 12 | using (var reader = new StreamReader(request.Body)) 13 | using (var textReader = new JsonTextReader(reader)) 14 | { 15 | request.Body.Seek(0, SeekOrigin.Begin); 16 | 17 | var serializer = JsonSerializer.Create(new JsonSerializerSettings() 18 | { 19 | ContractResolver = new CamelCasePropertyNamesContractResolver() 20 | }); 21 | 22 | return serializer.Deserialize(textReader); 23 | } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using IdentityServer4.Stores; 3 | 4 | namespace IdentityServer 5 | { 6 | public static class Extensions 7 | { 8 | /// 9 | /// Determines whether the client is configured to use PKCE. 10 | /// 11 | /// The store. 12 | /// The client identifier. 13 | /// 14 | public static async Task IsPkceClientAsync(this IClientStore store, string client_id) 15 | { 16 | if (!string.IsNullOrWhiteSpace(client_id)) 17 | { 18 | var client = await store.FindEnabledClientByIdAsync(client_id); 19 | return client?.RequirePkce == true; 20 | } 21 | 22 | return false; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_menu.scss: -------------------------------------------------------------------------------- 1 | @import '_utilities'; 2 | 3 | html { 4 | body { 5 | @include media('<=desktop') { 6 | @include media('>tablet') { 7 | padding-left: $menu-width; 8 | } 9 | 10 | &.show-menu { 11 | app-menu { 12 | transform: none; 13 | 14 | > .menu { 15 | > .menu-item { 16 | &.active:not(.show) { 17 | box-shadow: none; 18 | background-color: lighten($alternative-background-color, 10%); 19 | 20 | .menu-link { 21 | color: white; 22 | } 23 | } 24 | } 25 | } 26 | } 27 | 28 | .backdrop { 29 | opacity: 0.75; 30 | } 31 | } 32 | } 33 | 34 | @include media('<=tablet') { 35 | padding-bottom: $menu-height; 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /orders-service-dotnet/Functions/Infrastructure/HealthCheck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Extensions.Logging; 9 | using Newtonsoft.Json; 10 | 11 | namespace Serverless 12 | { 13 | public class HealthCheck 14 | { 15 | [FunctionName("Ping")] 16 | public IActionResult Run( 17 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "api/status/ping")] 18 | HttpRequest req, 19 | ExecutionContext context, 20 | ILogger log) 21 | { 22 | log.LogInformation("Ping HTTP trigger function processed a request."); 23 | 24 | return new OkObjectResult("OK"); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /products-service-dotnet/products-service-dotnet.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "products-service-dotnet", "products-service-dotnet.csproj", "{78D8D920-09AA-49FB-B43B-D4CE20A8CC05}" 5 | EndProject 6 | Global 7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 8 | Debug|Any CPU = Debug|Any CPU 9 | Release|Any CPU = Release|Any CPU 10 | EndGlobalSection 11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 12 | {78D8D920-09AA-49FB-B43B-D4CE20A8CC05}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 13 | {78D8D920-09AA-49FB-B43B-D4CE20A8CC05}.Debug|Any CPU.Build.0 = Debug|Any CPU 14 | {78D8D920-09AA-49FB-B43B-D4CE20A8CC05}.Release|Any CPU.ActiveCfg = Release|Any CPU 15 | {78D8D920-09AA-49FB-B43B-D4CE20A8CC05}.Release|Any CPU.Build.0 = Release|Any CPU 16 | EndGlobalSection 17 | EndGlobal 18 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/main.ts: -------------------------------------------------------------------------------- 1 | import {enableProdMode} from '@angular/core'; 2 | import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; 3 | 4 | import {environment} from './environments/environment'; 5 | import {hmrBootstrap} from './hmr'; 6 | import {AppModule} from './modules/app/module'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | const bootstrap = () => platformBrowserDynamic().bootstrapModule(AppModule); 13 | 14 | function start() { 15 | if (window.cordova) { 16 | return document.addEventListener('deviceready', bootstrap); 17 | } 18 | 19 | window.addEventListener('load', bootstrap); 20 | } 21 | 22 | if (environment.hmr) { 23 | if (module['hot']) { 24 | hmrBootstrap(module, bootstrap); 25 | } else { 26 | console.error('HMR is not enabled for webpack-dev-server!'); 27 | console.log('Are you using the --hmr flag for ng serve?'); 28 | } 29 | } else { 30 | start(); 31 | } 32 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | <_IsFunctionsSdkBuild Condition="$(_FunctionsTaskFramework) != ''">true 4 | <_FunctionsExtensionsDir>$(TargetDir) 5 | <_FunctionsExtensionsDir Condition="$(_IsFunctionsSdkBuild) == 'true'">$(_FunctionsExtensionsDir)bin 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Azure.WebJobs; 2 | using Microsoft.Azure.WebJobs.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Serverless; 6 | using Willezone.Azure.WebJobs.Extensions.AzureKeyVault; 7 | 8 | [assembly: WebJobsStartup(typeof(Startup))] 9 | 10 | namespace Serverless 11 | { 12 | public class Startup : IWebJobsStartup 13 | { 14 | public void Configure(IWebJobsBuilder builder) 15 | { 16 | var tempProvider = builder.Services.BuildServiceProvider(); 17 | var config = tempProvider.GetRequiredService(); 18 | 19 | // NOTE: This is *only* for local dev & demos - as we now have a secret in our code... again ;-( 20 | // For production use a MSI 21 | builder.AddAzureKeyVault(config["KeyVaultUrl"], config["KeyVaultClientId"], config["KeyVaultClientSecret"]); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /products-service-dotnet/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | <_IsFunctionsSdkBuild Condition="$(_FunctionsTaskFramework) != ''">true 4 | <_FunctionsExtensionsDir>$(TargetDir) 5 | <_FunctionsExtensionsDir Condition="$(_IsFunctionsSdkBuild) == 'true'">$(_FunctionsExtensionsDir)bin 6 | 7 | 8 | 9 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Grants/GrantsViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | 8 | namespace IdentityServer 9 | { 10 | public class GrantsViewModel 11 | { 12 | public IEnumerable Grants { get; set; } 13 | } 14 | 15 | public class GrantViewModel 16 | { 17 | public string ClientId { get; set; } 18 | public string ClientName { get; set; } 19 | public string ClientUrl { get; set; } 20 | public string ClientLogoUrl { get; set; } 21 | public DateTime Created { get; set; } 22 | public DateTime? Expires { get; set; } 23 | public IEnumerable IdentityGrantNames { get; set; } 24 | public IEnumerable ApiGrantNames { get; set; } 25 | } 26 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/styles/_loader.scss: -------------------------------------------------------------------------------- 1 | @import '_utilities'; 2 | 3 | .loader-container { 4 | position: fixed; 5 | display: flex; 6 | align-items: center; 7 | top: 0; 8 | bottom: 0; 9 | left: 0; 10 | right: 0; 11 | } 12 | 13 | .loader, 14 | .loader:after { 15 | border-radius: 50%; 16 | width: 10em; 17 | height: 10em; 18 | } 19 | 20 | .loader { 21 | margin: 60px auto; 22 | font-size: 10px; 23 | position: relative; 24 | text-indent: -9999em; 25 | border-top: 1.1em solid $primary-color; 26 | border-right: 1.1em solid $primary-color; 27 | border-bottom: 1.1em solid $primary-color; 28 | border-left: 1.1em solid #dddddd; 29 | transform: translateZ(0); 30 | animation: load8 1.1s infinite linear; 31 | } 32 | 33 | @keyframes load8 { 34 | 0% { 35 | -webkit-transform: rotate(0deg); 36 | transform: rotate(0deg); 37 | } 38 | 100% { 39 | -webkit-transform: rotate(360deg); 40 | transform: rotate(360deg); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Account/LoggedOut.cshtml: -------------------------------------------------------------------------------- 1 | @model LoggedOutViewModel 2 | 3 | @{ 4 | // set this so the layout rendering sees an anonymous user 5 | ViewData["signed-out"] = true; 6 | } 7 | 8 | 27 | 28 | @section scripts 29 | { 30 | @if (Model.AutomaticRedirectAfterSignOut) 31 | { 32 | 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /shipping-service-java/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | shipping-service-java 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | 25 | 1602503767655 26 | 27 | 30 28 | 29 | org.eclipse.core.resources.regexFilterMatcher 30 | node_modules|.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/list/orderList.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from "@angular/core"; 2 | import { OrdersService } from "../../services/ordersService"; 3 | import { PushService } from "../../services/pushService"; 4 | import { Observable } from "rxjs"; 5 | import { OrderWithItems } from "../../models/orderWithItems"; 6 | 7 | @Component({ 8 | selector: "app-order-list", 9 | templateUrl: "orderList.html", 10 | styleUrls: ["orderList.scss"] 11 | }) 12 | export class OrderListComponent implements OnInit { 13 | public ordersWithItems$: Observable; 14 | 15 | constructor( 16 | private _orderService: OrdersService, 17 | private _pushService: PushService 18 | ) { 19 | this._pushService.orderCreated.subscribe(_ => { 20 | this.loadOrders(); 21 | }); 22 | } 23 | 24 | private loadOrders() { 25 | this.ordersWithItems$ = this._orderService.getOrders(); 26 | } 27 | 28 | public ngOnInit(): void { 29 | this.loadOrders(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/header/header.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../styles/_utilities'; 2 | 3 | :host { 4 | top: 0; 5 | left: 0; 6 | right: 0; 7 | position: fixed; 8 | display: flex; 9 | height: $header-height; 10 | 11 | background-color: $primary-color; 12 | 13 | align-items: center; 14 | 15 | padding: $gap/2; 16 | color: white; 17 | 18 | @include media('<=desktop') { 19 | justify-content: center; 20 | } 21 | } 22 | 23 | .brand { 24 | padding-right: $gap/2; 25 | } 26 | 27 | .brand-logo { 28 | height: $header-height - $gap; 29 | margin-left: auto; 30 | 31 | @include media('<=desktop') { 32 | margin-left: inherit; 33 | position: absolute; 34 | right: $gap/2; 35 | } 36 | } 37 | 38 | .back-chevron { 39 | background-color: transparent; 40 | color: white; 41 | position: absolute; 42 | left: $gap/2; 43 | border: none; 44 | outline: none; 45 | 46 | i { 47 | font-size: 20px; 48 | } 49 | 50 | @include media('>desktop') { 51 | display: none; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/LoginViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | 9 | namespace IdentityServer 10 | { 11 | public class LoginViewModel : LoginInputModel 12 | { 13 | public bool AllowRememberLogin { get; set; } = true; 14 | public bool EnableLocalLogin { get; set; } = true; 15 | 16 | public IEnumerable ExternalProviders { get; set; } = Enumerable.Empty(); 17 | public IEnumerable VisibleExternalProviders => ExternalProviders.Where(x => !String.IsNullOrWhiteSpace(x.DisplayName)); 18 | 19 | public bool IsExternalLoginOnly => EnableLocalLogin == false && ExternalProviders?.Count() == 1; 20 | public string ExternalLoginScheme => IsExternalLoginOnly ? ExternalProviders?.SingleOrDefault()?.AuthenticationScheme : null; 21 | } 22 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/services/platformService.ts: -------------------------------------------------------------------------------- 1 | export class PlatformService { 2 | private _iOS: boolean; 3 | private _isAndroid: boolean; 4 | private _isElectron: boolean; 5 | 6 | public get isMobileDevice(): boolean { 7 | return this._iOS || this._isAndroid; 8 | } 9 | 10 | public get isMobileWeb(): boolean { 11 | return window.innerWidth <= 768; 12 | } 13 | 14 | public get isWeb(): boolean { 15 | return !this.isMobileDevice; 16 | } 17 | 18 | public get isIOS(): boolean { 19 | return this._iOS; 20 | } 21 | 22 | public get isAndroid(): boolean { 23 | return this._isAndroid; 24 | } 25 | 26 | public get isElectron(): boolean { 27 | return this._isElectron; 28 | } 29 | 30 | constructor() { 31 | this.guessPlatform(); 32 | } 33 | 34 | private guessPlatform(): void { 35 | this._iOS = window.cordova && window.cordova.platformId === 'ios'; 36 | this._isAndroid = window.cordova && window.cordova.platformId === 'android'; 37 | this._isElectron = window.navigator.userAgent.match(/Electron/) !== null; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Diagnostics/DiagnosticsController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System.Linq; 6 | using System.Threading.Tasks; 7 | using Microsoft.AspNetCore.Authentication; 8 | using Microsoft.AspNetCore.Authorization; 9 | using Microsoft.AspNetCore.Mvc; 10 | 11 | namespace IdentityServer 12 | { 13 | [SecurityHeaders] 14 | [Authorize] 15 | public class DiagnosticsController : Controller 16 | { 17 | public async Task Index() 18 | { 19 | var localAddresses = new string[] { "127.0.0.1", "::1", HttpContext.Connection.LocalIpAddress.ToString() }; 20 | if (!localAddresses.Contains(HttpContext.Connection.RemoteIpAddress.ToString())) 21 | { 22 | return NotFound(); 23 | } 24 | 25 | var model = new DiagnosticsViewModel(await HttpContext.AuthenticateAsync()); 26 | return View(model); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Shared/_ScopeListItem.cshtml: -------------------------------------------------------------------------------- 1 | @model ScopeViewModel 2 | 3 |
  • 4 | 24 | @if (Model.Required) 25 | { 26 | (required) 27 | } 28 | @if (Model.Description != null) 29 | { 30 | 33 | } 34 |
  • -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/root/root.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | import { DesktopIntegrationService } from "../../services/desktopIntegrationService"; 3 | import { PushService } from "../../services/pushService"; 4 | import { OAuthService } from "angular-oauth2-oidc"; 5 | import { resourceOwnerConfig } from "../../../../environments/environment"; 6 | 7 | @Component({ 8 | selector: "app-root", 9 | templateUrl: "root.html", 10 | styleUrls: ["root.scss"] 11 | }) 12 | export class RootComponent { 13 | constructor( 14 | private _securityService: OAuthService, 15 | private _pushService: PushService, 16 | private _desktopIntegration: DesktopIntegrationService 17 | ) { 18 | this.initOAuth(); 19 | 20 | this._desktopIntegration.register(); 21 | } 22 | 23 | private initOAuth() { 24 | this._securityService.setStorage(localStorage); 25 | this._securityService.configure(resourceOwnerConfig); 26 | this._securityService.loadDiscoveryDocument(); 27 | 28 | if (this._securityService.getAccessToken()) { 29 | this._pushService.start(); 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Thinktecture AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /identity-service-dotnet/Functions/Infrastructure/LetsEncrypt.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Text; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.Azure.WebJobs; 7 | using Microsoft.Azure.WebJobs.Extensions.Http; 8 | using Microsoft.Extensions.Logging; 9 | 10 | namespace Serverless 11 | { 12 | public static class LetsEncryptFunctions 13 | { 14 | [FunctionName("LetsEncrypt")] 15 | public static HttpResponseMessage Run( 16 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = ".well-known/acme-challenge/{code}")] 17 | HttpRequest req, 18 | string code, 19 | ILogger log) 20 | { 21 | log.LogInformation($"LetsEncrypt HTTP trigger function processed a request: {code}"); 22 | 23 | var content = File.ReadAllText(@"D:\home\site\LetsEncrypt\.well-known\acme-challenge\" + code); 24 | var resp = new HttpResponseMessage(HttpStatusCode.OK); 25 | resp.Content = new StringContent(content, Encoding.UTF8, "text/plain"); 26 | 27 | return resp; 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Account/AccountOptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using System; 6 | 7 | namespace IdentityServer 8 | { 9 | public class AccountOptions 10 | { 11 | public static bool AllowLocalLogin = true; 12 | public static bool AllowRememberLogin = true; 13 | public static TimeSpan RememberMeLoginDuration = TimeSpan.FromDays(30); 14 | 15 | public static bool ShowLogoutPrompt = true; 16 | public static bool AutomaticRedirectAfterSignOut = false; 17 | 18 | // specify the Windows authentication scheme being used 19 | public static readonly string WindowsAuthenticationSchemeName = Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme; 20 | // if user uses windows auth, should we load the groups from windows 21 | public static bool IncludeWindowsGroups = false; 22 | 23 | public static string InvalidCredentialsErrorMessage = "Invalid username or password"; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /orders-service-dotnet/Functions/Infrastructure/LetsEncrypt.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.Azure.WebJobs; 8 | using Microsoft.Azure.WebJobs.Extensions.Http; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace Serverless 12 | { 13 | public class LetsEncryptFunctions 14 | { 15 | [FunctionName("LetsEncrypt")] 16 | public HttpResponseMessage Run( 17 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = ".well-known/acme-challenge/{code}")] 18 | HttpRequest req, 19 | string code, 20 | ILogger log) 21 | { 22 | log.LogInformation($"LetsEncrypt HTTP trigger function processed a request: {code}"); 23 | 24 | var content = File.ReadAllText(@"D:\home\site\LetsEncrypt\.well-known\acme-challenge\" + code); 25 | var resp = new HttpResponseMessage(HttpStatusCode.OK); 26 | resp.Content = new StringContent(content, Encoding.UTF8, "text/plain"); 27 | 28 | return resp; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Thinktecture AG 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Shared/Error.cshtml: -------------------------------------------------------------------------------- 1 | @model ErrorViewModel 2 | 3 | @{ 4 | var error = Model?.Error?.Error; 5 | var errorDescription = Model?.Error?.ErrorDescription; 6 | var request_id = Model?.Error?.RequestId; 7 | } 8 | 9 |
    10 | 13 | 14 |
    15 |
    16 |
    17 | Sorry, there was an error 18 | 19 | @if (error != null) 20 | { 21 | 22 | 23 | : @error 24 | 25 | 26 | 27 | if (errorDescription != null) 28 | { 29 |
    @errorDescription
    30 | } 31 | } 32 |
    33 | 34 | @if (request_id != null) 35 | { 36 |
    Request Id: @request_id
    37 | } 38 |
    39 |
    40 |
    41 | -------------------------------------------------------------------------------- /notification-service-dotnet/Functions/Infrastructure/LetsEncrypt.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Net; 3 | using System.Net.Http; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Microsoft.AspNetCore.Http; 7 | using Microsoft.Azure.WebJobs; 8 | using Microsoft.Azure.WebJobs.Extensions.Http; 9 | using Microsoft.Extensions.Logging; 10 | 11 | namespace Serverless 12 | { 13 | public class LetsEncryptFunctions 14 | { 15 | [FunctionName("LetsEncrypt")] 16 | public HttpResponseMessage Run( 17 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = ".well-known/acme-challenge/{code}")] 18 | HttpRequest req, 19 | string code, 20 | ILogger log) 21 | { 22 | log.LogInformation($"LetsEncrypt HTTP trigger function processed a request: {code}"); 23 | 24 | var content = File.ReadAllText(@"D:\home\site\LetsEncrypt\.well-known\acme-challenge\" + code); 25 | var resp = new HttpResponseMessage(HttpStatusCode.OK); 26 | resp.Content = new StringContent(content, Encoding.UTF8, "text/plain"); 27 | 28 | return resp; 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /serverless-microservices.code-workspace: -------------------------------------------------------------------------------- 1 | { 2 | "folders": [ 3 | { 4 | "name": "identity-service-dotnet", 5 | "path": "identity-service-dotnet" 6 | }, 7 | { 8 | "name": "invoice-scanner-dotnet", 9 | "path": "invoice-scanner-dotnet" 10 | }, 11 | { 12 | "name": "notification-service-dotnet", 13 | "path": "notification-service-dotnet" 14 | }, 15 | { 16 | "name": "orders-service-dotnet", 17 | "path": "orders-service-dotnet" 18 | }, 19 | { 20 | "name": "products-service-js", 21 | "path": "products-service-js" 22 | }, 23 | { 24 | "name": "products-service-dotnet", 25 | "path": "products-service-dotnet" 26 | }, 27 | { 28 | "name": "shipping-service-dotnet", 29 | "path": "shipping-service-dotnet" 30 | }, 31 | { 32 | "name": "shipping-service-java", 33 | "path": "shipping-service-java" 34 | }, 35 | { 36 | "name": "shipping-service-ts", 37 | "path": "shipping-service-ts" 38 | }, 39 | { 40 | "name": "shopping-client-ng", 41 | "path": "shopping-client-ng" 42 | }, 43 | { 44 | "path": "plant-uml" 45 | } 46 | ], 47 | "settings": { 48 | "azureFunctions.showTargetFrameworkWarning": false 49 | } 50 | } -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/guards/isAuthenticated.ts: -------------------------------------------------------------------------------- 1 | import { 2 | CanActivate, 3 | ActivatedRouteSnapshot, 4 | RouterStateSnapshot, 5 | Router 6 | } from "@angular/router"; 7 | import { Injectable } from "@angular/core"; 8 | import { OAuthService } from "angular-oauth2-oidc"; 9 | import { environment } from "../../../environments/environment"; 10 | import { Observable } from "rxjs"; 11 | 12 | @Injectable() 13 | export class IsAuthenticated implements CanActivate { 14 | constructor(private _oauthService: OAuthService, private _router: Router) { 15 | if (!environment.loginRoute) { 16 | throw new Error("Login route has not been configured."); 17 | } 18 | } 19 | 20 | public canActivate( 21 | route: ActivatedRouteSnapshot, 22 | state: RouterStateSnapshot 23 | ): Observable | Promise | boolean { 24 | const result = this._oauthService.hasValidAccessToken(); 25 | 26 | if (!result) { 27 | this._router.navigate([environment.loginRoute], { 28 | queryParams: { 29 | redirectTo: state.url 30 | } 31 | }); 32 | 33 | return false; 34 | } 35 | 36 | return true; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /orders-service-dotnet/Client HTTP Scripts/GetAllOrders.http: -------------------------------------------------------------------------------- 1 | # Regularly update the token via the RetrieveToken.http script 2 | @token = eyJhbGciOiJSUzI1NiIsImtpZCI6IjljNTIxMGFiZWZmZTg2ZjlkMmI5ZTEzM2Q4NWNjZDA4IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NDgxNTA4ODAsImV4cCI6MTU0ODIzNzI4MCwiaXNzIjoiaHR0cHM6Ly90dC1pZGVudGl0eXNlcnZlcjQtZGVtby5henVyZXdlYnNpdGVzLm5ldCIsImF1ZCI6WyJodHRwczovL3R0LWlkZW50aXR5c2VydmVyNC1kZW1vLmF6dXJld2Vic2l0ZXMubmV0L3Jlc291cmNlcyIsImFwaSJdLCJjbGllbnRfaWQiOiJyZXNvdXJjZW93bmVyIiwic3ViIjoiODg0MjExMTMiLCJhdXRoX3RpbWUiOjE1NDgxNTA4ODAsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsImFwaSJdLCJhbXIiOlsicHdkIl19.zWFvJ1Gkd4zDkJLnqQWSrEh3KB7za5TvHMq-A2HlQylb4IKLWmEuitZBRUJyec4PXSAnrRq5nRX7SHclk11--KE9DMyHrP8kY9LYGK52M-cx9hP4ci9vjaW6nn-Mc0gEjbiLGyHN0jljzSu28zm-jWiv9FY7hVRllPG8Hjcpt4Pc4sGQRpDOgYHw8oq7MVcis6mnKbvnOWVlGPxGIConc_GFOPzYeCZ8UV2p478BOTnUS0x4HKv9f66Af8KxJT9z_NZaKMyMXyHSPDhPTSs9SqcWrjubmlm1HR4vRfTmIcvXYMCPaZrW0cbh-Nza2jtFFu54eZ_WXpmnjwDqSO08BQ 3 | 4 | GET http://localhost:7071/api/orders 5 | #GET https://orders.serverlessmicroservices.net/api/orders 6 | #GET http://cw-serverless-microservices-orders.azurewebsites.net/api/orders 7 | Content-Type: application/json 8 | Authorization: Bearer {{ token }} 9 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Diagnostics/DiagnosticsViewModel.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityModel; 6 | using Microsoft.AspNetCore.Authentication; 7 | using Newtonsoft.Json; 8 | using System.Collections.Generic; 9 | using System.Text; 10 | 11 | namespace IdentityServer 12 | { 13 | public class DiagnosticsViewModel 14 | { 15 | public DiagnosticsViewModel(AuthenticateResult result) 16 | { 17 | AuthenticateResult = result; 18 | 19 | if (result.Properties.Items.ContainsKey("client_list")) 20 | { 21 | var encoded = result.Properties.Items["client_list"]; 22 | var bytes = Base64Url.Decode(encoded); 23 | var value = Encoding.UTF8.GetString(bytes); 24 | 25 | Clients = JsonConvert.DeserializeObject(value); 26 | } 27 | } 28 | 29 | public AuthenticateResult AuthenticateResult { get; } 30 | public IEnumerable Clients { get; } = new List(); 31 | } 32 | } -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/css/site.min.css: -------------------------------------------------------------------------------- 1 | body{margin-top:65px;}.navbar-header{position:relative;top:-4px;}.navbar-brand>.icon-banner{position:relative;top:-2px;display:inline;}.icon{position:relative;top:-10px;}.logged-out iframe{display:none;width:0;height:0;}.page-consent .client-logo{float:left;}.page-consent .client-logo img{width:80px;height:80px;}.page-consent .consent-buttons{margin-top:25px;}.page-consent .consent-form .consent-scopecheck{display:inline-block;margin-right:5px;}.page-consent .consent-form .consent-description{margin-left:25px;}.page-consent .consent-form .consent-description label{font-weight:normal;}.page-consent .consent-form .consent-remember{padding-left:16px;}.grants .page-header{margin-bottom:10px;}.grants .grant{margin-top:20px;padding-bottom:20px;border-bottom:1px solid #d3d3d3;}.grants .grant img{width:100px;height:100px;}.grants .grant .clientname{font-size:140%;font-weight:bold;}.grants .grant .granttype{font-size:120%;font-weight:bold;}.grants .grant .created{font-size:120%;font-weight:bold;}.grants .grant .expires{font-size:120%;font-weight:bold;}.grants .grant li{list-style-type:none;display:inline;}.grants .grant li:after{content:', ';}.grants .grant li:last-child:after{content:'';} -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/list/orderList.html: -------------------------------------------------------------------------------- 1 |

    Orders

    2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 |
    DescriptionCreatedShipping
    14 |

    {{ orderWithItems.order.description }}

    15 |
      16 | 17 |
    • 18 | {{ orderWithItems.order.items[i].quantity }}x {{ item.name }} 19 |
    • 20 | 21 |
    • 22 | ... 23 |
    • 24 |
      25 |
      26 |
    27 |
    {{ orderWithItems.order.created | date: 'dd.MM.yyyy HH:mm' }}
    36 | -------------------------------------------------------------------------------- /notification-service-dotnet/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "problemMatcher": "$msCompile" 9 | }, 10 | { 11 | "label": "build", 12 | "command": "dotnet build", 13 | "type": "shell", 14 | "dependsOn": "clean", 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | }, 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "label": "clean release", 23 | "command": "dotnet clean --configuration Release", 24 | "type": "shell", 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "publish", 29 | "command": "dotnet publish --configuration Release", 30 | "type": "shell", 31 | "dependsOn": "clean release", 32 | "problemMatcher": "$msCompile" 33 | }, 34 | { 35 | "type": "func", 36 | "dependsOn": "build", 37 | "options": { 38 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp2.1" 39 | }, 40 | "command": "host start", 41 | "isBackground": true, 42 | "problemMatcher": "$func-watch" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /products-service-js/SearchProducts/index.js: -------------------------------------------------------------------------------- 1 | var request = require('request'); 2 | var adminKey = process.env['SearchServiceKey']; 3 | 4 | module.exports = function (context, req) { 5 | context.log('Start SearchProducts...'); 6 | 7 | const searchterm = req.params.searchterm; 8 | 9 | if (searchterm) { 10 | var url = process.env['SearchServiceUrl'] + 11 | searchterm; 12 | 13 | var headers = {'api-key': adminKey}; 14 | 15 | var options = { 16 | url: url, 17 | headers: headers, 18 | withCredentials: false 19 | }; 20 | 21 | request.get(options, function(error, response, body){ 22 | var data = JSON.parse(body).value; 23 | 24 | if (!error) { 25 | var result = data.map(r => { 26 | return { id: r.RowKey, name: r.Name, description: r.Description } 27 | }); 28 | context.res.status(200).json(result); 29 | } 30 | else { 31 | context.res.status(500).json({error : error}); 32 | } 33 | }); 34 | } 35 | else { 36 | context.res.status(404); 37 | context.done(); 38 | } 39 | }; -------------------------------------------------------------------------------- /products-service-dotnet/products-service-dotnet.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | products_service_dotnet 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | PreserveNewest 21 | Never 22 | 23 | 24 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/invoice-scanner.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.0 4 | v2 5 | invoice_scanner 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | PreserveNewest 21 | Never 22 | 23 | 24 | -------------------------------------------------------------------------------- /identity-service-dotnet/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "problemMatcher": "$msCompile" 9 | }, 10 | { 11 | "label": "build", 12 | "command": "dotnet build", 13 | "type": "shell", 14 | "dependsOn": "clean", 15 | "group": { 16 | "kind": "build", 17 | "isDefault": true 18 | }, 19 | "problemMatcher": "$msCompile" 20 | }, 21 | { 22 | "label": "clean release", 23 | "command": "dotnet clean --configuration Release", 24 | "type": "shell", 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "publish", 29 | "command": "dotnet publish --configuration Release", 30 | "type": "shell", 31 | "dependsOn": "clean release", 32 | "problemMatcher": "$msCompile" 33 | }, 34 | { 35 | "label": "runFunctionsHost", 36 | "type": "shell", 37 | "dependsOn": "build", 38 | "options": { 39 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp2.1" 40 | }, 41 | "command": "func host start", 42 | "isBackground": true, 43 | "problemMatcher": "$func-watch" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/login/login.ts: -------------------------------------------------------------------------------- 1 | import { Component, HostBinding } from "@angular/core"; 2 | import { ActivatedRoute, Router } from "@angular/router"; 3 | import { PushService } from "../../services/pushService"; 4 | import { OAuthService } from "angular-oauth2-oidc"; 5 | 6 | @Component({ 7 | selector: "app-security-login", 8 | styleUrls: ["login.scss"], 9 | templateUrl: "login.html" 10 | }) 11 | export class LoginComponent { 12 | @HostBinding("class.box") 13 | public loginCssClass = true; 14 | 15 | public username: string; 16 | public password: string; 17 | public error: string; 18 | 19 | constructor( 20 | private _oauthService: OAuthService, 21 | private _activatedRoute: ActivatedRoute, 22 | private _router: Router, 23 | private _pushService: PushService 24 | ) {} 25 | 26 | public submit(): void { 27 | this._oauthService 28 | .fetchTokenUsingPasswordFlowAndLoadUserProfile( 29 | this.username, 30 | this.password 31 | ) 32 | .then( 33 | () => { 34 | this._pushService.start(); 35 | this._router.navigate([ 36 | this._activatedRoute.snapshot.queryParams["redirectTo"] 37 | ]); 38 | }, 39 | error => (this.error = error) 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/header/header.ts: -------------------------------------------------------------------------------- 1 | import { Component } from "@angular/core"; 2 | import { Location } from "@angular/common"; 3 | import { PlatformService } from "../../services/platformService"; 4 | import { Router } from "@angular/router"; 5 | import { OAuthService } from "angular-oauth2-oidc"; 6 | 7 | @Component({ 8 | selector: "app-header", 9 | templateUrl: "header.html", 10 | styleUrls: ["header.scss"] 11 | }) 12 | export class HeaderComponent { 13 | public isLoggedIn = false; 14 | 15 | public get isBackChevronVisible(): boolean { 16 | return this._location.path() !== "/home" && this._platform.isIOS; 17 | } 18 | 19 | constructor( 20 | private _location: Location, 21 | private _router: Router, 22 | private _platform: PlatformService, 23 | private _oauthService: OAuthService 24 | ) { 25 | this.isLoggedIn = _oauthService.hasValidAccessToken(); 26 | this._oauthService.events.subscribe(e => { 27 | if (e.type === 'token_received') { 28 | this.isLoggedIn = true; 29 | } 30 | }); 31 | } 32 | 33 | public logout(): void { 34 | this.isLoggedIn = false; 35 | this._oauthService.logOut(); 36 | this._router.navigate(["/home"]); 37 | } 38 | 39 | public goBack() { 40 | this._location.back(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /orders-service-dotnet/Client HTTP Scripts/SumbitNewOrder.http: -------------------------------------------------------------------------------- 1 | # Regularly update the token via the RetrieveToken.http script 2 | @token = Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6IjljNTIxMGFiZWZmZTg2ZjlkMmI5ZTEzM2Q4NWNjZDA4IiwidHlwIjoiSldUIn0.eyJuYmYiOjE1NDgxNTA4ODAsImV4cCI6MTU0ODIzNzI4MCwiaXNzIjoiaHR0cHM6Ly90dC1pZGVudGl0eXNlcnZlcjQtZGVtby5henVyZXdlYnNpdGVzLm5ldCIsImF1ZCI6WyJodHRwczovL3R0LWlkZW50aXR5c2VydmVyNC1kZW1vLmF6dXJld2Vic2l0ZXMubmV0L3Jlc291cmNlcyIsImFwaSJdLCJjbGllbnRfaWQiOiJyZXNvdXJjZW93bmVyIiwic3ViIjoiODg0MjExMTMiLCJhdXRoX3RpbWUiOjE1NDgxNTA4ODAsImlkcCI6ImxvY2FsIiwic2NvcGUiOlsib3BlbmlkIiwicHJvZmlsZSIsImFwaSJdLCJhbXIiOlsicHdkIl19.zWFvJ1Gkd4zDkJLnqQWSrEh3KB7za5TvHMq-A2HlQylb4IKLWmEuitZBRUJyec4PXSAnrRq5nRX7SHclk11--KE9DMyHrP8kY9LYGK52M-cx9hP4ci9vjaW6nn-Mc0gEjbiLGyHN0jljzSu28zm-jWiv9FY7hVRllPG8Hjcpt4Pc4sGQRpDOgYHw8oq7MVcis6mnKbvnOWVlGPxGIConc_GFOPzYeCZ8UV2p478BOTnUS0x4HKv9f66Af8KxJT9z_NZaKMyMXyHSPDhPTSs9SqcWrjubmlm1HR4vRfTmIcvXYMCPaZrW0cbh-Nza2jtFFu54eZ_WXpmnjwDqSO08BQ 3 | 4 | POST http://localhost:7071/api/orders 5 | #POST https://orders.serverlessmicroservices.net/api/orders 6 | Content-Type: application/json 7 | Authorization: Bearer {{ token }} 8 | 9 | { 10 | "description": "Order for Valentin", 11 | "items": [ 12 | { 13 | "id": "906625b2-2aa8-4799-9a86-dd98b577b681", 14 | "quantity": 2 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /shipping-service-ts/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shipping-service-ts", 3 | "version": "0.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@azure/functions": { 8 | "version": "1.0.1-beta2", 9 | "resolved": "https://registry.npmjs.org/@azure/functions/-/functions-1.0.1-beta2.tgz", 10 | "integrity": "sha512-ewVNxU2fqSCLbLuHwwvcL2ExgYNIhaztgHQfBShM9bpCBlAufTrvqlGnsEMfYv2F+BmJrkvhcDWE7E8cDz4X0g==", 11 | "dev": true 12 | }, 13 | "guid-typescript": { 14 | "version": "1.0.9", 15 | "resolved": "https://registry.npmjs.org/guid-typescript/-/guid-typescript-1.0.9.tgz", 16 | "integrity": "sha512-Y8T4vYhEfwJOTbouREvG+3XDsjr8E3kIr7uf+JZ0BYloFsttiHU0WfvANVsR7TxNUJa/WpCnw/Ino/p+DeBhBQ==" 17 | }, 18 | "typescript": { 19 | "version": "3.3.3", 20 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.3.3.tgz", 21 | "integrity": "sha512-Y21Xqe54TBVp+VDSNbuDYdGw0BpoR/Q6wo/+35M8PAU0vipahnyduJWirxxdxjsAkS7hue53x2zp8gz7F05u0A==", 22 | "dev": true 23 | }, 24 | "uuid": { 25 | "version": "3.3.2", 26 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 27 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/services/authInterceptor.ts: -------------------------------------------------------------------------------- 1 | import { Injectable, Injector } from "@angular/core"; 2 | import { 3 | HttpEvent, 4 | HttpHandler, 5 | HttpInterceptor, 6 | HttpRequest 7 | } from "@angular/common/http"; 8 | import { OAuthService } from "angular-oauth2-oidc"; 9 | import { Observable } from "rxjs"; 10 | 11 | @Injectable() 12 | export class AuthInterceptor implements HttpInterceptor { 13 | private securityService: OAuthService; 14 | 15 | constructor(private injector: Injector) {} 16 | 17 | intercept( 18 | req: HttpRequest, 19 | next: HttpHandler 20 | ): Observable> { 21 | let requestToForward = req; 22 | 23 | if (this.securityService === undefined) { 24 | this.securityService = this.injector.get(OAuthService); 25 | } 26 | 27 | if (this.securityService !== undefined) { 28 | const token = this.securityService.getAccessToken(); 29 | 30 | if (token !== "") { 31 | const tokenValue = "Bearer " + token; 32 | requestToForward = req.clone({ 33 | setHeaders: { Authorization: tokenValue } 34 | }); 35 | } 36 | } else { 37 | // tslint:disable-next-line:no-console 38 | console.debug("OidcSecurityService undefined: NO auth header!"); 39 | } 40 | 41 | return next.handle(requestToForward); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /shipping-service-ts/CreateShipment/index.ts: -------------------------------------------------------------------------------- 1 | import { AzureFunction, Context } from "@azure/functions" 2 | import * as uuid from "uuid"; 3 | import { ShippingCreatedMessage } from "../Messages/shippingCreatedMessage"; 4 | 5 | const serviceBusQueueTrigger: AzureFunction = 6 | async function (context: Context, message: NewOrderMessage): Promise { 7 | context.log.info('***CreateShipment ServiceBus queue trigger function processed message', message); 8 | 9 | // NOTE: Look at our complex business logic! 10 | // TODO: Yes - do the REAL STUFF here... 11 | await sleep(5000); 12 | 13 | var shippingCreated = new ShippingCreatedMessage(); 14 | shippingCreated.Id = uuid.v4(); 15 | shippingCreated.Created = new Date().toISOString(); 16 | shippingCreated.OrderId = message.Order.Id; 17 | shippingCreated.UserId = message.UserId; 18 | 19 | context.log.info("***New shipment: {0}", shippingCreated); 20 | 21 | try { 22 | context.bindings.outQueue = shippingCreated; 23 | context.done(); 24 | } catch (err) { 25 | // TODO: retry policy... 26 | context.log.error("Service Bus Error", err); 27 | throw err; 28 | } 29 | }; 30 | 31 | function sleep(ms: number) { 32 | return new Promise(resolve => setTimeout(resolve, ms)); 33 | } 34 | 35 | export default serviceBusQueueTrigger; 36 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 16 | 17 | -------------------------------------------------------------------------------- /notification-service-dotnet/notification-service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netcoreapp2.1 4 | v2 5 | notification_service 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | PreserveNewest 18 | 19 | 20 | PreserveNewest 21 | 22 | 23 | PreserveNewest 24 | Never 25 | 26 | 27 | -------------------------------------------------------------------------------- /orders-service-dotnet/orders-service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | v2 5 | orders_service 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | PreserveNewest 19 | 20 | 21 | PreserveNewest 22 | 23 | 24 | PreserveNewest 25 | Never 26 | 27 | 28 | -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Home/Index.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | var version = typeof(IdentityServer4.Hosting.IdentityServerMiddleware).Assembly.GetName().Version.ToString(); 3 | } 4 | 5 |
    6 | 15 | 16 |
    17 |
    18 |

    19 | IdentityServer publishes a 20 | discovery document 21 | where you can find metadata and links to all the endpoints, key material, etc. 22 |

    23 |
    24 |
    25 |

    26 | Click here to manage your stored grants. 27 |

    28 |
    29 |
    30 |
    31 |
    32 |

    33 | Here are links to the 34 | source code repository, 35 | and ready to use samples. 36 |

    37 |
    38 |
    39 |
    40 | -------------------------------------------------------------------------------- /identity-service-dotnet/Stores/PersistedGrantContext.cs: -------------------------------------------------------------------------------- 1 | using IdentityServer4.Models; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.WindowsAzure.Storage; 4 | using SInnovations.Azure.TableStorageRepository; 5 | using SInnovations.Azure.TableStorageRepository.TableRepositories; 6 | 7 | namespace Serverless 8 | { 9 | public class PersistedGrantContext : TableStorageContext 10 | { 11 | public const string TABLENAME = "IdentityServer4Store"; 12 | 13 | public PersistedGrantContext( 14 | ILoggerFactory loggerFactory, 15 | IEntityTypeConfigurationsContainer container, 16 | CloudStorageAccount account) : 17 | base(loggerFactory, container, account) 18 | { 19 | this.InsertionMode = InsertionMode.AddOrReplace; 20 | } 21 | 22 | protected override void OnModelCreating(TableStorageModelBuilder modelbuilder) 23 | { 24 | modelbuilder.Entity() 25 | .HasKeys(k => new { k.SubjectId, k.ClientId }, r => new { r.Type, r.Key }) 26 | .WithIndex(k => k.Key, true, TABLENAME) 27 | .WithKeyTransformation(k => k.Key, FixPartitionKey) 28 | .ToTable(TABLENAME); 29 | 30 | base.OnModelCreating(modelbuilder); 31 | } 32 | 33 | public static string FixPartitionKey(string p) 34 | { 35 | return $"idx__{p.Replace('/', '_')}"; 36 | } 37 | 38 | public ITableRepository PersistedGrants { get; set; } 39 | } 40 | } -------------------------------------------------------------------------------- /notification-service-dotnet/Functions/NotifyClientsAboutOrderShipment.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.Azure.WebJobs; 3 | using Microsoft.Azure.WebJobs.Extensions.SignalRService; 4 | using Microsoft.Azure.WebJobs.Host; 5 | using Microsoft.Extensions.Logging; 6 | using Newtonsoft.Json; 7 | using Serverless.Messages; 8 | 9 | namespace Serverless 10 | { 11 | public class NotifyClientsAboutOrderShipmentFunctions 12 | { 13 | [FunctionName("NotifyClientsAboutOrderShipment")] 14 | public async Task Run( 15 | [ServiceBusTrigger("shippingsinitiated", Connection = "ServiceBus")] 16 | /*ShippingCreatedMessage*/ string msg, 17 | 18 | [SignalR(HubName="shippingsHub", ConnectionStringSetting="SignalR")] 19 | IAsyncCollector notificationMessages, 20 | 21 | ILogger log) 22 | { 23 | log.LogInformation($"NotifyClientsAboutOrderShipment SB queue trigger function processed message: {msg}"); 24 | 25 | ShippingCreatedMessage message = JsonConvert.DeserializeObject(msg); 26 | 27 | // TODO: Use group feature in SignalR binding 28 | var messageToNotify = new { userId = message.UserId, orderId = message.OrderId }; 29 | 30 | await notificationMessages.AddAsync(new SignalRMessage 31 | { 32 | Target = "shippingInitiated", 33 | Arguments = new[] { messageToNotify } 34 | }); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /shopping-client-ng/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "problemMatcher": "$msCompile", 9 | "options": { 10 | "cwd": "${workspaceFolder}/functions" 11 | } 12 | }, 13 | { 14 | "label": "build", 15 | "command": "dotnet build", 16 | "type": "shell", 17 | "dependsOn": "clean", 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | }, 22 | "problemMatcher": "$msCompile", 23 | "options": { 24 | "cwd": "${workspaceFolder}/functions" 25 | } 26 | }, 27 | { 28 | "label": "clean release", 29 | "command": "dotnet clean --configuration Release", 30 | "type": "shell", 31 | "problemMatcher": "$msCompile", 32 | "options": { 33 | "cwd": "${workspaceFolder}/functions" 34 | } 35 | }, 36 | { 37 | "label": "publish", 38 | "command": "dotnet publish --configuration Release", 39 | "type": "shell", 40 | "dependsOn": "clean release", 41 | "problemMatcher": "$msCompile", 42 | "options": { 43 | "cwd": "${workspaceFolder}/functions" 44 | } 45 | }, 46 | { 47 | "type": "func", 48 | "dependsOn": "build", 49 | "options": { 50 | "cwd": "${workspaceFolder}/functions/bin/Debug/netcoreapp2.1" 51 | }, 52 | "command": "host start", 53 | "isBackground": true, 54 | "problemMatcher": "$func-watch" 55 | } 56 | ] 57 | } 58 | -------------------------------------------------------------------------------- /orders-service-dotnet/Functions/GetOrders.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Azure.WebJobs.Host; 9 | using Microsoft.Extensions.Logging; 10 | using Newtonsoft.Json; 11 | using System.Collections.Generic; 12 | using System.Linq; 13 | using Microsoft.Azure.Documents; 14 | using Serverless.Messages; 15 | 16 | namespace Serverless 17 | { 18 | public class GetOrdersFunctions 19 | { 20 | [FunctionName("GetOrders")] 21 | public async Task Run( 22 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "api/orders")] 23 | HttpRequest req, 24 | IBinder binder, 25 | ILogger log) 26 | { 27 | log.LogInformation("GetOrders HTTP trigger function processed a request."); 28 | 29 | if (!await req.CheckAuthorization("api")) 30 | { 31 | return new UnauthorizedResult(); 32 | } 33 | 34 | var cosmosDb = new CosmosDBAttribute("ordersservice", "data"); 35 | cosmosDb.ConnectionStringSetting = "CosmosDB"; 36 | 37 | var ordersData = await binder.BindAsync>(cosmosDb); 38 | var orders = ordersData.Select(doc => doc.Order).OrderByDescending(o => o.Created).ToList(); 39 | 40 | return new OkObjectResult(orders); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "presentation": { 9 | "reveal": "always" 10 | }, 11 | "problemMatcher": "$msCompile" 12 | }, 13 | { 14 | "label": "build", 15 | "command": "dotnet build", 16 | "type": "shell", 17 | "dependsOn": "clean", 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | }, 22 | "presentation": { 23 | "reveal": "always" 24 | }, 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "clean release", 29 | "command": "dotnet clean --configuration Release", 30 | "type": "shell", 31 | "presentation": { 32 | "reveal": "always" 33 | }, 34 | "problemMatcher": "$msCompile" 35 | }, 36 | { 37 | "label": "publish", 38 | "command": "dotnet publish --configuration Release", 39 | "type": "shell", 40 | "dependsOn": "clean release", 41 | "presentation": { 42 | "reveal": "always" 43 | }, 44 | "problemMatcher": "$msCompile" 45 | }, 46 | { 47 | "label": "runFunctionsHost", 48 | "type": "shell", 49 | "dependsOn": "build", 50 | "options": { 51 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp2.0" 52 | }, 53 | "command": "func host start", 54 | "isBackground": true, 55 | "presentation": { 56 | "reveal": "always" 57 | }, 58 | "problemMatcher": "$func-watch" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /products-service-dotnet/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "presentation": { 9 | "reveal": "always" 10 | }, 11 | "problemMatcher": "$msCompile" 12 | }, 13 | { 14 | "label": "build", 15 | "command": "dotnet build", 16 | "type": "shell", 17 | "dependsOn": "clean", 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | }, 22 | "presentation": { 23 | "reveal": "always" 24 | }, 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "clean release", 29 | "command": "dotnet clean --configuration Release", 30 | "type": "shell", 31 | "presentation": { 32 | "reveal": "always" 33 | }, 34 | "problemMatcher": "$msCompile" 35 | }, 36 | { 37 | "label": "publish", 38 | "command": "dotnet publish --configuration Release", 39 | "type": "shell", 40 | "dependsOn": "clean release", 41 | "presentation": { 42 | "reveal": "always" 43 | }, 44 | "problemMatcher": "$msCompile" 45 | }, 46 | { 47 | "label": "runFunctionsHost", 48 | "type": "shell", 49 | "dependsOn": "build", 50 | "options": { 51 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp2.1" 52 | }, 53 | "command": "func host start", 54 | "isBackground": true, 55 | "presentation": { 56 | "reveal": "always" 57 | }, 58 | "problemMatcher": "$func-watch" 59 | } 60 | ] 61 | } 62 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/services/ordersService.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from "@angular/core"; 2 | import { environment } from "../../../environments/environment"; 3 | import { HttpClient } from "@angular/common/http"; 4 | import { Observable, of } from "rxjs"; 5 | import { catchError, map } from 'rxjs/operators'; 6 | import { Product } from "../models/product"; 7 | import { Order } from "../models/order"; 8 | import { PushService } from "./pushService"; 9 | import { OrderWithItems } from "../models/orderWithItems"; 10 | 11 | @Injectable() 12 | export class OrdersService { 13 | constructor(private _http: HttpClient, 14 | private _pushService: PushService) { } 15 | 16 | public getOrders(): Observable { 17 | return this.requestOrders().pipe( 18 | map(orders => 19 | orders.map(order => { 20 | const items = order.items.map(({ id }) => this.requestProductSafely(id)); 21 | const shipped$ = this._pushService.getShippingStatus(order.id); 22 | return { order, items, shipped$ }; 23 | }) 24 | ) 25 | ); 26 | } 27 | 28 | private requestOrders(): Observable { 29 | const url = `${environment.ordersApiBaseUrl}orders`; 30 | 31 | return this._http.get(url); 32 | } 33 | 34 | private requestProductSafely(id: string): Observable { 35 | return this.requestProduct(id) 36 | .pipe(catchError(err => of({ id, name: 'Ooops...' }))); 37 | } 38 | 39 | private requestProduct(id: string): Observable { 40 | const url = `${environment.productsApiBaseUrl}products/${id}`; 41 | 42 | return this._http.get(url); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /products-service-js/LetsEncrypt/index.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | module.exports = function (context, request) { 4 | const responseFilePath = `D:\\home\\site\\LetsEncrypt\\.well-known\\acme-challenge\\${context.bindingData.code}`; 5 | 6 | context.log(`Checking for ACME challenge response at '${responseFilePath}'...`); 7 | 8 | fs.exists(responseFilePath, (exists) => { 9 | if (!exists) { 10 | context.log(`ACME challenge response file '${responseFilePath}' not found.`); 11 | context.res = { 12 | status: 404, 13 | headers: { "Content-Type": "text/plain" }, 14 | body: 'ACME challenge response not found.' 15 | }; 16 | 17 | context.done(); 18 | 19 | return; 20 | } 21 | 22 | context.log(`ACME challenge response file '${responseFilePath}' found. Reading file...`); 23 | 24 | fs.readFile(responseFilePath, (error, data) => { 25 | if (error) { 26 | context.log.error(`An error occured while reading file '${responseFilePath}'.`, error); 27 | context.res = { status: 500 }; 28 | 29 | context.done(); 30 | 31 | return; 32 | } 33 | 34 | context.log(`ACME challenge response file '${responseFilePath}' read successfully.`); 35 | 36 | context.res = { 37 | status: 200, 38 | headers: { "Content-Type": "text/plain" }, 39 | body: data 40 | }; 41 | 42 | context.done(); 43 | }); 44 | }); 45 | }; -------------------------------------------------------------------------------- /shipping-service-ts/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | .env.test 60 | 61 | # parcel-bundler cache (https://parceljs.org/) 62 | .cache 63 | 64 | # next.js build output 65 | .next 66 | 67 | # nuxt.js build output 68 | .nuxt 69 | 70 | # vuepress build output 71 | .vuepress/dist 72 | 73 | # Serverless directories 74 | .serverless/ 75 | 76 | # FuseBox cache 77 | .fusebox/ 78 | 79 | # DynamoDB Local files 80 | .dynamodb/ 81 | 82 | # Azure Functions artifacts 83 | bin 84 | obj 85 | appsettings.json 86 | local.settings.json 87 | 88 | # TypeScript output 89 | dist 90 | out 91 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/components/login/login.scss: -------------------------------------------------------------------------------- 1 | .login-form { 2 | background-color: #fff; 3 | 4 | min-height: 250px; 5 | width: 90%; 6 | max-width: 400px; 7 | 8 | display: flex; 9 | box-shadow: 0 10px 20px 0 rgba(0,0,0, .1); 10 | margin: 0 auto; 11 | } 12 | 13 | form { 14 | width: 100%; 15 | 16 | display: flex; 17 | flex-flow: row wrap; 18 | padding: 10px 20px; 19 | 20 | legend { 21 | font-size: 24px; 22 | flex: 0 0 100%; 23 | } 24 | 25 | fieldset { 26 | border: none; 27 | flex: 0 0 100%; 28 | padding: 20px 0; 29 | } 30 | 31 | input { 32 | min-width: 100%; 33 | 34 | font-size: 15px; 35 | 36 | border: 1px solid rgba(0,0,0, .1); 37 | border-radius: 5px; 38 | margin: 5px 0; 39 | padding: 7px 10px; 40 | transition: .3s all; 41 | will-change: border-color, box-shadow; 42 | 43 | &:focus { 44 | border-color: #ff5850; 45 | box-shadow: 0 3px 7px 0 rgba(0,0,0, .12); 46 | outline: none; 47 | } 48 | } 49 | 50 | button { 51 | background-color: #ff5850; 52 | 53 | font-size: 15px; 54 | line-height: 20px; 55 | color: white; 56 | 57 | align-self: flex-end; 58 | border: 1px solid transparent; 59 | border-radius: 30px; 60 | cursor: pointer; 61 | margin: 0 0 15px auto; 62 | padding: 7px 25px; 63 | transition: .3s all; 64 | will-change: box-shadow, border-color, background-color; 65 | 66 | &:focus, &:hover { 67 | background-color: darken(#ff5850, 5%); 68 | border-color: lighten(#ff5850, 5%); 69 | box-shadow: 0 3px 7px 0 rgba(0,0,0, .12); 70 | outline: none; 71 | } 72 | } 73 | } 74 | 75 | 76 | -------------------------------------------------------------------------------- /invoice-scanner-dotnet/Functions/UploadDocument.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Azure.WebJobs; 5 | using Microsoft.Azure.WebJobs.Extensions.Http; 6 | using Microsoft.Extensions.Logging; 7 | using System.Net.Http; 8 | using System.Linq; 9 | using Microsoft.WindowsAzure.Storage.Blob; 10 | 11 | namespace Serverless 12 | { 13 | public static class UploadDocument 14 | { 15 | [FunctionName("UploadDocument")] 16 | public static async Task Run( 17 | [HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "documents")] 18 | HttpRequestMessage req, 19 | 20 | [Blob("invoices", FileAccess.Write)] 21 | CloudBlobContainer blobContainer, 22 | 23 | ILogger log) 24 | { 25 | var provider = new MultipartMemoryStreamProvider(); 26 | await req.Content.ReadAsMultipartAsync(provider); 27 | 28 | var file = provider.Contents.First(); 29 | 30 | if(file == null) 31 | { 32 | return new BadRequestResult(); 33 | } 34 | 35 | var fileInfo = file.Headers.ContentDisposition; 36 | 37 | if(fileInfo == null) 38 | { 39 | return new BadRequestResult(); 40 | } 41 | 42 | var fileName = fileInfo.FileName.Replace("\"", ""); 43 | var blob = blobContainer.GetBlockBlobReference(fileName); 44 | await blob.UploadFromStreamAsync(await file.ReadAsStreamAsync()); 45 | 46 | return new OkResult(); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /orders-service-dotnet/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "presentation": { 9 | "reveal": "always" 10 | }, 11 | "problemMatcher": "$msCompile" 12 | }, 13 | { 14 | "label": "build", 15 | "command": "dotnet build", 16 | "type": "shell", 17 | "dependsOn": "clean", 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | }, 22 | "presentation": { 23 | "reveal": "always" 24 | }, 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "clean release", 29 | "command": "dotnet clean --configuration Release", 30 | "type": "shell", 31 | "presentation": { 32 | "reveal": "always" 33 | }, 34 | "problemMatcher": "$msCompile" 35 | }, 36 | { 37 | "label": "publish", 38 | "identifier": "publish", 39 | "command": "dotnet publish --configuration Release", 40 | "type": "shell", 41 | "dependsOn": "clean release", 42 | "presentation": { 43 | "reveal": "always" 44 | }, 45 | "problemMatcher": "$msCompile" 46 | }, 47 | { 48 | "label": "Run Functions Host", 49 | "identifier": "runFunctionsHost", 50 | "type": "shell", 51 | "dependsOn": "build", 52 | "options": { 53 | "cwd": "${workspaceFolder}/bin/Debug/netstandard2.0" 54 | }, 55 | "command": "func host start", 56 | "isBackground": true, 57 | "presentation": { 58 | "reveal": "always" 59 | }, 60 | "problemMatcher": "$func-watch" 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /shipping-service-dotnet/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "clean", 6 | "command": "dotnet clean", 7 | "type": "shell", 8 | "presentation": { 9 | "reveal": "always" 10 | }, 11 | "problemMatcher": "$msCompile" 12 | }, 13 | { 14 | "label": "build", 15 | "command": "dotnet build", 16 | "type": "shell", 17 | "dependsOn": "clean", 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | }, 22 | "presentation": { 23 | "reveal": "always" 24 | }, 25 | "problemMatcher": "$msCompile" 26 | }, 27 | { 28 | "label": "clean release", 29 | "command": "dotnet clean --configuration Release", 30 | "type": "shell", 31 | "presentation": { 32 | "reveal": "always" 33 | }, 34 | "problemMatcher": "$msCompile" 35 | }, 36 | { 37 | "label": "publish", 38 | "identifier": "publish", 39 | "command": "dotnet publish --configuration Release", 40 | "type": "shell", 41 | "dependsOn": "clean release", 42 | "presentation": { 43 | "reveal": "always" 44 | }, 45 | "problemMatcher": "$msCompile" 46 | }, 47 | { 48 | "label": "Run Functions Host", 49 | "identifier": "runFunctionsHost", 50 | "type": "shell", 51 | "dependsOn": "build", 52 | "options": { 53 | "cwd": "${workspaceFolder}/bin/Debug/netstandard2.0" 54 | }, 55 | "command": "func host start", 56 | "isBackground": true, 57 | "presentation": { 58 | "reveal": "always" 59 | }, 60 | "problemMatcher": "$func-watch" 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/css/site.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 65px; 3 | } 4 | .navbar-header { 5 | position: relative; 6 | top: -4px; 7 | } 8 | .navbar-brand > .icon-banner { 9 | position: relative; 10 | top: -2px; 11 | display: inline; 12 | } 13 | .icon { 14 | position: relative; 15 | top: -10px; 16 | } 17 | .logged-out iframe { 18 | display: none; 19 | width: 0; 20 | height: 0; 21 | } 22 | .page-consent .client-logo { 23 | float: left; 24 | } 25 | .page-consent .client-logo img { 26 | width: 80px; 27 | height: 80px; 28 | } 29 | .page-consent .consent-buttons { 30 | margin-top: 25px; 31 | } 32 | .page-consent .consent-form .consent-scopecheck { 33 | display: inline-block; 34 | margin-right: 5px; 35 | } 36 | .page-consent .consent-form .consent-description { 37 | margin-left: 25px; 38 | } 39 | .page-consent .consent-form .consent-description label { 40 | font-weight: normal; 41 | } 42 | .page-consent .consent-form .consent-remember { 43 | padding-left: 16px; 44 | } 45 | .grants .page-header { 46 | margin-bottom: 10px; 47 | } 48 | .grants .grant { 49 | margin-top: 20px; 50 | padding-bottom: 20px; 51 | border-bottom: 1px solid lightgray; 52 | } 53 | .grants .grant img { 54 | width: 100px; 55 | height: 100px; 56 | } 57 | .grants .grant .clientname { 58 | font-size: 140%; 59 | font-weight: bold; 60 | } 61 | .grants .grant .granttype { 62 | font-size: 120%; 63 | font-weight: bold; 64 | } 65 | .grants .grant .created { 66 | font-size: 120%; 67 | font-weight: bold; 68 | } 69 | .grants .grant .expires { 70 | font-size: 120%; 71 | font-weight: bold; 72 | } 73 | .grants .grant li { 74 | list-style-type: none; 75 | display: inline; 76 | } 77 | .grants .grant li:after { 78 | content: ', '; 79 | } 80 | .grants .grant li:last-child:after { 81 | content: ''; 82 | } -------------------------------------------------------------------------------- /shipping-service-dotnet/Functions/CreateShipment.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Azure.ServiceBus; 4 | using Microsoft.Azure.WebJobs; 5 | using Microsoft.Azure.WebJobs.Host; 6 | using Microsoft.Extensions.Logging; 7 | 8 | namespace Serverless 9 | { 10 | public static class CreateShipmentFunction 11 | { 12 | [FunctionName("CreateShipment")] 13 | public static async Task Run( 14 | [ServiceBusTrigger("ordersforshipping", Connection = "ServiceBus")] 15 | NewOrderMessage message, 16 | 17 | [ServiceBus("shippingsinitiated", Connection = "ServiceBus")] 18 | IAsyncCollector shippingCreatedMessages, 19 | 20 | ILogger log) 21 | { 22 | log.LogInformation($"CreateShipment ServiceBus topic trigger function processed message: {message}"); 23 | 24 | // NOTE: Look at our complex business logic! 25 | // TODO: Yes - do the REAL STUFF here... 26 | await Task.Delay(5000); 27 | 28 | var shippingCreated = new ShippingCreatedMessage 29 | { 30 | Id = Guid.NewGuid(), 31 | Created = DateTime.UtcNow, 32 | OrderId = message.Order.Id, 33 | UserId = message.UserId 34 | }; 35 | 36 | log.LogInformation("New shipment: {0}", shippingCreated); 37 | 38 | try 39 | { 40 | await shippingCreatedMessages.AddAsync(shippingCreated); 41 | await shippingCreatedMessages.FlushAsync(); 42 | } 43 | catch (ServiceBusException sbx) 44 | { 45 | // TODO: retry policy... 46 | log.LogError(sbx, "Service Bus Error"); 47 | 48 | throw; 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /shipping-service-java/.classpath: -------------------------------------------------------------------------------- 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 | 45 | -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/desktop/index.js: -------------------------------------------------------------------------------- 1 | const { app, BrowserWindow, globalShortcut, Menu, Tray } = require('electron'); 2 | const appMenu = require('./appMenu'); 3 | 4 | const path = require('path'); 5 | const url = require('url'); 6 | 7 | let win; 8 | let trayApp; 9 | 10 | function createWindow() { 11 | win = new BrowserWindow({ 12 | minWidth: 1080, 13 | minHeight: 600, 14 | width: 1080, 15 | height: 600 16 | }); 17 | 18 | win.loadURL(url.format({ 19 | pathname: path.join(__dirname, 'web/index.html'), 20 | protocol: 'file:', 21 | slashes: true 22 | })); 23 | 24 | buildTrayIcon(); 25 | appMenu.buildMenu(); 26 | 27 | globalShortcut.register('CmdOrCtrl+Shift+i', () => { 28 | win.webContents.toggleDevTools(); 29 | }); 30 | 31 | globalShortcut.register('CmdOrCtrl+Shift+b', function () { 32 | if (process.platform == 'darwin') { 33 | app.dock.bounce('critical'); 34 | } 35 | app.dock.setBadge('EVIL:)'); 36 | }); 37 | 38 | win.on('closed', () => { 39 | win = null; 40 | }); 41 | } 42 | 43 | app.on('ready', createWindow); 44 | 45 | app.on('window-all-closed', () => { 46 | globalShortcut.unregisterAll(); 47 | if (process.platform !== 'darwin') { 48 | app.quit(); 49 | } 50 | }); 51 | 52 | app.on('activate', () => { 53 | if (win === null) { 54 | createWindow(); 55 | } 56 | }); 57 | 58 | let buildTrayIcon = () => { 59 | let trayIconPath = path.join(__dirname, 'icon.png'); 60 | var contextMenu = Menu.buildFromTemplate([ 61 | { 62 | label: 'Pokemons...', 63 | type: 'normal', 64 | click: function () { 65 | win.webContents.send('navigateTo', 'pokemon/list/pokemon/1'); 66 | } 67 | }, 68 | { 69 | label: 'Quit', 70 | accelerator: 'Command+Q', 71 | selector: 'terminate:' 72 | } 73 | ]); 74 | 75 | trayApp = new Tray(trayIconPath); 76 | trayApp.setToolTip('ng Demo'); 77 | trayApp.setContextMenu(contextMenu); 78 | }; 79 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/Home/HomeController.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityServer4.Services; 6 | using Microsoft.AspNetCore.Authorization; 7 | using Microsoft.AspNetCore.Hosting; 8 | using Microsoft.AspNetCore.Mvc; 9 | using Microsoft.Extensions.Logging; 10 | using System.Threading.Tasks; 11 | 12 | namespace IdentityServer 13 | { 14 | [SecurityHeaders] 15 | [AllowAnonymous] 16 | public class HomeController : Controller 17 | { 18 | private readonly IIdentityServerInteractionService _interaction; 19 | private readonly IHostingEnvironment _environment; 20 | private readonly ILogger _logger; 21 | 22 | public HomeController(IIdentityServerInteractionService interaction, IHostingEnvironment environment, ILogger logger) 23 | { 24 | _interaction = interaction; 25 | _environment = environment; 26 | _logger = logger; 27 | } 28 | 29 | public IActionResult Index() 30 | { 31 | return View(); 32 | } 33 | 34 | /// 35 | /// Shows the error page 36 | /// 37 | public async Task Error(string errorId) 38 | { 39 | var vm = new ErrorViewModel(); 40 | 41 | // retrieve error details from identityserver 42 | var message = await _interaction.GetErrorContextAsync(errorId); 43 | if (message != null) 44 | { 45 | vm.Error = message; 46 | 47 | if (!_environment.IsDevelopment()) 48 | { 49 | // only show in development 50 | message.ErrorDescription = null; 51 | } 52 | } 53 | 54 | return View("Error", vm); 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /identity-service-dotnet/Stores/TableStoragePersistedGrantStore.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using System.Threading.Tasks; 4 | using IdentityServer4.Models; 5 | using IdentityServer4.Stores; 6 | using SInnovations.Azure.TableStorageRepository.Queryable; 7 | 8 | namespace Serverless 9 | { 10 | public class TableStoragePersistedGrantStore : IPersistedGrantStore 11 | { 12 | private readonly PersistedGrantContext _context; 13 | 14 | public TableStoragePersistedGrantStore(PersistedGrantContext context) 15 | { 16 | this._context = context; 17 | } 18 | 19 | public async Task> GetAllAsync(string subjectId) 20 | { 21 | return await _context.PersistedGrants.Where(k => k.SubjectId == subjectId).ToListAsync().ConfigureAwait(false); 22 | } 23 | 24 | public async Task GetAsync(string key) 25 | { 26 | return await _context.PersistedGrants.FindByIndexAsync(key).ConfigureAwait(false); 27 | } 28 | 29 | public async Task StoreAsync(PersistedGrant grant) 30 | { 31 | this._context.PersistedGrants.Add(grant); 32 | 33 | await this._context.SaveChangesAsync().ConfigureAwait(false); 34 | } 35 | 36 | public Task RemoveAllAsync(string subjectId, string clientId) 37 | { 38 | return Task.CompletedTask; 39 | } 40 | 41 | public Task RemoveAllAsync(string subjectId, string clientId, string type) 42 | { 43 | return Task.CompletedTask; 44 | } 45 | 46 | public async Task RemoveAsync(string key) 47 | { 48 | this._context.PersistedGrants.Delete(await _context.PersistedGrants.FindByIndexAsync(key).ConfigureAwait(false)); 49 | 50 | await Task.WhenAll( 51 | this._context.PersistedGrants.DeleteByKey(PersistedGrantContext.FixPartitionKey(key), ""), 52 | this._context.SaveChangesAsync() 53 | ); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /shipping-service-java/src/main/java/com/thinktecture/serverless/functions/CreateShipment.java: -------------------------------------------------------------------------------- 1 | package com.thinktecture.serverless.functions; 2 | 3 | import java.io.IOException; 4 | import java.util.Date; 5 | import java.util.UUID; 6 | 7 | import com.google.gson.Gson; 8 | import com.google.gson.GsonBuilder; 9 | import com.microsoft.azure.functions.ExecutionContext; 10 | import com.microsoft.azure.functions.annotation.FunctionName; 11 | import com.microsoft.azure.functions.annotation.ServiceBusQueueOutput; 12 | import com.microsoft.azure.functions.annotation.ServiceBusQueueTrigger; 13 | import com.thinktecture.serverless.messages.NewOrderMessage; 14 | import com.thinktecture.serverless.messages.ShippingCreatedMessage; 15 | 16 | public class CreateShipment { 17 | /** 18 | * @throws InterruptedException 19 | * @throws IOException 20 | */ 21 | @FunctionName("CreateShipment") 22 | @ServiceBusQueueOutput(name = "$return", 23 | queueName = "shippingsinitiated", 24 | connection = "ServiceBus") 25 | public String run( 26 | @ServiceBusQueueTrigger(name = "message", 27 | queueName = "ordersforshipping", 28 | connection = "ServiceBus") 29 | NewOrderMessage msg, 30 | final ExecutionContext context 31 | ) throws InterruptedException, IOException { 32 | context.getLogger().info("CreateShipment ServiceBus queue trigger function processed message."); 33 | context.getLogger().info(msg.Order.Description); 34 | 35 | // NOTE: Look at our complex business logic! :-) 36 | // Yes - do the REAL STUFF here... 37 | Thread.sleep(5000); 38 | 39 | ShippingCreatedMessage shippingCreated = new ShippingCreatedMessage(); 40 | shippingCreated.Id = UUID.randomUUID(); 41 | shippingCreated.Created = new Date(); 42 | shippingCreated.OrderId = msg.Order.Id; 43 | shippingCreated.UserId = msg.UserId; 44 | 45 | Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'").create(); 46 | String shippingCreatedMessage = gson.toJson(shippingCreated); 47 | 48 | context.getLogger().info("ShippingCreated Message: " + shippingCreatedMessage); 49 | 50 | return shippingCreatedMessage; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /notification-service-dotnet/Functions/Infrastructure/GetSignalRConfguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Azure.WebJobs.Host; 9 | using Microsoft.Extensions.Logging; 10 | using Newtonsoft.Json; 11 | using Microsoft.Azure.WebJobs.Extensions.SignalRService; 12 | 13 | namespace Serverless 14 | { 15 | public class GetSignalRConfigurationFunctions 16 | { 17 | [FunctionName("GetOrdersHubSignalRConfguration")] 18 | public async Task GetOrdersHubSignalRConfguration( 19 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "api/config/ordersHub")] 20 | HttpRequest req, 21 | 22 | [SignalRConnectionInfo(HubName = "ordersHub", ConnectionStringSetting="SignalR")] 23 | SignalRConnectionInfo connectionInfo, 24 | 25 | ILogger log) 26 | { 27 | log.LogInformation("GetOrdersHubSignalRConfguration HTTP trigger function processed a request."); 28 | 29 | /*if (!await req.CheckAuthorization("api")) 30 | { 31 | return new UnauthorizedResult(); 32 | }*/ 33 | 34 | return new OkObjectResult(connectionInfo); 35 | } 36 | 37 | [FunctionName("GetShippingsHubSignalRConfguration")] 38 | public async Task GetShippingsHubSignalRConfguration( 39 | [HttpTrigger(AuthorizationLevel.Anonymous, "GET", Route = "api/config/shippingsHub")] 40 | HttpRequest req, 41 | 42 | [SignalRConnectionInfo(HubName = "shippingsHub", ConnectionStringSetting="SignalR")] 43 | SignalRConnectionInfo connectionInfo, 44 | 45 | ILogger log) 46 | { 47 | log.LogInformation("GetShippingsHubSignalRConfguration HTTP trigger function processed a request."); 48 | 49 | /*if (!await req.CheckAuthorization("api")) 50 | { 51 | return new UnauthorizedResult(); 52 | }*/ 53 | 54 | return new OkObjectResult(connectionInfo); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/modules/app/module.ts: -------------------------------------------------------------------------------- 1 | import { AuthInterceptor } from "./services/authInterceptor"; 2 | import { OAuthService, OAuthModule } from "angular-oauth2-oidc"; 3 | import { BrowserModule } from "@angular/platform-browser"; 4 | import { NgModule } from "@angular/core"; 5 | import { FormsModule } from "@angular/forms"; 6 | import { RouterModule } from "@angular/router"; 7 | 8 | import { RootComponent } from "./components/root/root"; 9 | import { ROUTES } from "./routes"; 10 | import { HomeComponent } from "./components/home/home"; 11 | import { HeaderComponent } from "./components/header/header"; 12 | import { MenuComponent } from "./components/menu/menu"; 13 | import { WindowRef } from "./services/windowRef"; 14 | import { PlatformService } from "./services/platformService"; 15 | import { NgxElectronModule } from "ngx-electron"; 16 | import { DesktopIntegrationService } from "./services/desktopIntegrationService"; 17 | import { LoginComponent } from "./components/login/login"; 18 | import { IsAuthenticated } from "./guards/isAuthenticated"; 19 | import { OrdersService } from "./services/ordersService"; 20 | import { OrderListComponent } from "./components/list/orderList"; 21 | import { PushService } from "./services/pushService"; 22 | import { HttpClientModule, HTTP_INTERCEPTORS } from "@angular/common/http"; 23 | import { NgProgressModule } from "@ngx-progressbar/core"; 24 | import { NgProgressHttpModule } from "@ngx-progressbar/http"; 25 | 26 | @NgModule({ 27 | declarations: [ 28 | RootComponent, 29 | LoginComponent, 30 | HomeComponent, 31 | HeaderComponent, 32 | MenuComponent, 33 | OrderListComponent 34 | ], 35 | imports: [ 36 | BrowserModule, 37 | FormsModule, 38 | HttpClientModule, 39 | RouterModule.forRoot(ROUTES, { useHash: true }), 40 | NgProgressModule, 41 | NgProgressHttpModule, 42 | NgxElectronModule, 43 | OAuthModule.forRoot() 44 | ], 45 | bootstrap: [RootComponent], 46 | providers: [ 47 | WindowRef, 48 | OAuthService, 49 | OrdersService, 50 | PlatformService, 51 | PushService, 52 | DesktopIntegrationService, 53 | { 54 | provide: HTTP_INTERCEPTORS, 55 | useClass: AuthInterceptor, 56 | multi: true 57 | }, 58 | IsAuthenticated 59 | ] 60 | }) 61 | export class AppModule {} 62 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/TestUsers.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using IdentityModel; 6 | using IdentityServer4.Test; 7 | using System.Collections.Generic; 8 | using System.Security.Claims; 9 | 10 | namespace IdentityServer 11 | { 12 | public class TestUsers 13 | { 14 | public static List Users = new List 15 | { 16 | new TestUser{SubjectId = "818727", Username = "alice", Password = "alice", 17 | Claims = 18 | { 19 | new Claim(JwtClaimTypes.Name, "Alice Smith"), 20 | new Claim(JwtClaimTypes.GivenName, "Alice"), 21 | new Claim(JwtClaimTypes.FamilyName, "Smith"), 22 | new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"), 23 | new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), 24 | new Claim(JwtClaimTypes.WebSite, "http://alice.com"), 25 | new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json) 26 | } 27 | }, 28 | new TestUser{SubjectId = "88421113", Username = "bob", Password = "bob", 29 | Claims = 30 | { 31 | new Claim(JwtClaimTypes.Name, "Bob Smith"), 32 | new Claim(JwtClaimTypes.GivenName, "Bob"), 33 | new Claim(JwtClaimTypes.FamilyName, "Smith"), 34 | new Claim(JwtClaimTypes.Email, "BobSmith@email.com"), 35 | new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), 36 | new Claim(JwtClaimTypes.WebSite, "http://bob.com"), 37 | new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json), 38 | new Claim("location", "somewhere") 39 | } 40 | } 41 | }; 42 | } 43 | } -------------------------------------------------------------------------------- /invoice-scanner-dotnet/Services/OcrClient.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Azure.CognitiveServices.Vision.ComputerVision; 4 | using Microsoft.Azure.CognitiveServices.Vision.ComputerVision.Models; 5 | 6 | namespace Serverless 7 | { 8 | public class OcrClient 9 | { 10 | private const TextRecognitionMode textRecognitionMode = TextRecognitionMode.Printed; 11 | private const int numberOfCharsInOperationId = 36; 12 | private ComputerVisionClient computerVision; 13 | 14 | public OcrClient(string endpoint, string subscriptionKey) 15 | { 16 | computerVision = new ComputerVisionClient( 17 | new ApiKeyServiceClientCredentials(subscriptionKey), 18 | new System.Net.Http.DelegatingHandler[] { }); 19 | computerVision.Endpoint = endpoint; 20 | } 21 | 22 | public async Task RecognizeText(string remoteImageUrl) 23 | { 24 | return await ExtractRemoteTextAsync(computerVision, remoteImageUrl); 25 | } 26 | 27 | private async Task ExtractRemoteTextAsync(ComputerVisionClient computerVision, string imageUrl) 28 | { 29 | if (!Uri.IsWellFormedUriString(imageUrl, UriKind.Absolute)) 30 | { 31 | throw new UriFormatException(imageUrl); 32 | } 33 | 34 | var textHeaders = await computerVision.RecognizeTextAsync(imageUrl, textRecognitionMode); 35 | 36 | return await GetTextAsync(computerVision, textHeaders.OperationLocation); 37 | } 38 | 39 | private async Task GetTextAsync(ComputerVisionClient computerVision, string operationLocation) 40 | { 41 | var operationId = operationLocation.Substring(operationLocation.Length - numberOfCharsInOperationId); 42 | var result = await computerVision.GetTextOperationResultAsync(operationId); 43 | 44 | int i = 0; 45 | int maxRetries = 10; 46 | 47 | while ((result.Status == TextOperationStatusCodes.Running || 48 | result.Status == TextOperationStatusCodes.NotStarted) && i++ < maxRetries) 49 | { 50 | await Task.Delay(1000); 51 | 52 | result = await computerVision.GetTextOperationResultAsync(operationId); 53 | } 54 | 55 | return result.RecognitionResult; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /identity-service-dotnet/wwwroot/css/site.less: -------------------------------------------------------------------------------- 1 | body { 2 | margin-top: 65px; 3 | } 4 | 5 | .navbar-header { 6 | position: relative; 7 | top: -4px; 8 | } 9 | 10 | .navbar-brand > .icon-banner { 11 | position: relative; 12 | top: -2px; 13 | display: inline; 14 | } 15 | 16 | .icon { 17 | position: relative; 18 | top: -10px; 19 | } 20 | 21 | .logged-out iframe { 22 | display: none; 23 | width: 0; 24 | height: 0; 25 | } 26 | 27 | .page-consent { 28 | .client-logo { 29 | float: left; 30 | 31 | img { 32 | width: 80px; 33 | height: 80px; 34 | } 35 | } 36 | 37 | .consent-buttons { 38 | margin-top: 25px; 39 | } 40 | 41 | .consent-form { 42 | .consent-scopecheck { 43 | display: inline-block; 44 | margin-right: 5px; 45 | } 46 | 47 | .consent-scopecheck[disabled] { 48 | //visibility:hidden; 49 | } 50 | 51 | .consent-description { 52 | margin-left: 25px; 53 | 54 | label { 55 | font-weight: normal; 56 | } 57 | } 58 | 59 | .consent-remember { 60 | padding-left: 16px; 61 | } 62 | } 63 | } 64 | 65 | .grants { 66 | .page-header { 67 | margin-bottom: 10px; 68 | } 69 | 70 | .grant { 71 | margin-top: 20px; 72 | padding-bottom: 20px; 73 | border-bottom: 1px solid lightgray; 74 | 75 | img { 76 | width: 100px; 77 | height: 100px; 78 | } 79 | 80 | .clientname { 81 | font-size: 140%; 82 | font-weight: bold; 83 | } 84 | 85 | .granttype { 86 | font-size: 120%; 87 | font-weight: bold; 88 | } 89 | 90 | .created { 91 | font-size: 120%; 92 | font-weight: bold; 93 | } 94 | 95 | .expires { 96 | font-size: 120%; 97 | font-weight: bold; 98 | } 99 | 100 | li { 101 | list-style-type: none; 102 | display: inline; 103 | 104 | &:after { 105 | content: ', '; 106 | } 107 | 108 | &:last-child:after { 109 | content: ''; 110 | } 111 | 112 | .displayname { 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /identity-service-dotnet/Views/Shared/_Layout.cshtml: -------------------------------------------------------------------------------- 1 | @using IdentityServer4.Extensions 2 | @{ 3 | string name = null; 4 | if (!true.Equals(ViewData["signed-out"])) 5 | { 6 | name = Context.User?.GetDisplayName(); 7 | } 8 | } 9 | 10 | 11 | 12 | 13 | 14 | 15 | IdentityServer4 16 | 17 | 18 | 19 | 20 | 21 | 22 | 52 | 53 |
    54 | @RenderBody() 55 |
    56 | 57 | 58 | 59 | @RenderSection("scripts", required: false) 60 | 61 | 62 | -------------------------------------------------------------------------------- /shopping-client-ng/client/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | /*************************************************************************************************** 17 | * BROWSER POLYFILLS 18 | */ 19 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 20 | // import 'core-js/es6/symbol'; 21 | // import 'core-js/es6/object'; 22 | // import 'core-js/es6/function'; 23 | // import 'core-js/es6/parse-int'; 24 | // import 'core-js/es6/parse-float'; 25 | // import 'core-js/es6/number'; 26 | // import 'core-js/es6/math'; 27 | // import 'core-js/es6/string'; 28 | // import 'core-js/es6/date'; 29 | // import 'core-js/es6/array'; 30 | // import 'core-js/es6/regexp'; 31 | // import 'core-js/es6/map'; 32 | // import 'core-js/es6/set'; 33 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 34 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 35 | /** IE10 and IE11 requires the following to support `@angular/animation`. */ 36 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 37 | /** Evergreen browsers require these. **/ 38 | import 'core-js/es6/reflect'; 39 | 40 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/ 41 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 42 | /*************************************************************************************************** 43 | * Zone JS is required by Angular itself. 44 | */ 45 | import 'zone.js/dist/zone'; // Included with Angular CLI. 46 | 47 | 48 | /*************************************************************************************************** 49 | * APPLICATION IMPORTS 50 | */ 51 | 52 | /** 53 | * Date, currency, decimal and percent pipes. 54 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 55 | */ 56 | // import 'intl'; // Run `npm install --save intl`. 57 | -------------------------------------------------------------------------------- /identity-service-dotnet/Program.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Microsoft.AspNetCore; 3 | using Microsoft.AspNetCore.Hosting; 4 | using Microsoft.Extensions.Configuration; 5 | using Serilog; 6 | using Serilog.Events; 7 | using Serilog.Sinks.SystemConsole.Themes; 8 | using System; 9 | 10 | namespace IdentityServer 11 | { 12 | public class Program 13 | { 14 | public static void Main(string[] args) 15 | { 16 | var host = CreateWebHostBuilder(args).Build(); 17 | host.Run(); 18 | } 19 | 20 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) 21 | { 22 | var functionPath = Path.Combine(new FileInfo(typeof(Program).Assembly.Location).Directory.FullName, ".."); 23 | Environment.SetEnvironmentVariable("HOST_FUNCTION_CONTENT_PATH", functionPath, EnvironmentVariableTarget.Process); 24 | 25 | return WebHost.CreateDefaultBuilder(args) 26 | .ConfigureAppConfiguration((builderContext, config) => 27 | { 28 | config 29 | .SetBasePath(functionPath) 30 | .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 31 | .AddJsonFile($"appsettings.{builderContext.HostingEnvironment.EnvironmentName}.json", 32 | optional: true, reloadOnChange: true) 33 | .AddEnvironmentVariables(); 34 | 35 | var builtConfig = config.Build(); 36 | 37 | config.AddAzureKeyVault( 38 | builtConfig["KeyVault:BaseUrl"], 39 | builtConfig["KeyVault:ClientId"], 40 | builtConfig["KeyVault:ClientSecret"]); 41 | }) 42 | .UseApplicationInsights() 43 | .UseContentRoot(functionPath) 44 | .UseStartup() 45 | .UseSerilog((context, configuration) => 46 | { 47 | configuration 48 | .MinimumLevel.Debug() 49 | .MinimumLevel.Override("Microsoft", LogEventLevel.Warning) 50 | .MinimumLevel.Override("System", LogEventLevel.Warning) 51 | .MinimumLevel.Override("Microsoft.AspNetCore.Authentication", LogEventLevel.Information) 52 | .Enrich.FromLogContext() 53 | .WriteTo.Console(outputTemplate: "[{Timestamp:HH:mm:ss} {Level}] {SourceContext}{NewLine}{Message:lj}{NewLine}{Exception}{NewLine}", theme: AnsiConsoleTheme.Literate) 54 | .WriteTo.ApplicationInsightsTraces(System.Environment.GetEnvironmentVariable("APPINSIGHTS_INSTRUMENTATIONKEY")); 55 | }); 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /orders-service-dotnet/Functions/CreateNewOrder.cs: -------------------------------------------------------------------------------- 1 | 2 | using System; 3 | using System.IO; 4 | using System.Threading.Tasks; 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.Azure.WebJobs; 7 | using Microsoft.Azure.WebJobs.Extensions.Http; 8 | using Microsoft.AspNetCore.Http; 9 | using Microsoft.Azure.WebJobs.Host; 10 | using Microsoft.Extensions.Logging; 11 | using Newtonsoft.Json; 12 | using Microsoft.Azure.ServiceBus; 13 | using System.Threading; 14 | using System.Security.Claims; 15 | using System.Linq; 16 | using Microsoft.Azure.Documents; 17 | using Microsoft.Azure.WebJobs.Extensions.SignalRService; 18 | using Serverless.Messages; 19 | 20 | namespace Serverless 21 | { 22 | public class CreateNewOrderFunctions 23 | { 24 | [FunctionName("CreateNewOrder")] 25 | public async Task Run( 26 | [ServiceBusTrigger("neworders", Connection = "ServiceBus")] 27 | NewOrderMessage message, 28 | 29 | [CosmosDB("ordersservice", "data", ConnectionStringSetting = "CosmosDB")] 30 | IAsyncCollector data, 31 | 32 | [ServiceBus("ordersforshipping", Connection = "ServiceBus")] 33 | IAsyncCollector messages, 34 | 35 | [SignalR(HubName="ordersHub", ConnectionStringSetting="SignalR")] 36 | IAsyncCollector notificationMessages, 37 | 38 | ILogger log) 39 | { 40 | log.LogInformation("CreateNewOrder SB queue trigger function processed a request."); 41 | 42 | // NOTE: talk to other systems, do checks etc. ... - do the REAL work :-) 43 | // This is a demo, after all. 44 | 45 | try 46 | { 47 | await data.AddAsync(message); 48 | await data.FlushAsync(); 49 | } 50 | catch (DocumentClientException dcx) 51 | { 52 | // TODO: retry policy... 53 | log.LogError(dcx, "Cosmos DB Error"); 54 | throw; 55 | } 56 | 57 | try 58 | { 59 | await messages.AddAsync(message); 60 | await messages.FlushAsync(); 61 | } 62 | catch (ServiceBusException sbx) 63 | { 64 | // TODO: retry policy... 65 | log.LogError(sbx, "Service Bus Error"); 66 | throw; 67 | } 68 | 69 | var messageToNotify = new { userId = message.UserId, orderId = message.Order.Id }; 70 | 71 | await notificationMessages.AddAsync(new SignalRMessage 72 | { 73 | Target = "orderCreated", 74 | Arguments = new[] { messageToNotify } 75 | }); 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /shopping-client-ng/client/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": ["node_modules/codelyzer"], 3 | "rules": { 4 | "callable-types": true, 5 | "class-name": true, 6 | "comment-format": [true, "check-space"], 7 | "curly": true, 8 | "eofline": true, 9 | "forin": true, 10 | "import-blacklist": [true], 11 | "import-spacing": true, 12 | "indent": [true, "spaces"], 13 | "interface-over-type-literal": true, 14 | "label-position": true, 15 | "max-line-length": [true, 140], 16 | "member-access": false, 17 | "member-ordering": [ 18 | true, 19 | "static-before-instance", 20 | "variables-before-functions" 21 | ], 22 | "no-arg": true, 23 | "no-bitwise": true, 24 | "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], 25 | "no-construct": true, 26 | "no-debugger": true, 27 | "no-duplicate-variable": true, 28 | "no-empty": false, 29 | "no-empty-interface": true, 30 | "no-eval": true, 31 | "no-inferrable-types": [true, "ignore-params"], 32 | "no-shadowed-variable": true, 33 | "no-string-literal": false, 34 | "no-string-throw": true, 35 | "no-switch-case-fall-through": true, 36 | "no-trailing-whitespace": true, 37 | "no-unused-expression": true, 38 | "no-use-before-declare": true, 39 | "no-var-keyword": true, 40 | "object-literal-sort-keys": false, 41 | "one-line": [ 42 | true, 43 | "check-open-brace", 44 | "check-catch", 45 | "check-else", 46 | "check-whitespace" 47 | ], 48 | "prefer-const": true, 49 | "quotemark": [false, "double"], 50 | "radix": true, 51 | "semicolon": ["always"], 52 | "triple-equals": [true, "allow-null-check"], 53 | "typedef-whitespace": [ 54 | true, 55 | { 56 | "call-signature": "nospace", 57 | "index-signature": "nospace", 58 | "parameter": "nospace", 59 | "property-declaration": "nospace", 60 | "variable-declaration": "nospace" 61 | } 62 | ], 63 | "typeof-compare": true, 64 | "unified-signatures": true, 65 | "variable-name": false, 66 | "whitespace": [ 67 | true, 68 | "check-branch", 69 | "check-decl", 70 | "check-operator", 71 | "check-separator", 72 | "check-type" 73 | ], 74 | "directive-selector": [true, "attribute", "app", "camelCase"], 75 | "component-selector": [true, "element", "app", "kebab-case"], 76 | "use-input-property-decorator": true, 77 | "use-output-property-decorator": true, 78 | "use-host-property-decorator": true, 79 | "no-input-rename": true, 80 | "no-output-rename": true, 81 | "use-life-cycle-interface": true, 82 | "use-pipe-transform-interface": true, 83 | "component-class-suffix": true, 84 | "directive-class-suffix": true, 85 | "no-access-missing-member": true, 86 | "templates-use-public": true, 87 | "invoke-injectable": true 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /shopping-client-ng/client/buildAssets/mobile/config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Cross-Platform Demo 4 | 5 | A simple Angular cross-platform sample app 6 | 7 | 8 | Thinktecture AG 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 | -------------------------------------------------------------------------------- /identity-service-dotnet/Quickstart/SecurityHeadersAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Brock Allen & Dominick Baier. All rights reserved. 2 | // Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. 3 | 4 | 5 | using Microsoft.AspNetCore.Mvc; 6 | using Microsoft.AspNetCore.Mvc.Filters; 7 | 8 | namespace IdentityServer 9 | { 10 | public class SecurityHeadersAttribute : ActionFilterAttribute 11 | { 12 | public override void OnResultExecuting(ResultExecutingContext context) 13 | { 14 | var result = context.Result; 15 | if (result is ViewResult) 16 | { 17 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options 18 | if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Type-Options")) 19 | { 20 | context.HttpContext.Response.Headers.Add("X-Content-Type-Options", "nosniff"); 21 | } 22 | 23 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options 24 | if (!context.HttpContext.Response.Headers.ContainsKey("X-Frame-Options")) 25 | { 26 | context.HttpContext.Response.Headers.Add("X-Frame-Options", "SAMEORIGIN"); 27 | } 28 | 29 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy 30 | var csp = "default-src 'self'; object-src 'none'; frame-ancestors 'none'; sandbox allow-forms allow-same-origin allow-scripts; base-uri 'self';"; 31 | // also consider adding upgrade-insecure-requests once you have HTTPS in place for production 32 | //csp += "upgrade-insecure-requests;"; 33 | // also an example if you need client images to be displayed from twitter 34 | // csp += "img-src 'self' https://pbs.twimg.com;"; 35 | 36 | // once for standards compliant browsers 37 | if (!context.HttpContext.Response.Headers.ContainsKey("Content-Security-Policy")) 38 | { 39 | context.HttpContext.Response.Headers.Add("Content-Security-Policy", csp); 40 | } 41 | // and once again for IE 42 | if (!context.HttpContext.Response.Headers.ContainsKey("X-Content-Security-Policy")) 43 | { 44 | context.HttpContext.Response.Headers.Add("X-Content-Security-Policy", csp); 45 | } 46 | 47 | // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy 48 | var referrer_policy = "no-referrer"; 49 | if (!context.HttpContext.Response.Headers.ContainsKey("Referrer-Policy")) 50 | { 51 | context.HttpContext.Response.Headers.Add("Referrer-Policy", referrer_policy); 52 | } 53 | } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /orders-service-dotnet/Functions/SubmitNewOrder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.Azure.WebJobs; 6 | using Microsoft.Azure.WebJobs.Extensions.Http; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.Azure.WebJobs.Host; 9 | using Microsoft.Extensions.Logging; 10 | using Newtonsoft.Json; 11 | using Microsoft.Azure.ServiceBus; 12 | using System.Threading; 13 | using System.Security.Claims; 14 | using System.Linq; 15 | using Microsoft.Azure.Documents; 16 | using AutoMapper; 17 | 18 | namespace Serverless 19 | { 20 | public class SubmitNewOrderFunctions 21 | { 22 | static SubmitNewOrderFunctions() 23 | { 24 | InitializeMapper(); 25 | } 26 | 27 | [FunctionName("SubmitNewOrder")] 28 | public async Task Run( 29 | [HttpTrigger(AuthorizationLevel.Anonymous, "POST", Route = "api/orders")] 30 | HttpRequest req, 31 | 32 | [ServiceBus("neworders", Connection="ServiceBus")] 33 | IAsyncCollector messages, 34 | 35 | ILogger log) 36 | { 37 | log.LogInformation("SubmitNewOrder HTTP trigger function processed a request."); 38 | 39 | if (!await req.CheckAuthorization("api")) 40 | { 41 | return new UnauthorizedResult(); 42 | } 43 | 44 | var newOrder = req.Deserialize(); 45 | newOrder.Id = Guid.NewGuid(); 46 | newOrder.Created = DateTime.UtcNow; 47 | 48 | var identity = Thread.CurrentPrincipal.Identity as ClaimsIdentity; 49 | var userId = identity.Name; 50 | 51 | var newOrderMessage = new Messages.NewOrderMessage 52 | { 53 | Order = Mapper.Map(newOrder), 54 | UserId = userId 55 | }; 56 | 57 | try 58 | { 59 | await messages.AddAsync(newOrderMessage); 60 | await messages.FlushAsync(); 61 | } 62 | catch (ServiceBusException sbx) 63 | { 64 | // TODO: think about retry policy (e.g. https://github.com/jeffhollan/functions-csharp-queue-exponential/blob/master/ExponentialRetry.cs) 65 | log.LogError(sbx, "Service Bus Error"); 66 | throw; 67 | } 68 | 69 | return new OkResult(); 70 | } 71 | 72 | private static void InitializeMapper() 73 | { 74 | Mapper.Initialize(cfg => 75 | { 76 | cfg.CreateMap(); 77 | cfg.CreateMap() 78 | .ForMember(d => d.Items, opt => opt.MapFrom(s => s.Items)); 79 | }); 80 | Mapper.AssertConfigurationIsValid(); 81 | } 82 | } 83 | } 84 | --------------------------------------------------------------------------------