├── .devcontainer
├── Dockerfile
├── devcontainer.json
└── library-scripts
│ ├── docker-in-docker.sh
│ └── node-debian.sh
├── .github
└── workflows
│ ├── 2wr-app.yaml
│ ├── admin.yaml
│ └── api.yaml
├── .gitignore
├── .vscode
├── launch.json
├── settings.json
└── tasks.json
├── 2wr-app
├── .env-sample
├── .gitignore
├── .prettierrc
├── README.md
├── babel.config.js
├── code-tour
│ └── UITour.tour
├── jsconfig.json
├── package-lock.json
├── package.json
├── playwright.config.js
├── public
│ ├── favicon.ico
│ ├── images
│ │ ├── hazards
│ │ │ ├── earthquake-description.png
│ │ │ ├── earthquake.png
│ │ │ ├── flood.png
│ │ │ ├── landslide.png
│ │ │ ├── power-outage.png
│ │ │ ├── public-health-emergency.png
│ │ │ ├── radiological.png
│ │ │ ├── severe-weather.png
│ │ │ ├── tsunami.png
│ │ │ ├── volcano.png
│ │ │ └── wildfire.png
│ │ └── kits
│ │ │ ├── build-a-kit.png
│ │ │ ├── child-kit.png
│ │ │ ├── go-kit.png
│ │ │ ├── home-kit.png
│ │ │ ├── pet-kit.png
│ │ │ ├── vehicle-kit.png
│ │ │ └── work-kit.png
│ ├── img
│ │ └── icons
│ │ │ ├── android-chrome-192x192.png
│ │ │ ├── android-chrome-512x512.png
│ │ │ ├── android-chrome-maskable-192x192.png
│ │ │ ├── android-chrome-maskable-512x512.png
│ │ │ ├── apple-touch-icon-120x120.png
│ │ │ ├── apple-touch-icon-152x152.png
│ │ │ ├── apple-touch-icon-180x180.png
│ │ │ ├── apple-touch-icon-60x60.png
│ │ │ ├── apple-touch-icon-76x76.png
│ │ │ ├── apple-touch-icon.png
│ │ │ ├── favicon-16x16.png
│ │ │ ├── favicon-32x32.png
│ │ │ ├── msapplication-icon-144x144.png
│ │ │ ├── mstile-150x150.png
│ │ │ └── safari-pinned-tab.svg
│ ├── index.html
│ ├── robots.txt
│ └── service-worker.js
├── src
│ ├── App.vue
│ ├── api
│ │ ├── base-api-instance.js
│ │ ├── base-kit-api.js
│ │ ├── emergency-kit-api.js
│ │ ├── family-plans-api.js
│ │ ├── hazard-hunt-api.js
│ │ ├── hazard-info-api.js
│ │ └── photos-api.js
│ ├── assets
│ │ ├── app.scss
│ │ └── logo.svg
│ ├── auth
│ │ └── index.js
│ ├── components
│ │ ├── common
│ │ │ ├── ConfirmDialog.vue
│ │ │ ├── DatePickerInput.vue
│ │ │ ├── EditableTextBlock.vue
│ │ │ ├── IconTextBlock.vue
│ │ │ ├── InfoBar.vue
│ │ │ ├── SecureImg.vue
│ │ │ └── globalComponents.js
│ │ ├── prepare
│ │ │ ├── emergency-kits
│ │ │ │ ├── emergency-kit-build.vue
│ │ │ │ ├── emergency-kit-details.vue
│ │ │ │ └── emergency-kit-list.vue
│ │ │ ├── family-plans
│ │ │ │ ├── address-view.vue
│ │ │ │ ├── children-list.vue
│ │ │ │ ├── editors
│ │ │ │ │ ├── address-editor.vue
│ │ │ │ │ ├── child-editor.vue
│ │ │ │ │ ├── emergency-contact-editor.vue
│ │ │ │ │ ├── pet-editor.vue
│ │ │ │ │ ├── photo-editor.vue
│ │ │ │ │ ├── photos-editor.vue
│ │ │ │ │ └── route-location-editor.vue
│ │ │ │ ├── emergency-contact-view.vue
│ │ │ │ ├── family-plan-contacts-view.vue
│ │ │ │ ├── family-plans-list.vue
│ │ │ │ ├── family-plans-view.vue
│ │ │ │ ├── pets-list.vue
│ │ │ │ └── route-location-list.vue
│ │ │ ├── hazards
│ │ │ │ ├── hazard-hunt-list.vue
│ │ │ │ ├── hazard-hunt.vue
│ │ │ │ ├── hazard-info-list.vue
│ │ │ │ └── hazard-info.vue
│ │ │ ├── make-a-plan
│ │ │ │ └── make-a-plan.vue
│ │ │ └── prepare-landing.vue
│ │ ├── recent
│ │ │ └── recent-landing.vue
│ │ ├── settings
│ │ │ └── settings-landing.vue
│ │ └── welcome
│ │ │ └── welcome-landing.vue
│ ├── functions
│ │ ├── goBack.js
│ │ └── setFocusVuetify.js
│ ├── lookups
│ │ └── states.js
│ ├── main.js
│ ├── models
│ │ └── family-plans
│ │ │ ├── Address.js
│ │ │ ├── Child.js
│ │ │ ├── EmergencyContact.js
│ │ │ ├── FamilyPlan.js
│ │ │ ├── Pet.js
│ │ │ └── RouteLocation.js
│ ├── plugins
│ │ └── vuetify.js
│ ├── register-service-worker.js
│ ├── router
│ │ ├── familyPlanRoutes.js
│ │ └── index.js
│ ├── rules
│ │ └── index.js
│ ├── store
│ │ ├── index.js
│ │ └── modules
│ │ │ ├── global
│ │ │ └── global-store.js
│ │ │ └── prepare
│ │ │ ├── base-kits
│ │ │ └── base-kit-store.js
│ │ │ ├── emergency-kits
│ │ │ └── emergency-kit-store.js
│ │ │ ├── family-plans
│ │ │ ├── actions.js
│ │ │ ├── getters.js
│ │ │ ├── index.js
│ │ │ ├── mutations.js
│ │ │ └── state.js
│ │ │ └── hazards
│ │ │ ├── hazard-hunt-store.js
│ │ │ └── hazard-info-store.js
│ └── views
│ │ ├── prepare
│ │ ├── emergency-kits
│ │ │ ├── emergency-kit-build.vue
│ │ │ ├── emergency-kit-details.vue
│ │ │ └── emergency-kit-listing.vue
│ │ ├── family-plans
│ │ │ ├── children.vue
│ │ │ ├── contacts.vue
│ │ │ ├── distant-contacts.vue
│ │ │ ├── landing.vue
│ │ │ ├── pets.vue
│ │ │ ├── routes.vue
│ │ │ └── view.vue
│ │ ├── hazards
│ │ │ ├── hazard-hunt-list-view.vue
│ │ │ ├── hazard-hunt-view.vue
│ │ │ ├── hazard-info-list-view.vue
│ │ │ └── hazard-info-view.vue
│ │ ├── make-a-plan
│ │ │ └── make-a-plan.vue
│ │ └── prepare.vue
│ │ ├── recent
│ │ └── recent.vue
│ │ ├── settings
│ │ └── settings.vue
│ │ └── welcome
│ │ └── welcome.vue
├── tests
│ ├── global-setup.js
│ ├── hazard-info.spec.js
│ └── welcome.spec.js
└── vue.config.js
├── LICENSE
├── README.md
├── TwoWeeksReady.Common
├── EmergencyKits
│ ├── BaseKit.cs
│ ├── BaseKitItem.cs
│ ├── Kit.cs
│ └── KitItem.cs
├── FamilyMembers
│ └── FamilyMember.cs
├── FamilyPlans
│ ├── Address.cs
│ ├── Child.cs
│ ├── Contact.cs
│ ├── FamilyPlan.cs
│ ├── Pet.cs
│ ├── RouteLocation.cs
│ └── WalkThroughStep.cs
├── Hazards
│ ├── HazardBaseInfo.cs
│ ├── HazardHunt.cs
│ └── HazardInfo.cs
└── TwoWeeksReady.Common.csproj
├── admin
├── TwoWeeksReady.Admin
│ ├── App.razor
│ ├── Components
│ │ └── KitItemDisplay.razor
│ ├── Data
│ │ ├── ClientImage.cs
│ │ ├── ClientImageService.cs
│ │ ├── FunctionsRepository.cs
│ │ ├── IRepository.cs
│ │ └── StubRepository.cs
│ ├── Pages
│ │ ├── Error.cshtml
│ │ ├── Error.cshtml.cs
│ │ ├── HazardHunts
│ │ │ ├── Details.razor
│ │ │ └── List.razor
│ │ ├── HazardInfos
│ │ │ ├── Details.razor
│ │ │ └── List.razor
│ │ ├── Index.razor
│ │ ├── Kits
│ │ │ ├── Details.razor
│ │ │ └── List.razor
│ │ ├── Login.cshtml
│ │ ├── Login.cshtml.cs
│ │ ├── Logout.cshtml
│ │ ├── Logout.cshtml.cs
│ │ └── _Host.cshtml
│ ├── Program.cs
│ ├── Properties
│ │ └── launchSettings.json
│ ├── Security
│ │ └── TokenProvider.cs
│ ├── Shared
│ │ ├── AccessControl.razor
│ │ ├── MainLayout.razor
│ │ ├── MainLayout.razor.css
│ │ ├── NavMenu.razor
│ │ └── NavMenu.razor.css
│ ├── Startup.cs
│ ├── TwoWeeksReady.Admin.csproj
│ ├── _Imports.razor
│ ├── appsettings.Development.json
│ ├── appsettings.json
│ └── wwwroot
│ │ ├── css
│ │ ├── bootstrap
│ │ │ ├── bootstrap.min.css
│ │ │ └── bootstrap.min.css.map
│ │ ├── open-iconic
│ │ │ ├── FONT-LICENSE
│ │ │ ├── ICON-LICENSE
│ │ │ ├── README.md
│ │ │ └── font
│ │ │ │ ├── css
│ │ │ │ └── open-iconic-bootstrap.min.css
│ │ │ │ └── fonts
│ │ │ │ ├── open-iconic.eot
│ │ │ │ ├── open-iconic.otf
│ │ │ │ ├── open-iconic.svg
│ │ │ │ ├── open-iconic.ttf
│ │ │ │ └── open-iconic.woff
│ │ └── site.css
│ │ └── favicon.ico
└── admin.sln
├── api
├── .gitignore
├── .vscode
│ ├── extensions.json
│ ├── launch.json
│ ├── settings.json
│ └── tasks.json
├── CodeTour
│ └── ApiTour.tour
├── README.md
├── TwoWeeksReady
│ ├── .vscode
│ │ ├── extensions.json
│ │ ├── launch.json
│ │ ├── settings.json
│ │ └── tasks.json
│ ├── Authorization
│ │ ├── AuthorizationExtensions.cs
│ │ └── Roles.cs
│ ├── Common
│ │ └── BaseFunction.cs
│ ├── EmergencyKits
│ │ ├── BaseKitsApi.cs
│ │ ├── CreateKitFromBaseRequest.cs
│ │ └── EmergencyKitsApi.cs
│ ├── FamilyMembers
│ │ └── FamilyMembersApi.cs
│ ├── FamilyPlans
│ │ └── FamilyPlansApi.cs
│ ├── Hazards
│ │ ├── HazardApiBase.cs
│ │ ├── HazardHuntApi.cs
│ │ └── HazardInfoApi.cs
│ ├── Photos
│ │ └── PhotoFunction.cs
│ ├── Startup.cs
│ ├── TwoWeeksReady.csproj
│ └── host.json
├── api.code-workspace
└── api.sln
├── assets
├── icons
│ ├── app
│ │ ├── 2 Weeks Ready Icon-128.png
│ │ ├── 2 Weeks Ready Icon-16.png
│ │ ├── 2 Weeks Ready Icon-256.png
│ │ ├── 2 Weeks Ready Icon-32.png
│ │ ├── 2 Weeks Ready Icon-512.png
│ │ ├── 2 Weeks Ready Icon-64.png
│ │ └── 2 Weeks Ready Icon.svg
│ └── kits
│ │ ├── 2WR Kit.png
│ │ ├── 2WR Kit.svg
│ │ ├── Child Kit.svg
│ │ ├── Child Kit128-.png
│ │ ├── Child Kit16-.png
│ │ ├── Child Kit256-.png
│ │ ├── Child Kit32-.png
│ │ ├── Child Kit512-.png
│ │ ├── Child Kit64-.png
│ │ ├── Miscellaneous Icons V3.ai
│ │ ├── Pet Kit.svg
│ │ ├── Pet Kit128-.png
│ │ ├── Pet Kit16-.png
│ │ ├── Pet Kit256-.png
│ │ ├── Pet Kit32-.png
│ │ ├── Pet Kit512-.png
│ │ ├── Pet Kit64-.png
│ │ ├── Vehicle Kit.svg
│ │ ├── Vehicle Kit128-.png
│ │ ├── Vehicle Kit16-.png
│ │ ├── Vehicle Kit256-.png
│ │ ├── Vehicle Kit32-.png
│ │ ├── Vehicle Kit512-.png
│ │ └── Vehicle Kit64-.png
├── images
│ ├── 210909_2WR_EMAIL GRAPHIC.png
│ ├── Build A Kit
│ │ ├── Child Kit.png
│ │ ├── Home Kit.png
│ │ ├── Pet Kit.png
│ │ ├── Vehicle Kit.png
│ │ └── Work Kit.png
│ ├── Hazard Information
│ │ ├── Earthquake.png
│ │ ├── Flood.png
│ │ ├── Landslide.png
│ │ ├── Power Outage.png
│ │ ├── Public Health Emergency.png
│ │ ├── Radiological.png
│ │ ├── Severe Weather.png
│ │ ├── Tsunami.png
│ │ ├── Volcano.png
│ │ └── Wildfire.png
│ ├── codetour_api.png
│ ├── codetour_ui.png
│ ├── forestfire_resized.jpg
│ ├── seismograph_resized.jpg
│ └── twoweeksready.png
├── models
│ ├── EmergencyKits.drawio
│ ├── EmergencyKits.png
│ ├── HazardHuntHazardInformation.drawio
│ └── HazardHuntHazardInformation.png
└── wiki
│ ├── Family plan page 1.PNG
│ ├── Family plan page 2.PNG
│ ├── Family plan page 3.PNG
│ ├── Family plan page 4.PNG
│ ├── Family plan page 5.PNG
│ ├── Family plan page 6.PNG
│ ├── Family plan page 7.PNG
│ ├── Family plan page 8.PNG
│ ├── HazardHuntDetails.png
│ ├── HazardHuntEntry.png
│ └── HazardHuntListing.png
├── az
├── create-admin-app-resources.sh
├── create-backend-resources.sh
├── create-frontend-resources.sh
├── deploy-admin-app.sh
├── deploy-backend.sh
└── deploy-frontend.sh
├── solution architecture.xml
└── tools
├── CosmosEmulator
├── CosmosEmulator.csproj
├── CosmosInitializer.cs
├── Program.cs
├── start-emulator.sh
└── stop-emulator.sh
├── first-build.sh
├── samples
└── local.settings.sample.json
└── setup-config.sh
/.devcontainer/Dockerfile:
--------------------------------------------------------------------------------
1 | # Find the Dockerfile for mcr.microsoft.com/azure-functions/dotnet:3.0-dotnet3-core-tools at this URL
2 | # https://github.com/Azure/azure-functions-docker/blob/main/host/3.0/buster/amd64/dotnet/dotnet-core-tools.Dockerfile
3 | FROM mcr.microsoft.com/azure-functions/dotnet:4-dotnet6-core-tools
4 |
5 | # Uncomment following lines If you want to enable Development Container Script
6 | # For more details https://github.com/microsoft/vscode-dev-containers/tree/main/script-library
7 |
8 | # Avoid warnings by switching to noninteractive
9 | # ENV DEBIAN_FRONTEND=noninteractive
10 |
11 | # # Comment out these lines if you want to use zsh.
12 |
13 | ARG INSTALL_ZSH=false
14 | ARG USERNAME=vscode
15 | ARG USER_UID=1000
16 | ARG USER_GID=$USER_UID
17 |
18 | RUN apt-get update && curl -ssL https://raw.githubusercontent.com/microsoft/vscode-dev-containers/main/script-library/common-debian.sh -o /tmp/common-script.sh \
19 | && /bin/bash /tmp/common-script.sh "$INSTALL_ZSH" "$USERNAME" "$USER_UID" "$USER_GID" \
20 | && rm /tmp/common-script.sh
21 |
22 | # Setup .NET 5 & 6 SDKs
23 | RUN wget https://packages.microsoft.com/config/debian/10/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
24 | RUN dpkg -i packages-microsoft-prod.deb
25 | RUN rm packages-microsoft-prod.deb
26 | RUN apt-get update \
27 | && apt-get install -y apt-transport-https \
28 | && apt-get update \
29 | && apt-get install -y dotnet-sdk-5.0 \
30 | && apt-get install -y dotnet-sdk-6.0
31 |
32 | # Install Chrome for Desktop Testing through VNC
33 | RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
34 | && curl -sSL https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -o /tmp/chrome.deb \
35 | && apt-get -y install /tmp/chrome.deb
--------------------------------------------------------------------------------
/.devcontainer/devcontainer.json:
--------------------------------------------------------------------------------
1 | // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at:
2 | // https://github.com/microsoft/vscode-dev-containers/tree/v0.209.6/containers/azure-functions-dotnetcore-3.1
3 | {
4 | "name": "TwoWeeksReady",
5 | "dockerFile": "Dockerfile",
6 | "forwardPorts": [ 7071, 6080, 5901 ],
7 |
8 | // Set *default* container specific settings.json values on container create.
9 | "settings": {},
10 |
11 | // Add the IDs of extensions you want installed when the container is created.
12 | "extensions": [
13 | "ms-azuretools.vscode-azurefunctions",
14 | "ms-dotnettools.csharp",
15 | "azurite.azurite",
16 | //"ms-azuretools.vscode-cosmosdb"
17 | // unable to get preview extension working through devcontainer emulator due to certificate error, but works with deprecated feature in Azure Storage Explorer
18 | ],
19 |
20 | "features": {
21 | "docker-in-docker": {
22 | "version": "latest",
23 | "moby": true
24 | },
25 | "node": {
26 | "version": "lts",
27 | "nodeGypDependencies": true
28 | },
29 | "desktop-lite": {
30 | "password": "vscode",
31 | "webPort": "6080",
32 | "vncPort": "5901"
33 | },
34 | "github-cli": "latest"
35 | },
36 |
37 | // Use 'postCreateCommand' to run commands after the container is created.
38 | "postCreateCommand": "bash -i tools/first-build.sh",
39 |
40 | // Comment out connect as root instead. More info: https://aka.ms/vscode-remote/containers/non-root.
41 | "remoteUser": "vscode"
42 | }
43 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | // Use IntelliSense to find out which attributes exist for C# debugging
6 | // Use hover for the description of the existing attributes
7 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
8 | "name": ".NET Core Launch (web)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceFolder}/admin/TwoWeeksReady.Admin/bin/Debug/net5.0/TwoWeeksReady.Admin.dll",
14 | "args": [],
15 | "cwd": "${workspaceFolder}/admin/TwoWeeksReady.Admin",
16 | "stopAtEntry": false,
17 | // Enable launching a web browser when ASP.NET Core starts. For more information: https://aka.ms/VSCode-CS-LaunchJson-WebBrowser
18 | "serverReadyAction": {
19 | "action": "openExternally",
20 | "pattern": "\\bNow listening on:\\s+(https?://\\S+)"
21 | },
22 | "env": {
23 | "ASPNETCORE_ENVIRONMENT": "Development"
24 | },
25 | "sourceFileMap": {
26 | "/Views": "${workspaceFolder}/Views"
27 | }
28 | },
29 | {
30 | "name": ".NET Core Attach",
31 | "type": "coreclr",
32 | "request": "attach",
33 | "processId": "${command:pickProcess}"
34 | }
35 | ]
36 | }
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.projectSubpath": "api/TwoWeeksReady",
3 | "azureFunctions.deploySubpath": "api/TwoWeeksReady/bin/Release/net6.0/publish",
4 | "azureFunctions.projectLanguage": "C#",
5 | "azureFunctions.projectRuntime": "~4",
6 | "debug.internalConsoleOptions": "neverOpen",
7 | "azureFunctions.preDeployTask": "publish (functions)"
8 | }
--------------------------------------------------------------------------------
/2wr-app/.env-sample:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | VUE_APP_VERSION_TAG=LOCALDEV
3 | VUE_APP_TITLE=Two Weeks Ready - Local
4 | VUE_APP_APIROOT=http://localhost:7071/api/
5 | VUE_APP_AUTH0_DOMAIN=login.2wr.org
6 | VUE_APP_AUTH0_CLIENTID=6TSzRpgtMKR3NI1D4Is1nGO6brBB2wB0
7 | VUE_APP_AUTH0_AUDIENCE=https://2wrdev.azurewebsites.net
--------------------------------------------------------------------------------
/2wr-app/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 |
5 | /tests/_storagestate
6 | /playwright-report
7 |
8 | # local env files
9 | .env
10 | .env.local
11 | .env.*.local
12 |
13 | #test results
14 | /test-results
15 |
16 | # Log files
17 | npm-debug.log*
18 | yarn-debug.log*
19 | yarn-error.log*
20 | pnpm-debug.log*
21 |
22 | # Editor directories and files
23 | .idea
24 | .vscode
25 | *.suo
26 | *.ntvs*
27 | *.njsproj
28 | *.sln
29 | *.sw?
30 |
--------------------------------------------------------------------------------
/2wr-app/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "tabWidth": 2,
3 | "useTabs": false,
4 |
5 | }
6 |
--------------------------------------------------------------------------------
/2wr-app/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/2wr-app/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "module": "commonjs",
4 | "target": "es6",
5 | "baseUrl": ".",
6 | "paths": {
7 | "@/*": ["./src/*"]
8 | },
9 | "types": ["vuetify"]
10 | },
11 | "exclude": ["node_modules", "dist"],
12 | "include": ["src/**/*"]
13 | }
--------------------------------------------------------------------------------
/2wr-app/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "2wr-app",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "dev": "cross-env NODE_ENV=development npm-run-all --parallel dev:*",
7 | "dev:serve": "vue-cli-service serve",
8 | "dev:napi": "func start --prefix ..\\api\\TwoWeeksReady\\",
9 | "serve": "vue-cli-service serve",
10 | "build": "vue-cli-service build",
11 | "lint": "vue-cli-service lint",
12 | "api": "func start --prefix ..\\api\\TwoWeeksReady\\",
13 | "azurite": "azurite --silent --location c:\\temp\\azurite",
14 | "e2etest": "playwright test"
15 | },
16 | "dependencies": {
17 | "@auth0/auth0-spa-js": "^1.13.6",
18 | "@vue/composition-api": "^1.0.0-rc.7",
19 | "auth0-js": "^9.14.2",
20 | "core-js": "^3.8.2",
21 | "localforage": "^1.9.0",
22 | "lodash": "^4.17.21",
23 | "redaxios": "^0.3.0",
24 | "register-service-worker": "^1.7.2",
25 | "us": "^2.0.0",
26 | "uuid": "^3.4.0",
27 | "vue": "^2.6.11",
28 | "vue-router": "^3.4.9",
29 | "vuetify": "^2.5.10",
30 | "vuex": "^3.6.0"
31 | },
32 | "devDependencies": {
33 | "@mdi/font": "^5.8.55",
34 | "@playwright/test": "^1.40.0",
35 | "@vue/cli-plugin-babel": "^4.5.10",
36 | "@vue/cli-plugin-eslint": "^4.5.10",
37 | "@vue/cli-plugin-pwa": "^4.5.10",
38 | "@vue/cli-plugin-router": "^4.5.10",
39 | "@vue/cli-service": "^4.5.10",
40 | "axe-playwright": "^1.2.3",
41 | "babel-eslint": "^10.1.0",
42 | "cross-env": "^7.0.3",
43 | "dotenv-webpack": "^4.0.0",
44 | "eslint": "^6.7.2",
45 | "eslint-plugin-vue": "^6.2.2",
46 | "npm-run-all": "^4.1.5",
47 | "sass": "~1.32.4",
48 | "sass-loader": "^8.0.2",
49 | "vue-cli-plugin-vuetify": "^2.0.9",
50 | "vue-template-compiler": "^2.6.11",
51 | "vuetify-loader": "^1.3.0"
52 | },
53 | "eslintConfig": {
54 | "root": true,
55 | "env": {
56 | "node": true
57 | },
58 | "extends": [
59 | "plugin:vue/essential",
60 | "eslint:recommended"
61 | ],
62 | "parserOptions": {
63 | "parser": "babel-eslint"
64 | },
65 | "rules": {}
66 | },
67 | "browserslist": [
68 | "> 1%",
69 | "last 2 versions",
70 | "not dead"
71 | ]
72 | }
73 |
--------------------------------------------------------------------------------
/2wr-app/playwright.config.js:
--------------------------------------------------------------------------------
1 | // playwright.config.js
2 | // @ts-check
3 | /** @type {import('@playwright/test').PlaywrightTestConfig} */
4 |
5 | if (
6 | !process.env.TWO_WEEKS_READY_E2E_TEST_USERNAME ||
7 | !process.env.TWO_WEEKS_READY_E2E_TEST_PASSWORD
8 | ) {
9 | console.error(
10 | "TWO_WEEKS_READY_E2E_TEST_USERNAME and TWO_WEEKS_READY_E2E_TEST_PASSWORD environment variables must be set for end-to-end tests to run."
11 | );
12 | process.exit(-1);
13 | }
14 |
15 | const config = {
16 | timeout: 30000,
17 | webServer: {
18 | command: "npm run serve",
19 | url: "http://localhost:8080",
20 | timeout: 120 * 1000,
21 | reuseExistingServer: !process.env.CI
22 | },
23 | globalSetup: require.resolve("./tests/global-setup"),
24 | use: {
25 | baseURL: "http://localhost:8080/",
26 | screenshot: "only-on-failure",
27 | recording: "retain-on-failure",
28 | trace: "retain-on-failure",
29 | // Tell all tests to load signed-in state from 'storageState.json'.
30 | storageState: "./tests/_storagestate/storageState.json"
31 | },
32 | reporter: [["list"], ["html", { output: "reports/report.html" }]]
33 | };
34 | module.exports = config;
35 |
--------------------------------------------------------------------------------
/2wr-app/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/favicon.ico
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/earthquake-description.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/earthquake-description.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/earthquake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/earthquake.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/flood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/flood.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/landslide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/landslide.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/power-outage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/power-outage.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/public-health-emergency.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/public-health-emergency.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/radiological.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/radiological.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/severe-weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/severe-weather.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/tsunami.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/tsunami.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/volcano.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/volcano.png
--------------------------------------------------------------------------------
/2wr-app/public/images/hazards/wildfire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/hazards/wildfire.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/build-a-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/build-a-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/child-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/child-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/go-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/go-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/home-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/home-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/pet-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/pet-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/vehicle-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/vehicle-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/images/kits/work-kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/images/kits/work-kit.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/android-chrome-maskable-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-maskable-192x192.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/android-chrome-maskable-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/android-chrome-maskable-512x512.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/apple-touch-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-120x120.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/apple-touch-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-152x152.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/apple-touch-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-180x180.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/apple-touch-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-60x60.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/apple-touch-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon-76x76.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/msapplication-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/msapplication-icon-144x144.png
--------------------------------------------------------------------------------
/2wr-app/public/img/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/2wr-app/public/img/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/2wr-app/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | <%= process.env.VUE_APP_TITLE %>
9 |
10 |
11 |
12 |
13 | We're sorry but <%= process.env.VUE_APP_TITLE %> doesn't work properly without JavaScript enabled. Please enable it to continue.
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/2wr-app/public/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Disallow:
3 |
--------------------------------------------------------------------------------
/2wr-app/public/service-worker.js:
--------------------------------------------------------------------------------
1 | // custom service-worker.js
2 | if (workbox) {
3 | // adjust log level for displaying workbox logs
4 | //workbox.core.setLogLevel(workbox.core.LOG_LEVELS.debug)
5 |
6 | // apply precaching. In the built version, the precacheManifest will
7 | // be imported using importScripts (as is workbox itself) and we can
8 | // precache this. This is all we need for precaching
9 | workbox.precaching.precacheAndRoute(self.__precacheManifest);
10 |
11 | // Make sure to return a specific response for all navigation requests.
12 | // Since we have a SPA here, this should be index.html always.
13 | // https://stackoverflow.com/questions/49963982/vue-router-history-mode-with-pwa-in-offline-mode
14 | workbox.routing.registerNavigationRoute('/index.html')
15 |
16 | // Setup cache strategy for Google Fonts. They consist of two parts, a static one
17 | // coming from fonts.gstatic.com (strategy CacheFirst) and a more ferquently updated on
18 | // from fonts.googleapis.com. Hence, split in two registerroutes
19 | workbox.routing.registerRoute(
20 | /^https:\/\/fonts\.googleapis\.com/,
21 | new workbox.strategies.StaleWhileRevalidate({
22 | cacheName: 'google-fonts-stylesheets',
23 | })
24 | );
25 |
26 | workbox.routing.registerRoute(
27 | /^https:\/\/fonts\.gstatic\.com/,
28 | new workbox.strategies.CacheFirst({
29 | cacheName: 'google-fonts-webfonts',
30 | plugins: [
31 | new workbox.cacheableResponse.Plugin({
32 | statuses: [0, 200],
33 | }),
34 | new workbox.expiration.Plugin({
35 | maxAgeSeconds: 60 * 60 * 24 * 365,
36 | maxEntries: 30,
37 | }),
38 | ],
39 | })
40 | );
41 | }
42 |
43 | //attempted api call regex: /^http[s]?(.*)\/api\/(.*)/
44 |
45 |
46 | // This code listens for the user's confirmation to update the app.
47 | // self.addEventListener('message', (e) => {
48 | // if (!e.data) {
49 | // return;
50 | // }
51 |
52 | // switch (e.data) {
53 | // case 'skipWaiting':
54 | // self.skipWaiting();
55 | // break;
56 | // default:
57 | // // NOOP
58 | // break;
59 | // }
60 | // })
61 |
62 | // Listen to Push
63 | // self.addEventListener('push', (e) => {
64 | // let data
65 | // if (e.data) {
66 | // data = e.data.json()
67 | // }
68 |
69 | // const options = {
70 | // body: data.body,
71 | // icon: '/img/icons/android-chrome-192x192.png',
72 | // image: '/img/autumn-forest.png',
73 | // vibrate: [300, 200, 300],
74 | // badge: '/img/icons/plint-badge-96x96.png',
75 | // }
76 |
77 | // e.waitUntil(self.registration.showNotification(data.title, options))
78 | // })
--------------------------------------------------------------------------------
/2wr-app/src/api/base-api-instance.js:
--------------------------------------------------------------------------------
1 | // Using RedAxios so we can intercept fetch if necessary
2 | import axios from "redaxios";
3 | import { getAuthInstance } from "../auth";
4 | const baseApiInstance = {
5 | async getInstance(customOptions) {
6 | // Allows options to be added by specific APIs
7 | const options = { ...customOptions };
8 | options.baseURL = process.env.VUE_APP_APIROOT;
9 | const token = await getAuthInstance().getTokenSilently();
10 |
11 | // Allows headers to be set by client
12 | if (options.headers) {
13 | options.headers.Authorization = `Bearer ${token}`;
14 | } else {
15 | options.headers = {
16 | Authorization: `Bearer ${token}`
17 | };
18 | }
19 | return axios.create(options);
20 | }
21 | };
22 |
23 | export default baseApiInstance;
24 |
--------------------------------------------------------------------------------
/2wr-app/src/api/base-kit-api.js:
--------------------------------------------------------------------------------
1 | import baseApiInstance from './base-api-instance';
2 |
3 | const emergencyKitApi = {
4 | async getAll() {
5 | return (await baseApiInstance.getInstance()).get('basekits');
6 | }
7 | }
8 |
9 | export default emergencyKitApi;
--------------------------------------------------------------------------------
/2wr-app/src/api/emergency-kit-api.js:
--------------------------------------------------------------------------------
1 | import baseApiInstance from './base-api-instance';
2 |
3 | const emergencyKitApi = {
4 | async getAllByBaseKitId(baseKitId) {
5 | return (await baseApiInstance.getInstance()).get(`emergencykits/${baseKitId}`);
6 | },
7 | async getById(id) {
8 | return (await baseApiInstance.getInstance()).get(`emergencykit-by-id/${id}`);
9 | },
10 | async create(newKit) {
11 | return (await baseApiInstance.getInstance()).post('emergencykit-create', newKit);
12 | },
13 | async save(updatedKit) {
14 | return (await baseApiInstance.getInstance()).put('emergencykit-update', updatedKit);
15 | }
16 | }
17 |
18 | export default emergencyKitApi;
--------------------------------------------------------------------------------
/2wr-app/src/api/family-plans-api.js:
--------------------------------------------------------------------------------
1 | import baseApiInstance from './base-api-instance';
2 |
3 | export default {
4 | async getAll() {
5 | return (await baseApiInstance.getInstance()).get("familyplans-getall");
6 | },
7 | async upsertPlan(plan) {
8 | return (await baseApiInstance.getInstance()).post('familyplans-upsert', plan);
9 | },
10 | async deletePlan(plan) {
11 | return (await baseApiInstance.getInstance()).delete(`familyplans-delete/${plan.id}`);
12 | }
13 | }
--------------------------------------------------------------------------------
/2wr-app/src/api/hazard-hunt-api.js:
--------------------------------------------------------------------------------
1 | import baseApiInstance from './base-api-instance';
2 |
3 | export default {
4 | async getDocuments() {
5 | return (await baseApiInstance.getInstance()).get('hazardhunt-list');
6 | },
7 | async get(id) {
8 | return (await baseApiInstance.getInstance()).get(`hazardhunt-by-id/${id}`);
9 | }
10 | };
--------------------------------------------------------------------------------
/2wr-app/src/api/hazard-info-api.js:
--------------------------------------------------------------------------------
1 | import baseApiInstance from './base-api-instance';
2 |
3 | export default {
4 | async getAll() {
5 | return (await baseApiInstance.getInstance()).get('hazardinfo-list');
6 | },
7 |
8 | async get(id) {
9 | return (await baseApiInstance.getInstance()).get(`hazardinfo-by-id/${id}`);
10 | }
11 | };
--------------------------------------------------------------------------------
/2wr-app/src/api/photos-api.js:
--------------------------------------------------------------------------------
1 | import baseApiInstance from "./base-api-instance";
2 | import { getAuthInstance } from "../auth";
3 |
4 | export default {
5 | async uploadPhoto(photo) {
6 |
7 | const token = await getAuthInstance().getTokenSilently();
8 |
9 | // Can't use redaxios (bug dealing with blobs, so use fetch)
10 | return fetch(`${process.env.VUE_APP_APIROOT}photo`,{
11 | method: "POST",
12 | body: photo,
13 | headers: {
14 | "Authorization": `Bearer ${token}`,
15 | "Content-Type": photo.type
16 | }
17 | });
18 | },
19 |
20 | async getPhoto(photo) {
21 | return (await baseApiInstance.getInstance({ responseType: "blob", headers: { Accept: "image/*"}})).get(`photo/${photo}`);
22 | }
23 | };
24 |
--------------------------------------------------------------------------------
/2wr-app/src/assets/app.scss:
--------------------------------------------------------------------------------
1 | .pseudo-text-block-label {
2 | margin-left: .5rem;
3 | position: absolute;
4 | background-color: #fff;
5 | margin-top: -9px;
6 | padding: 1px;
7 | }
8 |
9 | .hidden {
10 | display: none;
11 | }
12 | .img-cover {
13 | object-fit: cover;
14 | }
15 |
16 | .cursor-pointer {
17 | cursor: pointer;
18 | }
--------------------------------------------------------------------------------
/2wr-app/src/assets/logo.svg:
--------------------------------------------------------------------------------
1 | Artboard 46
2 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/ConfirmDialog.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | {{ title }}
7 |
8 |
9 |
10 | {{ message }}
11 |
12 |
13 |
14 | {{ denyButtonText }}
15 | {{ confirmButtonText }}
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/DatePickerInput.vue:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
20 |
21 |
30 |
31 |
32 |
33 |
74 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/EditableTextBlock.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ label }}
5 |
6 | {{ theText }}
7 | {{ theText }}
8 |
9 | mdi-pencil
10 |
11 |
12 |
13 |
22 |
23 |
24 | cancel
25 | save
26 |
27 |
28 |
29 |
30 |
31 |
32 |
91 |
92 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/IconTextBlock.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ icon }}
6 | {{ icon }}
7 |
8 |
9 |
10 |
11 |
21 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/InfoBar.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mdi-arrow-left
5 | {{ title }}
6 |
7 |
8 |
9 |
10 |
25 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/SecureImg.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
30 |
--------------------------------------------------------------------------------
/2wr-app/src/components/common/globalComponents.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import EditableTextBlock from './EditableTextBlock.vue';
3 | import IconTextBlock from './IconTextBlock.vue';
4 | import InfoBar from './InfoBar.vue';
5 | import DatePickerInput from "./DatePickerInput.vue";
6 | import SecureImg from './SecureImg.vue';
7 | import ConfirmDialog from './ConfirmDialog.vue';
8 |
9 | export default function () {
10 | Vue.component("EditableTextBlock", EditableTextBlock);
11 | Vue.component("IconTextBlock", IconTextBlock);
12 | Vue.component("InfoBar", InfoBar);
13 | Vue.component("DatePickerInput", DatePickerInput);
14 | Vue.component("SecureImg", SecureImg);
15 | Vue.component("ConfirmDialog", ConfirmDialog);
16 | }
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/emergency-kits/emergency-kit-build.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mdi-arrow-left
5 | mdi-medical-bag
6 | Build your Emergency Kits
7 |
8 |
13 |
14 |
17 |
18 |
19 |
20 | After a disaster, you may be on your own for at least 2 weeks. After you fill out your family plan, this section will help you determine what you need to build your kits for you and your family, one step at a time.
21 |
22 |
23 |
28 |
29 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/address-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | {{ title }}
5 |
6 |
7 | mdi-pencil
8 |
9 |
10 | No Address: Click pencil to specify address.
13 |
17 |
18 |
19 |
20 |
21 |
22 | Edit Address
23 |
24 |
25 |
29 |
30 |
31 |
32 | Cancel
33 | Save
34 |
35 |
36 |
37 |
38 |
39 |
40 |
95 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/editors/address-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 |
18 |
26 |
34 |
35 |
43 |
44 |
45 |
46 |
87 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/editors/emergency-contact-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
16 |
17 |
23 |
24 |
31 |
38 |
45 |
49 |
53 |
59 |
60 |
61 | Cancel
62 | Save
63 |
64 |
65 |
66 |
67 |
68 |
104 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/editors/pet-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
16 |
23 |
29 |
30 |
31 |
32 |
33 |
34 | Cancel
35 | Save
36 |
37 |
38 |
39 |
40 |
41 |
97 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/editors/photo-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
11 | mdi-delete
12 |
19 | mdi-camera
20 |
21 |
28 |
29 |
30 |
31 |
58 |
59 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/editors/photos-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
13 | mdi-plus
14 |
15 | {{ title }}
16 |
17 |
22 |
23 |
24 |
25 |
26 |
27 |
34 |
35 |
36 |
37 |
69 |
70 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/editors/route-location-editor.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
11 |
12 |
18 |
19 |
20 |
21 | Cancel
22 | Save
23 |
24 |
25 |
26 |
27 |
28 |
65 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/family-plans/family-plans-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
14 | mdi-plus
15 |
16 |
17 |
18 |
19 | My Family Plan
20 |
21 | Plans Shared
22 | With Me
23 |
24 |
25 |
26 |
27 |
28 |
35 |
36 |
37 |
44 |
45 |
46 | mdi-alarm-light
47 | mdi-alarm-light-off
48 |
49 | {{ item.title }}
50 |
51 | mdi-chevron-right
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 | Shared Plans
61 |
62 |
63 |
64 |
65 |
66 |
96 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/hazards/hazard-hunt-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mdi-arrow-left
5 | mdi-shield-alert-outline
6 | Hazard Hunt
7 |
8 |
13 |
14 |
19 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
62 |
63 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/hazards/hazard-info-list.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mdi-arrow-left
5 | mdi-shield-alert-outline
6 | Hazard Information
7 |
8 |
13 |
14 |
19 |
21 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
62 |
63 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/make-a-plan/make-a-plan.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mdi-arrow-left
5 | Make A Plan
6 |
7 |
8 |
9 | Placeholder
10 |
11 |
12 | My Family Plan
13 |
14 |
15 |
16 |
17 |
18 |
19 |
26 |
27 |
--------------------------------------------------------------------------------
/2wr-app/src/components/prepare/prepare-landing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | mdi-clipboard-list-outline
5 | Prepare
6 |
7 |
8 | You are using the {{versionTag}} version of 2 Weeks Ready. This version is
9 | for testing purposes only!
10 |
11 |
12 |
13 |
14 |
20 |
21 | mdi-shield-alert-outline
22 | Learn Your Hazards
23 |
24 |
25 | Learn all about common hazards.
26 |
27 |
28 |
34 |
35 | mdi-notebook-multiple
36 | Make a Plan
37 |
38 |
39 | Make an actionable plan to share with friends and family. Know what to do in the event of a disaster.
40 |
41 |
42 |
43 |
44 |
50 |
51 | mdi-medical-bag
52 | Build a Kit
53 |
54 |
55 | Create a grab-and-go kit so you have all that you need in the event
56 | of an emergency.
57 |
58 |
59 |
60 |
61 |
67 |
68 | mdi-shield-search
69 | Hazard Hunt
70 |
71 |
72 | Observe your surroundings and identify common hazards that could
73 | mean danger in certain situations.
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
96 |
--------------------------------------------------------------------------------
/2wr-app/src/components/recent/recent-landing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Recent Events
6 |
7 |
8 |
9 |
10 |
11 |
17 |
--------------------------------------------------------------------------------
/2wr-app/src/components/settings/settings-landing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Settings
6 |
7 |
8 |
9 |
10 |
11 |
17 |
--------------------------------------------------------------------------------
/2wr-app/src/components/welcome/welcome-landing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 | Welcome to 2 weeks ready
10 |
11 | 2 Weeks Ready is a mobile application that makes
12 | emergency preparedness a simple ,
13 | easy , sharable , and
14 | time-saving experience to protect you and people you
15 | care about.
16 |
17 |
18 |
19 | You and earthquake risk
20 |
21 | The Pacific Northwest is earthquake country with the
22 | second highest risk for earthquakes in the United States!
25 | There are also a wide assortment of hazards that can impact you
26 | including tsunamis, volcanic eruptions, and wildfires to name a few.
27 |
28 |
29 |
30 | Let's get started!
31 |
32 | There's a lot to prepare for and learn about.
33 | 2 Weeks Ready can help! Are you ready to start your
34 | preparedness Journey?
35 | Let's begin by creating an account and answering some
37 | questions.
39 |
40 |
41 |
42 |
43 |
55 | mdi-chevron-right
56 |
57 |
58 |
59 |
60 |
61 |
79 |
84 |
--------------------------------------------------------------------------------
/2wr-app/src/functions/goBack.js:
--------------------------------------------------------------------------------
1 | import router from "@/router";
2 |
3 | export default function () {
4 | window.history.length > 1 ? router.go(-1) : router.push("/");
5 | }
--------------------------------------------------------------------------------
/2wr-app/src/functions/setFocusVuetify.js:
--------------------------------------------------------------------------------
1 | import {
2 | nextTick
3 | } from "@vue/composition-api";
4 |
5 | export default function setFocusVuetify(refs, name) {
6 | nextTick(() => {
7 | var inputs = refs[name].$el.getElementsByTagName("input");
8 | if (inputs && inputs.length > 0) inputs[0].focus();
9 | });
10 | }
--------------------------------------------------------------------------------
/2wr-app/src/lookups/states.js:
--------------------------------------------------------------------------------
1 | import { states } from "us";
2 |
3 | const stateList = []
4 |
5 | for (const id in states) stateList.push({ text: states[id].name, value: states[id].abbr});
6 |
7 | export default stateList;
--------------------------------------------------------------------------------
/2wr-app/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import App from './App.vue';
3 | import './register-service-worker';
4 | import vuetify from './plugins/vuetify';
5 | import router from './router';
6 | import store from './store';
7 | import { Auth0Plugin } from "./auth";
8 | import VueCompositionAPI from '@vue/composition-api';
9 | import globalComponents from "@/components/common/globalComponents";
10 | import './assets/app.scss';
11 |
12 | Vue.config.productionTip = false
13 |
14 | Vue.use(Auth0Plugin, {
15 | domain: process.env.VUE_APP_AUTH0_DOMAIN,
16 | clientId: process.env.VUE_APP_AUTH0_CLIENTID,
17 | audience: process.env.VUE_APP_AUTH0_AUDIENCE,
18 | onRedirectCallback: appState => {
19 | router.push(
20 | appState && appState.targetUrl
21 | ? appState.targetUrl
22 | : window.location.pathname
23 | );
24 | }
25 | });
26 |
27 | // Enable Composition API
28 | Vue.use(VueCompositionAPI)
29 |
30 | // Register global components
31 | globalComponents();
32 |
33 | new Vue({
34 | vuetify,
35 | router,
36 | store,
37 | render: h => h(App),
38 | methods: {
39 | isOnlineChanged(){
40 | this.$store.commit('globalStore/SET_ONLINE_STATUS', navigator.onLine);
41 | },
42 | },
43 | mounted() {
44 | this.$store.commit('globalStore/SET_ONLINE_STATUS', navigator.onLine);
45 | window.addEventListener('online', this.isOnlineChanged);
46 | window.addEventListener('offline', this.isOnlineChanged);
47 | },
48 | beforeDestroy() {
49 | window.removeEventListener('online', this.isOnlineChanged);
50 | window.removeEventListener('offline', this.isOnlineChanged);
51 | }
52 | }).$mount('#app');
53 |
--------------------------------------------------------------------------------
/2wr-app/src/models/family-plans/Address.js:
--------------------------------------------------------------------------------
1 | export default class Address {
2 | address1 = "";
3 | address2 = "";
4 | cityTown = "";
5 | stateProvince = "";
6 | postalCode = "";
7 | }
--------------------------------------------------------------------------------
/2wr-app/src/models/family-plans/Child.js:
--------------------------------------------------------------------------------
1 | import Address from "./Address";
2 |
3 | export default class Child {
4 | id = "";
5 | name = "";
6 | birthday = "";
7 | phoneNumber = "";
8 | image = "";
9 | schoolName = "";
10 | schoolAddress = new Address();
11 | schoolPhone = ""
12 | relationship = "";
13 | }
--------------------------------------------------------------------------------
/2wr-app/src/models/family-plans/EmergencyContact.js:
--------------------------------------------------------------------------------
1 | export default class EmergencyContact {
2 | id = "";
3 | fullName = "";
4 | cellPhone = "";
5 | email = "";
6 | schoolInformation = "";
7 | workInformation = "";
8 | medicalInformation = "";
9 | notifyLastLocation = false;
10 | sharePlanWith = false;
11 | }
--------------------------------------------------------------------------------
/2wr-app/src/models/family-plans/FamilyPlan.js:
--------------------------------------------------------------------------------
1 | import Address from "./Address";
2 |
3 | export default class FamilyPlan {
4 | id = "";
5 | userId = "";
6 | title = "";
7 | phoneNumber = "";
8 | address = new Address();
9 | emergencyContacts = [];
10 | routes = [];
11 | children = [];
12 | pets = [];
13 | allowAlerts = false;
14 |
15 | }
--------------------------------------------------------------------------------
/2wr-app/src/models/family-plans/Pet.js:
--------------------------------------------------------------------------------
1 | export default class Pet {
2 | id = "";
3 | name = "";
4 | type = "";
5 | description = "";
6 | image = "";
7 | microchipId = "";
8 | }
--------------------------------------------------------------------------------
/2wr-app/src/models/family-plans/RouteLocation.js:
--------------------------------------------------------------------------------
1 | import Address from "./Address";
2 |
3 | export default class RouteLocation {
4 | id = "";
5 | name = "";
6 | images = [];
7 | instructions = "";
8 | address = new Address();
9 | }
--------------------------------------------------------------------------------
/2wr-app/src/plugins/vuetify.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuetify from 'vuetify/lib';
3 | import '@mdi/font/css/materialdesignicons.css';
4 | import colors from 'vuetify/lib/util/colors';
5 | import VueRouter from 'vue-router'
6 |
7 | const themeColors = {
8 | lightOrange: "#f99b2c",
9 | darkOrange: "#c14d23",
10 | background: "#f8f1c7"
11 | }
12 |
13 | Vue.use(Vuetify);
14 | Vue.use(VueRouter);
15 |
16 | const vuetify = new Vuetify({
17 | icons: {
18 | iconfont: 'mdi'
19 | },
20 | theme: {
21 | themes: {
22 | light: {
23 | primary: themeColors.lightOrange,
24 | secondary: themeColors.darkOrange,
25 | accent: colors.cyan.base,
26 | error: colors.red.base,
27 | warning: colors.amber.base,
28 | info: colors.blueGrey.base,
29 | success: colors.green.base,
30 | background: themeColors.background
31 | }
32 | }
33 | }
34 | });
35 |
36 | export default vuetify;
37 |
--------------------------------------------------------------------------------
/2wr-app/src/register-service-worker.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable no-console */
2 |
3 | import { register } from 'register-service-worker'
4 |
5 | if (process.env.NODE_ENV === 'production') {
6 | register(`${process.env.BASE_URL}service-worker.js`, {
7 | ready () {
8 | console.log(
9 | 'App is being served from cache by a service worker.\n' +
10 | 'For more details, visit https://goo.gl/AFskqB'
11 | );
12 | },
13 | registered () {
14 | console.log('Service worker has been registered.');
15 | },
16 | cached () {
17 | console.log('Content has been cached for offline use.');
18 | },
19 | updatefound () {
20 | console.log('New content is downloading.');
21 | },
22 | updated () {
23 | console.log('New content is available; please refresh.');
24 | // setTimeout(() => {
25 | // window.location.reload(true);
26 | // }, 1000);
27 | },
28 | offline () {
29 | console.log('No internet connection found. App is running in offline mode.');
30 | },
31 | error (error) {
32 | console.error('Error during service worker registration:', error);
33 | }
34 | })
35 | }
36 |
--------------------------------------------------------------------------------
/2wr-app/src/router/familyPlanRoutes.js:
--------------------------------------------------------------------------------
1 | import FamilyPlanLanding from '../views/prepare/family-plans/landing.vue';
2 | import FamilyPlanView from '../views/prepare/family-plans/view.vue';
3 | import FamilyPlanContacts from "../views/prepare/family-plans/contacts.vue"
4 | import FamilyPlanDistantContacts from "../views/prepare/family-plans/distant-contacts.vue"
5 | import FamilyPlanRoutes from "../views/prepare/family-plans/routes.vue";
6 | import FamilyPlanChildren from '@/views/prepare/family-plans/children.vue';
7 | import FamilyPlanPets from '@/views/prepare/family-plans/pets.vue';
8 |
9 | export default [
10 | {
11 | path: '/prepare/familyplan',
12 | name: 'familyplan',
13 | component: FamilyPlanLanding,
14 | meta: {
15 | requiresAuth: true
16 | }
17 | },
18 | {
19 | path: '/prepare/familyplan/:planId',
20 | name: 'familyplan-view',
21 | component: FamilyPlanView,
22 | props: true,
23 | meta: {
24 | requiresAuth: true
25 | }
26 | },
27 | {
28 | path: '/prepare/familyplan/:planId/distantcontacts',
29 | name: "familyplan-distantcontacts",
30 | component: FamilyPlanDistantContacts,
31 | props: true,
32 | meta: {
33 | requiresAuth: true
34 | }
35 | },
36 | {
37 | path: '/prepare/familyplan/:planId/emergencycontacts',
38 | name: "familyplay-contacts",
39 | component: FamilyPlanContacts,
40 | props: true,
41 | meta: {
42 | requiresAuth: true
43 | }
44 | },
45 | {
46 | path: '/prepare/familyplan/:planId/routes',
47 | name: "familyplay-routes",
48 | component: FamilyPlanRoutes,
49 | props: true,
50 | meta: {
51 | requiresAuth: true
52 | }
53 | },
54 | {
55 | path: '/prepare/familyplan/:planId/children',
56 | name: "familyplay-children",
57 | component: FamilyPlanChildren,
58 | props: true,
59 | meta: {
60 | requiresAuth: true
61 | }
62 | },
63 | {
64 | path: '/prepare/familyplan/:planId/pets',
65 | name: "familyplay-pets",
66 | component: FamilyPlanPets,
67 | props: true,
68 | meta: {
69 | requiresAuth: true
70 | }
71 | }
72 | ];
73 |
--------------------------------------------------------------------------------
/2wr-app/src/rules/index.js:
--------------------------------------------------------------------------------
1 | export function required(msg) {
2 | if (!msg) msg = "Required.";
3 | return (v) => !!v || msg;
4 | }
5 |
6 | export function minLength(len, msg) {
7 | if (!msg) msg = "Length Required.";
8 | return (v) => v.length >= len || msg;
9 | }
10 |
11 | export function maxLength(len, msg) {
12 | if (!msg) msg = `Must be less than ${len} characters.`
13 | return (v) => v.length < len || msg;
14 | }
15 |
16 | export function phoneNumber(msg) {
17 | if (!msg) msg = "Must be a valid phone number. (e.g. (404) 555-1212, 404-555-1212)";
18 | return (v) => !v || /^(\([0-9]{3}\)\s?|[0-9]{3}-)[0-9]{3}-[0-9]{4}$/.test(v) || msg;
19 | }
20 |
21 |
22 | export function email(msg) {
23 | if (!msg) msg = "Must be a valid email.";
24 | return (v) => !v || /^[^@]+@[^@]+\.[^@]+$/.test(v) || msg;
25 | }
26 |
27 | export function zipCode(msg) {
28 | if (!msg) msg = "Must be a valid zipcode.";
29 | return (v) => !v || /^[0-9]{5}(?:-[0-9]{4})?$$/.test(v) || msg;
30 | }
31 |
--------------------------------------------------------------------------------
/2wr-app/src/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import baseKitStore from './modules/prepare/base-kits/base-kit-store';
4 | import emergencyKitStore from './modules/prepare/emergency-kits/emergency-kit-store';
5 | import hazardHuntStore from './modules/prepare/hazards/hazard-hunt-store';
6 | import hazardInfoStore from './modules/prepare/hazards/hazard-info-store';
7 | import globalStore from './modules/global/global-store';
8 | import familyPlansStore from './modules/prepare/family-plans';
9 |
10 | Vue.use(Vuex);
11 |
12 | const store = new Vuex.Store({
13 | strict: process.env.NODE_ENV !== 'production',
14 | state: {
15 | isBusy: false,
16 | error: ""
17 | },
18 | mutations: {
19 | clearBusy: (state) => state.isBusy = false,
20 | setBusy: (state) => state.isBusy = true,
21 | setError: (state, msg) => state.error = msg
22 | },
23 | // actions: {
24 |
25 | // },
26 | modules: {
27 | globalStore,
28 | baseKitStore,
29 | emergencyKitStore,
30 | hazardHuntStore,
31 | hazardInfoStore,
32 | familyPlansStore
33 | }
34 | });
35 |
36 | export default store;
37 |
38 |
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/global/global-store.js:
--------------------------------------------------------------------------------
1 | const globalStore = {
2 | namespaced: true,
3 | state: {
4 | online: navigator.onLine
5 | },
6 | mutations: {
7 | SET_ONLINE_STATUS(state, payload) {
8 | state.online = payload;
9 | }
10 | }
11 | };
12 |
13 | export default globalStore;
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/base-kits/base-kit-store.js:
--------------------------------------------------------------------------------
1 | import baseKitApi from "../../../../api/base-kit-api";
2 | import localForage from "localforage";
3 |
4 | const baseKitStore = {
5 | namespaced: true,
6 | state: {
7 | list: [],
8 | isLoading: false,
9 | loadErrorMessage: null,
10 | selectedKit: null,
11 | },
12 | mutations: {
13 | SET_LIST(state, payload) {
14 | state.list = payload;
15 | },
16 | LOAD_START(state) {
17 | state.isLoading = true;
18 | },
19 | LOAD_SUCCESS(state, payload) {
20 | state.isLoading = false;
21 | state.item = payload;
22 | },
23 | LOAD_ERROR(state, payload) {
24 | state.isLoading = false;
25 | state.loadErrorMessage = payload;
26 | }
27 | },
28 | actions: {
29 | async getBaseKitListAsync({ commit, rootState }) {
30 | if (rootState.globalStore.online) {
31 | let response = await baseKitApi.getAll();
32 | commit("SET_LIST", response.data);
33 | await localForage.setItem("getBaseKitListAsync", response.data);
34 | } else {
35 | var data = await localForage.getItem("getBaseKitListAsync");
36 | if (data) {
37 | console.log("Serving from cache");
38 | commit("SET_LIST", data);
39 | } else {
40 | console.log("Offline without data");
41 | }
42 | }
43 | },
44 | },
45 | };
46 |
47 | export default baseKitStore;
48 |
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/family-plans/getters.js:
--------------------------------------------------------------------------------
1 | export default {
2 | findFamilyPlan: (state) => (id) => {
3 | let found = state.familyPlans.find(item => item.id === id);
4 | return found;
5 | }
6 | }
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/family-plans/index.js:
--------------------------------------------------------------------------------
1 | import state from "./state";
2 | import mutations from "./mutations";
3 | import actions from "./actions";
4 | import getters from "./getters";
5 |
6 | export default {
7 | namespaced: true,
8 | state,
9 | mutations,
10 | actions,
11 | getters
12 | }
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/family-plans/mutations.js:
--------------------------------------------------------------------------------
1 | export default {
2 | setFamilyPlans: (state, plans) => (state.familyPlans = plans),
3 | setSharedPlans: (state, plans) => (state.sharedPlans = plans),
4 | addToFamilyPlans: (state, newPlan) =>
5 | state.familyPlans.splice(state.familyPlans.length, 0, newPlan),
6 | removeFromFamilyPlans: (state, plan) => {
7 | const index = state.familyPlans.indexOf(plan);
8 | if (index > -1) state.familyPlans.splice(index, 1);
9 | },
10 | replaceContact: (state, { contact, plan }) => {
11 | const index = plan.emergencyContacts.findIndex(i => i.id == contact.id);
12 | plan.emergencyContacts.splice(index, 1, contact);
13 | },
14 | addContact: (state, { contact, plan }) => {
15 | plan.emergencyContacts.splice(plan.emergencyContacts.length, 0, contact);
16 | },
17 | replaceRoute: (state, { route, plan }) => {
18 | const index = plan.routeLocations.findIndex(i => i.id == route.id);
19 | plan.routeLocations.splice(index, 1, route);
20 | },
21 | addRoute: (state, { route, plan }) => {
22 | plan.routeLocations.splice(plan.routeLocations.length, 0, route);
23 | },
24 | replaceChild: (state, { child, plan }) => {
25 | const index = plan.children.findIndex(i => i.id == child.id);
26 | plan.children.splice(index, 1, child);
27 | },
28 | addChild: (state, { child, plan }) => {
29 | plan.children.splice(plan.children.length, 0, child);
30 | },
31 | replacePet: (state, { pet, plan }) => {
32 | const index = plan.pets.findIndex(i => i.id == pet.id);
33 | plan.pets.splice(index, 1, pet);
34 | },
35 | addPet: (state, { pet, plan }) => {
36 | plan.pets.splice(plan.pets.length, 0, pet);
37 | },
38 | addPhotoToRoute: (state, { photo, route }) => {
39 | route.images.splice(route.images.length, 0, photo);
40 | },
41 | addPhotoToChild: (state, { photo, child }) => {
42 | child.image = photo;
43 | },
44 | addPhotoToPet: (state, { photo, pet }) => {
45 | pet.image = photo;
46 | }
47 | };
48 |
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/family-plans/state.js:
--------------------------------------------------------------------------------
1 | export default {
2 | familyPlans: [],
3 | sharedPlans: []
4 | };
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/hazards/hazard-hunt-store.js:
--------------------------------------------------------------------------------
1 | import api from '../../../../api/hazard-hunt-api';
2 | import localForage from 'localforage';
3 |
4 | const CACHE_KEY = 'HazardHunts';
5 | const SET_LIST = 'SET_LIST';
6 | const SET_ITEM = 'SET_ITEM';
7 |
8 | export default {
9 | namespaced: true,
10 | state: {
11 | list: [],
12 | item: null
13 | },
14 | mutations: {
15 | [SET_LIST](state, payload) {
16 | state.list = payload;
17 | },
18 | [SET_ITEM](state, payload) {
19 | state.item = payload;
20 | }
21 | },
22 | actions: {
23 | async getHazardHuntsAsync({ commit, rootState }) {
24 | if (rootState.globalStore.online) {
25 | let response = await api.getDocuments();
26 | commit(SET_LIST, response.data);
27 | await localForage.setItem(CACHE_KEY, response.data);
28 | } else {
29 | var data = await localForage.getItem(CACHE_KEY)
30 | if (data) {
31 | console.log("Serving from cache");
32 | commit(SET_LIST, data);
33 | } else {
34 | console.log("Offline without data");
35 | }
36 |
37 | }
38 | },
39 | async getHazardHuntAsync({ commit, rootState} , id) {
40 |
41 | try {
42 | commit("setBusy", null, { root: true });
43 | commit("setError", "", { root: true });
44 | const itemCacheKey = `${CACHE_KEY}/${id}`
45 | if (rootState.globalStore.online) {
46 | let response = await api.get(id);
47 | commit(SET_ITEM, response.data);
48 | await localForage.setItem(itemCacheKey, response.data);
49 | } else {
50 | var data = await localForage.getItem(itemCacheKey)
51 | if (data) {
52 | console.log("Serving from cache");
53 | commit(SET_ITEM, data);
54 | } else {
55 | console.log("Offline without data");
56 | }
57 | }
58 | } catch {
59 | commit("setError", "Could not load hazard hunt.", { root: true });
60 | } finally {
61 | commit("clearBusy", null, { root: true });
62 | }
63 | }
64 | }
65 | };
--------------------------------------------------------------------------------
/2wr-app/src/store/modules/prepare/hazards/hazard-info-store.js:
--------------------------------------------------------------------------------
1 | import api from '../../../../api/hazard-info-api';
2 | import localForage from 'localforage';
3 |
4 | const CACHE_KEY = 'HazardInfos';
5 | const SET_LIST = 'SET_LIST';
6 | const SET_ITEM = 'SET_ITEM';
7 |
8 | export default {
9 | namespaced: true,
10 | state: {
11 | list: [],
12 | item: null
13 | },
14 | mutations: {
15 | [SET_LIST](state, payload) {
16 | state.list = payload;
17 | },
18 | [SET_ITEM](state, payload) {
19 | state.item = payload;
20 | }
21 | },
22 | actions: {
23 | async getHazardInfosAsync({ commit, rootState }) {
24 |
25 | try {
26 | commit("setBusy", null, { root: true });
27 | commit("setError", "", { root: true });
28 |
29 | if (rootState.globalStore.online) {
30 | let response = await api.getAll();
31 | commit(SET_LIST, response.data);
32 | await localForage.setItem(CACHE_KEY, response.data);
33 | } else {
34 | var data = await localForage.getItem(CACHE_KEY)
35 | if (data) {
36 | console.log("Serving from cache");
37 | commit(SET_LIST, data);
38 | } else {
39 | console.log("Offline without data");
40 | }
41 | }
42 | } catch {
43 | commit("setError", "Could not load hazard information.", { root: true });
44 | } finally {
45 | commit("clearBusy", null, { root: true });
46 | }
47 | },
48 | async getHazardInfoAsync({ commit, rootState} , id) {
49 |
50 | try {
51 | commit("setBusy", null, { root: true });
52 | commit("setError", "", { root: true });
53 | const itemCacheKey = `${CACHE_KEY}/${id}`
54 | if (rootState.globalStore.online) {
55 | let response = await api.get(id);
56 | commit(SET_ITEM, response.data);
57 | await localForage.setItem(itemCacheKey, response.data);
58 | } else {
59 | var data = await localForage.getItem(itemCacheKey)
60 | if (data) {
61 | console.log("Serving from cache");
62 | commit(SET_ITEM, data);
63 | } else {
64 | console.log("Offline without data");
65 | }
66 | }
67 | } catch {
68 | commit("setError", "Could not load hazard information.", { root: true });
69 | } finally {
70 | commit("clearBusy", null, { root: true });
71 | }
72 | }
73 | }
74 | };
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/emergency-kits/emergency-kit-build.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/emergency-kits/emergency-kit-details.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/emergency-kits/emergency-kit-listing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/children.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/contacts.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/distant-contacts.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/landing.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/pets.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/routes.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
14 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/family-plans/view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/hazards/hazard-hunt-list-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/hazards/hazard-hunt-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/hazards/hazard-info-list-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/hazards/hazard-info-view.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/make-a-plan/make-a-plan.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
15 |
--------------------------------------------------------------------------------
/2wr-app/src/views/prepare/prepare.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/src/views/recent/recent.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/src/views/settings/settings.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/src/views/welcome/welcome.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/2wr-app/tests/global-setup.js:
--------------------------------------------------------------------------------
1 | // global-setup.js
2 | const { chromium, expect } = require("@playwright/test");
3 |
4 | module.exports = async () => {
5 | const browser = await chromium.launch();
6 | const page = await browser.newPage();
7 | await page.goto("http://localhost:8080/");
8 |
9 | // Save not signed-in state to 'newuser-storageState.json'.
10 | await page
11 | .context()
12 | .storageState({ path: "./tests/_storagestate/newuser-storageState.json" });
13 |
14 | await page.getByTestId("welcome-next-button").click();
15 | await expect(
16 | page.getByRole("heading", { name: "You and earthquake risk" })
17 | ).toBeVisible();
18 | await page.getByTestId("welcome-next-button").click();
19 | await expect(
20 | page.getByRole("heading", { name: "Let's get started!" })
21 | ).toBeVisible();
22 | await page.getByTestId("welcome-next-button").click();
23 |
24 | await page
25 | .getByLabel("Email address")
26 | .fill(process.env.TWO_WEEKS_READY_E2E_TEST_USERNAME);
27 | await page
28 | .getByLabel("Password")
29 | .fill(process.env.TWO_WEEKS_READY_E2E_TEST_PASSWORD);
30 |
31 | await page.getByRole('button', { name: 'Continue', exact: true }).click();
32 | await page.waitForURL("http://localhost:8080/prepare");
33 |
34 | // Save signed-in state to 'storageState.json'.
35 | await page
36 | .context()
37 | .storageState({ path: "./tests/_storagestate/storageState.json" });
38 |
39 | // TODO: Add a environment variable to allow for optional seeding of data by calling admin APIs
40 | // const token = await page.evaluate(async () =>await document.getElementById("app").__vue__.$auth.getTokenSilently());
41 | // const response = await page.request.post("http://localhost:7071/api/hazardinfo-create", {
42 | // data: {
43 | // name: "Earthquake",
44 | // beforeSafetyDetails: "Practice how to drop, cover, and hold on"
45 | // },
46 | // headers: {
47 | // 'Authorization': `Bearer ${token}`,
48 | // },
49 | // });
50 | // expect(response.ok()).toBeTruthy();
51 | await browser.close();
52 | };
53 |
--------------------------------------------------------------------------------
/2wr-app/tests/welcome.spec.js:
--------------------------------------------------------------------------------
1 | const { expect, test, chromium } = require("@playwright/test");
2 | const { injectAxe, checkA11y } = require("axe-playwright");
3 |
4 | test.use({ storageState: "./tests/_storagestate/newuser-storageState.json" });
5 |
6 | test.describe("Welcome page accessibility test", () => {
7 | let browser;
8 | let page;
9 |
10 | test.beforeAll(async () => {
11 | browser = await chromium.launch();
12 | page = await browser.newPage();
13 | await page.goto("./welcome/");
14 | await injectAxe(page);
15 | });
16 |
17 | test("Check Accessibility", async () => {
18 | await checkA11y(page, null, {
19 | axeOptions: {},
20 | detailedReport: true,
21 | detailedReportOptions: {
22 | html: true
23 | }
24 | });
25 | });
26 | });
27 |
28 | test("Welcome page loads", async ({ page }) => {
29 | await page.goto("./");
30 |
31 | await expect(page).toHaveURL(/.*welcome/);
32 | });
33 |
--------------------------------------------------------------------------------
/2wr-app/vue.config.js:
--------------------------------------------------------------------------------
1 | const Dotenv = require("dotenv-webpack");
2 |
3 | module.exports = {
4 | css: {
5 | sourceMap: true
6 | },
7 | pwa: {
8 | workboxPluginMode: "InjectManifest",
9 | workboxOptions: {
10 | swSrc: "public/service-worker.js"
11 | },
12 | manifestOptions: {
13 | name: "Two Weeks Ready",
14 | short_name: "Two Weeks Ready",
15 | description:
16 | "Support preparedness and alerting related to emergency situations.",
17 | start_url: "/index.html",
18 | background_color: "#F7F1C7",
19 | theme_color: "#D75727",
20 | icons: [
21 | {
22 | src: "./img/icons/android-chrome-192x192.png",
23 | sizes: "192x192",
24 | type: "image/png"
25 | },
26 | {
27 | src: "./img/icons/android-chrome-512x512.png",
28 | sizes: "512x512",
29 | type: "image/png"
30 | },
31 | {
32 | src: "./img/icons/android-chrome-maskable-192x192.png",
33 | sizes: "192x192",
34 | type: "image/png",
35 | purpose: "maskable"
36 | },
37 | {
38 | src: "./img/icons/android-chrome-maskable-512x512.png",
39 | sizes: "512x512",
40 | type: "image/png",
41 | purpose: "maskable"
42 | },
43 | {
44 | src: "./img/icons/apple-touch-icon-60x60.png",
45 | sizes: "60x60",
46 | type: "image/png"
47 | },
48 | {
49 | src: "./img/icons/apple-touch-icon-76x76.png",
50 | sizes: "76x76",
51 | type: "image/png"
52 | },
53 | {
54 | src: "./img/icons/apple-touch-icon-120x120.png",
55 | sizes: "120x120",
56 | type: "image/png"
57 | },
58 | {
59 | src: "./img/icons/apple-touch-icon-152x152.png",
60 | sizes: "152x152",
61 | type: "image/png"
62 | },
63 | {
64 | src: "./img/icons/apple-touch-icon-180x180.png",
65 | sizes: "180x180",
66 | type: "image/png"
67 | },
68 | {
69 | src: "./img/icons/apple-touch-icon.png",
70 | sizes: "180x180",
71 | type: "image/png"
72 | },
73 | {
74 | src: "./img/icons/favicon-16x16.png",
75 | sizes: "16x16",
76 | type: "image/png"
77 | },
78 | {
79 | src: "./img/icons/favicon-32x32.png",
80 | sizes: "32x32",
81 | type: "image/png"
82 | },
83 | {
84 | src: "./img/icons/msapplication-icon-144x144.png",
85 | sizes: "144x144",
86 | type: "image/png"
87 | },
88 | {
89 | src: "./img/icons/mstile-150x150.png",
90 | sizes: "150x150",
91 | type: "image/png"
92 | }
93 | ]
94 | }
95 | },
96 | configureWebpack: {
97 | plugins: [new Dotenv()]
98 | },
99 | transpileDependencies: ["vuetify"]
100 | };
101 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Humanitarian Toolbox
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 |
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/EmergencyKits/BaseKit.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace TwoWeeksReady.Common.EmergencyKits
5 | {
6 | public class BaseKit
7 | {
8 | [JsonProperty(PropertyName = "id")]
9 | public string Id { get; set; }
10 |
11 | [JsonProperty(PropertyName = "name")]
12 | public string Name { get; set; }
13 |
14 | [JsonProperty(PropertyName = "description")]
15 | public string Description { get; set; }
16 |
17 | [JsonProperty(PropertyName = "iconUrl")]
18 | public string IconUrl { get; set; }
19 |
20 | [JsonProperty(PropertyName = "items")]
21 | public List Items { get; set; } = new List();
22 | }
23 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/EmergencyKits/BaseKitItem.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TwoWeeksReady.Common.EmergencyKits
4 | {
5 | public class BaseKitItem
6 | {
7 | [JsonProperty(PropertyName = "id")]
8 | public string Id { get; set; }
9 |
10 | [JsonProperty(PropertyName = "name")]
11 | public string Name { get; set; }
12 |
13 | [JsonProperty(PropertyName = "description")]
14 | public string Description { get; set; }
15 |
16 | [JsonProperty(PropertyName = "quantityPerAdult")]
17 | public int QuantityPerAdult { get; set; } //per adult
18 |
19 | [JsonProperty(PropertyName = "quantityPerChild")]
20 | public int QuantityPerChild { get; set; } //per child
21 |
22 | [JsonProperty(PropertyName = "quantityPerPet")]
23 | public int QuantityPerPet { get; set; } //per pet
24 |
25 | [JsonProperty(PropertyName = "quantityUnit")]
26 | public string QuantityUnit { get; set; } //measurement unit, 14 days
27 | }
28 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/EmergencyKits/Kit.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 | using System.Collections.Generic;
3 |
4 | namespace TwoWeeksReady.Common.EmergencyKits
5 | {
6 | public class Kit
7 | {
8 | [JsonProperty(PropertyName = "id")]
9 | public string Id { get; set; }
10 |
11 | [JsonProperty(PropertyName = "baseKitId")]
12 | public string BaseKitId { get; set; }
13 |
14 | [JsonProperty(PropertyName = "userId")]
15 | public string UserId { get; set; }
16 |
17 | [JsonProperty(PropertyName = "name")]
18 | public string Name { get; set; }
19 |
20 | [JsonProperty(PropertyName = "kitItems")]
21 | public List Items { get; set; } = new List();
22 | }
23 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/EmergencyKits/KitItem.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TwoWeeksReady.Common.EmergencyKits
4 | {
5 | public class KitItem
6 | {
7 | [JsonProperty(PropertyName = "id")]
8 | public string Id { get; set; }
9 |
10 | [JsonProperty(PropertyName = "baseKitItemId")]
11 | public string BaseKitItemId { get; set; }
12 |
13 | [JsonProperty(PropertyName = "userId")]
14 | public string UserId { get; set; }
15 |
16 | [JsonProperty(PropertyName = "name")]
17 | public string Name { get; set; }
18 |
19 | [JsonProperty(PropertyName = "description")]
20 | public string Description { get; set; }
21 |
22 | [JsonProperty(PropertyName = "quantity")]
23 | public int Quantity { get; set; }
24 |
25 | [JsonProperty(PropertyName = "quantityUnit")]
26 | public string QuantityUnit { get; set; }
27 |
28 | [JsonProperty(PropertyName = "photo")]
29 | public string Photo { get; set; } // URL ?
30 |
31 | [JsonProperty(PropertyName = "isAvailableInKit")]
32 | public bool IsAvailableInKit { get; set; } //checklist for user to see if they have everything they need.
33 | }
34 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyMembers/FamilyMember.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TwoWeeksReady.Common.FamilyMembers
4 | {
5 | public class FamilyMember
6 | {
7 | public Guid Id { get; set; }
8 | public string Name { get; set; }
9 | }
10 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/Address.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TwoWeeksReady.Common.FamilyPlans
4 | {
5 | public class Address
6 | {
7 | [JsonProperty(PropertyName = "address1")]
8 | public string Address1 { get; set; }
9 | [JsonProperty(PropertyName = "address2")]
10 | public string Address2 { get; set; }
11 | [JsonProperty(PropertyName = "cityTown")]
12 | public string CityTown { get; set; }
13 | [JsonProperty(PropertyName = "stateProvince")]
14 | public string StateProvince { get; set; }
15 | [JsonProperty(PropertyName = "postalCode")]
16 | public string PostalCode { get; set; }
17 | }
18 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/Child.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Newtonsoft.Json;
3 |
4 | namespace TwoWeeksReady.Common.FamilyPlans
5 | {
6 | public class Child
7 | {
8 | [JsonProperty("id")]
9 | public string Id { get; set; }
10 | [JsonProperty("name")]
11 | public string Name { get; set; }
12 | [JsonProperty("birthday")]
13 | public DateTime Birthday { get; set; }
14 | [JsonProperty("phoneNumber")]
15 | public string PhoneNumber { get; set; }
16 | [JsonProperty("image")]
17 | public string Image { get; set; }
18 | [JsonProperty("schoolName")]
19 | public string SchoolName { get; set; }
20 | [JsonProperty("schoolAddress")]
21 | public Address SchoolAddress { get; set; }
22 | [JsonProperty("schoolPhone")]
23 | public string SchoolPhone { get; set; }
24 | [JsonProperty("relationship")]
25 | public string Relationship { get; set; }
26 |
27 | }
28 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/Contact.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TwoWeeksReady.Common.FamilyPlans
4 | {
5 | public class Contact
6 | {
7 | [JsonProperty("id")]
8 | public string Id { get; set; }
9 | [JsonProperty("fullName")]
10 | public string FullName { get; set; }
11 | [JsonProperty("cellPhone")]
12 | public string CellPhone { get; set; }
13 | [JsonProperty("email")]
14 | public string Email { get; set; }
15 | [JsonProperty("schoolInformation")]
16 | public string SchoolInformation { get; set; }
17 | [JsonProperty("workInformation")]
18 | public string WorkInformation { get; set; }
19 | [JsonProperty("medicalInformation")]
20 | public string MedicalInformation { get; set; }
21 | [JsonProperty("notifyLastLocation")]
22 | public bool NotifyLastLocation { get; set; }
23 | [JsonProperty("sharePlanWith")]
24 | public bool SharePlanWith { get; set; }
25 | [JsonProperty("distant")]
26 | public bool Distant { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/FamilyPlan.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using Newtonsoft.Json;
4 |
5 | namespace TwoWeeksReady.Common.FamilyPlans
6 | {
7 | public class FamilyPlan
8 | {
9 | [JsonProperty("id")]
10 | public string Id { get; set; }
11 |
12 | [JsonProperty("userid")]
13 | public string UserId { get; set; }
14 |
15 | [JsonProperty("title")]
16 | public string Title { get; set; }
17 |
18 | [JsonProperty("address")]
19 | public Address Address { get; set; }
20 |
21 | [JsonProperty("phoneNumber")]
22 | public string PhoneNumber { get; set; }
23 |
24 | [JsonProperty("allowAlerts")]
25 | public bool AllowAlerts { get; set; }
26 |
27 | [JsonProperty("emergencyContacts")]
28 | public List EmergencyContacts { get; set; } = new List();
29 |
30 | [JsonProperty("routeLocations")]
31 | public List RouteLocations { get; set; } = new List();
32 |
33 | [JsonProperty("children")]
34 | public List Children { get; set; } = new List();
35 |
36 | [JsonProperty("pets")]
37 | public List Pets { get; set; } = new List();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/Pet.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TwoWeeksReady.Common.FamilyPlans
4 | {
5 | public class Pet
6 | {
7 | [JsonProperty("id")]
8 | public string Id { get; set; }
9 | [JsonProperty("name")]
10 | public string Name { get; set; }
11 | [JsonProperty("type")]
12 | public string Type { get; set; }
13 | [JsonProperty("description")]
14 | public string Description { get; set; }
15 | [JsonProperty("image")]
16 | public string Image { get; set; }
17 | [JsonProperty("microchipId")]
18 | public string MicrochipId { get; set; }
19 |
20 | }
21 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/RouteLocation.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using Newtonsoft.Json;
3 |
4 | namespace TwoWeeksReady.Common.FamilyPlans
5 | {
6 | public class RouteLocation
7 | {
8 | [JsonProperty("id")]
9 | public string Id { get; set; }
10 | [JsonProperty("name")]
11 | public string Name { get; set; }
12 | [JsonProperty("images")]
13 | public List Images { get; set; }
14 | [JsonProperty("instructions")]
15 | public string Instructions { get; set; }
16 | [JsonProperty("address")]
17 | public Address Address { get; set; }
18 | }
19 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/FamilyPlans/WalkThroughStep.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace TwoWeeksReady.Common.FamilyPlans
4 | {
5 | public class WalkThroughStep
6 | {
7 | public List RouteLocations { get; set; }
8 | public string Instructions { get; set; }
9 | }
10 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/Hazards/HazardBaseInfo.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | public class HazardBaseInfo
4 | {
5 | [JsonProperty(PropertyName = "id")]
6 | public string Id { get; set; }
7 |
8 | [JsonProperty(PropertyName = "name")]
9 | public string Name { get; set; }
10 |
11 | [JsonProperty(PropertyName = "description")]
12 | public string Description { get; set; }
13 |
14 | [JsonProperty(PropertyName = "iconUrl")]
15 | public string IconUrl {get; set;}
16 |
17 | ///
18 | /// URL of image or video describing the hazard
19 | ///
20 | [JsonProperty(PropertyName = "mediaUrl")]
21 | public string MediaUrl { get; set; }
22 |
23 | [JsonProperty(PropertyName = "externalLinks")]
24 | public string[] ExternalLinks { get; set; }
25 |
26 | ///
27 | /// HTML used in the Before section of the UI for this Hazard
28 | ///
29 | [JsonProperty(PropertyName = "beforeSafetyDetails")]
30 | public string BeforeSafetyDetails {get; set;}
31 |
32 | ///
33 | /// HTML used in the During section of the UI for this Hazard
34 | ///
35 | [JsonProperty(PropertyName = "duringSafetyDetails")]
36 | public string DuringSafetyDetails {get; set;}
37 |
38 | ///
39 | /// HTML used in the After section of the UI for this Hazard
40 | ///
41 | [JsonProperty(PropertyName = "afterSafetyDetails")]
42 | public string AfterSafetyDetails {get; set;}
43 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/Hazards/HazardHunt.cs:
--------------------------------------------------------------------------------
1 | public class HazardHunt : HazardBaseInfo
2 | {
3 |
4 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/Hazards/HazardInfo.cs:
--------------------------------------------------------------------------------
1 | public class HazardInfo : HazardBaseInfo
2 | {
3 |
4 | }
--------------------------------------------------------------------------------
/TwoWeeksReady.Common/TwoWeeksReady.Common.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | netstandard2.0
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/App.razor:
--------------------------------------------------------------------------------
1 | @using TwoWeeksReady.Admin.Security
2 | @inject TokenProvider Service
3 |
4 |
5 |
6 |
7 |
8 |
9 | Determining session state, please wait...
10 |
11 |
12 | Sorry
13 | You're not authorized to reach this page. You need to log in and must be an admin.
14 |
15 |
16 |
17 |
18 |
19 | Sorry, there's nothing at this address.
20 |
21 |
22 |
23 |
24 |
25 | @code {
26 |
27 | [Parameter]
28 | public TokenProvider InitialState { get; set; }
29 |
30 | protected override void OnInitialized()
31 | {
32 | Service.AccessToken = InitialState.AccessToken;
33 | base.OnInitialized();
34 | }
35 | }
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Components/KitItemDisplay.razor:
--------------------------------------------------------------------------------
1 | @inject IRepository repository
2 |
3 |
51 |
52 | @code {
53 | [Parameter]
54 | public BaseKitItem Item { get; set; }
55 | }
56 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Data/ClientImage.cs:
--------------------------------------------------------------------------------
1 | namespace TwoWeeksReady.Admin.Data
2 | {
3 | public class ClientImage
4 | {
5 | public string RelativePath { get; set; }
6 | public string AbsolutePath { get; set; }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Data/ClientImageService.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Extensions.Configuration;
2 | using System.IO;
3 | using System.Linq;
4 |
5 | namespace TwoWeeksReady.Admin.Data
6 | {
7 | ///
8 | /// Provides a list of image that are available within the 2wr client app.
9 | /// These are use in Hazard Info and in Base Kits
10 | ///
11 | public class ClientImageService
12 | {
13 | public readonly IConfiguration _configuration;
14 | public readonly ClientImage[] clientImages;
15 |
16 | public ClientImageService(IConfiguration configuration)
17 | {
18 | _configuration = configuration;
19 |
20 | var imagePaths = File.ReadAllLines("./client-images.txt");
21 | var appUrl = _configuration["2wrAppUrl"].TrimEnd('/');
22 |
23 | clientImages = imagePaths
24 | .Select(i => i.Replace("\\", "/"))
25 | .Select(i => new ClientImage
26 | {
27 | AbsolutePath = ToAbsolutePath(i),
28 | RelativePath = i
29 | }).ToArray();
30 | }
31 |
32 |
33 | public ClientImage[] Images => clientImages;
34 |
35 | public string ToAbsolutePath(string relativeImagePath)
36 | {
37 | var appUrl = _configuration["2wrAppUrl"].TrimEnd('/');
38 | if (string.IsNullOrEmpty(relativeImagePath))
39 | {
40 | return appUrl;
41 | }
42 |
43 | return $"{appUrl}/{relativeImagePath.TrimStart('/')}";
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Data/IRepository.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using System.Threading.Tasks;
3 | using TwoWeeksReady.Common.EmergencyKits;
4 |
5 | namespace TwoWeeksReady.Admin.Data
6 | {
7 | public interface IRepository
8 | {
9 | Task> GetAllBaseKits();
10 | Task GetBaseKitById(string id);
11 | Task CreateBaseKit(BaseKit kit);
12 | Task SaveBaseKit(BaseKit kit);
13 | Task DeleteBaseKit(string id);
14 |
15 | Task> GetAllHazardHunts();
16 | Task GetHazardHuntById(string id);
17 | Task CreateHazardHunt(HazardHunt hazardHunt);
18 | Task SaveHazardHunt(HazardHunt hazardHunt);
19 | Task DeleteHazardHunt(string id);
20 |
21 | Task> GetAllHazardInfos();
22 | Task GetHazardInfoById(string id);
23 | Task CreateHazardInfo(HazardInfo hazardInfo);
24 | Task SaveHazardInfo(HazardInfo hazardInfo);
25 | Task DeleteHazardInfo(string id);
26 | }
27 |
28 | }
29 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Error.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model TwoWeeksReady.Admin.Pages.ErrorModel
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Error
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
Error.
19 |
An error occurred while processing your request.
20 |
21 | @if (Model.ShowRequestId)
22 | {
23 |
24 | Request ID: @Model.RequestId
25 |
26 | }
27 |
28 |
Development Mode
29 |
30 | Swapping to the Development environment displays detailed information about the error that occurred.
31 |
32 |
33 | The Development environment shouldn't be enabled for deployed applications.
34 | It can result in displaying sensitive information from exceptions to end users.
35 | For local debugging, enable the Development environment by setting the ASPNETCORE_ENVIRONMENT environment variable to Development
36 | and restarting the app.
37 |
38 |
39 |
40 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Error.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Threading.Tasks;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.AspNetCore.Mvc.RazorPages;
8 | using Microsoft.Extensions.Logging;
9 |
10 | namespace TwoWeeksReady.Admin.Pages
11 | {
12 | [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
13 | [IgnoreAntiforgeryToken]
14 | public class ErrorModel : PageModel
15 | {
16 | public string RequestId { get; set; }
17 |
18 | public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
19 |
20 | private readonly ILogger _logger;
21 |
22 | public ErrorModel(ILogger logger)
23 | {
24 | _logger = logger;
25 | }
26 |
27 | public void OnGet()
28 | {
29 | RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/HazardHunts/List.razor:
--------------------------------------------------------------------------------
1 | @page "/HazardHunts/"
2 | @attribute [Authorize(Roles = "admin")]
3 |
4 | @inject IRepository Repository
5 | Administer Hazard Hunt for Two Weeks Ready
6 |
7 | @if (_HazardHunts != null && _HazardHunts.Any())
8 | {
9 |
10 |
11 |
12 |
13 | Name
14 |
15 |
16 |
17 | @foreach (var hazard in _HazardHunts)
18 | {
19 |
20 |
21 |
22 |
23 | @hazard.Name
24 |
25 |
26 |
27 | }
28 |
29 |
30 |
31 |
32 | }
33 | else
34 | {
35 | No Hazards defined.
36 | Add New Hazard
37 | }
38 |
39 | @code {
40 | private IEnumerable _HazardHunts { get; set; }
41 |
42 | protected override async Task OnInitializedAsync()
43 | {
44 |
45 | try {
46 | _HazardHunts = await Repository.GetAllHazardHunts();
47 | } catch (NotImplementedException) {
48 | // Application is still growing, let's not throw an error yet
49 | _HazardHunts = Enumerable.Empty();
50 | }
51 |
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/HazardInfos/List.razor:
--------------------------------------------------------------------------------
1 | @page "/HazardInfos/"
2 | @attribute [Authorize(Roles = "admin")]
3 | @inject IRepository Repository
4 | Administer Hazard Info
5 |
6 | @if (_HazardInfos != null && _HazardInfos.Any())
7 | {
8 |
9 |
10 |
11 |
12 | Name
13 |
14 |
15 |
16 | @foreach (var hazard in _HazardInfos)
17 | {
18 |
19 |
20 |
21 |
22 | @hazard.Name
23 |
24 |
25 |
26 | }
27 |
28 |
29 |
30 | Add New Hazard
31 |
32 | }
33 | else if (_HazardInfos == null)
34 | {
35 | Loading....
36 | }
37 | else
38 | {
39 | No hazard infos defined
40 | Add New Hazard
41 | }
42 |
43 | @code {
44 | private IEnumerable _HazardInfos { get; set; }
45 |
46 | protected override async Task OnInitializedAsync()
47 | {
48 |
49 | _HazardInfos = await Repository.GetAllHazardInfos();
50 |
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Index.razor:
--------------------------------------------------------------------------------
1 | @page "/"
2 |
3 | Homepage
4 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Kits/Details.razor:
--------------------------------------------------------------------------------
1 | @page "/Kits/{id}"
2 | @page "/Kits/new"
3 | @attribute [Authorize(Roles = "admin")]
4 | @inject IRepository repository
5 | @inject IJSRuntime JS
6 | @inject ClientImageService clientImages
7 |
8 | @if (Kit != null)
9 | {
10 | Kit Details :: @Kit.Name
11 |
12 |
13 |
14 |
15 | Kit Name
16 |
17 |
18 |
19 | Description
20 |
22 |
23 |
35 |
36 |
37 |
38 |
39 |
40 | @foreach (var item in Kit.Items)
41 | {
42 |
43 | }
44 |
45 |
46 | Add Item
47 | Save Kit
48 | }
49 | else
50 | {
51 | Loading...
52 | }
53 |
54 |
55 | @code {
56 |
57 | [Parameter]
58 | public string Id { get; set; }
59 |
60 | public BaseKit Kit { get; set; }
61 |
62 | public void AddKitItem()
63 | {
64 | if (Kit != null && Kit.Items != null)
65 | {
66 | Kit.Items.Add(new BaseKitItem { Id = Guid.NewGuid().ToString() });
67 | }
68 | }
69 |
70 | public async Task SaveBaseKit()
71 | {
72 | if (Kit != null)
73 | {
74 | if (string.IsNullOrEmpty(Kit.Id))
75 | {
76 | Kit = await repository.CreateBaseKit(Kit);
77 | }
78 | else
79 | {
80 | Kit = await repository.SaveBaseKit(Kit);
81 | }
82 |
83 | await JS.InvokeVoidAsync("alert", new object[] { "Base Kit Saved" });
84 | }
85 | }
86 |
87 | protected override async Task OnInitializedAsync()
88 | {
89 | if (string.IsNullOrEmpty(Id))
90 | {
91 | Kit = new BaseKit();
92 | }
93 | else
94 | {
95 | Kit = await repository.GetBaseKitById(Id);
96 | }
97 | await base.OnInitializedAsync();
98 | }
99 |
100 | }
101 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Kits/List.razor:
--------------------------------------------------------------------------------
1 | @page "/Kits/"
2 | @attribute [Authorize (Roles = "admin")]
3 | @inject IRepository Repository
4 | @inject ClientImageService clientImages
5 |
6 | Administer Base Kits
7 |
8 | @if (BaseKits != null && BaseKits.Any())
9 | {
10 |
11 |
12 |
13 |
14 | Name
15 | Line Item Count
16 |
17 |
18 |
19 | @foreach (var kit in BaseKits)
20 | {
21 |
22 |
23 |
24 | @kit.Name
25 |
26 |
27 | @kit.Items.Count()
28 |
29 | }
30 |
31 |
32 |
33 | Add New Kit
34 | }
35 | else if (BaseKits == null)
36 | {
37 | Loading....
38 | }
39 | else
40 | {
41 | No base kits defined.
42 | Add New Kit
43 | }
44 |
45 | @code {
46 |
47 | public IEnumerable BaseKits { get; set; }
48 |
49 | protected override async Task OnInitializedAsync()
50 | {
51 |
52 | try {
53 | BaseKits = await Repository.GetAllBaseKits();
54 | } catch (NotImplementedException)
55 | {
56 | // do nothing for now... site is still growing
57 | BaseKits = Enumerable.Empty();
58 | }
59 |
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Login.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model TwoWeeksReady.Admin.Page.LoginModel
3 | @{
4 | }
5 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Login.cshtml.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Microsoft.AspNetCore.Authentication;
3 | using Microsoft.AspNetCore.Mvc.RazorPages;
4 |
5 | namespace TwoWeeksReady.Admin.Page
6 | {
7 | public class LoginModel : PageModel
8 | {
9 | public async Task OnGet(string redirectUri)
10 | {
11 | await HttpContext.ChallengeAsync("Auth0", new AuthenticationProperties
12 | {
13 | RedirectUri = redirectUri
14 | });
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Logout.cshtml:
--------------------------------------------------------------------------------
1 | @page
2 | @model TwoWeeksReady.Admin.Page.LogoutModel
3 | @{
4 | }
5 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/Logout.cshtml.cs:
--------------------------------------------------------------------------------
1 |
2 | using System.Threading.Tasks;
3 | using Microsoft.AspNetCore.Authentication;
4 | using Microsoft.AspNetCore.Authentication.Cookies;
5 | using Microsoft.AspNetCore.Mvc.RazorPages;
6 |
7 | namespace TwoWeeksReady.Admin.Page
8 | {
9 | public class LogoutModel : PageModel
10 | {
11 | public async Task OnGet()
12 | {
13 | await HttpContext.SignOutAsync("Auth0", new AuthenticationProperties { RedirectUri = "/"});
14 | await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Pages/_Host.cshtml:
--------------------------------------------------------------------------------
1 | @page "/"
2 | @namespace TwoWeeksReady.Admin.Pages
3 | @using TwoWeeksReady.Admin.Security
4 | @using Microsoft.AspNetCore.Authentication
5 | @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
6 | @{
7 | Layout = null;
8 | }
9 |
10 |
11 |
12 |
13 |
14 |
15 | Two Weeks Ready :: Application Administration
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | @{
25 | var token = new TokenProvider
26 | {
27 | AccessToken = await HttpContext.GetTokenAsync("access_token")
28 | };
29 | }
30 |
31 |
32 |
33 |
34 |
35 |
36 | An error has occurred. This application may no longer respond until reloaded.
37 |
38 |
39 | An unhandled exception has occurred. See browser dev tools for details.
40 |
41 |
Reload
42 |
🗙
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Program.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components;
2 | using Microsoft.AspNetCore.Components.Web;
3 | using TwoWeeksReady.Admin;
4 |
5 | var builder = WebApplication.CreateBuilder(args);
6 |
7 | // Configure the container.
8 | builder.Services.ConfigureServices(builder.Configuration);
9 |
10 | var app = builder.Build();
11 |
12 | // Configure the HTTP request pipeline.
13 | if (!app.Environment.IsDevelopment())
14 | {
15 | app.UseExceptionHandler("/Error");
16 | // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
17 | app.UseHsts();
18 | }
19 |
20 | app.UseHttpsRedirection();
21 | app.UseStaticFiles();
22 |
23 | app.UseRouting();
24 |
25 | app.UseCookiePolicy();
26 | app.UseAuthentication();
27 | app.UseAuthorization();
28 |
29 | app.MapBlazorHub();
30 | app.MapFallbackToPage("/_Host");
31 |
32 | app.Run();
33 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "iisSettings": {
3 | "windowsAuthentication": false,
4 | "anonymousAuthentication": true,
5 | "iisExpress": {
6 | "applicationUrl": "http://localhost:54838",
7 | "sslPort": 44379
8 | }
9 | },
10 | "profiles": {
11 | "IIS Express": {
12 | "commandName": "IISExpress",
13 | "launchBrowser": true,
14 | "environmentVariables": {
15 | "ASPNETCORE_ENVIRONMENT": "Development"
16 | }
17 | },
18 | "adminweb": {
19 | "commandName": "Project",
20 | "dotnetRunMessages": "true",
21 | "launchBrowser": true,
22 | "applicationUrl": "https://localhost:5001;http://localhost:5000",
23 | "environmentVariables": {
24 | "ASPNETCORE_ENVIRONMENT": "Development"
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Security/TokenProvider.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.AspNetCore.Components.Authorization;
2 | using System.Linq;
3 | using System.Threading.Tasks;
4 |
5 | namespace TwoWeeksReady.Admin.Security
6 | {
7 | public class TokenProvider
8 | {
9 | public string AccessToken { get; set; }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Shared/AccessControl.razor:
--------------------------------------------------------------------------------
1 |
2 |
3 | Logout
4 |
5 |
6 | Log in
7 |
8 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Shared/MainLayout.razor:
--------------------------------------------------------------------------------
1 | @inherits LayoutComponentBase
2 |
3 |
4 |
7 |
8 |
9 |
13 |
14 |
15 | @Body
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Shared/MainLayout.razor.css:
--------------------------------------------------------------------------------
1 | .page {
2 | position: relative;
3 | display: flex;
4 | flex-direction: column;
5 | }
6 |
7 | .main {
8 | flex: 1;
9 | }
10 |
11 | .sidebar {
12 | background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
13 | }
14 |
15 | .top-row {
16 | background-color: #f7f7f7;
17 | border-bottom: 1px solid #d6d5d5;
18 | justify-content: flex-end;
19 | height: 3.5rem;
20 | display: flex;
21 | align-items: center;
22 | }
23 |
24 | .top-row ::deep a, .top-row .btn-link {
25 | white-space: nowrap;
26 | margin-left: 1.5rem;
27 | }
28 |
29 | .top-row a:first-child {
30 | overflow: hidden;
31 | text-overflow: ellipsis;
32 | }
33 |
34 | @media (max-width: 640.98px) {
35 | .top-row:not(.auth) {
36 | display: none;
37 | }
38 |
39 | .top-row.auth {
40 | justify-content: space-between;
41 | }
42 |
43 | .top-row a, .top-row .btn-link {
44 | margin-left: 0;
45 | }
46 | }
47 |
48 | @media (min-width: 641px) {
49 | .page {
50 | flex-direction: row;
51 | }
52 |
53 | .sidebar {
54 | width: 250px;
55 | height: 100vh;
56 | position: sticky;
57 | top: 0;
58 | }
59 |
60 | .top-row {
61 | position: sticky;
62 | top: 0;
63 | z-index: 1;
64 | }
65 |
66 | .main > div {
67 | padding-left: 2rem !important;
68 | padding-right: 1.5rem !important;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Shared/NavMenu.razor:
--------------------------------------------------------------------------------
1 |
7 |
8 |
32 |
33 | @code {
34 | private bool collapseNavMenu = true;
35 |
36 | private string NavMenuCssClass => collapseNavMenu ? "collapse" : null;
37 |
38 | private void ToggleNavMenu()
39 | {
40 | collapseNavMenu = !collapseNavMenu;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/Shared/NavMenu.razor.css:
--------------------------------------------------------------------------------
1 | .navbar-toggler {
2 | background-color: rgba(255, 255, 255, 0.1);
3 | }
4 |
5 | .top-row {
6 | height: 3.5rem;
7 | background-color: rgba(0,0,0,0.4);
8 | }
9 |
10 | .navbar-brand {
11 | font-size: 1.1rem;
12 | }
13 |
14 | .oi {
15 | width: 2rem;
16 | font-size: 1.1rem;
17 | vertical-align: text-top;
18 | top: -2px;
19 | }
20 |
21 | .nav-item {
22 | font-size: 0.9rem;
23 | padding-bottom: 0.5rem;
24 | }
25 |
26 | .nav-item:first-of-type {
27 | padding-top: 1rem;
28 | }
29 |
30 | .nav-item:last-of-type {
31 | padding-bottom: 1rem;
32 | }
33 |
34 | .nav-item ::deep a {
35 | color: #d7d7d7;
36 | border-radius: 4px;
37 | height: 3rem;
38 | display: flex;
39 | align-items: center;
40 | line-height: 3rem;
41 | }
42 |
43 | .nav-item ::deep a.active {
44 | background-color: rgba(255,255,255,0.25);
45 | color: white;
46 | }
47 |
48 | .nav-item ::deep a:hover {
49 | background-color: rgba(255,255,255,0.1);
50 | color: white;
51 | }
52 |
53 | @media (min-width: 641px) {
54 | .navbar-toggler {
55 | display: none;
56 | }
57 |
58 | .collapse {
59 | /* Never collapse the sidebar for wide screens */
60 | display: block;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/TwoWeeksReady.Admin.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0
5 | 4c82d094-3afe-4274-922b-9c0d8bdda7c5
6 | enable
7 |
8 |
9 |
10 |
11 | Always
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 | %(ClientImages.Identity)
37 | $([MSBuild]::Add($(ClientImage.IndexOf(`2wr-app`)), 14))
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/_Imports.razor:
--------------------------------------------------------------------------------
1 | @using System.Net.Http
2 | @using Microsoft.AspNetCore.Authorization
3 | @using Microsoft.AspNetCore.Components.Authorization
4 | @using Microsoft.AspNetCore.Components.Forms
5 | @using Microsoft.AspNetCore.Components.Routing
6 | @using Microsoft.AspNetCore.Components.Web
7 | @using Microsoft.AspNetCore.Components.Web.Virtualization
8 | @using Microsoft.JSInterop
9 | @using TwoWeeksReady.Admin
10 | @using TwoWeeksReady.Admin.Data
11 | @using TwoWeeksReady.Admin.Shared
12 | @using TwoWeeksReady.Common
13 | @using TwoWeeksReady.Common.EmergencyKits
14 | @using TwoWeeksReady.Admin.Components
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/appsettings.Development.json:
--------------------------------------------------------------------------------
1 | {
2 | "DetailedErrors": true,
3 | "Logging": {
4 | "LogLevel": {
5 | "Default": "Information",
6 | "Microsoft": "Warning",
7 | "Microsoft.Hosting.Lifetime": "Information"
8 | }
9 | },
10 | "AllowedHosts": "*"
11 | }
12 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/appsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "Logging": {
3 | "LogLevel": {
4 | "Default": "Information",
5 | "Microsoft": "Warning",
6 | "Microsoft.Hosting.Lifetime": "Information"
7 | }
8 | },
9 | "AllowedHosts": "*",
10 | "TinyMCEApiKey": "your-api-key",
11 | "ApiUrl": "http://localhost:7071/api/",
12 | "2wrAppUrl": "http://localhost:8080/",
13 | "Auth0": {
14 | "Domain": "YOUR_AUTH0_DOMAIN",
15 | "ClientId": "YOUR_CLIENT_ID",
16 | "ClientSecret": "YOUR_CLIENT_SECRET"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/ICON-LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Waybury
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
13 | all 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
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.eot
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.otf
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/css/open-iconic/font/fonts/open-iconic.woff
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/css/site.css:
--------------------------------------------------------------------------------
1 | @import url('open-iconic/font/css/open-iconic-bootstrap.min.css');
2 |
3 | html, body {
4 | font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
5 | }
6 |
7 | a, .btn-link {
8 | color: #0366d6;
9 | }
10 |
11 | .btn-primary {
12 | color: #fff;
13 | background-color: #1b6ec2;
14 | border-color: #1861ac;
15 | }
16 |
17 | .content {
18 | padding-top: 1.1rem;
19 | }
20 |
21 | .valid.modified:not([type=checkbox]) {
22 | outline: 1px solid #26b050;
23 | }
24 |
25 | .invalid {
26 | outline: 1px solid red;
27 | }
28 |
29 | .validation-message {
30 | color: red;
31 | }
32 |
33 | #blazor-error-ui {
34 | background: lightyellow;
35 | bottom: 0;
36 | box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
37 | display: none;
38 | left: 0;
39 | padding: 0.6rem 1.25rem 0.7rem 1.25rem;
40 | position: fixed;
41 | width: 100%;
42 | z-index: 1000;
43 | }
44 |
45 | #blazor-error-ui .dismiss {
46 | cursor: pointer;
47 | position: absolute;
48 | right: 0.75rem;
49 | top: 0.5rem;
50 | }
51 |
52 |
53 | /**
54 | Required Material Design Configuration
55 | */
56 |
57 | .mdi::before {
58 | font-size: 24px;
59 | line-height: 14px;
60 | }
61 |
62 | .btn .mdi::before {
63 | position: relative;
64 | top: 4px;
65 | }
66 |
67 | .btn-xs .mdi::before {
68 | font-size: 18px;
69 | top: 3px;
70 | }
71 |
72 | .btn-sm .mdi::before {
73 | font-size: 18px;
74 | top: 3px;
75 | }
76 |
77 | .dropdown-menu .mdi {
78 | width: 18px;
79 | }
80 |
81 | .dropdown-menu .mdi::before {
82 | position: relative;
83 | top: 4px;
84 | left: -8px;
85 | }
86 |
87 | .nav .mdi::before {
88 | position: relative;
89 | top: 4px;
90 | }
91 |
92 | .navbar .navbar-toggle .mdi::before {
93 | position: relative;
94 | top: 4px;
95 | color: #FFF;
96 | }
97 |
98 | .breadcrumb .mdi::before {
99 | position: relative;
100 | top: 4px;
101 | }
102 |
103 | .breadcrumb a:hover {
104 | text-decoration: none;
105 | }
106 |
107 | .breadcrumb a:hover span {
108 | text-decoration: underline;
109 | }
110 |
111 | .alert .mdi::before {
112 | position: relative;
113 | top: 4px;
114 | margin-right: 2px;
115 | }
116 |
117 | .input-group-addon .mdi::before {
118 | position: relative;
119 | top: 3px;
120 | }
121 |
122 | .navbar-brand .mdi::before {
123 | position: relative;
124 | top: 2px;
125 | margin-right: 2px;
126 | }
127 |
128 | .list-group-item .mdi::before {
129 | position: relative;
130 | top: 3px;
131 | left: -3px
132 | }
133 | /** End Required Material Design Configuration */
--------------------------------------------------------------------------------
/admin/TwoWeeksReady.Admin/wwwroot/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/admin/TwoWeeksReady.Admin/wwwroot/favicon.ico
--------------------------------------------------------------------------------
/api/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-dotnettools.csharp"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/api/.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 | }
--------------------------------------------------------------------------------
/api/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": "TwoWeeksReady/bin/Release/netcoreapp3.1/publish",
3 | "azureFunctions.projectLanguage": "C#",
4 | "azureFunctions.projectRuntime": "~3",
5 | "debug.internalConsoleOptions": "neverOpen",
6 | "azureFunctions.preDeployTask": "publish"
7 | }
--------------------------------------------------------------------------------
/api/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "clean",
6 | "command": "dotnet",
7 | "args": [
8 | "clean",
9 | "/property:GenerateFullPaths=true",
10 | "/consoleloggerparameters:NoSummary"
11 | ],
12 | "type": "process",
13 | "problemMatcher": "$msCompile",
14 | "options": {
15 | "cwd": "${workspaceFolder}/TwoWeeksReady"
16 | }
17 | },
18 | {
19 | "label": "build",
20 | "command": "dotnet",
21 | "args": [
22 | "build",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "type": "process",
27 | "dependsOn": "clean",
28 | "group": {
29 | "kind": "build",
30 | "isDefault": true
31 | },
32 | "problemMatcher": "$msCompile",
33 | "options": {
34 | "cwd": "${workspaceFolder}/TwoWeeksReady"
35 | }
36 | },
37 | {
38 | "label": "clean release",
39 | "command": "dotnet",
40 | "args": [
41 | "clean",
42 | "--configuration",
43 | "Release",
44 | "/property:GenerateFullPaths=true",
45 | "/consoleloggerparameters:NoSummary"
46 | ],
47 | "type": "process",
48 | "problemMatcher": "$msCompile",
49 | "options": {
50 | "cwd": "${workspaceFolder}/TwoWeeksReady"
51 | }
52 | },
53 | {
54 | "label": "publish",
55 | "command": "dotnet",
56 | "args": [
57 | "publish",
58 | "--configuration",
59 | "Release",
60 | "/property:GenerateFullPaths=true",
61 | "/consoleloggerparameters:NoSummary"
62 | ],
63 | "type": "process",
64 | "dependsOn": "clean release",
65 | "problemMatcher": "$msCompile",
66 | "options": {
67 | "cwd": "${workspaceFolder}/TwoWeeksReady"
68 | }
69 | },
70 | {
71 | "type": "func",
72 | "dependsOn": "build",
73 | "options": {
74 | "cwd": "${workspaceFolder}/TwoWeeksReady/bin/Debug/net6.0"
75 | },
76 | "command": "host start",
77 | "isBackground": true,
78 | "problemMatcher": "$func-dotnet-watch"
79 | }
80 | ]
81 | }
--------------------------------------------------------------------------------
/api/TwoWeeksReady/.vscode/extensions.json:
--------------------------------------------------------------------------------
1 | {
2 | "recommendations": [
3 | "ms-azuretools.vscode-azurefunctions",
4 | "ms-dotnettools.csharp"
5 | ]
6 | }
7 |
--------------------------------------------------------------------------------
/api/TwoWeeksReady/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "Attach to .NET Functions",
9 | "type": "coreclr",
10 | "request": "attach",
11 | "processId": "${command:azureFunctions.pickProcess}"
12 | }
13 | ]
14 | }
--------------------------------------------------------------------------------
/api/TwoWeeksReady/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "azureFunctions.deploySubpath": "bin/Release/netcoreapp3.1/publish",
3 | "azureFunctions.projectLanguage": "C#",
4 | "azureFunctions.projectRuntime": "~3",
5 | "debug.internalConsoleOptions": "neverOpen",
6 | "azureFunctions.preDeployTask": "publish"
7 | }
--------------------------------------------------------------------------------
/api/TwoWeeksReady/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "clean",
6 | "command": "dotnet",
7 | "args": [
8 | "clean",
9 | "/property:GenerateFullPaths=true",
10 | "/consoleloggerparameters:NoSummary"
11 | ],
12 | "type": "process",
13 | "problemMatcher": "$msCompile"
14 | },
15 | {
16 | "label": "build",
17 | "command": "dotnet",
18 | "args": [
19 | "build",
20 | "/property:GenerateFullPaths=true",
21 | "/consoleloggerparameters:NoSummary"
22 | ],
23 | "type": "process",
24 | "dependsOn": "clean",
25 | "group": {
26 | "kind": "build",
27 | "isDefault": true
28 | },
29 | "problemMatcher": "$msCompile"
30 | },
31 | {
32 | "label": "clean release",
33 | "command": "dotnet",
34 | "args": [
35 | "clean",
36 | "--configuration",
37 | "Release",
38 | "/property:GenerateFullPaths=true",
39 | "/consoleloggerparameters:NoSummary"
40 | ],
41 | "type": "process",
42 | "problemMatcher": "$msCompile"
43 | },
44 | {
45 | "label": "publish",
46 | "command": "dotnet",
47 | "args": [
48 | "publish",
49 | "--configuration",
50 | "Release",
51 | "/property:GenerateFullPaths=true",
52 | "/consoleloggerparameters:NoSummary"
53 | ],
54 | "type": "process",
55 | "dependsOn": "clean release",
56 | "problemMatcher": "$msCompile"
57 | },
58 | {
59 | "type": "func",
60 | "dependsOn": "build",
61 | "options": {
62 | "cwd": "${workspaceFolder}/bin/Debug/netcoreapp3.1"
63 | },
64 | "command": "host start",
65 | "isBackground": true,
66 | "problemMatcher": "$func-watch"
67 | }
68 | ]
69 | }
--------------------------------------------------------------------------------
/api/TwoWeeksReady/Authorization/AuthorizationExtensions.cs:
--------------------------------------------------------------------------------
1 | using AzureFunctions.OidcAuthentication;
2 | using System.Linq;
3 |
4 | namespace TwoWeeksReady.Authorization
5 | {
6 | public static class AuthorizationExtensions
7 | {
8 | public static bool IsInRole(this ApiAuthenticationResult authenticationResult, string roleName)
9 | {
10 | var roles = authenticationResult.User.FindAll("https://schemas.2wradmin.com/role");
11 | return roles.Any(r => r.Value == roleName);
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/api/TwoWeeksReady/Authorization/Roles.cs:
--------------------------------------------------------------------------------
1 | namespace TwoWeeksReady.Authorization
2 | {
3 | public static class Roles
4 | {
5 | public static string Admin = "admin";
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/api/TwoWeeksReady/Common/BaseFunction.cs:
--------------------------------------------------------------------------------
1 | using System.Net.Http;
2 | using System.Security.Claims;
3 | using System.Threading.Tasks;
4 | using AzureFunctions.OidcAuthentication;
5 | using Microsoft.AspNetCore.Http;
6 | using Microsoft.Azure.Documents.Client;
7 | using Microsoft.Extensions.Logging;
8 |
9 | namespace TwoWeeksReady.Common
10 | {
11 | public abstract class BaseFunction
12 | {
13 | protected const string DefaultDatabaseName = "2wr";
14 | protected const string DefaultDbConnectionName = "CosmosDbConnection";
15 |
16 | protected BaseFunction(IApiAuthentication apiAuthentication)
17 | {
18 | ApiAuthentication = apiAuthentication;
19 | }
20 |
21 | protected IApiAuthentication ApiAuthentication
22 | {
23 | get;
24 | private set;
25 | }
26 | protected ClaimsPrincipal Principal
27 | {
28 | get;
29 | private set;
30 | }
31 |
32 | protected async Task Authorized(HttpRequest req, ILogger log)
33 | {
34 | var authorizationResult = await ApiAuthentication.AuthenticateAsync(req.Headers);
35 | if (authorizationResult.Failed)
36 | {
37 | log.LogWarning(authorizationResult.FailureReason);
38 | return false;
39 | }
40 |
41 | Principal = authorizationResult.User;
42 | return true;
43 | }
44 |
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/api/TwoWeeksReady/EmergencyKits/CreateKitFromBaseRequest.cs:
--------------------------------------------------------------------------------
1 | using Newtonsoft.Json;
2 |
3 | namespace TwoWeeksReady.EmergencyKits
4 | {
5 | public class CreateKitFromBaseRequest
6 | {
7 | [JsonProperty(PropertyName = "baseKitId")]
8 | public string BaseKitId {get; set;}
9 |
10 | [JsonProperty(PropertyName="name")]
11 | public string Name {get;set;}
12 |
13 | [JsonProperty(PropertyName = "count")]
14 | public int Count {get;set;}
15 | }
16 | }
--------------------------------------------------------------------------------
/api/TwoWeeksReady/FamilyMembers/FamilyMembersApi.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.AspNetCore.Http;
6 | using Microsoft.AspNetCore.Mvc;
7 | using Microsoft.Azure.Documents.Client;
8 | using Microsoft.Azure.Documents.Linq;
9 | using Microsoft.Azure.WebJobs;
10 | using Microsoft.Azure.WebJobs.Extensions.Http;
11 | using Microsoft.Azure.WebJobs.Host;
12 | using Microsoft.Extensions.Logging;
13 | using TwoWeeksReady.Common.FamilyMembers;
14 |
15 | namespace TwoWeeksReady.FamilyMembers
16 | {
17 | public class FamilyMembersApi
18 | {
19 |
20 | [FunctionName("familymembers")]
21 | public async Task GetList(
22 | [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)]
23 | HttpRequest req,
24 | [CosmosDB( databaseName: "2wr", collectionName: "familymembers", ConnectionStringSetting = "CosmosDBConnection")]
25 | DocumentClient client,
26 | ILogger log)
27 | {
28 | log.LogInformation($"Getting list of family members");
29 |
30 | Uri collectionUri = UriFactory.CreateDocumentCollectionUri("2wr", "familymembers");
31 |
32 | var query = client.CreateDocumentQuery(collectionUri).AsDocumentQuery();
33 | var familyMembers = new List();
34 | while (query.HasMoreResults)
35 | {
36 | var result = await query.ExecuteNextAsync();
37 | familyMembers.AddRange(result);
38 |
39 | }
40 |
41 | return new OkObjectResult(familyMembers);
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/api/TwoWeeksReady/Startup.cs:
--------------------------------------------------------------------------------
1 | using Microsoft.Azure.Functions.Extensions.DependencyInjection;
2 | using Microsoft.Extensions.DependencyInjection;
3 | using AzureFunctions.OidcAuthentication;
4 |
5 | [assembly: FunctionsStartup(typeof(TwoWeeksReady.Startup))]
6 |
7 | namespace TwoWeeksReady
8 | {
9 | public class Startup : FunctionsStartup
10 | {
11 | public override void Configure(IFunctionsHostBuilder builder)
12 | {
13 | builder.Services.AddOidcApiAuthorization();
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/api/TwoWeeksReady/TwoWeeksReady.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 | net6.0
4 | v4
5 | <_FunctionsSkipCleanOutput>true
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 | PreserveNewest
26 |
27 |
28 | PreserveNewest
29 | Never
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/api/TwoWeeksReady/host.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0",
3 | "logging": {
4 | "applicationInsights": {
5 | "samplingExcludedTypes": "Request",
6 | "samplingSettings": {
7 | "isEnabled": true
8 | }
9 | }
10 | }
11 | }
--------------------------------------------------------------------------------
/api/api.code-workspace:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": "."
5 | },
6 | {
7 | "path": "..\\TwoWeeksReady.Common"
8 | }
9 | ],
10 | "settings": {
11 | "debug.internalConsoleOptions": "neverOpen"
12 | }
13 | }
--------------------------------------------------------------------------------
/api/api.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.31205.134
5 | MinimumVisualStudioVersion = 15.0.26124.0
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwoWeeksReady", "TwoWeeksReady\TwoWeeksReady.csproj", "{917B6C53-4118-4DC9-A04A-448AC3F35452}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TwoWeeksReady.Common", "..\TwoWeeksReady.Common\TwoWeeksReady.Common.csproj", "{ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}"
9 | EndProject
10 | Global
11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
12 | Debug|Any CPU = Debug|Any CPU
13 | Debug|x64 = Debug|x64
14 | Debug|x86 = Debug|x86
15 | Release|Any CPU = Release|Any CPU
16 | Release|x64 = Release|x64
17 | Release|x86 = Release|x86
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x64.ActiveCfg = Debug|Any CPU
23 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x64.Build.0 = Debug|Any CPU
24 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x86.ActiveCfg = Debug|Any CPU
25 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Debug|x86.Build.0 = Debug|Any CPU
26 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x64.ActiveCfg = Release|Any CPU
29 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x64.Build.0 = Release|Any CPU
30 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x86.ActiveCfg = Release|Any CPU
31 | {917B6C53-4118-4DC9-A04A-448AC3F35452}.Release|x86.Build.0 = Release|Any CPU
32 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x64.ActiveCfg = Debug|Any CPU
35 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x64.Build.0 = Debug|Any CPU
36 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x86.ActiveCfg = Debug|Any CPU
37 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Debug|x86.Build.0 = Debug|Any CPU
38 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x64.ActiveCfg = Release|Any CPU
41 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x64.Build.0 = Release|Any CPU
42 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x86.ActiveCfg = Release|Any CPU
43 | {ABE959FE-25C1-4E9D-ADD2-E7D78AEEE89C}.Release|x86.Build.0 = Release|Any CPU
44 | EndGlobalSection
45 | GlobalSection(SolutionProperties) = preSolution
46 | HideSolutionNode = FALSE
47 | EndGlobalSection
48 | GlobalSection(ExtensibilityGlobals) = postSolution
49 | SolutionGuid = {D66B7A36-58A8-47DB-A7B5-23FDA5880877}
50 | EndGlobalSection
51 | EndGlobal
52 |
--------------------------------------------------------------------------------
/assets/icons/app/2 Weeks Ready Icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-128.png
--------------------------------------------------------------------------------
/assets/icons/app/2 Weeks Ready Icon-16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-16.png
--------------------------------------------------------------------------------
/assets/icons/app/2 Weeks Ready Icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-256.png
--------------------------------------------------------------------------------
/assets/icons/app/2 Weeks Ready Icon-32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-32.png
--------------------------------------------------------------------------------
/assets/icons/app/2 Weeks Ready Icon-512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-512.png
--------------------------------------------------------------------------------
/assets/icons/app/2 Weeks Ready Icon-64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/app/2 Weeks Ready Icon-64.png
--------------------------------------------------------------------------------
/assets/icons/kits/2WR Kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/2WR Kit.png
--------------------------------------------------------------------------------
/assets/icons/kits/Child Kit128-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit128-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Child Kit16-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit16-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Child Kit256-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit256-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Child Kit32-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit32-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Child Kit512-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit512-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Child Kit64-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Child Kit64-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Miscellaneous Icons V3.ai:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Miscellaneous Icons V3.ai
--------------------------------------------------------------------------------
/assets/icons/kits/Pet Kit128-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit128-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Pet Kit16-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit16-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Pet Kit256-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit256-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Pet Kit32-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit32-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Pet Kit512-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit512-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Pet Kit64-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Pet Kit64-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Vehicle Kit128-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit128-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Vehicle Kit16-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit16-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Vehicle Kit256-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit256-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Vehicle Kit32-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit32-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Vehicle Kit512-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit512-.png
--------------------------------------------------------------------------------
/assets/icons/kits/Vehicle Kit64-.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/icons/kits/Vehicle Kit64-.png
--------------------------------------------------------------------------------
/assets/images/210909_2WR_EMAIL GRAPHIC.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/210909_2WR_EMAIL GRAPHIC.png
--------------------------------------------------------------------------------
/assets/images/Build A Kit/Child Kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Child Kit.png
--------------------------------------------------------------------------------
/assets/images/Build A Kit/Home Kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Home Kit.png
--------------------------------------------------------------------------------
/assets/images/Build A Kit/Pet Kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Pet Kit.png
--------------------------------------------------------------------------------
/assets/images/Build A Kit/Vehicle Kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Vehicle Kit.png
--------------------------------------------------------------------------------
/assets/images/Build A Kit/Work Kit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Build A Kit/Work Kit.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Earthquake.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Earthquake.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Flood.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Flood.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Landslide.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Landslide.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Power Outage.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Power Outage.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Public Health Emergency.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Public Health Emergency.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Radiological.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Radiological.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Severe Weather.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Severe Weather.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Tsunami.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Tsunami.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Volcano.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Volcano.png
--------------------------------------------------------------------------------
/assets/images/Hazard Information/Wildfire.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/Hazard Information/Wildfire.png
--------------------------------------------------------------------------------
/assets/images/codetour_api.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/codetour_api.png
--------------------------------------------------------------------------------
/assets/images/codetour_ui.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/codetour_ui.png
--------------------------------------------------------------------------------
/assets/images/forestfire_resized.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/forestfire_resized.jpg
--------------------------------------------------------------------------------
/assets/images/seismograph_resized.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/seismograph_resized.jpg
--------------------------------------------------------------------------------
/assets/images/twoweeksready.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/images/twoweeksready.png
--------------------------------------------------------------------------------
/assets/models/EmergencyKits.drawio:
--------------------------------------------------------------------------------
1 | 7Vxbd9o4EP41nLP7kB5fMJDHQC5Nm+6mTdPu2ZceYcugIluuLELor9+RLNsYOQkk3JL1OSTg0cXSfN9IM2NByx1E9xccJeNPLMC05VjBfcs9bTmO7bR78CYl80zStTqZYMRJoCuVghvyG2uhpaVTEuC0UlEwRgVJqkKfxTH2RUWGOGezarWQ0epdEzTChuDGR9SUfieBGGfSntMt5e8xGY3zO9ud46wkQnllPZN0jAI2WxC5Zy13wBkT2afofoCpVF6ul++X8+/0atK5+PA5/YVu+x+//vXtKOvsfJ0mxRQ4jsWzu/49Cc/ff2v//Ce5Pv88sy5Ohh+OdBPrDtGp1lcfpfjHRyL0nMU8V2Q6IxFFMVz1QxaLG10CaugjSkYxfPZhfJiD4A5zQQCDE10gWAJSf0xocIXmbCpnkQrkT/Kr/phx8hu6RRSKbBBAMReaTk6nUuNGtgSxBVKOU6hznavGLkRXKBW6js8oRUlKhmrAskqE+IjEfSYEi/KO2DQOcKCvCqzVheBsUrBHtg8JpQNGGVeqcQOEe6Ff1Fwo6fg9PAyhZEUINdRSf/h+gcAa0gvMIiz4HKrc5+aYtdDWabf19azkut3RsnGF51qItH2Niq6Lu30Be0TxCLRW3M5xn3k/p1O9HaLAlBgJ3Jd6TxeZCx8WZlqKFJ/X4LZtclsS+zIwqA26Fgs0pjgUD5I4TZBP4tGVqnPaLiVf9GSliEHbkCoCjUkQ4FgRTCCBMg5KViWMxEJpw+vDC3Q2sN55LQ8GNIBru7yGl6zOxYDFwDBEFIUwEHyGJclryPWosT9NrnkVtHXBXeRSBdV1IXQMCP9CEX5z+D2y9oxFRPXHbaHsObtD+ao/Op//8DpeNwjjbz//HV3bfx95BsqX4A00KG8U5W5vz7bcMVBuvIzX4mUcV3d9z17Vy+g8y8uwl7wMt3e4Xka3jtb/Xx+jszK1DsXH6BkA3qaYv0EEN7r/rI3z3r2MduNLbh/lXXoZtSibXka2TzYwbxJm22rvGWfbNOcmaNg8zu4zHa+N7c62W+tfCRw1ocNGQ4dce+cLLWOmtLmtqMLNd4t1w4oi67leWOG2VwgrujsPK2rXt/qwAmj/Bh3TFVevYik4yNiifpcyc9BNcLENpPceXeRLVxNebBXnvccXxwbMpzj1OUkEabzPTaO9/zDDTA6d3SeEz09h82/Q3jDauww26hdx83nj5ymKBRHzBuwNg+3t2zdzTBc7B/s2rnky1QD+MsB7e3fRzFTC9ZgJ1iC94ajL2reT5phIX6Ynd4hQqfDLuO7BcwP6y0B3d+iq1Y/ZXM/zs4xNuvDVnDRwvWpOcPUDjcfPygl63is60GhGI/0fTVqwuzLHDuXIgW1mEZpk0eZx3mVSsP74qpkUbLJFW4N77yccHTPb3wQYWwB6p2nBeqQfThRdYz4A9TQBxqZB33t28GHMm3zRFvDeZYKw3sjNs2QGyDgOTuSXFOGKJQqRJyKtqlahuTxvoctwMMJ5GIrpkM3OSkFfCaAgJ9DaMVjKptzHj8xX6xbi1BFeBUs53EeR1DhLwi2GWG09II4pEuRusY9Ho7drye3Wg19Fc/Lsfd5FNmHdquSC0ZF7/ERHmUae7uho+XzJUj8sDFNc6WJTkWFNLjtHveSqyiMsrBVPrExDnU3oUzTEtI/8yUiRd+lwkMqdZGkN21l9QciNS3/tVw+rVXzZdvWMwdEL6ZSzcmdYmVH8JxSbD5gegotnS9+rxWsz1p8fkNoievUPEUz0XvOmsO81fCn75i0n8VZew5ePEi53dFBreD2zzKTQ4azhj9rCm17D60MBM7FzWGv4lvF63Wt4TZ6m5XSoemwDRZ2R/CSfHUGdswjDwhH7cvLqsWFWD+5bVs2FSS645vgoREMO0ApY1h1rQiAoA9d6jIR6kz0D7P4U9Ce/nGJNU6wqMIkjtE5YIstkPQR/MZ5llXjW2Tt4u82uZkRNOMVU/nqKY4UcCJS1oiSVEhbCv2E2HT0QFMtRkThQIyyGFE+joepUltyRYIpoWTvBIpX3lYqR1zKBCe1IKkPL2knpofkcL89kIjUJ5bAD5i2JwFGqbl2IyjHD/2gqfzOGziEoLir8Kg7nWMO5IrZKvFhpgn0SEjXMP1RJgnmqBqwGpkXizwU4kxLN+kBeB7228VgsN0rz4LwO4kHglVdfZcR/KpcQtz8bw7RvQC5vNeMoeTDMX3QQ1tviV7fqztLWZyZcvF5NAG471sOW/7KMi5lyMQ31WRY6mKZC2Yk2iACHJFZ8UdxA2tok379mxJYkJhmFwoL4mpvanFRPOY+Bi1T1J1tHKAZbygxFMRAGjLleHIa5QYVhvR1l3aOKRbxrqLtI3V6Vum1ni9yFy/JHn7I9qfzpLPfsPw==
--------------------------------------------------------------------------------
/assets/models/EmergencyKits.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/models/EmergencyKits.png
--------------------------------------------------------------------------------
/assets/models/HazardHuntHazardInformation.drawio:
--------------------------------------------------------------------------------
1 | 7Vnbdto4FP0aHunCNubyGCCBtEyHhjSZ6UuXsGVbQZZcWQ6Qr++RLF+IaUoy6WQurMUy0taxztHZW0ISLWccb6cCJdFv3Me0ZXf8bcuZtGzbGthD+FLIziAdp5sjoSC+wSpgSR5wYWjQjPg43TOUnFNJkn3Q44xhT+5hSAi+2TcLON33mqAQN4Clh2gTvSW+jHJ0YPcrfIZJGBWerZ4ZcYwKYzOSNEI+39Qg57zljAXnMi/F2zGmKntFXm4vd7d0vu5N339Kv6HPow/XH2/aeWcXz3mlHILATL6464d1cDG76d79kSwuPm0607PV+3a7l3d9j2hm8jVDD0j4lyzgLedshFL8lahyngG5K9KabkhMEYPaKOBMLk0LJGWEKAkZlD2IFgsA7rGQBBg5Mw2SJ4B6EaH+HO14psaUSuSti9oo4oI8QLeIQpMFADQLacRl9/YslupNgDuACpyCzaJIlFVCc5RKY+NxSlGSkpUOWJnESISEjbiUPC464hnzsW9qJfO6IgVfl1pS7weE0jGnXOjUOD7Cg8ArLWstPW+AVwG0HEmoIV7lD29rcjYETzGPsRQ7MDGtjmO0amar7Zr6ppK+1TNYVJN9YYfMbAvLrktvVzA7EQsha6U765E7Z3CkO7u37w5RUApDEo9U3tO6jqFQG2kFaXU/Q+lWvyF1re7Lk7r/Leoe7qutVNbP1GYNX6Ru133kr/sPVvegoe5LvyFryLOsSZjiQP5QwGmCPMLCubaZdCvkygxUQRzeDagWT0R8HzMtLokkyvWnFJVwwqTOhDuCD+Rr3HnntlwIaAx1q6rDR5kLOeYM1IWIlg8GcW+wEvgBYT091X+urN0+Y89lti6kPUqfzd+wwd9HFOP/HINPrDyRjKkp/jKeXfuNeS72kjWeJzj1BEkk4exE9+vS3R+8Nd1Wg+5FxGVzw3Ei+i8RbXW6b8203ZzYRMCmgtyfVvHXZtt54UbsJWzPR+HF7qvbc/t+wG7uvoQL6/d2k+zzrd7j0Tlh6xPfr8y3+zduzw7z3VzHW3aP6sMcNPVCVVLHSbBRB0oRo/z3PLcBn5VZASYFsMTiHqd52PDQl1yQb9MDVAQ8BUZ+mzOq0gJNyiqBw586hPr6Sk09IuU/S7F4B9/XEVH96UfeR3618zjEsXLK/Hr7LAMG7U7M/YzqyGSEFOBlQpGrgxD4WwYLnM4cYErIyhFGMoO4VACTPMzc94oDc/UuQUU67yus5woXehwpBv3ASUm7IKwclBmytstDznSyV3nOPYrSNM+hHglhERZEhRwIOPXqXuKiR4/76p22hnV6Nmh3KMQIqbXbRIBWhBK5K3KN7znVrZq0ImzVALmQRGegJD+puD+8MphZZDWO1YznlxC1M7iBzKoAgFvVrtUSMlG7TGe0iYjES8CVq41AyQ/Xjfrkbk7i1zm7Dx6dpZsruDs4dHS3nzi6Hzulg7v5bGrZ/e7Zh8/bxfDLn9fdq3ZzRufy19o3N5+nu6FfdDfU0M2xkjv65tPq/w9uPqFa/f2Qm1f/4jjn3wE=
--------------------------------------------------------------------------------
/assets/models/HazardHuntHazardInformation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/models/HazardHuntHazardInformation.png
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 1.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 1.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 2.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 2.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 3.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 3.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 4.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 4.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 5.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 5.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 6.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 6.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 7.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 7.PNG
--------------------------------------------------------------------------------
/assets/wiki/Family plan page 8.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/Family plan page 8.PNG
--------------------------------------------------------------------------------
/assets/wiki/HazardHuntDetails.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/HazardHuntDetails.png
--------------------------------------------------------------------------------
/assets/wiki/HazardHuntEntry.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/HazardHuntEntry.png
--------------------------------------------------------------------------------
/assets/wiki/HazardHuntListing.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HTBox/TwoWeeksReady/204cf15b3f538713652a0414ccba835188dddd1a/assets/wiki/HazardHuntListing.png
--------------------------------------------------------------------------------
/az/create-admin-app-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | RESOURCE_GROUP='2wr-resources'
5 | ENV_PREFIX='2wrdev'
6 | LOCATION='centralus'
7 |
8 | while getopts :r:e: opt; do
9 | case ${opt} in
10 | r) RESOURCE_GROUP=${OPTARG};;
11 | e) ENV_PREFIX=${OPTARG};;
12 | l) LOCATION=${OPTARG};;
13 | esac
14 | done
15 |
16 | az configure -d group=$RESOURCE_GROUP
17 | az configure -d location=$LOCATION
18 | az group create -n $RESOURCE_GROUP
19 |
20 | echo "Create Web apps"
21 | APPSERVICEPLAN_NAME=${ENV_PREFIX}admin_asp
22 | WEBAPP_NAME=${ENV_PREFIX}admin
23 | az appservice plan create --sku B1 --name $APPSERVICEPLAN_NAME
24 | az webapp create --plan $APPSERVICEPLAN_NAME --name $WEBAPP_NAME --runtime "DOTNET|5.0"
25 |
26 |
--------------------------------------------------------------------------------
/az/create-backend-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | RESOURCE_GROUP='2wr-resources'
5 | ENV_PREFIX='2wrdev'
6 | LOCATION='centralus'
7 |
8 | while getopts :r:e: opt; do
9 | case ${opt} in
10 | r) RESOURCE_GROUP=${OPTARG};;
11 | e) ENV_PREFIX=${OPTARG};;
12 | l) LOCATION=${OPTARG};;
13 | esac
14 | done
15 |
16 | az configure -d group=$RESOURCE_GROUP
17 | az configure -d location=$LOCATION
18 | az group create -n $RESOURCE_GROUP
19 |
20 |
21 | STORAGE_ACCOUNT=${ENV_PREFIX}fnstorage
22 | echo "Creating Storage Account ${STORAGE_ACCOUNT}"
23 | az storage account create -n $STORAGE_ACCOUNT
24 |
25 | echo "Create app insights"
26 | az extension add -n application-insights
27 | APP_INSIGHTS=${ENV_PREFIX}ai
28 | az monitor app-insights component create --app $APP_INSIGHTS
29 |
30 | echo "Create function apps"
31 | az functionapp create --consumption-plan-location $LOCATION --name $ENV_PREFIX --os-type Windows --runtime dotnet --storage-account $STORAGE_ACCOUNT --app-insights $APP_INSIGHTS --functions-version 3
32 | CDN_PROFILE_NAME=${ENV_PREFIX}
33 | ALLOWED_ORIGINS="https://${CDN_PROFILE_NAME}.azureedge.net http://localhost:8080"
34 | az functionapp cors remove -n $ENV_PREFIX --allowed-origins $ALLOWED_ORIGINS
35 | az functionapp cors add -n $ENV_PREFIX --allowed-origins $ALLOWED_ORIGINS
36 |
37 | echo "Create Cosmos DB"
38 | az cosmosdb create -n $ENV_PREFIX --enable-free-tier true
39 | az cosmosdb sql database create -a $ENV_PREFIX -n 2wr --throughput 400
40 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n basekits --partition-key-path "/id"
41 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n familymembers --partition-key-path "/id"
42 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n familyplans --partition-key-path "/userid"
43 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n emergencykits --partition-key-path "/userId"
44 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n hazardhunts --partition-key-path "/id"
45 | az cosmosdb sql container create -a $ENV_PREFIX -d 2wr -n hazardinformation --partition-key-path "/id"
46 |
47 | echo "Configure function apps"
48 | CONNECTION_STRING=$(az cosmosdb keys list --type connection-strings -n $ENV_PREFIX --query connectionStrings[0].connectionString --out tsv )
49 | az webapp config connection-string set -n $ENV_PREFIX --setting CosmosDBConnection="$CONNECTION_STRING" -t "Custom"
--------------------------------------------------------------------------------
/az/create-frontend-resources.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | RESOURCE_GROUP='2wr-resources'
5 | ENV_PREFIX='2wrdev'
6 | LOCATION='centralus'
7 |
8 | while getopts :r:e: opt; do
9 | case ${opt} in
10 | r) RESOURCE_GROUP=${OPTARG};;
11 | e) ENV_PREFIX=${OPTARG};;
12 | l) LOCATION=${OPTARG};;
13 | esac
14 | done
15 |
16 | echo "Creating Resource Group $RESOURCE_GROUP in $LOCATION"
17 |
18 | az configure -d group=$RESOURCE_GROUP
19 | az configure -d location=$LOCATION
20 | az group create -n $RESOURCE_GROUP
21 |
22 | STORAGE_ACCOUNT=${ENV_PREFIX}webstorage
23 | echo "Creating static site Storage Account ${STORAGE_ACCOUNT}"
24 | az storage account create -n $STORAGE_ACCOUNT
25 | az storage blob service-properties update --account-name $STORAGE_ACCOUNT --static-website --404-document 404.html --index-document index.html
26 | STORAGE_WEB_ENDPOINT=$(az storage account show -n $STORAGE_ACCOUNT --query primaryEndpoints.web -o tsv | awk -F "/" '{ print $3 }')
27 |
28 | echo "Storage endpoint for static site hosting: $STORAGE_WEB_ENDPOINT"
29 |
30 | CDN_PROFILE_NAME=${ENV_PREFIX}
31 | echo "Creating CDN Profile $CDN_PROFILE_NAME"
32 | az cdn profile create -n $CDN_PROFILE_NAME --sku Standard_Microsoft
33 | az cdn endpoint create -n $CDN_PROFILE_NAME --profile-name $CDN_PROFILE_NAME --origin $STORAGE_WEB_ENDPOINT --origin-host-header $STORAGE_WEB_ENDPOINT --enable-compression
34 | az cdn endpoint rule add -n $CDN_PROFILE_NAME --profile-name $CDN_PROFILE_NAME --rule-name enforcehttps --order 1 --action-name "UrlRedirect" --redirect-type Found --redirect-protocol HTTPS --match-variable RequestScheme --operator Equal --match-value HTTP
35 | az cdn endpoint rule add -n $CDN_PROFILE_NAME --profile-name $CDN_PROFILE_NAME --rule-name sparewrite --order 2 --action-name "UrlRewrite" --source-pattern '/' --destination /index.html --preserve-unmatched-path false --match-variable UrlFileExtension --operator LessThan --match-value 1
36 |
37 |
--------------------------------------------------------------------------------
/az/deploy-admin-app.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | RESOURCE_GROUP='2wr-resources'
5 | ENV_PREFIX='2wrdev'
6 |
7 | while getopts :r:e:z: opt; do
8 | case ${opt} in
9 | r) RESOURCE_GROUP=${OPTARG};;
10 | e) ENV_PREFIX=${OPTARG};;
11 | z) ZIP_PACKAGE=${OPTARG};;
12 | esac
13 | done
14 |
15 | az configure -d group=$RESOURCE_GROUP
16 |
17 | echo "Deploying admin app"
18 | WEBAPP_NAME=${ENV_PREFIX}admin
19 | az webapp deployment source config-zip -n $WEBAPP_NAME --src $ZIP_PACKAGE
--------------------------------------------------------------------------------
/az/deploy-backend.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | RESOURCE_GROUP='2wr-resources'
5 | ENV_PREFIX='2wrdev'
6 |
7 | while getopts :r:e:z: opt; do
8 | case ${opt} in
9 | r) RESOURCE_GROUP=${OPTARG};;
10 | e) ENV_PREFIX=${OPTARG};;
11 | z) ZIP_PACKAGE=${OPTARG};;
12 | esac
13 | done
14 |
15 | az configure -d group=$RESOURCE_GROUP
16 |
17 | echo "Deploying function app"
18 | az functionapp deployment source config-zip -n $ENV_PREFIX --src $ZIP_PACKAGE
--------------------------------------------------------------------------------
/az/deploy-frontend.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | RESOURCE_GROUP='2wr-resources'
5 | ENV_PREFIX='2wrdev'
6 | SOURCE_FOLDER='../2wr-app/dist'
7 |
8 | while getopts :r:e:s: opt; do
9 | case ${opt} in
10 | r) RESOURCE_GROUP=${OPTARG};;
11 | e) ENV_PREFIX=${OPTARG};;
12 | s) SOURCE_FOLDER=${OPTARG};;
13 | esac
14 | done
15 |
16 | az configure -d group=$RESOURCE_GROUP
17 |
18 | STORAGE_ACCOUNT=${ENV_PREFIX}webstorage
19 | echo "Deploying to $STORAGE_ACCOUNT"
20 | az storage blob upload-batch --account-name $STORAGE_ACCOUNT -s $SOURCE_FOLDER -d '$web'
21 | az cdn endpoint purge -n $ENV_PREFIX --profile-name $ENV_PREFIX --no-wait --content-paths '/' '/index.html' '/manifest.json' '/sw.js'
--------------------------------------------------------------------------------
/solution architecture.xml:
--------------------------------------------------------------------------------
1 | 7VrbcuI4EP0aqnYf4vId/Agh7FwyVdSmajKzLykFK7YmsuWV5QD5+m3ZEvhGYBKcnYdJKmC1hC6nu093i4ycy2TzF0dZ/IWFmI5sM9yMnPnIti3XcuFNSraVZDxRgoiTUA3aC27IM1ZCU0kLEuK8MVAwRgXJmsIVS1O8Eg0Z4pytm8MeGG2umqEIdwQ3K0S70lsSilhJLdPcd3zAJIrV0hNPdSRID1aCPEYhW9dEztXIueSMieop2VxiKsHTuFSfWxzo3W2M41Sc8oFv11/IPzeZa339YX7/bH16yK7GF+NqlidEC3VgtVmx1QhEnBWZGoa5wJs+3NG9Hm5292XtTgtmglmCBd/CEDXRREOpLMTTCK73eNtaFtegth0lRErH0W7uPQzwoJD4CVTc46isYyLwTYZWsr0G2x85s1gksMzcgkeUZ5U1PpANhqVmBwGsA3VYRV306ujYfejYQ6FjHUenc/waNBkjqSj35M1G3lyCRUmUgmAFQGAOApKUXjl7YKlQlGDZe/mcJBHsnJJ7eEXPBcfyRCECK0Q5kIW9mErh3SXLE5bfzWdG/hQNoQM1i980YKtrv0GPgoKh9OP36MensOqsoA01+f8WknxKmC/yEucpDLCCbLPvhKdIvZdzUPL6OT4g/ox4mOu57vnb91Mawjk3Cb6LofMzEflgayxQQqi0oCVF6XDLXCWYRzhdbU85DwilfWhhy6PBZaQ8F5w94ktGGfjpPGVp6aaE0pao5u99TCl9kECQnSrPT0gYypVmDHoeaBkmY5DhtMUCwRBurFOTE+OO5Q/GrOYvEI6dJpvteKoGizV+V1iCDirT5cc3R+TzmZVl9iNaR8x/V8Qmv2aIXrEkKwSw62JRpCtBWHo3zbL8zeH5kALUNJ7VsOjAcC1r7Ltj05tMbMdzOvbtu11leb6x+4QdwAz+UCRgdXSFQ6hJVJNxEbOIpYhe7aUzIIU0lGqcm5JFd2OuGcuUUn9gIbZKVagQrKnytjccZOhcIC6msrKS5kBRnpOVFi8I1fNVZ5AbP6hKfU5W8BU+no3DAhF+yQqCfiPgmCJBnpr7OL/W7OMupzG9RveYLllOpAdA1z0TgiU9oAvWIrFdDSm1HKI83qm8Csy6RFVjM7lwsolkaW6gNOSMhEYWQ4i2O7F8ZDsrU/6+lhpfDiteM6r0BRWrr4pxB4u1Xkdh9u3fIJgul5AFoURCn97nWS1FkvlqlR99LWSO+OkGXv5Y3k7/PJQv1XV3YurUodqDrtgX8ZpEMIAiW+mB4/dosrdaH0yRffVOm0DT8ABldcUvkCJAxLffFLZl47tsGLan2/NNvXe+Va0zsqEmmtfSYU1PfWrSspNZU62wlClDzd0nTTNxzZb6q3OqT9VvrVoT+W1781oTVTh0JipNaXfsN1hX94ZsGiYklUSRZdL9ZxQ9M95lAFYISlJweH0xKQ0BqDgkoPM2DbC9CIjYc70Z5CAncAYMnowDK/Db8eCVsaZDPi94Q9lW5zX7MuxOBFrnrgGbL+BYqMz+Qpw/VguXKSfmV0+4yjz1JdNbqMpu2WDPxaIVjI1J1wusyWBsdUJqfm62ujAN02oylufaRyirbC0xJ3BuaQln57Hxbx57Tx7rFtEfQ1AaERLMLyiFsi3Bau26MWon1gXfUWKhsmOGVo9RmYvUmOqh/DnMPW3+KJecaqlZqy5jIeT3P1MJk70oMspQaKzJIxhrSJDBuCw+ZTuT7aryTJi8aVuIuEhkUerJP/lwDZUSENHdtBCxWZai9gKqPTPbXHS6jCw9uVJ9mZvGnm04k2M5se2ODd/uWvdg9KQp8x3o6exc8n9xhG3tYkg70vwsS4xbZVLnhmhglrBP+G7nXNFpQ0SZShvBxFNtlU07rmrvQ5NsbGuNIQPTqQm29WtFpvb3Sa+NTG675B7a5k64OTm7zTUs7mVr01lUI4PaNYYv+ILf5ngec4Tm/r8tquH7/1lxrv4D
--------------------------------------------------------------------------------
/tools/CosmosEmulator/CosmosEmulator.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net6.0
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/tools/CosmosEmulator/CosmosInitializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Threading.Tasks;
4 | using Microsoft.Azure.Cosmos;
5 |
6 | namespace CosmosEmulator
7 | {
8 | internal class CosmosInitializer
9 | {
10 | // Hardcoded in the emulator
11 | const string ConnectionString = "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
12 | const string DbName = "2wr";
13 |
14 | internal async Task Run()
15 | {
16 | try
17 | {
18 | Console.WriteLine($"Creating Cosmos Client");
19 | var client = new CosmosClient(ConnectionString);
20 | Console.WriteLine($"Creating Database: {DbName}");
21 | var db = await client.CreateDatabaseIfNotExistsAsync(DbName);
22 | switch (db.StatusCode)
23 | {
24 | case HttpStatusCode.OK:
25 | Console.WriteLine($"Database Already Existed: {DbName}");
26 | break;
27 | case HttpStatusCode.Created:
28 | Console.WriteLine($"Database Created: {DbName}");
29 | break;
30 | default:
31 | {
32 | Console.WriteLine($"Database failed to Create: {DbName}");
33 | return -1;
34 | }
35 | }
36 |
37 | var collections = new []
38 | {
39 | (name: "basekits", key: "/id"),
40 | (name: "emergencykits", key: "/userId"),
41 | (name: "familymembers", key: "/id"),
42 | (name: "familyplans", key: "/userid"),
43 | (name: "hazardhunts", key: "/id"),
44 | (name: "hazardinformation", key: "/id")
45 | };
46 |
47 | foreach (var collection in collections)
48 | {
49 | Console.WriteLine($"Creating collection: {collection.name}");
50 | var response = await db.Database.CreateContainerIfNotExistsAsync(collection.name, collection.key, 400);
51 | switch (db.StatusCode)
52 | {
53 | case HttpStatusCode.Created:
54 | Console.WriteLine($"Created Container {collection.name} Successfully.");
55 | break;
56 | case HttpStatusCode.OK:
57 | Console.WriteLine($"Container {collection.name} Exists.");
58 | break;
59 | default:
60 | {
61 | Console.WriteLine($"Collection failed to Create: {collection.name}.");
62 | return -1;
63 | }
64 | }
65 | };
66 |
67 | Console.WriteLine($"Setup complete....");
68 |
69 | return 0;
70 | }
71 | catch (Exception ex)
72 | {
73 | Console.WriteLine($"Failed to setup Emulator: {ex}");
74 | }
75 |
76 | return -1;
77 | }
78 | }
79 | }
--------------------------------------------------------------------------------
/tools/CosmosEmulator/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace CosmosEmulator
5 | {
6 | class Program
7 | {
8 | static async Task Main(string[] args)
9 | {
10 | if (args.Length == 1 && args[0].ToLower() == "/setup")
11 | {
12 | Console.WriteLine("Starting to setup the CosmosDB Emulator.");
13 | return await new CosmosInitializer().Run();
14 | }
15 | else
16 | {
17 | Console.WriteLine("No command specified.");
18 | return 0;
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/tools/CosmosEmulator/start-emulator.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Setup CosmosDB Docker Emulator
4 | ipaddr="`ifconfig | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}' | head -n 1`"
5 | docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator
6 |
7 | # start emulator
8 | docker run --detach --rm -p 8081:8081 -p 10251:10251 -p 10252:10252 -p 10253:10253 -p 10254:10254 -m 3g --cpus=2.0 --name=test-linux-emulator -e AZURE_COSMOS_EMULATOR_PARTITION_COUNT=10 -e AZURE_COSMOS_EMULATOR_ENABLE_DATA_PERSISTENCE=true -e AZURE_COSMOS_EMULATOR_IP_ADDRESS_OVERRIDE=$ipaddr -it mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator &
9 |
10 | # wait for process to complete and server to start
11 | wait
12 | sleep 120s # necessary wait time for the cosmosdb server to start up and start responding to web requests
13 |
14 | # install the certificate
15 | curl --insecure --url https://localhost:8081/_explorer/emulator.pem -o ~/emulatorcert.crt
16 | sudo cp ~/emulatorcert.crt /usr/local/share/ca-certificates/emulatorcert.crt
17 | sudo update-ca-certificates
18 |
19 | # setup database tables
20 | pushd ./tools/CosmosEmulator
21 | dotnet run /setup
22 | popd
23 |
--------------------------------------------------------------------------------
/tools/CosmosEmulator/stop-emulator.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # stop docker process
4 | docker stop test-linux-emulator
5 |
6 | # remove SSL certificate
7 | sudo rm /usr/local/share/ca-certificates/emulatorcert.crt
8 | sudo update-ca-certificates
--------------------------------------------------------------------------------
/tools/first-build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # restore and build dotnet projects (api & admin)
4 | dotnet restore ./TwoWeeksReady.Common
5 | dotnet restore ./api/api.sln
6 | dotnet restore ./admin/admin.sln
7 | dotnet build ./TwoWeeksReady.Common
8 | dotnet build ./api/api.sln
9 | dotnet build ./admin/admin.sln
10 |
11 | # restore Vue app (2wr-app)
12 | pushd ./2wr-app
13 | npm install
14 | npm install -g azurite
15 | npx playwright install
16 | npm run build
17 | popd
18 |
19 | # setup default configuration files
20 | bash ./tools/setup-config.sh > /dev/null
--------------------------------------------------------------------------------
/tools/samples/local.settings.sample.json:
--------------------------------------------------------------------------------
1 | {
2 | "IsEncrypted": false,
3 | "Values": {
4 | "AzureWebJobsStorage": "UseDevelopmentStorage=true",
5 | "FUNCTIONS_WORKER_RUNTIME": "dotnet",
6 | "OidcApiAuthSettings:Audience": "https://2wrdev.azurewebsites.net",
7 | "OidcApiAuthSettings:IssuerUrl": "https://login.2wr.org/"
8 | },
9 | "ConnectionStrings": {
10 | "CosmosDBConnection": "AccountEndpoint=https://localhost:8081/;AccountKey=C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
11 | "StorageConnection": "UseDevelopmentStorage=true"
12 | },
13 | "Host":{
14 | "CORS": "*"
15 | }
16 | }
--------------------------------------------------------------------------------
/tools/setup-config.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # navigate to script directory
4 | SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
5 | pushd $SCRIPT_DIR
6 |
7 | # create api settings file from sample
8 | API_SETTINGS_FILE=../api/TwoWeeksReady/local.settings.json
9 | if [[ ! -f $API_SETTINGS_FILE ]]
10 | then
11 | cp ./samples/local.settings.sample.json $API_SETTINGS_FILE
12 | fi
13 |
14 | # create 2wr-app env from sample
15 | APP_SETTINGS_FILE=../2wr-app/.env
16 | if [[ ! -f $APP_SETTINGS_FILE ]]
17 | then
18 | cp ../2wr-app/.env-sample $APP_SETTINGS_FILE
19 | fi
20 | popd
--------------------------------------------------------------------------------