├── website
├── static
│ ├── .nojekyll
│ ├── CNAME
│ └── img
│ │ ├── app.png
│ │ ├── admin.png
│ │ ├── input.png
│ │ ├── logo.png
│ │ ├── play.png
│ │ ├── aerogear.png
│ │ ├── config.png
│ │ ├── favicon.ico
│ │ ├── features.png
│ │ ├── rocket.png
│ │ ├── architecture.png
│ │ └── plugin-blog.jpg
├── .gitignore
├── sidebars.js
├── src
│ ├── pages
│ │ ├── styles.module.css
│ │ └── index.js
│ ├── components
│ │ ├── styles.module.css
│ │ ├── Hero
│ │ │ ├── styles.module.css
│ │ │ └── index.jsx
│ │ ├── Terminal
│ │ │ ├── styles.module.css
│ │ │ └── index.jsx
│ │ ├── Video
│ │ │ └── index.jsx
│ │ └── Features
│ │ │ └── styles.module.css
│ └── css
│ │ └── custom.css
└── package.json
├── .env
├── platform
├── server
│ ├── src
│ │ ├── config
│ │ │ ├── playground.gql
│ │ │ ├── keycloak.json
│ │ │ ├── auth.ts
│ │ │ └── config.ts
│ │ ├── CrudService.ts
│ │ ├── db.ts
│ │ ├── pubsub.ts
│ │ ├── index.ts
│ │ ├── graphql.ts
│ │ └── auth.ts
│ ├── .dockerignore
│ ├── .gitignore
│ ├── mongodump
│ │ └── showcase
│ │ │ ├── product
│ │ │ ├── 5ef7401712f76aecc84af1f1.bson
│ │ │ ├── 5ef7410912f76aecc84af1f3.bson
│ │ │ ├── 5ef7419b12f76aecc84af1f5.bson
│ │ │ ├── 5ef741a512f76aecc84af1f6.bson
│ │ │ ├── 5ef741b812f76aecc84af1f7.bson
│ │ │ ├── 5ef741d812f76aecc84af1f8.bson
│ │ │ ├── 5ef741f012f76aecc84af1f9.bson
│ │ │ ├── 5ef7421512f76aecc84af1fa.bson
│ │ │ ├── 5ef7423012f76aecc84af1fb.bson
│ │ │ ├── 5ef7430812f76aecc84af1fc.bson
│ │ │ ├── 5ef7442912f76aecc84af1fe.bson
│ │ │ ├── 5ef7444012f76aecc84af1ff.bson
│ │ │ └── 5ef7449d12f76aecc84af200.bson
│ │ │ ├── recipient
│ │ │ ├── 5ef73f9412f76aecc84af1f0.bson
│ │ │ ├── 5ef7418312f76aecc84af1f4.bson
│ │ │ ├── 5ef90768f37edb606082f456.bson
│ │ │ ├── 5ef907b0f37edb606082f463.bson
│ │ │ ├── 5ef907d2f37edb606082f479.bson
│ │ │ ├── 5ef907e3f37edb606082f480.bson
│ │ │ ├── 5ef907f5f37edb606082f485.bson
│ │ │ ├── 5ef90811f37edb606082f48c.bson
│ │ │ ├── 5ef90824f37edb606082f4a2.bson
│ │ │ ├── 5ef90831f37edb606082f4a7.bson
│ │ │ └── 5ef90845f37edb606082f4ac.bson
│ │ │ ├── volunteer
│ │ │ ├── 5ef6262d90701a3b90ebb227.bson
│ │ │ ├── 5ef6266890701a3b90ebb237.bson
│ │ │ ├── 5ef6269490701a3b90ebb245.bson
│ │ │ ├── 5ef626c190701a3b90ebb24f.bson
│ │ │ ├── 5ef626e690701a3b90ebb25b.bson
│ │ │ ├── 5ef6271a90701a3b90ebb26a.bson
│ │ │ └── 5ef9c631da553f262c7a95dc.bson
│ │ │ ├── dailyactionplan
│ │ │ ├── 5efa28d793802a8fb60e8acf.bson
│ │ │ ├── 5efa28de93802a8fb60e8ad0.bson
│ │ │ ├── 5efa28e593802a8fb60e8ad1.bson
│ │ │ ├── 5efa2a1a0f9e4e90fe73a30d.bson
│ │ │ ├── 5efa2a2c0f9e4e90fe73a30e.bson
│ │ │ ├── 5efa2a7e0f9e4e90fe73a30f.bson
│ │ │ ├── 5efa2a800f9e4e90fe73a310.bson
│ │ │ ├── 5efa2a810f9e4e90fe73a311.bson
│ │ │ ├── 5efa2a850f9e4e90fe73a312.bson
│ │ │ ├── 5efa2aa60f9e4e90fe73a313.bson
│ │ │ ├── 5efa2aa70f9e4e90fe73a314.bson
│ │ │ └── 5efa2aaa0f9e4e90fe73a315.bson
│ │ │ ├── volunteeraction
│ │ │ ├── 5ef9c4f9da553f262c7a95d7.bson
│ │ │ ├── 5ef9c684da553f262c7a95dd.bson
│ │ │ ├── 5efa273a93802a8fb60e8ac0.bson
│ │ │ ├── 5efa27d993802a8fb60e8ac4.bson
│ │ │ ├── 5efa280793802a8fb60e8ac8.bson
│ │ │ └── 5efa282893802a8fb60e8acc.bson
│ │ │ ├── distributioncentre
│ │ │ ├── 5ef740ac12f76aecc84af1f2.bson
│ │ │ └── 5ef7437a12f76aecc84af1fd.bson
│ │ │ └── volunteeractionproduct
│ │ │ ├── 5ef9c4f9da553f262c7a95d8.bson
│ │ │ ├── 5ef9c4f9da553f262c7a95d9.bson
│ │ │ ├── 5ef9c4f9da553f262c7a95da.bson
│ │ │ ├── 5ef9c4f9da553f262c7a95db.bson
│ │ │ ├── 5efa273a93802a8fb60e8ac1.bson
│ │ │ ├── 5efa273a93802a8fb60e8ac2.bson
│ │ │ ├── 5efa273a93802a8fb60e8ac3.bson
│ │ │ ├── 5efa27d993802a8fb60e8ac5.bson
│ │ │ ├── 5efa27d993802a8fb60e8ac6.bson
│ │ │ ├── 5efa27d993802a8fb60e8ac7.bson
│ │ │ ├── 5efa280793802a8fb60e8ac9.bson
│ │ │ ├── 5efa280793802a8fb60e8aca.bson
│ │ │ ├── 5efa280793802a8fb60e8acb.bson
│ │ │ ├── 5efa282893802a8fb60e8acd.bson
│ │ │ └── 5efa282893802a8fb60e8ace.bson
│ ├── Dockerfile
│ ├── integrations
│ │ ├── mqtt
│ │ │ └── docker-compose.yml
│ │ └── keycloak
│ │ │ ├── docker-compose.yml
│ │ │ └── getToken.js
│ ├── .env
│ ├── .graphqlrc.yml
│ ├── docker-compose.yml
│ ├── tsconfig.json
│ └── package.json
├── client
│ ├── src
│ │ ├── react-app-env.d.ts
│ │ ├── config
│ │ │ ├── index.ts
│ │ │ ├── SimpleSchema.ts
│ │ │ └── clientConfig.ts
│ │ ├── hooks
│ │ │ ├── index.ts
│ │ │ └── useSubscribeToMore.ts
│ │ ├── helpers
│ │ │ ├── index.ts
│ │ │ ├── ConflictLogger.ts
│ │ │ └── CapacitorNetworkStatus.ts
│ │ ├── pages
│ │ │ ├── index.ts
│ │ │ └── ActionPage.tsx
│ │ ├── graphql
│ │ │ └── queries
│ │ │ │ ├── findLoggedVolunteer.graphql
│ │ │ │ └── findMyVolunteerActions.graphql
│ │ ├── components
│ │ │ ├── index.ts
│ │ │ ├── Loading.tsx
│ │ │ ├── Empty.tsx
│ │ │ ├── ActionsList.tsx
│ │ │ ├── Action.tsx
│ │ │ ├── Router.tsx
│ │ │ └── Header.tsx
│ │ ├── App.tsx
│ │ ├── index.tsx
│ │ ├── transformer
│ │ │ └── volunteerTransformer.ts
│ │ ├── declarations.ts
│ │ ├── theme
│ │ │ ├── index.ts
│ │ │ └── styles.css
│ │ ├── forms
│ │ │ ├── distributionCentre.ts
│ │ │ ├── volunteerAction.ts
│ │ │ ├── recipient.ts
│ │ │ └── volunteer.ts
│ │ ├── context
│ │ │ └── AuthContext.tsx
│ │ ├── AppContainer.tsx
│ │ └── keycloakAuth.ts
│ ├── .env
│ ├── public
│ │ ├── assets
│ │ │ ├── icon
│ │ │ │ ├── icon.png
│ │ │ │ ├── favicon.png
│ │ │ │ ├── aerogear.png
│ │ │ │ └── keycloak.png
│ │ │ └── shapes.svg
│ │ ├── keycloak.example.json
│ │ ├── keycloak.json
│ │ ├── manifest.json
│ │ └── index.html
│ ├── ionic.config.json
│ ├── capacitor.config.json
│ ├── .gitignore
│ ├── tsconfig.json
│ ├── README.adoc
│ ├── .graphqlrc.yml
│ ├── samples.graphql
│ └── package.json
├── client-admin
│ ├── src
│ │ ├── react-app-env.d.ts
│ │ ├── config
│ │ │ ├── index.ts
│ │ │ ├── SimpleSchema.ts
│ │ │ ├── MarkerIcons.ts
│ │ │ └── clientConfig.ts
│ │ ├── hooks
│ │ │ ├── index.ts
│ │ │ └── useSubscribeToMore.ts
│ │ ├── pages
│ │ │ ├── index.ts
│ │ │ ├── ProductsPage.tsx
│ │ │ ├── VolunteersPage.tsx
│ │ │ ├── RecipientsPage.tsx
│ │ │ ├── ActionPage.tsx
│ │ │ ├── ProfilePage.tsx
│ │ │ └── SchedulePage.tsx
│ │ ├── graphql
│ │ │ ├── queries
│ │ │ │ ├── findLoggedVolunteer.graphql
│ │ │ │ ├── findIdAndNamesOfAllDistributionCentres.graphql
│ │ │ │ ├── findAllDistributionCenters.graphql
│ │ │ │ └── findVolunteerActionDetails.graphql
│ │ │ └── mutations
│ │ │ │ └── assignVolunteers.graphql
│ │ ├── App.tsx
│ │ ├── components
│ │ │ ├── index.ts
│ │ │ ├── generic
│ │ │ │ ├── Loading.tsx
│ │ │ │ └── Empty.tsx
│ │ │ ├── model
│ │ │ │ ├── ActionList.tsx
│ │ │ │ ├── ProductList.tsx
│ │ │ │ ├── VolunteerList.tsx
│ │ │ │ ├── RecipientList.tsx
│ │ │ │ ├── Product.tsx
│ │ │ │ ├── Action.tsx
│ │ │ │ ├── Recipient.tsx
│ │ │ │ └── Volunteer.tsx
│ │ │ ├── Map.tsx
│ │ │ ├── Header.tsx
│ │ │ ├── Menu.css
│ │ │ └── Menu.tsx
│ │ ├── context
│ │ │ └── AuthContext.tsx
│ │ ├── index.tsx
│ │ ├── declarations.ts
│ │ ├── transformer
│ │ │ └── volunteerTransformer.ts
│ │ ├── forms
│ │ │ ├── volunteerActionRecipient.ts
│ │ │ ├── admin.ts
│ │ │ ├── product.ts
│ │ │ ├── distributionCentre.ts
│ │ │ ├── dailyAction.ts
│ │ │ ├── volunteerAction.ts
│ │ │ ├── recipient.ts
│ │ │ ├── createVolunteer.ts
│ │ │ ├── createVolunteerAction.ts
│ │ │ └── volunteer.ts
│ │ ├── theme
│ │ │ ├── index.ts
│ │ │ └── styles.css
│ │ ├── AppContainer.tsx
│ │ └── keycloakAuth.ts
│ ├── public
│ │ ├── assets
│ │ │ ├── icon
│ │ │ │ ├── icon.png
│ │ │ │ ├── aerogear.png
│ │ │ │ ├── favicon.png
│ │ │ │ └── keycloak.png
│ │ │ └── shapes.svg
│ │ ├── keycloak.example.json
│ │ ├── keycloak.json
│ │ ├── manifest.json
│ │ └── index.html
│ ├── ionic.config.json
│ ├── .env
│ ├── capacitor.config.json
│ ├── .gitignore
│ ├── tsconfig.json
│ ├── README.adoc
│ ├── .graphqlrc.yml
│ └── package.json
├── .openshift
│ ├── amq.yml
│ ├── amq-topics.yml
│ └── README.md
└── package.json
├── cli
├── types
│ ├── index.d.ts
│ ├── components
│ │ ├── index.d.ts
│ │ └── init.d.ts
│ ├── utils
│ │ └── index.d.ts
│ ├── init
│ │ ├── starterTemplates.d.ts
│ │ └── templateMetadata.d.ts
│ └── commands
│ │ └── init.d.ts
├── dist
│ ├── init
│ │ └── templateMetadata.js
│ ├── components
│ │ └── index.js
│ ├── index.js
│ └── utils
│ │ └── index.js
├── tests
│ └── workflow-test.ts
├── tsconfig.json
├── src
│ ├── index.ts
│ ├── utils
│ │ └── index.ts
│ ├── init
│ │ └── templateMetadata.ts
│ └── commands
│ │ └── init.ts
├── README.md
├── jest.config.js
└── package.json
├── scripts
└── docker.sh
├── renovate.json
├── docs
├── client.md
├── features.md
├── referencegs.md
├── architecture.md
├── clientref.md
├── gettingstarted.md
└── integrations_graphback_keycloak.md
├── .github
├── ISSUE_TEMPLATE
│ ├── 3-ask-for-help.md
│ ├── 1-bug-report.md
│ └── 2-feature-request.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── node.js.yml
├── .gitignore
├── .vscode
└── launch.json
├── LICENSE
└── .circleci
└── config.yml
/website/static/.nojekyll :
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | SKIP_PREFLIGHT_CHECK=true
--------------------------------------------------------------------------------
/website/static/CNAME:
--------------------------------------------------------------------------------
1 | openvolunteer.org
--------------------------------------------------------------------------------
/platform/server/src/config/playground.gql:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cli/types/index.d.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | export {};
3 |
--------------------------------------------------------------------------------
/platform/server/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | npm-debug.log
--------------------------------------------------------------------------------
/cli/dist/init/templateMetadata.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | exports.__esModule = true;
3 |
--------------------------------------------------------------------------------
/platform/client/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/platform/client-admin/src/react-app-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/platform/client/src/config/index.ts:
--------------------------------------------------------------------------------
1 | export { clientConfig } from './clientConfig';
2 |
--------------------------------------------------------------------------------
/platform/client-admin/src/config/index.ts:
--------------------------------------------------------------------------------
1 | export { clientConfig } from './clientConfig';
2 |
--------------------------------------------------------------------------------
/platform/client/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useSubscribeToMore } from './useSubscribeToMore';
--------------------------------------------------------------------------------
/platform/client-admin/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useSubscribeToMore } from './useSubscribeToMore';
--------------------------------------------------------------------------------
/platform/client/src/helpers/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export { ConflictLogger } from './ConflictLogger';
3 |
--------------------------------------------------------------------------------
/website/static/img/app.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/app.png
--------------------------------------------------------------------------------
/platform/client/.env:
--------------------------------------------------------------------------------
1 | SKIP_PREFLIGHT_CHECK=true
2 | REACT_APP_GOOGLE_MAP_API_KEY=AIzaSyAmAwkv8-x2I--ne-NtA3C_4E_-aLCsFJ1
3 |
--------------------------------------------------------------------------------
/platform/server/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 | types
4 | yarn.lock
5 | yarn-error.log
6 | data/*
7 | admin
8 | website
--------------------------------------------------------------------------------
/website/static/img/admin.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/admin.png
--------------------------------------------------------------------------------
/website/static/img/input.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/input.png
--------------------------------------------------------------------------------
/website/static/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/logo.png
--------------------------------------------------------------------------------
/website/static/img/play.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/play.png
--------------------------------------------------------------------------------
/scripts/docker.sh:
--------------------------------------------------------------------------------
1 | set -e
2 |
3 | docker build -t wtrocki/openvolunteer:latest .
4 | docker push wtrocki/openvolunteer:latest
--------------------------------------------------------------------------------
/website/static/img/aerogear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/aerogear.png
--------------------------------------------------------------------------------
/website/static/img/config.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/config.png
--------------------------------------------------------------------------------
/website/static/img/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/favicon.ico
--------------------------------------------------------------------------------
/website/static/img/features.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/features.png
--------------------------------------------------------------------------------
/website/static/img/rocket.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/rocket.png
--------------------------------------------------------------------------------
/website/static/img/architecture.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/architecture.png
--------------------------------------------------------------------------------
/website/static/img/plugin-blog.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/website/static/img/plugin-blog.jpg
--------------------------------------------------------------------------------
/platform/client/public/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client/public/assets/icon/icon.png
--------------------------------------------------------------------------------
/platform/client/public/assets/icon/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client/public/assets/icon/favicon.png
--------------------------------------------------------------------------------
/cli/types/components/index.d.ts:
--------------------------------------------------------------------------------
1 | export * from './db';
2 | export * from './generate';
3 | export * from './config';
4 | export * from './transformOpenApiSpec';
5 |
--------------------------------------------------------------------------------
/platform/client/public/assets/icon/aerogear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client/public/assets/icon/aerogear.png
--------------------------------------------------------------------------------
/platform/client/public/assets/icon/keycloak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client/public/assets/icon/keycloak.png
--------------------------------------------------------------------------------
/platform/client-admin/public/assets/icon/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client-admin/public/assets/icon/icon.png
--------------------------------------------------------------------------------
/platform/client-admin/public/assets/icon/aerogear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client-admin/public/assets/icon/aerogear.png
--------------------------------------------------------------------------------
/platform/client-admin/public/assets/icon/favicon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client-admin/public/assets/icon/favicon.png
--------------------------------------------------------------------------------
/platform/client-admin/public/assets/icon/keycloak.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/client-admin/public/assets/icon/keycloak.png
--------------------------------------------------------------------------------
/platform/client/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "appId": "com.datasync.starter",
4 | "integrations": {
5 | "capacitor": {}
6 | },
7 | "type": "react"
8 | }
9 |
--------------------------------------------------------------------------------
/platform/client/src/pages/index.ts:
--------------------------------------------------------------------------------
1 | export { ActionPage } from './ActionPage';
2 | export { ProfilePage } from './ProfilePage';
3 | export { ViewActionPage } from './ViewActionPage';
4 |
--------------------------------------------------------------------------------
/platform/client-admin/ionic.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "appId": "com.datasync.starter",
4 | "integrations": {
5 | "capacitor": {}
6 | },
7 | "type": "react"
8 | }
9 |
--------------------------------------------------------------------------------
/platform/client-admin/src/pages/index.ts:
--------------------------------------------------------------------------------
1 | export { ActionPage } from './ActionPage';
2 | export { ProfilePage } from './ProfilePage';
3 | export { ViewActionPage } from './ViewActionPage';
4 |
--------------------------------------------------------------------------------
/platform/client-admin/.env:
--------------------------------------------------------------------------------
1 | SKIP_PREFLIGHT_CHECK=true
2 | REACT_APP_GOOGLE_MAP_API_KEY=AIzaSyDLv7YJxcswz2uJGuHKXICnddMjZ_CyLas
3 | REACT_APP_REPORT_COLUMN_SIZE=4
4 | REACT_APP_NEARBY_MAX_DISTANCE=100
--------------------------------------------------------------------------------
/cli/tests/workflow-test.ts:
--------------------------------------------------------------------------------
1 | import { existsSync } from 'fs';
2 | import { join, resolve } from 'path';
3 |
4 | test('Test cli workflow', async () => {
5 | // TODO
6 | expect(true).toBe(true);
7 | });
8 |
9 |
--------------------------------------------------------------------------------
/platform/client/src/config/SimpleSchema.ts:
--------------------------------------------------------------------------------
1 | import SimpleSchema from 'simpl-schema';
2 |
3 | // Register custom property.
4 | SimpleSchema.extendOptions(['uniforms']);
5 |
6 | export default SimpleSchema;
7 |
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7401712f76aecc84af1f1.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7401712f76aecc84af1f1.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7410912f76aecc84af1f3.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7410912f76aecc84af1f3.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7419b12f76aecc84af1f5.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7419b12f76aecc84af1f5.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef741a512f76aecc84af1f6.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef741a512f76aecc84af1f6.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef741b812f76aecc84af1f7.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef741b812f76aecc84af1f7.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef741d812f76aecc84af1f8.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef741d812f76aecc84af1f8.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef741f012f76aecc84af1f9.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef741f012f76aecc84af1f9.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7421512f76aecc84af1fa.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7421512f76aecc84af1fa.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7423012f76aecc84af1fb.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7423012f76aecc84af1fb.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7430812f76aecc84af1fc.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7430812f76aecc84af1fc.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7442912f76aecc84af1fe.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7442912f76aecc84af1fe.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7444012f76aecc84af1ff.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7444012f76aecc84af1ff.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/product/5ef7449d12f76aecc84af200.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/product/5ef7449d12f76aecc84af200.bson
--------------------------------------------------------------------------------
/platform/client-admin/src/config/SimpleSchema.ts:
--------------------------------------------------------------------------------
1 | import SimpleSchema from 'simpl-schema';
2 |
3 | // Register custom property.
4 | SimpleSchema.extendOptions(['uniforms']);
5 |
6 | export default SimpleSchema;
7 |
--------------------------------------------------------------------------------
/platform/client/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "io.ionic.starter",
3 | "appName": "client",
4 | "bundledWebRuntime": true,
5 | "npmClient": "npm",
6 | "webDir": "build",
7 | "cordova": {}
8 | }
9 |
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef73f9412f76aecc84af1f0.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef73f9412f76aecc84af1f0.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef7418312f76aecc84af1f4.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef7418312f76aecc84af1f4.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef90768f37edb606082f456.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef90768f37edb606082f456.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef907b0f37edb606082f463.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef907b0f37edb606082f463.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef907d2f37edb606082f479.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef907d2f37edb606082f479.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef907e3f37edb606082f480.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef907e3f37edb606082f480.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef907f5f37edb606082f485.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef907f5f37edb606082f485.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef90811f37edb606082f48c.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef90811f37edb606082f48c.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef90824f37edb606082f4a2.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef90824f37edb606082f4a2.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef90831f37edb606082f4a7.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef90831f37edb606082f4a7.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/recipient/5ef90845f37edb606082f4ac.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/recipient/5ef90845f37edb606082f4ac.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef6262d90701a3b90ebb227.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef6262d90701a3b90ebb227.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef6266890701a3b90ebb237.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef6266890701a3b90ebb237.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef6269490701a3b90ebb245.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef6269490701a3b90ebb245.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef626c190701a3b90ebb24f.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef626c190701a3b90ebb24f.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef626e690701a3b90ebb25b.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef626e690701a3b90ebb25b.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef6271a90701a3b90ebb26a.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef6271a90701a3b90ebb26a.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteer/5ef9c631da553f262c7a95dc.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteer/5ef9c631da553f262c7a95dc.bson
--------------------------------------------------------------------------------
/renovate.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": [
3 | "config:base",
4 | ":pinVersions"
5 | ],
6 | "groupName": "all",
7 | "automerge": false,
8 | "major": {
9 | "automerge": false
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/platform/client-admin/capacitor.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "appId": "io.ionic.starter",
3 | "appName": "client",
4 | "bundledWebRuntime": true,
5 | "npmClient": "npm",
6 | "webDir": "build",
7 | "cordova": {}
8 | }
9 |
--------------------------------------------------------------------------------
/platform/client-admin/src/config/MarkerIcons.ts:
--------------------------------------------------------------------------------
1 | export const RED_ICON = "http://maps.google.com/mapfiles/ms/icons/red-dot.png";
2 | export const YELLOW_ICON = "http://maps.google.com/mapfiles/ms/icons/yellow-dot.png";
3 |
--------------------------------------------------------------------------------
/platform/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:12.18.3
2 |
3 | # Create app directory
4 | WORKDIR /usr/src/app
5 |
6 | COPY . .
7 | RUN npm install
8 |
9 | VOLUME ./files
10 |
11 | EXPOSE 4000
12 | CMD [ "npm", "start" ]
13 |
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa28d793802a8fb60e8acf.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa28d793802a8fb60e8acf.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa28de93802a8fb60e8ad0.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa28de93802a8fb60e8ad0.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa28e593802a8fb60e8ad1.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa28e593802a8fb60e8ad1.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2a1a0f9e4e90fe73a30d.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2a1a0f9e4e90fe73a30d.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2a2c0f9e4e90fe73a30e.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2a2c0f9e4e90fe73a30e.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2a7e0f9e4e90fe73a30f.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2a7e0f9e4e90fe73a30f.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2a800f9e4e90fe73a310.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2a800f9e4e90fe73a310.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2a810f9e4e90fe73a311.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2a810f9e4e90fe73a311.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2a850f9e4e90fe73a312.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2a850f9e4e90fe73a312.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2aa60f9e4e90fe73a313.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2aa60f9e4e90fe73a313.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2aa70f9e4e90fe73a314.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2aa70f9e4e90fe73a314.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/dailyactionplan/5efa2aaa0f9e4e90fe73a315.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/dailyactionplan/5efa2aaa0f9e4e90fe73a315.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeraction/5ef9c4f9da553f262c7a95d7.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeraction/5ef9c4f9da553f262c7a95d7.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeraction/5ef9c684da553f262c7a95dd.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeraction/5ef9c684da553f262c7a95dd.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeraction/5efa273a93802a8fb60e8ac0.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeraction/5efa273a93802a8fb60e8ac0.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeraction/5efa27d993802a8fb60e8ac4.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeraction/5efa27d993802a8fb60e8ac4.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeraction/5efa280793802a8fb60e8ac8.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeraction/5efa280793802a8fb60e8ac8.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeraction/5efa282893802a8fb60e8acc.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeraction/5efa282893802a8fb60e8acc.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/distributioncentre/5ef740ac12f76aecc84af1f2.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/distributioncentre/5ef740ac12f76aecc84af1f2.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/distributioncentre/5ef7437a12f76aecc84af1fd.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/distributioncentre/5ef7437a12f76aecc84af1fd.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95d8.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95d8.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95d9.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95d9.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95da.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95da.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95db.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5ef9c4f9da553f262c7a95db.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa273a93802a8fb60e8ac1.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa273a93802a8fb60e8ac1.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa273a93802a8fb60e8ac2.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa273a93802a8fb60e8ac2.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa273a93802a8fb60e8ac3.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa273a93802a8fb60e8ac3.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa27d993802a8fb60e8ac5.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa27d993802a8fb60e8ac5.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa27d993802a8fb60e8ac6.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa27d993802a8fb60e8ac6.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa27d993802a8fb60e8ac7.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa27d993802a8fb60e8ac7.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa280793802a8fb60e8ac9.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa280793802a8fb60e8ac9.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa280793802a8fb60e8aca.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa280793802a8fb60e8aca.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa280793802a8fb60e8acb.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa280793802a8fb60e8acb.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa282893802a8fb60e8acd.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa282893802a8fb60e8acd.bson
--------------------------------------------------------------------------------
/platform/server/mongodump/showcase/volunteeractionproduct/5efa282893802a8fb60e8ace.bson:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/aerogear/OpenVolunteerPlatform/HEAD/platform/server/mongodump/showcase/volunteeractionproduct/5efa282893802a8fb60e8ace.bson
--------------------------------------------------------------------------------
/platform/client/src/graphql/queries/findLoggedVolunteer.graphql:
--------------------------------------------------------------------------------
1 | query findActiveVolunteer($username: String!) {
2 | findVolunteers(filter: { username: {eq: $username} }, page: {limit: 1}) {
3 | items {
4 | ...VolunteerFields
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/platform/client-admin/src/graphql/queries/findLoggedVolunteer.graphql:
--------------------------------------------------------------------------------
1 | query findActiveVolunteer($username: String!) {
2 | findVolunteers(filter: { username: {eq: $username} }, page: {limit: 1}) {
3 | items {
4 | ...VolunteerFields
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/platform/client-admin/src/graphql/mutations/assignVolunteers.graphql:
--------------------------------------------------------------------------------
1 | mutation assignVolunteers{
2 | assignVolunteers{
3 | _id
4 | owner
5 | date
6 | numberOfVolunteersAssigned
7 | numberOfCasesCreated
8 | numberOfRecipients
9 | }
10 | }
--------------------------------------------------------------------------------
/platform/client/src/components/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export { Action } from './Action';
3 | export { Empty } from './Empty';
4 | export { Header } from './Header';
5 | export { Router } from './Router';
6 | export { Loading } from './Loading';
7 | export { ActionsList } from './ActionsList';
--------------------------------------------------------------------------------
/platform/server/integrations/mqtt/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 | services:
3 | # Mosca is a simple MQTT Broker
4 | # In OpenShift/Production we would use the Red Hat AMQ broker
5 | mosca:
6 | image: eclipse-mosquitto:latest
7 | ports:
8 | - "1883:1883" # MQTT
--------------------------------------------------------------------------------
/platform/client/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Router } from './components';
3 |
4 | // load all styles
5 | import './theme';
6 | export const App: React.FC= () => {
7 |
8 | return (
9 | <>
10 |
11 | >
12 | );
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/platform/client-admin/src/App.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { Router } from './components';
3 |
4 | // load all styles
5 | import './theme';
6 | export const App: React.FC= () => {
7 |
8 | return (
9 | <>
10 |
11 | >
12 | );
13 | };
14 |
15 |
--------------------------------------------------------------------------------
/platform/client/public/keycloak.example.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "",
3 | "auth-server-url": "https://your-server/auth",
4 | "ssl-required": "none",
5 | "resource": "",
6 | "public-client": true,
7 | "use-resource-role-mappings": true,
8 | "confidential-port": 0
9 | }
--------------------------------------------------------------------------------
/platform/client-admin/public/keycloak.example.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "",
3 | "auth-server-url": "https://your-server/auth",
4 | "ssl-required": "none",
5 | "resource": "",
6 | "public-client": true,
7 | "use-resource-role-mappings": true,
8 | "confidential-port": 0
9 | }
--------------------------------------------------------------------------------
/platform/server/integrations/keycloak/docker-compose.yml:
--------------------------------------------------------------------------------
1 | version: '3'
2 |
3 | services:
4 | keycloak:
5 | image: jboss/keycloak:3.4.3.Final
6 | ports:
7 | - "8080:8080"
8 | environment:
9 | DB_VENDOR: h2
10 | KEYCLOAK_USER: admin
11 | KEYCLOAK_PASSWORD: admin
--------------------------------------------------------------------------------
/platform/client-admin/src/components/index.ts:
--------------------------------------------------------------------------------
1 |
2 | export { Volunteer } from './model/Volunteer';
3 | export { Empty } from './generic/Empty';
4 | export { Header } from './Header';
5 | export { Router } from './Router';
6 | export { ActionsList } from './model/ActionList';
7 | export { Loading } from './generic/Loading';
--------------------------------------------------------------------------------
/platform/client-admin/src/graphql/queries/findIdAndNamesOfAllDistributionCentres.graphql:
--------------------------------------------------------------------------------
1 | query findIdAndNamesOfAllDistributionCentres($limit: Int, $offset: Int) {
2 | findDistributionCentres(page: {limit: $limit, offset: $offset}) {
3 | items {
4 | _id,
5 | name
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/platform/client/public/keycloak.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "open-volunteer-platform",
3 | "auth-server-url": "http://localhost:8080/auth",
4 | "ssl-required": "none",
5 | "resource": "open-volunteer-platform-public",
6 | "public-client": true,
7 | "use-resource-role-mappings": true,
8 | "confidential-port": 0
9 | }
--------------------------------------------------------------------------------
/platform/client-admin/public/keycloak.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "open-volunteer-platform",
3 | "auth-server-url": "http://localhost:8080/auth",
4 | "ssl-required": "none",
5 | "resource": "open-volunteer-platform-public",
6 | "public-client": true,
7 | "use-resource-role-mappings": true,
8 | "confidential-port": 0
9 | }
--------------------------------------------------------------------------------
/platform/server/src/config/keycloak.json:
--------------------------------------------------------------------------------
1 | {
2 | "realm": "open-volunteer-platform",
3 | "auth-server-url": "http://localhost:8080/auth",
4 | "ssl-required": "none",
5 | "resource": "open-volunteer-platform-bearer",
6 | "public-client": true,
7 | "use-resource-role-mappings": true,
8 | "confidential-port": 0
9 | }
--------------------------------------------------------------------------------
/cli/types/components/init.d.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * init command handler
3 | * @param name name of project folder
4 | * @param templateName name of the template provided(if any)
5 | * @param templateUrl github url to the template
6 | */
7 | export declare function init(name: string, templateName?: string, templateUrl?: string): Promise;
8 |
--------------------------------------------------------------------------------
/cli/dist/components/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | function __export(m) {
3 | for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p];
4 | }
5 | exports.__esModule = true;
6 | __export(require("./db"));
7 | __export(require("./generate"));
8 | __export(require("./config"));
9 | __export(require("./transformOpenApiSpec"));
10 |
--------------------------------------------------------------------------------
/cli/types/utils/index.d.ts:
--------------------------------------------------------------------------------
1 | export declare const log: {
2 | (message?: any, ...optionalParams: any[]): void;
3 | (message?: any, ...optionalParams: any[]): void;
4 | };
5 | export declare const logError: (s: string) => void;
6 | export declare const logInfo: (s: string) => void;
7 | export declare const logDetail: (s: string) => void;
8 |
--------------------------------------------------------------------------------
/platform/client/src/components/Loading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IonLoading } from '@ionic/react';
3 | import { ILoadingProps } from '../declarations';
4 |
5 | export const Loading: React.FC = ({ loading }) => {
6 | return ;
10 | };
--------------------------------------------------------------------------------
/platform/client/src/graphql/queries/findMyVolunteerActions.graphql:
--------------------------------------------------------------------------------
1 | query findMyVolunteerActions($volunteerId: GraphbackObjectID!, $status: String) {
2 | findVolunteerActions(filter: { volunteerId: {eq: $volunteerId}, status: {
3 | eq: $status
4 | } }) {
5 | items {
6 | ...VolunteerActionFields
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/website/.gitignore:
--------------------------------------------------------------------------------
1 | # Dependencies
2 | /node_modules
3 |
4 | # Production
5 | /build
6 |
7 | # Generated files
8 | .docusaurus
9 | .cache-loader
10 |
11 | # Misc
12 | .DS_Store
13 | .env.local
14 | .env.development.local
15 | .env.test.local
16 | .env.production.local
17 |
18 | npm-debug.log*
19 | yarn-debug.log*
20 | yarn-error.log*
21 |
--------------------------------------------------------------------------------
/platform/client-admin/src/context/AuthContext.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { KeycloakInstance, KeycloakProfile } from 'keycloak-js';
3 | export interface IAuthContext {
4 | keycloak?: KeycloakInstance | undefined
5 | profile?: KeycloakProfile | undefined
6 | }
7 |
8 | export const AuthContext = React.createContext({});
--------------------------------------------------------------------------------
/cli/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "./src/**/*.ts"
4 | ],
5 | "compilerOptions": {
6 | "outDir": "./dist/",
7 | "declaration": true,
8 | "declarationDir": "types",
9 | "lib": [
10 | "esnext.asynciterable",
11 | "es2015",
12 | "es2018.promise",
13 | "dom",
14 | "es2016"
15 | ]
16 | }
17 | }
--------------------------------------------------------------------------------
/platform/client/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { App } from './App';
4 | import { AppContainer } from './AppContainer';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | serviceWorker.register();
10 |
--------------------------------------------------------------------------------
/platform/client-admin/src/components/generic/Loading.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { IonLoading } from '@ionic/react';
3 | import { ILoadingProps } from '../../declarations';
4 |
5 | export const Loading: React.FC = ({ loading }) => {
6 | return ;
10 | };
--------------------------------------------------------------------------------
/platform/client-admin/src/index.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import { App } from './App';
4 | import { AppContainer } from './AppContainer';
5 | import * as serviceWorker from './serviceWorker';
6 |
7 | ReactDOM.render(, document.getElementById('root'));
8 |
9 | serviceWorker.register();
10 |
--------------------------------------------------------------------------------
/platform/client-admin/src/graphql/queries/findAllDistributionCenters.graphql:
--------------------------------------------------------------------------------
1 |
2 | query findFlatDistributionCentres($page: PageRequest, $orderBy: OrderByInput) {
3 | findDistributionCentres(page: $page, orderBy: $orderBy) {
4 | items {
5 | ...DistributionCentreFields
6 | }
7 | offset
8 | limit
9 | count
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/platform/client/src/hooks/useSubscribeToMore.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 |
3 | export const useSubscribeToMore: any = ({ options, subscribeToMore } : { options: any, subscribeToMore: Function }) => {
4 |
5 | useEffect(()=>{
6 | options.forEach((option: any) => {
7 | subscribeToMore(option);
8 | });
9 | }, [options, subscribeToMore]);
10 |
11 | };
12 |
--------------------------------------------------------------------------------
/website/sidebars.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | docs: {
3 | Introduction: ["gettingstarted", "features", "architecture"],
4 | "Reference Apps": ["gettingstartedref", "coding"],
5 | Development: ["clientref", "serverfullstack"],
6 | Customizations: ["datamodel", "keycloak-authz", "liveupdates", "adding-and-customizing-forms"],
7 | Tools: ["client"]
8 | },
9 | };
10 |
--------------------------------------------------------------------------------
/platform/client-admin/src/hooks/useSubscribeToMore.ts:
--------------------------------------------------------------------------------
1 | import { useEffect } from 'react';
2 |
3 | export const useSubscribeToMore: any = ({ options, subscribeToMore } : { options: any, subscribeToMore: Function }) => {
4 |
5 | useEffect(()=>{
6 | options.forEach((option: any) => {
7 | subscribeToMore(option);
8 | });
9 | }, [options, subscribeToMore]);
10 |
11 | };
12 |
--------------------------------------------------------------------------------
/cli/src/index.ts:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 |
3 | import * as yargs from 'yargs';
4 |
5 | if (require.main === module) {
6 | // eslint-disable-next-line no-unused-expressions
7 | yargs
8 | .commandDir('commands')
9 | .demandCommand(1)
10 | .strict()
11 | .recommendCommands()
12 | .help()
13 | .alias('h', 'help')
14 | .version()
15 | .alias('v', 'version')
16 | .argv;
17 | }
--------------------------------------------------------------------------------
/platform/client-admin/src/declarations.ts:
--------------------------------------------------------------------------------
1 | import { KeycloakInstance } from "keycloak-js";
2 |
3 |
4 | export interface IContainerProps {
5 | app: React.FC
6 | };
7 |
8 | export interface ILoadingProps {
9 | loading: boolean
10 | };
11 |
12 | export interface IUpdateMatchParams {
13 | id: string
14 | }
15 |
16 | export interface IAuthHeaders {
17 | headers: {
18 | Authorization: String
19 | }
20 | }
--------------------------------------------------------------------------------
/cli/src/utils/index.ts:
--------------------------------------------------------------------------------
1 | import * as chalk from 'chalk';
2 | import * as emoji from 'node-emoji';
3 |
4 | //tslint:disable-next-line: no-console
5 | export const log = console.log;
6 | export const logError = (s: string) => log(emoji.emojify(chalk.default.bold.red(s)));
7 | export const logInfo = (s: string) => log(emoji.emojify(chalk.default.bold(s)));
8 | export const logDetail = (s: string) => log(emoji.emojify(chalk.default.dim(s)));
9 |
--------------------------------------------------------------------------------
/platform/client/src/transformer/volunteerTransformer.ts:
--------------------------------------------------------------------------------
1 | import { VolunteerFieldsFragment } from "../dataFacade";
2 |
3 | export const volunteerTransformer = (volunteer: VolunteerFieldsFragment) => {
4 | // Restructure data
5 | if (volunteer.dateOfBirth) {
6 | //volunteer.dateOfBirth = new Date(volunteer.dateOfBirth);
7 | }
8 | //delete volunteer.__typename;
9 |
10 | return volunteer as VolunteerFieldsFragment;
11 | }
--------------------------------------------------------------------------------
/cli/types/init/starterTemplates.d.ts:
--------------------------------------------------------------------------------
1 | import { Template } from './templateMetadata';
2 | /**
3 | * available templates
4 | */
5 | export declare const allTemplates: Template[];
6 | /**
7 | * download and extract template from repository into project folder
8 | * @param template template information
9 | * @param name name of project folder
10 | */
11 | export declare function extractTemplate(template: Template, name: string): Promise;
12 |
--------------------------------------------------------------------------------
/platform/server/.env:
--------------------------------------------------------------------------------
1 | ## Mongo
2 | MONGO_USER=user
3 | MONGO_PASSWORD=password
4 | MONGO_ADMIN_PASSWORD=password
5 | MONGO_DATABASE=showcase
6 | MONGO_HOST=
7 |
8 | ## MQTT
9 | MQTT_HOST=
10 | MQTT_PORT=
11 | MQTT_PASSWORD=
12 | MQTT_USERNAME=
13 | MQTT_PROTOCOL=
14 |
15 | # Hack to enable keycloak with self signed certs
16 | # don't do it in production
17 | NODE_TLS_REJECT_UNAUTHORIZED=0
18 |
19 | BACKUP_DEMO_DATA=false
20 | USE_DEMO_DATA=true
--------------------------------------------------------------------------------
/platform/client-admin/src/transformer/volunteerTransformer.ts:
--------------------------------------------------------------------------------
1 | import { VolunteerFieldsFragment } from "../dataFacade";
2 |
3 | export const volunteerTransformer = (volunteer: VolunteerFieldsFragment) => {
4 | // Restructure data
5 | if (volunteer.dateOfBirth) {
6 | volunteer.dateOfBirth = new Date(volunteer.dateOfBirth);
7 | }
8 | delete volunteer.__typename;
9 |
10 | return volunteer as VolunteerFieldsFragment;
11 | }
12 |
--------------------------------------------------------------------------------
/platform/client/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 | .vscode
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/platform/client-admin/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | /.pnp
6 | .pnp.js
7 |
8 | # testing
9 | /coverage
10 |
11 | # production
12 | /build
13 |
14 | # misc
15 | .DS_Store
16 | .env.local
17 | .env.development.local
18 | .env.test.local
19 | .env.production.local
20 | .vscode
21 |
22 | npm-debug.log*
23 | yarn-debug.log*
24 | yarn-error.log*
25 |
--------------------------------------------------------------------------------
/cli/types/commands/init.d.ts:
--------------------------------------------------------------------------------
1 | import { Argv } from 'yargs';
2 | declare type Params = {
3 | name?: string;
4 | templateName?: string;
5 | templateUrl: string;
6 | };
7 | export declare const command = "init ";
8 | export declare const desc = "Create project from available templates";
9 | export declare const builder: (args: Argv<{}>) => void;
10 | export declare function handler({ name, templateName, templateUrl }: Params): Promise;
11 | export {};
12 |
--------------------------------------------------------------------------------
/cli/dist/index.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | "use strict";
3 | exports.__esModule = true;
4 | var yargs = require("yargs");
5 | if (require.main === module) {
6 | // eslint-disable-next-line no-unused-expressions
7 | yargs
8 | .commandDir('commands')
9 | .demandCommand(1)
10 | .strict()
11 | .recommendCommands()
12 | .help()
13 | .alias('h', 'help')
14 | .version()
15 | .alias('v', 'version')
16 | .argv;
17 | }
18 |
--------------------------------------------------------------------------------
/cli/dist/utils/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | exports.__esModule = true;
3 | var chalk = require("chalk");
4 | var emoji = require("node-emoji");
5 | //tslint:disable-next-line: no-console
6 | exports.log = console.log;
7 | exports.logError = function (s) { return exports.log(emoji.emojify(chalk["default"].bold.red(s))); };
8 | exports.logInfo = function (s) { return exports.log(emoji.emojify(chalk["default"].bold(s))); };
9 | exports.logDetail = function (s) { return exports.log(emoji.emojify(chalk["default"].dim(s))); };
10 |
--------------------------------------------------------------------------------
/docs/client.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: client
3 | title: CLI commands
4 | ---
5 |
6 | # Open Volunteer Platform CLI
7 |
8 | The command-line tool (CLI) helps you bootstrap your Open Volunteer Platform template.
9 |
10 | ## Requirements
11 |
12 | * [Node.js 10.0.0](https://nodejs.org/en/download/) or later version
13 | * Docker and Docker compose
14 |
15 | ## Usage
16 |
17 | 1. Execute starter
18 |
19 | ```
20 | npx openvp init yourproject
21 | ```
22 | 2. Answer the question prompts and pick the template that suits your needs.
23 |
--------------------------------------------------------------------------------
/cli/src/init/templateMetadata.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Template name, description and Repository information
3 | */
4 | export interface Template {
5 | name: string
6 | description: string
7 | repo: TemplateRepository
8 | }
9 |
10 | /**
11 | * Github Repository information, uri, branch and path
12 | */
13 | export interface TemplateRepository {
14 | uri: string
15 | branch: string
16 | path: string
17 | }
18 |
19 | /**
20 | * name of example model, content
21 | */
22 | export interface GraphQLModel {
23 | name: string
24 | content: string
25 | }
--------------------------------------------------------------------------------
/platform/client/src/declarations.ts:
--------------------------------------------------------------------------------
1 | import { ApolloClient, InMemoryCache } from "@apollo/client";
2 |
3 | export interface IContainerProps {
4 | app: React.FC
5 | };
6 |
7 | export interface ILoadingProps {
8 | loading: boolean
9 | };
10 |
11 | export interface IUpdateMatchParams {
12 | id: string
13 | }
14 |
15 | export interface IAuthHeaders {
16 | headers: {
17 | Authorization: String
18 | }
19 | }
20 |
21 | export interface ILogoutParams {
22 | keycloak: Keycloak.KeycloakInstance | undefined,
23 | client: ApolloClient
} />;
33 | }
34 |
35 | return (
36 |
37 |
38 |
39 |
40 | {content}
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 | OpenVolunteer Platform
50 |
51 |
52 |
53 | );
54 |
55 | };
56 |
--------------------------------------------------------------------------------
/platform/client-admin/src/pages/RecipientsPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | IonPage,
4 | IonFooter,
5 | IonLoading,
6 | IonContent,
7 | IonIcon,
8 | IonFab,
9 | IonFabButton,
10 | } from '@ionic/react';
11 | import { Empty, Header } from '../components';
12 | import { RouteComponentProps } from 'react-router';
13 | import { useFindRecipientsQuery } from '../dataFacade';
14 | import { RecipientList } from '../components/model/RecipientList';
15 | import { add } from 'ionicons/icons';
16 |
17 | export const RecipientsPage: React.FC = ({ match }) => {
18 | let { data, loading, error } = useFindRecipientsQuery();
19 |
20 | if (error) {
21 | console.log(error);
22 | }
23 |
24 | if (loading) return ;
28 |
29 | let content;
30 | if (data?.findRecipients?.items.length !== 0) {
31 | content =
32 | } else {
33 | content = No data!} />;
34 | }
35 |
36 |
37 | return (
38 |
39 |
40 |
41 |
42 | {content}
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | OpenVolunteer Platform
52 |
53 |
54 |
55 | );
56 |
57 | };
58 |
--------------------------------------------------------------------------------
/platform/client-admin/src/components/model/Volunteer.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | IonItem,
4 | IonButton,
5 | IonLabel,
6 | IonBadge,
7 | IonIcon,
8 | IonButtons
9 | } from '@ionic/react';
10 | import { peopleOutline, open } from 'ionicons/icons';
11 | import { Link } from 'react-router-dom';
12 | import { VolunteerFieldsFragment } from '../../dataFacade';
13 |
14 | export const Volunteer: React.FC<{ volunteer: VolunteerFieldsFragment }> = ({ volunteer }) => {
15 |
16 | return (
17 |
18 |
19 |
20 | {volunteer.firstName} {volunteer.lastName}
21 |
22 | {volunteer.canDeliver &&
23 |
24 | Action Type
25 |
26 | Delivery
27 |
28 |
}
29 |
30 | Status
31 |
32 | {volunteer.active ? "Active" : "Inactive"}
33 |
34 |
35 |
36 | Actions Completed
37 |
38 | {volunteer.actionsCompleted}
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | );
54 |
55 | };
56 |
--------------------------------------------------------------------------------
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | jobs:
3 | build:
4 | working_directory: ~/aerogear
5 | docker:
6 | - image: circleci/node:lts
7 | steps:
8 | - checkout
9 | - restore_cache:
10 | key: dependency-cache-{{ checksum "client/package.json" }}-{{checksum "server/package.json"}}
11 | - run:
12 | name: install-dependencies
13 | command: yarn
14 | - run:
15 | name: install-package-dependencies
16 | command: yarn
17 | - save_cache:
18 | key: dependency-cache-{{ checksum "client/package.json" }}-{{checksum "server/package.json"}}
19 | paths:
20 | - ./node_modules
21 | - run:
22 | name: run build
23 | command: "yarn build"
24 |
25 | publish_container:
26 | docker:
27 | # image for building docker containers
28 | - image: circleci/node:lts
29 | steps:
30 | - checkout
31 | - run:
32 | name: install-dependencies
33 | command: yarn
34 | # special workaround to allow running docker in docker https://circleci.com/docs/2.0/building-docker-images/
35 | - setup_remote_docker:
36 | version: 17.05.0-ce
37 | - run: |
38 | yarn
39 | yarn prepare:client
40 | - run: |
41 | cd server
42 | TAG=$CIRCLE_TAG ../scripts/publish_container.sh
43 | workflows:
44 | version: 2
45 | build_and_release:
46 | jobs:
47 | - build:
48 | filters:
49 | tags:
50 | only: /.*/
51 | - publish_container:
52 | filters:
53 | tags:
54 | only: /.*/
55 | branches:
56 | only: ignored
57 |
58 |
59 |
--------------------------------------------------------------------------------
/platform/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "OVP-starter",
3 | "version": "1.0.0",
4 | "private": true,
5 | "description": "Mono repository for OVP Starter",
6 | "main": "index.js",
7 | "devDependencies": {
8 | "del-cli": "3.0.1",
9 | "graphback-cli": "0.16.2",
10 | "graphql": "15.3.0"
11 | },
12 | "scripts": {
13 | "start:server": "cd server && yarn start",
14 | "start:client": "cd client && yarn start",
15 | "build:server": "cd server && yarn build",
16 | "build:client": "cd client && yarn build",
17 | "removeQueries": "del ./client/src/graphql ; del ./client-admin/src/graphql",
18 | "build:clientGeneric": "cd client/ && yarn build:generic",
19 | "build:adminGeneric": "cd client-admin/ && yarn build:generic",
20 | "prepare:client": "del ./client/build ./server/website ; yarn build:clientGeneric && mv ./client/build/ ./server/website",
21 | "prepare:admin": "del ./client-admin/build ./server/admin ; yarn build:adminGeneric && mv ./client-admin/build/ ./server/admin",
22 | "build": "yarn workspaces run build",
23 | "unlock": "yarn workspaces run del package-lock.json && del yarn.lock",
24 | "clean": "yarn workspaces run del ./dist && del ./types",
25 | "walkthrough": "./scripts/create_walkthrough.sh",
26 | "generate:client": "cd client && yarn graphback generate && yarn graphql codegen",
27 | "generate:admin": "cd client-admin && yarn graphback generate && yarn graphql codegen",
28 | "generate:all": "yarn generate:client && yarn generate:admin",
29 | "prepare:all": "yarn prepare:client && yarn prepare:admin"
30 | },
31 | "workspaces": [
32 | "client",
33 | "client-admin",
34 | "server"
35 | ],
36 | "resolutions": {
37 | "@types/react": "16.9.49"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/platform/server/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ovp-server-starter",
3 | "version": "1.0.0",
4 | "private": true,
5 | "scripts": {
6 | "start": "ts-node src/index.ts",
7 | "startMQTT": "MQTT_HOST=127.0.0.1:1883 ts-node src/index.ts",
8 | "build": "tsc",
9 | "keycloak": "docker-compose -f ./integrations/keycloak/docker-compose.yml up",
10 | "keycloak:init": "node ./integrations/keycloak/initKeycloak.js",
11 | "mqtt": "docker-compose -f ./integrations/mqtt/docker-compose.yml up",
12 | "amq:config": "node ./integrations/mqtt/configureAMQ.js"
13 | },
14 | "license": "MIT",
15 | "devDependencies": {
16 | "@types/cors": "2.8.7",
17 | "@types/express": "4.17.0",
18 | "@types/node": "13.13.16",
19 | "keycloak-request-token": "0.1.0",
20 | "ts-node": "8.10.2",
21 | "ts-node-dev": "1.0.0-pre.62",
22 | "tslint": "6.1.3",
23 | "typescript": "3.9.7"
24 | },
25 | "dependencies": {
26 | "@aerogear/graphql-mqtt-subscriptions": "1.1.3",
27 | "@graphback/datasync": "0.16.2",
28 | "@graphback/keycloak-authz": "0.16.2",
29 | "@graphback/runtime-mongo": "0.16.2",
30 | "@graphql-tools/graphql-file-loader": "6.2.6",
31 | "@graphql-tools/load": "6.2.5",
32 | "@types/react": "16.9.49",
33 | "apollo-server-express": "2.17.0",
34 | "cors": "2.8.5",
35 | "dotenv": "8.2.0",
36 | "express": "4.17.1",
37 | "express-session": "1.17.1",
38 | "graphback": "0.16.2",
39 | "graphql": "15.3.0",
40 | "graphql-merge-resolvers": "1.1.16",
41 | "graphql-subscriptions": "1.1.0",
42 | "graphql-tag": "2.11.0",
43 | "keycloak-connect": "10.0.2",
44 | "keycloak-connect-graphql": "0.6.1",
45 | "mongo-seeding": "3.4.1",
46 | "mongodb": "3.6.1",
47 | "mongodb-backup": "1.6.9",
48 | "mongodb-restore": "1.6.2"
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/platform/client-admin/src/pages/ActionPage.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import {
3 | IonPage,
4 | IonFooter,
5 | IonLoading,
6 | IonContent,
7 | IonIcon,
8 | IonFab,
9 | IonFabButton
10 | } from '@ionic/react';
11 | import { Empty, ActionsList, Header } from '../components';
12 | import { RouteComponentProps } from 'react-router';
13 | import { useFindVolunteerActionsQuery } from '../dataFacade';
14 | import { add, filter } from 'ionicons/icons';
15 |
16 | export const ActionPage: React.FC = ({ match }) => {
17 | const { data, loading, error } = useFindVolunteerActionsQuery();
18 |
19 | if (error) {
20 | console.log(error);
21 | }
22 |
23 | if (loading) return ;
27 |
28 | let content;
29 | if (data?.findVolunteerActions?.items.length !== 0) {
30 | content =
31 | } else {
32 | content = No actions!} />;
33 | }
34 |
35 |
36 | return (
37 |
38 |
39 |
40 |
41 |
42 | {/* TODO add handling */}
43 |
44 |
45 |
46 |
47 | {content}
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 | OpenVolunteer Platform
57 |
58 |
59 |
60 | );
61 |
62 | };
63 |
--------------------------------------------------------------------------------
/website/src/css/custom.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable docusaurus/copyright-header */
2 | /**
3 | * Any CSS included here will be global. The classic template
4 | * bundles Infima by default. Infima is a CSS framework designed to
5 | * work well for content-centric websites.
6 | */
7 |
8 | /* You can override the default Infima variables here. */
9 | :root {
10 | --ifm-color-primary: #23246f;
11 | --ifm-color-primary-dark: #1e1f5e;
12 | --ifm-color-primary-darker: #202064;
13 | --ifm-color-primary-darkest: #23246f;
14 | --ifm-color-primary-light: #27287a;
15 | --ifm-color-primary-lighter: #282980;
16 | --ifm-color-primary-lightest: #2e2f90;
17 | --ifm-code-font-size: 95%;
18 | }
19 |
20 | #__docusaurus {
21 | position: relative;
22 | }
23 |
24 | .docusaurus-highlight-code-line {
25 | background-color: rgb(72, 77, 91);
26 | display: block;
27 | margin: 0 calc(-1 * var(--ifm-pre-padding));
28 | padding: 0 var(--ifm-pre-padding);
29 | }
30 |
31 | .navbar {
32 | box-shadow: none;
33 | }
34 |
35 | .button--rounded {
36 | border-radius: 2rem;
37 | }
38 |
39 | .hero .hero__title {
40 | text-align: center;
41 |
42 | line-height: 3rem;
43 | font-weight: 300;
44 |
45 | /* font-size: 5rem !important; */
46 | }
47 |
48 | .hero__subtitle {
49 | font-size: 3rem;
50 | font-weight: 600;
51 | /* font-size: 5rem !important; */
52 | }
53 |
54 | .hide-modal {
55 | opacity: 0 !important;
56 | visibility: hidden !important;
57 | }
58 |
59 | .hidden {
60 | visibility: hidden;
61 | }
62 |
63 | .card-anchor {
64 | color: #222;
65 | }
66 |
67 | .card-ancher:hover {
68 | text-decoration: none;
69 | }
70 |
71 | a.card-anchor:hover > .card-demo > .card {
72 | border: transparent;
73 | box-shadow: 0 1px 2px -2px rgba(0, 0, 0, 0.16), 0 3px 6px 0 rgba(0, 0, 0, 0.12), 0 5px 12px 4px rgba(0, 0, 0, 0.09);
74 | }
75 |
76 | .footer.footer--dark {
77 | background: #00003C !important;
78 | }
--------------------------------------------------------------------------------
/platform/client/src/theme/styles.css:
--------------------------------------------------------------------------------
1 | .list-md {
2 | padding: 0;
3 | }
4 |
5 | .task-item {
6 | padding-bottom: 0;
7 | }
8 |
9 | .item ion-label {
10 | overflow: visible;
11 | white-space: pre-wrap;
12 | }
13 |
14 | ion-note {
15 | padding: 10px;
16 | line-height: 21px;
17 | white-space: pre-wrap;
18 | }
19 |
20 | ion-badge {
21 | vertical-align: middle;
22 | white-space: pre-line;
23 | text-align: left;
24 | }
25 |
26 | ion-footer div {
27 | margin: 10px;
28 | }
29 |
30 | .create-button {
31 | margin-left:15px;
32 | z-index: 9999;
33 | }
34 |
35 | .trash-button {
36 | margin-left:5px;
37 | z-index: 9999;
38 | }
39 |
40 | .network-badge {
41 | float: right;
42 | height: calc(2.1em + 4px);
43 | font-size: 13px;
44 | text-transform: uppercase;
45 | vertical-align: middle;
46 | line-height: calc(2.1em + 4px);
47 | --padding-top: 0;
48 | --padding-bottom: 0;
49 | --padding-start: 0.9em;
50 | --padding-end: 0.9em;
51 | }
52 |
53 | .offline-queue-button {
54 | -webkit-margin-start: 0px;
55 | margin-inline-start: 0px;
56 | }
57 |
58 | .offline-queue-badge {
59 | margin-left: -7px;
60 | vertical-align: top;
61 | }
62 |
63 | .task-item {
64 | padding-bottom: 0;
65 | }
66 |
67 | .list-md {
68 | padding: 0;
69 | }
70 |
71 | .item .sc-ion-label-md-h {
72 | overflow: visible;
73 | white-space: pre-wrap;
74 | }
75 |
76 | ion-note {
77 | padding: 10px;
78 | line-height: 21px;
79 | white-space: pre-wrap;
80 | }
81 |
82 | ion-badge {
83 | vertical-align: middle;
84 | white-space: pre-line;
85 | text-align: left;
86 | }
87 |
88 | .queue-empty {
89 | height: 100%;
90 | display: flex;
91 | align-items: center;
92 | text-align: center;
93 | }
94 |
95 | .queue-empty p {
96 | line-height: 150%
97 | }
98 |
99 | .submit-btn {
100 | margin-top: 30px;
101 | }
--------------------------------------------------------------------------------
/platform/client-admin/src/theme/styles.css:
--------------------------------------------------------------------------------
1 | .list-md {
2 | padding: 0;
3 | }
4 |
5 | .task-item {
6 | padding-bottom: 0;
7 | }
8 |
9 | .item ion-label {
10 | overflow: visible;
11 | white-space: pre-wrap;
12 | }
13 |
14 | ion-note {
15 | padding: 10px;
16 | line-height: 21px;
17 | white-space: pre-wrap;
18 | }
19 |
20 | ion-badge {
21 | vertical-align: middle;
22 | white-space: pre-line;
23 | text-align: left;
24 | }
25 |
26 | ion-footer div {
27 | margin: 10px;
28 | }
29 |
30 | .create-button {
31 | margin-left:15px;
32 | z-index: 9999;
33 | }
34 |
35 | .trash-button {
36 | margin-left:5px;
37 | z-index: 9999;
38 | }
39 |
40 | .network-badge {
41 | float: right;
42 | height: calc(2.1em + 4px);
43 | font-size: 13px;
44 | text-transform: uppercase;
45 | vertical-align: middle;
46 | line-height: calc(2.1em + 4px);
47 | --padding-top: 0;
48 | --padding-bottom: 0;
49 | --padding-start: 0.9em;
50 | --padding-end: 0.9em;
51 | }
52 |
53 | .offline-queue-button {
54 | -webkit-margin-start: 0px;
55 | margin-inline-start: 0px;
56 | }
57 |
58 | .offline-queue-badge {
59 | margin-left: -7px;
60 | vertical-align: top;
61 | }
62 |
63 | .task-item {
64 | padding-bottom: 0;
65 | }
66 |
67 | .list-md {
68 | padding: 0;
69 | }
70 |
71 | .item .sc-ion-label-md-h {
72 | overflow: visible;
73 | white-space: pre-wrap;
74 | }
75 |
76 | ion-note {
77 | padding: 10px;
78 | line-height: 21px;
79 | white-space: pre-wrap;
80 | }
81 |
82 | ion-badge {
83 | vertical-align: middle;
84 | white-space: pre-line;
85 | text-align: left;
86 | }
87 |
88 | .queue-empty {
89 | height: 100%;
90 | display: flex;
91 | align-items: center;
92 | text-align: center;
93 | }
94 |
95 | .queue-empty p {
96 | line-height: 150%
97 | }
98 |
99 | .submit-btn {
100 | margin-top: 30px;
101 | }
--------------------------------------------------------------------------------
/website/src/components/Video/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import classnames from 'classnames';
3 | import useBaseUrl from '@docusaurus/useBaseUrl';
4 | import styles from './styles.module.css';
5 |
6 | function VideoModal({ open, close}) {
7 | console.log(open);
8 | return (
9 |
10 |
11 |
close
12 |
13 |
14 |
26 |
27 |
28 |
29 | );
30 | }
31 |
32 | export function Video() {
33 | const [open, setOpen] = useState(false);
34 |
35 | const toggleModal = (event) => {
36 | event.preventDefault();
37 | setOpen(!open);
38 | }
39 |
40 | return (
41 | <>
42 |
43 |
44 |
45 |
Open Volunteer Platform in 10 minutes
46 |
52 |
53 |
54 | >
55 | );
56 | }
--------------------------------------------------------------------------------
/platform/client-admin/src/pages/ProfilePage.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import {
3 | IonContent,
4 | IonCard,
5 | IonCardHeader,
6 | IonCardTitle,
7 | IonCardSubtitle,
8 | IonCardContent,
9 | IonItemGroup,
10 | IonItemDivider,
11 | IonList,
12 | } from '@ionic/react';
13 | import { Header } from '../components';
14 | import { AuthContext } from '../context/AuthContext';
15 | import { RouteComponentProps } from 'react-router';
16 |
17 | import adminForm from '../forms/admin';
18 | import { AutoForm, AutoFields, ErrorsField } from 'uniforms-ionic'
19 |
20 | export const ProfilePage: React.FC = ({ match }) => {
21 | let { keycloak, profile } = useContext(AuthContext);
22 |
23 | if (!keycloak || !profile) return (
24 |
25 |
26 | Authentication not configured
27 | IDM service required
28 |
29 |
30 | Profile page cannot be displayed.
31 | Please enable Auth SDK by providing configuration pointing to your IDM service
32 |
33 |
34 | );
35 |
36 | return (
37 | <>
38 |
39 |
40 |
41 |
42 |
43 |
44 | Admin user information
45 |
46 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | >
60 | );
61 |
62 | };
63 |
--------------------------------------------------------------------------------
/platform/client-admin/src/components/Menu.css:
--------------------------------------------------------------------------------
1 | ion-menu ion-content {
2 | --padding-top: 20px;
3 | --padding-bottom: 20px;
4 |
5 | --background: var(--ion-item-background, var(--ion-background-color, #fff));
6 | }
7 |
8 | /* Remove background transitions for switching themes */
9 | ion-menu ion-item {
10 | --transition: none;
11 | }
12 |
13 | ion-item.selected {
14 | --color: var(--ion-color-primary);
15 | }
16 |
17 | /*
18 | * Material Design Menu
19 | */
20 | ion-menu.md ion-list {
21 | padding: 20px 0;
22 | }
23 |
24 | ion-menu.md ion-list-header {
25 | padding-left: 18px;
26 | padding-right: 18px;
27 |
28 | text-transform: uppercase;
29 | letter-spacing: .1em;
30 | font-weight: 450;
31 | }
32 |
33 | ion-menu.md ion-item {
34 | --padding-start: 18px;
35 |
36 | margin-right: 10px;
37 |
38 | border-radius: 0 50px 50px 0;
39 |
40 | font-weight: 500;
41 | }
42 |
43 | ion-menu.md ion-item.selected {
44 | --background: rgba(var(--ion-color-primary-rgb), 0.14);
45 | }
46 |
47 | ion-menu.md ion-item.selected ion-icon {
48 | color: var(--ion-color-primary);
49 | }
50 |
51 | ion-menu.md ion-list-header,
52 | ion-menu.md ion-item ion-icon {
53 | color: var(--ion-color-step-650, #5f6368);
54 | }
55 |
56 | ion-menu.md ion-list:not(:last-of-type) {
57 | border-bottom: 1px solid var(--ion-color-step-150, #d7d8da);
58 | }
59 |
60 |
61 | /*
62 | * iOS Menu
63 | */
64 | ion-menu.ios ion-list-header {
65 | padding-left: 16px;
66 | padding-right: 16px;
67 |
68 | margin-bottom: 8px;
69 | }
70 |
71 | ion-menu.ios ion-list {
72 | padding: 20px 0 0;
73 | }
74 |
75 | ion-menu.ios ion-item {
76 | --padding-start: 16px;
77 | --min-height: 50px;
78 | }
79 |
80 | ion-menu.ios ion-item ion-icon {
81 | font-size: 24px;
82 | color: #73849a;
83 | }
84 |
85 | ion-menu.ios ion-item.selected ion-icon {
86 | color: var(--ion-color-primary);
87 | }
88 |
89 | ion-col > div {
90 | background-color: #f7f7f7;
91 | border: solid 5px #ddd;
92 | padding: 60px;
93 | }
94 |
--------------------------------------------------------------------------------
/docs/clientref.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: clientref
3 | title: Mobile and Admin Apps
4 | ---
5 | # React Client
6 |
7 | React Web implementation for the Open Volunteer Platform
8 |
9 | ## Getting Started
10 |
11 | * [Running the Client in Developer Mode](#Running-the-Client-in-Developer-Mode)
12 | * [Adding Keycloak Integration to the Client](#Adding-Keycloak-Integration-to-the-Client)
13 | * [Customizing the Action Reports Grid](#Customizing-the-Action-Reports-Grid)
14 | * [Customizing Action Report Nearby Distance](#Customizing-Action-Report-Nearby-Distance)
15 |
16 | **Requirements:**
17 |
18 | * [Node.js 12.x](https://nodejs.org/en/download/current/) or later version
19 | * Keycloak server (_Optional_)
20 |
21 | ### Running the Client in Developer Mode
22 |
23 | 1. Install Ionic
24 |
25 | ```shell
26 | npm install -g @ionic/cli
27 | ```
28 |
29 | 2. Install dependencies
30 |
31 | ```shell
32 | npm install
33 | ```
34 |
35 | 3. Start the app
36 |
37 | ```shell
38 | npm run dev
39 | ```
40 |
41 | ### Adding Keycloak Integration to the Client
42 |
43 | Rename the `keycloak.example.json` to `keycloak.json` and update the fields accordingly.
44 |
45 |
46 | ```
47 | {
48 | "realm": "",
49 | "auth-server-url": "https://your-server/auth",
50 | "ssl-required": "none",
51 | "resource": "",
52 | "public-client": true,
53 | "use-resource-role-mappings": true,
54 | "confidential-port": 0
55 | }
56 | ```
57 |
58 | ### Customizing the Action Reports Grid
59 |
60 | * Column size can be customized by using the `REACT_APP_REPORT_COLUMN_SIZE` environment variable.
61 | * This value can be changed in the `.env` file.
62 | * The default value is `4`.
63 |
64 |
65 | ### Customizing Action Report Nearby Distance
66 |
67 | * Nearby distance to calculate actions reports depending on closeness of recipient location can be customized via `REACT_APP_NEARBY_MAX_DISTANCE` environment variable.
68 | * This value can be changed in `.env` file.
69 | * The default value is `100` km.*
70 |
--------------------------------------------------------------------------------
/website/src/components/Features/styles.module.css:
--------------------------------------------------------------------------------
1 | /* stylelint-disable docusaurus/copyright-header */
2 | /**
3 | * CSS files with the .module.css suffix will be treated as CSS modules
4 | * and scoped locally.
5 | */
6 |
7 | .splitContainer {
8 | height: 450vh;
9 | width: 100%;
10 | display: block;
11 | }
12 |
13 | .leftSplit,
14 | .rightSplit {
15 | padding-left: var(--ifm-spacing-horizontal);
16 | padding-right: var(--ifm-spacing-horizontal);
17 | }
18 |
19 | .leftSplit {
20 | height: 100vh;
21 | width: 50%;
22 | float: left;
23 | display: flex;
24 | justify-content: center;
25 | align-items: center;
26 | background-color: #1B1E59;
27 | color: #fff;
28 | /* padding: ; */
29 | }
30 |
31 | .featureSticky {
32 | position: sticky;
33 | top: 0;
34 | }
35 |
36 | .stickyContent {
37 | max-width: calc(var(--ifm-container-width)/3);
38 | margin-left: auto;
39 | margin-right: auto;
40 | }
41 |
42 | .rightSplit {
43 | float: right;
44 | width: 50%;
45 | /* background-image: linear-gradient(150deg, #686BA6, #1B1E59) */
46 | background-image: linear-gradient(150deg, #e535ab, #1B1E59)
47 | }
48 |
49 | .splitRow {
50 | height: 100vh;
51 | display: flex;
52 | justify-content: center;
53 | align-items: center;
54 | max-width: calc(var(--ifm-container-width)/3);
55 | margin-left: auto;
56 | margin-right: auto;
57 | color: #fff;
58 | }
59 |
60 | .splitRow.before,
61 | .splitRow.after {
62 | height: 75vh;
63 | }
64 |
65 | @media screen and (max-width: 966px) {
66 | .splitContainer {
67 | height: 100%;
68 | }
69 | .leftSplit, .rightSplit {
70 | width: 100%;
71 | }
72 |
73 | .leftSplit, .splitRow {
74 | height: 50vh;
75 | }
76 |
77 | .splitRow.before,
78 | .splitRow.after {
79 | display: none;
80 | height: 25vh;
81 | }
82 |
83 | }
84 |
85 | .featureImage {
86 | /* height: 200px; */
87 | width: 200px;
88 | margin-bottom: 1rem;
89 | }
90 |
91 | .featureTitle {
92 | font-size: 2rem;
93 | font-weight: 600;
94 | }
--------------------------------------------------------------------------------
/cli/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "openvp",
3 | "version": "0.5.1",
4 | "description": "Command line tool for Open Voluteer Platform",
5 | "main": "dist/index.js",
6 | "bin": {
7 | "openvp": "dist/index.js"
8 | },
9 | "types": "types/index.d.ts",
10 | "typescript": {
11 | "definition": "types/index.d.ts"
12 | },
13 | "author": "wtrocki@redhat.com",
14 | "scripts": {
15 | "clean": "rimraf coverage dist types",
16 | "build": "tsc",
17 | "cmdinit": "ts-node ./dist/index.js init test",
18 | "watch": "tsc -w",
19 | "lint": "eslint -t stylish --project \"tsconfig.json\"",
20 | "test": "jest"
21 | },
22 | "engines": {
23 | "node": "14.9.0"
24 | },
25 | "devDependencies": {
26 | "@types/chalk": "0.4.31",
27 | "@types/inquirer": "6.5.0",
28 | "@types/jest": "25.2.3",
29 | "@types/js-yaml": "3.12.5",
30 | "@types/node": "12.12.55",
31 | "@types/node-emoji": "1.8.1",
32 | "@types/through": "0.0.30",
33 | "@types/yargs": "15.0.5",
34 | "jest": "26.6.3",
35 | "lint-staged": "10.3.0",
36 | "ncp": "2.0.0",
37 | "rimraf": "3.0.2",
38 | "ts-jest": "25.5.1",
39 | "ts-node": "8.10.2",
40 | "tsutils": "3.17.1",
41 | "typescript": "3.9.7",
42 | "typescript-eslint-parser": "21.0.2"
43 | },
44 | "dependencies": {
45 | "chalk": "2.4.2",
46 | "chokidar": "3.4.2",
47 | "debounce": "1.2.0",
48 | "execa": "4.0.3",
49 | "figlet": "1.5.0",
50 | "glob": "7.1.6",
51 | "inquirer": "7.3.3",
52 | "node-emoji": "1.10.0",
53 | "ora": "3.4.0",
54 | "parse-github-url": "1.0.2",
55 | "request": "2.88.2",
56 | "tar": "6.0.5",
57 | "tmp": "0.2.1",
58 | "yargs": "15.4.1"
59 | },
60 | "jest": {
61 | "transform": {
62 | "^.+\\.tsx?$": "/node_modules/ts-jest/preprocessor.js"
63 | },
64 | "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$",
65 | "moduleFileExtensions": [
66 | "ts",
67 | "tsx",
68 | "js",
69 | "json",
70 | "jsx"
71 | ]
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/docs/gettingstarted.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: gettingstarted
3 | title: Introduction to OpenVolunteerPlatform
4 | sidebar_label: Overview
5 | ---
6 |
7 | Open Platform for Rapid Development of Volunteer Management Systems
8 |
9 | ## Motivation
10 |
11 | The OpenVolunteerPlatform allows you to automate and optimize volunteer work for your
12 | organization or charity so that volunteers can deliver help when needed.
13 |
14 | Platform helps connect people in need with volunteers who can provide support, while adhering to social-distancing measures. It keeps individuals safe and out of danger, while alleviating the pressure on public services, the healthcare infrastructure, and other services that provide essentials to those in need during crisis.
15 |
16 | Platform facilitates organizational flexibility by offering a ready to use reference implementation
17 | containing volunteer and admin applications, as well as tools to organize and schedule volunteer work.
18 | It eases the customization of reference implementations for your own use cases and integrations, by using an autogenerated and secure backend along with client-side components that wrap your data.
19 |
20 | By empowering communities to collaborate through software, our volunteers can easily organize the collection and delivery of goods while practicing effective social distancing.
21 |
22 | For more information watch our motivation video:
23 |
24 | [](https://www.youtube.com/watch?v=mu9Rnu6Q9_o)
25 |
26 | Open Volunteer in action:
27 |
28 | [](https://www.youtube.com/watch?v=_cn_ZoZLq5g)
29 |
30 |
31 | Are you interested in deploying OpenVolunteer for your organization
32 | feel free to reach out to us for free training sessions.
33 |
34 | ## Reference implementation
35 |
36 | 
37 |
38 | OpenVolunteerPlatform provides reference admin and volunteer applications that can be used to help on a national or regional scale.
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/platform/server/src/graphql.ts:
--------------------------------------------------------------------------------
1 | import { resolve } from 'path';
2 | import { connect } from './db';
3 | import { Config } from './config/config';
4 | import { ApolloServer, ApolloServerExpressConfig } from "apollo-server-express";
5 | import { Express } from "express";
6 | import customResolvers from './resolvers/custom-resolvers';
7 | import { buildKeycloakApolloConfig } from './auth';
8 | import { createKeycloakCRUDService } from './CrudService'
9 | import { GraphQLFileLoader } from '@graphql-tools/graphql-file-loader'
10 | import { loadSchemaSync } from '@graphql-tools/load'
11 | import { buildGraphbackAPI } from "graphback"
12 | import { createMongoDbProvider } from "@graphback/runtime-mongo"
13 | import { authConfig } from './config/auth';
14 | import GMR from 'graphql-merge-resolvers';
15 |
16 | /**
17 | * Creates Apollo server
18 | */
19 | export const createApolloServer = async function (app: Express, config: Config) {
20 | const db = await connect(config);
21 |
22 | const modelDefs = loadSchemaSync(resolve(__dirname, '../model/main.graphql'), {
23 | loaders: [
24 | new GraphQLFileLoader()
25 | ]
26 | })
27 |
28 | const { typeDefs, resolvers, contextCreator } = buildGraphbackAPI(modelDefs, {
29 | serviceCreator: createKeycloakCRUDService(authConfig),
30 | dataProviderCreator: createMongoDbProvider(db)
31 | });
32 | // TODO enable custom resolvers
33 | const mergedResolvers: any = GMR.merge([resolvers, customResolvers]);
34 | let apolloConfig: ApolloServerExpressConfig = {
35 | typeDefs: typeDefs,
36 | resolvers: mergedResolvers,
37 | playground: true,
38 | context: (context) => {
39 | return {
40 | ...contextCreator(context),
41 | db: db
42 | }
43 | }
44 | }
45 |
46 | if (config.keycloakConfig) {
47 | apolloConfig = buildKeycloakApolloConfig(app, apolloConfig)
48 | }
49 |
50 | const apolloServer = new ApolloServer(apolloConfig)
51 | apolloServer.applyMiddleware({ app });
52 |
53 | return apolloServer;
54 | }
55 |
--------------------------------------------------------------------------------
/platform/client/src/components/Router.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import {
3 | HashRouter as AppRouter,
4 | Switch,
5 | Redirect,
6 | Route,
7 | } from 'react-router-dom';
8 | import { IonApp } from '@ionic/react';
9 | import { ActionPage, ProfilePage } from '../pages';
10 | import { ViewActionPage } from '../pages/ViewActionPage';
11 | import { AuthContext, AuthContextProvider } from '../context/AuthContext';
12 | import { useFindActiveVolunteerLazyQuery, VolunteerFieldsFragment } from '../dataFacade';
13 | import { Loading } from './Loading';
14 | import { volunteerTransformer } from '../transformer/volunteerTransformer';
15 |
16 | export const Router: React.FC = () => {
17 | const { profile, keycloak } = useContext(AuthContext);
18 |
19 | let [findVolunteerQuery, { data, loading, error, called }] = useFindActiveVolunteerLazyQuery({
20 | fetchPolicy: "network-only"
21 | });
22 |
23 | if (loading) {
24 | return ;
25 | }
26 |
27 | if (error) {
28 | console.log(`Error when fetching user ${error}`)
29 | return (<>`Error`>)
30 | }
31 |
32 | if (profile?.username && !called) {
33 | findVolunteerQuery({ variables: { username: profile?.username } });
34 | }
35 |
36 | let volunteer: VolunteerFieldsFragment | undefined;
37 |
38 |
39 | if (data?.findVolunteers?.items.length === 1 && data?.findVolunteers.items[0]) {
40 | volunteer = volunteerTransformer(data.findVolunteers.items[0]);
41 | }
42 |
43 | return (
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 | volunteer ?
52 | :
53 | } />
54 |
55 |
56 |
57 |
58 | );
59 | }
--------------------------------------------------------------------------------
/platform/client-admin/src/keycloakAuth.ts:
--------------------------------------------------------------------------------
1 | import Keycloak, { KeycloakInstance } from 'keycloak-js';
2 |
3 | export let keycloak: KeycloakInstance | undefined;
4 |
5 | /**
6 | * Get keycloak instance
7 | *
8 | * @return an initiated keycloak instance or `undefined`
9 | * if keycloak isn't configured
10 | *
11 | */
12 | export const getKeycloakInstance = async () => {
13 | if (!keycloak) await init();
14 | return keycloak;
15 | }
16 |
17 | /**
18 | * Initiate keycloak instance.
19 | *
20 | * Set keycloak to undefined if
21 | * keycloak isn't configured
22 | *
23 | */
24 | export const init = async () => {
25 | try {
26 | keycloak = new (Keycloak as any )();
27 | if (keycloak) {
28 | await keycloak.init({
29 | onLoad: 'login-required'
30 | });
31 | }
32 | } catch {
33 | keycloak = undefined;
34 | console.warn('Auth: Unable to initialize keycloak. Client side will not be configured to use authentication');
35 | }
36 | }
37 |
38 |
39 | /**
40 | * This function keeps getting called by wslink
41 | * connection param function, so carry out
42 | * an early return if keycloak is not initialized
43 | * otherwise get the auth token
44 | *
45 | * @return authorization header or empty string
46 | *
47 | */
48 | export const getAuthHeader = async () => {
49 | if (!keycloak) return '';
50 | return {
51 | 'authorization': `Bearer ${await getKeyCloakToken()}`
52 | };
53 | };
54 |
55 |
56 | /**
57 | * Use keycloak update token function to retrieve
58 | * keycloak token
59 | *
60 | * @return keycloak token or empty string if keycloak
61 | * isn't configured
62 | *
63 | */
64 | const getKeyCloakToken = async () => {
65 | await keycloak?.updateToken(50);
66 | if (keycloak?.token) return keycloak.token;
67 | console.error('No keycloak token available');
68 | return '';
69 | }
70 |
71 | /**
72 | * logout of keycloak then redirect to keycloak login page
73 | *
74 | * @param keycloak the keycloak instance
75 | *
76 | */
77 | export const logout = async (keycloak: Keycloak.KeycloakInstance | undefined) => {
78 | if(keycloak) {
79 | await keycloak.logout();
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/website/src/components/Hero/index.jsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import classnames from 'classnames';
3 | import components from '@theme/MDXComponents';
4 | import useBaseUrl from '@docusaurus/useBaseUrl';
5 | import Link from '@docusaurus/Link';
6 | import styles from './styles.module.css';
7 |
8 | export function Hero({ siteConfig }) {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |

16 |
17 |
{siteConfig.tagline}
18 |
19 | - Open Platform for Rapid Development of Volunteer Management Systems
20 | - Reference implementation to cover most of the use cases
21 | - Out of the box, GraphQL Compliant API
22 | - Components for Dynamic Forms and Maps
23 | - Keycloak based security and Role Based Authentication
24 | - Live updates using GraphQL subscriptions
25 |
26 |
27 |
33 | Get Started
34 |
35 |
36 |
37 | {/*
38 |
39 |
40 |
41 | {
42 | `${require('!!raw-loader!../../schema/datamodel.gql').default}`
43 | }
44 |
45 |
46 |
47 |
*/}
48 |
49 |
50 |
51 | );
52 | }
--------------------------------------------------------------------------------
/platform/client/src/pages/ActionPage.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext } from 'react';
2 | import {
3 | IonPage,
4 | IonSegment,
5 | IonSegmentButton,
6 | IonLabel,
7 | IonFooter,
8 | IonLoading,
9 | IonContent
10 | } from '@ionic/react';
11 | import { Empty, ActionsList, Header } from '../components';
12 | import { RouteComponentProps } from 'react-router';
13 | import { useFindMyVolunteerActionsLazyQuery, ActionStatus } from '../dataFacade';
14 | import { AuthContext } from '../context/AuthContext';
15 |
16 | export const ActionPage: React.FC = ({ match }) => {
17 | const { volunteer } = useContext(AuthContext);
18 | let [findActions, { data, loading, error, called, refetch }] = useFindMyVolunteerActionsLazyQuery({ fetchPolicy: "network-only" })
19 |
20 | if (volunteer && !called) {
21 | findActions({ variables: { volunteerId: volunteer._id, status: ActionStatus.Assigned } })
22 | }
23 | if (error) {
24 | console.log(error);
25 | }
26 |
27 | if (loading) return ;
31 |
32 | let content;
33 | if (data?.findVolunteerActions?.items.length !== 0) {
34 | content =
35 | } else {
36 | content = No actions assigned to you! You will be notified about new actions soon} />;
37 | }
38 |
39 | const updateFilter = (e: CustomEvent) => {
40 | if (volunteer && refetch) {
41 | refetch({ volunteerId: volunteer._id, status: e.detail.value })
42 | }
43 | }
44 |
45 |
46 | return (
47 |
48 |
49 |
50 |
51 |
52 | Open Actions
53 |
54 |
55 | Finished Actions
56 |
57 |
58 | {content}
59 |
60 |
61 |
62 | OpenVolunteer Platform
63 |
64 |
65 |
66 | );
67 |
68 | };
69 |
--------------------------------------------------------------------------------
/platform/.openshift/README.md:
--------------------------------------------------------------------------------
1 | ## OpenShift templates
2 |
3 | ### Starter App template
4 |
5 | Name: `datasync-app-template.yml`
6 |
7 | This template starts datasync container on top of the mongodb instances:
8 |
9 | #### Prerequisites
10 |
11 | 1. Running MongoDB instance
12 | 2. Connection details to MongoDB server
13 |
14 | #### Steps
15 |
16 | 1. Add template to your openshift
17 | 2. Provide MongoDB connection details
18 | 3. Wait for the pods to start
19 |
20 | # Deploying Server with AMQ
21 |
22 | Prerequisites
23 |
24 | * AMQ Online is installed in the cluster
25 |
26 |
27 | This section describes how to deploy the application in an OpenShift cluster by using the supplied `amq-topics.yml` template file.
28 | * The template is already prefilled with all of the necessary values that can be inspected
29 | * The only field you might want to change is `AMQ Messaging User Password`.
30 | * The default value is `Password1` in base64 encoding
31 | * The value *must* be base64 encoded
32 | * A custom value can be created in the terminal using `$ echo | base64`
33 | * Execute template on your openshift instance by `oc process -f amq-topics.yml | oc create -f -`
34 |
35 | The hostname for the AMQ Online Broker is only made available after the resources from the the template have been provisioned. One more step is needed to supply extra environment variables to running server.
36 |
37 | * From the terminal, ensure you have the correct namespace selected.
38 |
39 | ```
40 | oc project
41 | ```
42 |
43 | * Update the deployment to add the `MQTT_HOST` variable.
44 |
45 | ```
46 | oc get addressspace datasync -o jsonpath='{.status.endpointStatuses[?(@.name=="messaging")].serviceHost}'
47 | ```
48 |
49 | If you want to use service outside the OpenShift cluster please request external URL:
50 | ```
51 | oc get addressspace datasync -o jsonpath='{.status.endpointStatuses[?(@.name=="messaging")].externalHost}'
52 | ```
53 |
54 | Provide set of the environment variables required to connect to the running AMQ
55 |
56 | ```
57 | MQTT_HOST=messaging-nj2y0929dk-redhat-rhmi-amq-online.apps.youropenshift.io
58 | MQTT_PORT=443
59 | MQTT_PASSWORD=Password1
60 | MQTT_USERNAME=messaging-user
61 | MQTT_PROTOCOL=tls
62 | ```
63 |
64 | Check `../server/.env` file for all available variables
65 |
--------------------------------------------------------------------------------
/platform/client/src/components/Header.tsx:
--------------------------------------------------------------------------------
1 | import React, { useContext, useState } from 'react';
2 | import { IonHeader, IonToolbar, IonButtons, IonTitle, IonToast, IonButton, IonIcon } from '@ionic/react';
3 | import { person, exit, arrowBack } from 'ionicons/icons';
4 | import { AuthContext } from '../context/AuthContext';
5 | import { logout } from '../keycloakAuth';
6 | import { Link } from 'react-router-dom';
7 | import { useApolloClient } from "@apollo/client"
8 |
9 | export const Header: React.FC<{ title: string, backHref?: string, match: any }> = ({ title, backHref, match }) => {
10 |
11 | const { url } = match;
12 | const client = useApolloClient();
13 | const { keycloak } = useContext(AuthContext);
14 | const [showToast, setShowToast] = useState(false);
15 |
16 | const handleLogout = async () => {
17 | await logout({ keycloak, client });
18 | }
19 |
20 | // if keycloak is not configured, don't display logout and
21 | // profile icons. Only show login and profile icons on the home
22 | // screen
23 | const buttons = (!keycloak || url !== '/actions') ? <>> : (
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 | );
35 |
36 | return (
37 | <>
38 |
39 |
40 | {
41 | url !== '/actions' &&
42 |
47 |
48 |
49 |
50 |
51 |
52 |
53 | }
54 | {title}
55 | {buttons}
56 |
57 |
58 | setShowToast(false)}
61 | message="You are currently offline. Unable to logout."
62 | position="top"
63 | color="danger"
64 | duration={1000}
65 | />
66 | >
67 | );
68 | };
69 |
--------------------------------------------------------------------------------
/platform/client/src/keycloakAuth.ts:
--------------------------------------------------------------------------------
1 | import Keycloak, { KeycloakInstance } from 'keycloak-js';
2 | import { ILogoutParams } from './declarations';
3 |
4 | export let keycloak: KeycloakInstance | undefined;
5 |
6 | /**
7 | * Get keycloak instance
8 | *
9 | * @return an initiated keycloak instance or `undefined`
10 | * if keycloak isn't configured
11 | *
12 | */
13 | export const getKeycloakInstance = async () => {
14 | if (!keycloak) await init();
15 | return keycloak;
16 | }
17 |
18 | /**
19 | * Initiate keycloak instance.
20 | *
21 | * Set keycloak to undefined if
22 | * keycloak isn't configured
23 | *
24 | */
25 | export const init = async () => {
26 | try {
27 | keycloak = new (Keycloak as any )();
28 | if (keycloak) {
29 | await keycloak.init({
30 | onLoad: 'login-required'
31 | });
32 | }
33 | } catch {
34 | keycloak = undefined;
35 | console.warn('Auth: Unable to initialize keycloak. Client side will not be configured to use authentication');
36 | }
37 | }
38 |
39 |
40 | /**
41 | * This function keeps getting called by wslink
42 | * connection param function, so carry out
43 | * an early return if keycloak is not initialized
44 | * otherwise get the auth token
45 | *
46 | * @return authorization header or empty string
47 | *
48 | */
49 | export const getAuthHeader = async () => {
50 | if (!keycloak) return '';
51 | return {
52 | 'authorization': `Bearer ${await getKeyCloakToken()}`
53 | };
54 | };
55 |
56 |
57 | /**
58 | * Use keycloak update token function to retrieve
59 | * keycloak token
60 | *
61 | * @return keycloak token or empty string if keycloak
62 | * isn't configured
63 | *
64 | */
65 | const getKeyCloakToken = async () => {
66 | await keycloak?.updateToken(50);
67 | if (keycloak?.token) return keycloak.token;
68 | console.error('No keycloak token available');
69 | return '';
70 | }
71 |
72 | /**
73 | * logout of keycloak, clear cache and offline store then redirect to
74 | * keycloak login page
75 | *
76 | * @param keycloak the keycloak instance
77 | * @param client offix client
78 | *
79 | */
80 | export const logout = async ({ keycloak, client: apolloClient } : ILogoutParams) => {
81 | if(keycloak) {
82 | await keycloak.logout();
83 | // clear offix client offline store
84 | await apolloClient.resetStore();
85 | // clear offix client cache
86 | await apolloClient.cache.reset();
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/platform/client-admin/src/pages/SchedulePage.tsx:
--------------------------------------------------------------------------------
1 | import React, { useState } from 'react';
2 | import { useFindDailyActionPlansQuery, useAssignVolunteersMutation } from '../dataFacade';
3 | import { IonLoading, IonPage, IonContent, IonFooter, IonItemDivider, IonCard, IonButton } from '@ionic/react';
4 | import { Header } from '../components';
5 | import dailyActionForm from '../forms/dailyAction'
6 | import { RouteComponentProps } from 'react-router-dom';
7 | import { AutoForm, AutoFields, ErrorsField } from 'uniforms-ionic';
8 |
9 | export const SchedulePage: React.FC = ({ match }) => {
10 | const { data, loading, error } = useFindDailyActionPlansQuery();
11 | const [dailyPlan, setDailyPlan] = useState({})
12 | const [assignVolunteer] = useAssignVolunteersMutation();
13 | if (error) {
14 | console.log(error);
15 | }
16 |
17 | let content = (No scheduler run today
)
18 | const submit = () => {
19 | assignVolunteer().then((result) => {
20 | setDailyPlan({...result.data?.assignVolunteers});
21 | }).catch((error) => {
22 | console.log("Failure", error);
23 | })
24 | }
25 | if (loading) return ;
26 | if (!Object.keys(dailyPlan).length && data?.findDailyActionPlans && data?.findDailyActionPlans.items && data?.findDailyActionPlans.items.length !== 0) {
27 | const items = data?.findDailyActionPlans.items
28 | setDailyPlan({...items[items.length - 1]});
29 | }
30 |
31 | if (Object.keys(dailyPlan)) {
32 | content = (
33 |
39 |
40 |
41 |
42 |
43 |
44 | )
45 | }
46 |
47 | return (
48 |
49 |
50 |
51 |
52 |
53 | Last scheduled daily assignments
54 |
55 |
56 | {content}
57 |
58 | submit()}>Schedule daily assignments
59 |
60 |
61 |
62 |
63 | OpenVolunteer Platform
64 |
65 |
66 |
67 | );
68 | };
69 |
--------------------------------------------------------------------------------
/docs/integrations_graphback_keycloak.md:
--------------------------------------------------------------------------------
1 | ---
2 | id: keycloak-authz
3 | title: Out of the box Keycloak based authentication
4 | sidebar_label: Keycloak Auth
5 | ---
6 |
7 | ## Authorization using Keycloak
8 |
9 | Graphback Keycloak Authz enables [Keycloak](https://www.keycloak.org/) integration in [Graphback](https://graphback.dev) based applications. This enables you to declaratively add authorization capabilities like role based access on top of the CRUD model that is used within the Open Volunteer Platform.
10 |
11 |
12 | Under the hood, Open Volunteer authorization is designed to work with [`keycloak-connect`](https://www.npmjs.com/package/keycloak-connect) and [`keycloak-connect-graphql`](https://www.npmjs.com/package/keycloak-connect-graphql). `keycloak-connect` is the official Keycloak middleware for Express applications. `keycloak-connect-graphql` provides deeper Keycloak integration into GraphQL servers.
13 |
14 |
15 | ## Customization
16 |
17 |
18 | Open Volunteer Platform provides out of the box Keycloak integration.
19 |
20 | The authorization rules in place are defined in [`server/src/config/auth.ts`](../platform/server/src/config/auth.ts). The initial configurations looks like below:
21 |
22 | ```ts
23 | export const authConfig: CrudServicesAuthConfig = {
24 | DistributionCentre: {
25 | create: { roles: ['admin'] },
26 | read: { roles: [] },
27 | update: { roles: ['admin'] },
28 | delete: { roles: ['admin'] },
29 | },
30 | Volunteer: {
31 | create: { roles: ['admin'] },
32 | read: { roles: [] },
33 | update: { roles: [] },
34 | delete: { roles: ['admin'] },
35 | },
36 | Recipient: {
37 | create: { roles: ['admin'] },
38 | read: { roles: [] },
39 | update: { roles: ['admin'] },
40 | delete: { roles: ['admin'] },
41 | },
42 | VolunteerAction: {
43 | create: { roles: ['admin'] },
44 | read: { roles: [] },
45 | update: { roles: ['admin'] },
46 | delete: { roles: ['admin'] },
47 | },
48 | VolunteerActionProduct: {
49 | create: { roles: ['admin'] },
50 | read: { roles: [] },
51 | update: { roles: ['admin'] },
52 | delete: { roles: ['admin'] },
53 | },
54 | }
55 | ```
56 |
57 | With this configuration the following rules are in place.
58 |
59 | - Only Admin users can create, update and delete entities, and all users can read them.
60 |
61 |
62 | You modify this file to add additional rules when you new business models are added or if you need to modify custom existing rules.
63 |
64 |
--------------------------------------------------------------------------------
/platform/client-admin/src/components/Menu.tsx:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { useLocation } from 'react-router';
3 |
4 | import { IonContent, IonIcon, IonItem, IonLabel, IonList, IonListHeader, IonMenu, IonMenuToggle } from '@ionic/react';
5 |
6 | import { textOutline, informationCircleOutline, peopleCircleSharp, mapOutline, peopleOutline, optionsSharp, codeWorking, cart } from 'ionicons/icons';
7 |
8 | import './Menu.css'
9 |
10 | const routes = {
11 | operationPages: [
12 | { title: 'Actions', path: '/actions', icon: codeWorking },
13 | { title: 'Action Map', path: '/map', icon: mapOutline },
14 | { title: 'Scheduling', path: '/schedule', icon: optionsSharp },
15 | { title: 'Reports', path: '/reports', icon: textOutline },
16 | ],
17 | managementPages: [
18 | { title: 'Volunteers', path: '/volunteers', icon: peopleOutline },
19 | { title: 'Recipients', path: '/recipients', icon: peopleCircleSharp },
20 | { title: 'Products', path: '/products', icon: cart },
21 | { title: 'Distribution Centre', path: '/distributionCentre', icon: informationCircleOutline }
22 | ]
23 | };
24 |
25 | interface Pages {
26 | title: string,
27 | path: string,
28 | icon: string,
29 | routerDirection?: string
30 | }
31 | interface StateProps {
32 | darkMode?: boolean;
33 | isAuthenticated?: boolean;
34 | menuEnabled?: boolean;
35 | }
36 |
37 | interface MenuProps { }
38 |
39 | export const Menu: React.FC = () => {
40 | const location = useLocation();
41 |
42 | function renderlistItems(list: Pages[]) {
43 | return list
44 | .filter(route => !!route.path)
45 | .map(p => (
46 |
47 |
48 |
49 | {p.title}
50 |
51 |
52 | ));
53 | }
54 |
55 | return (
56 |
57 |
58 |
59 | Operations
60 | {renderlistItems(routes.operationPages)}
61 |
62 |
63 | Management
64 | {renderlistItems(routes.managementPages)}
65 |
66 |
67 |
68 | );
69 | };
70 |
71 |
--------------------------------------------------------------------------------
/platform/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starter-client",
3 | "version": "0.0.1",
4 | "private": true,
5 | "dependencies": {
6 | "@capacitor/core": "2.4.5",
7 | "@ionic/react": "5.3.2",
8 | "@ionic/react-router": "5.3.2",
9 | "google-maps-react": "2.0.6",
10 | "graphql": "15.3.0",
11 | "graphql-tag": "2.11.0",
12 | "ionicons": "5.1.2",
13 | "keycloak-js": "9.0.3",
14 | "offix-cache": "0.15.5",
15 | "offix-client": "0.15.5",
16 | "@apollo/client": "3.2.0",
17 | "react": "16.13.1",
18 | "react-dom": "16.13.1",
19 | "react-offix-hooks": "0.15.5",
20 | "react-router": "5.2.0",
21 | "react-router-dom": "5.2.0",
22 | "simpl-schema": "1.10.0",
23 | "subscriptions-transport-ws": "0.9.18",
24 | "uniforms": "3.0.0-rc.3",
25 | "uniforms-bridge-simple-schema-2": "3.0.0-rc.3",
26 | "uniforms-ionic": "0.1.0"
27 | },
28 | "scripts": {
29 | "start": "yarn build && cap serve",
30 | "dev": "react-scripts start",
31 | "build": "react-scripts build",
32 | "build:generic": "REACT_APP_URI_FORMAT=RELATIVEURI react-scripts build",
33 | "run:android": "cap copy android && cap open android",
34 | "run:ios": "cap copy ios && cap open ios",
35 | "eject": "react-scripts eject"
36 | },
37 | "eslintConfig": {
38 | "extends": "react-app"
39 | },
40 | "browserslist": {
41 | "production": [
42 | ">0.2%",
43 | "not dead",
44 | "not op_mini all"
45 | ],
46 | "development": [
47 | "last 1 chrome version",
48 | "last 1 firefox version",
49 | "last 1 safari version"
50 | ]
51 | },
52 | "devDependencies": {
53 | "@capacitor/cli": "2.4.5",
54 | "@graphql-codegen/add": "2.0.1",
55 | "@graphql-codegen/typescript": "1.17.9",
56 | "@graphql-codegen/typescript-operations": "1.17.8",
57 | "@graphql-codegen/typescript-react-apollo": "2.0.6",
58 | "@test-graphql-cli/codegen": "4.0.1-beta.6",
59 | "@testing-library/jest-dom": "5.11.4",
60 | "@testing-library/react": "10.4.9",
61 | "@testing-library/user-event": "10.4.1",
62 | "@types/googlemaps": "3.39.13",
63 | "@types/jest": "25.2.3",
64 | "@types/node": "12.12.55",
65 | "@types/react": "16.9.49",
66 | "@types/react-dom": "16.9.8",
67 | "@types/react-router": "5.1.8",
68 | "@types/react-router-dom": "5.1.5",
69 | "@types/simpl-schema": "0.2.8",
70 | "graphql-cli": "4.0.1-beta.6",
71 | "react-scripts": "3.4.3",
72 | "typescript": "3.9.7"
73 | },
74 | "description": "An Ionic project"
75 | }
76 |
--------------------------------------------------------------------------------
/platform/client/src/config/clientConfig.ts:
--------------------------------------------------------------------------------
1 |
2 | import { WebSocketLink } from '@apollo/client/link/ws';
3 | import { setContext } from '@apollo/client/link/context'
4 | import { getMainDefinition } from 'apollo-utilities';
5 | import { getAuthHeader } from '../keycloakAuth';
6 | import { Capacitor } from '@capacitor/core';
7 | import { InMemoryCache, FetchPolicy, ApolloLink, HttpLink } from '@apollo/client';
8 |
9 | let httpUri = 'http://localhost:4000/graphql';
10 | let wsUri = 'ws://localhost:4000/graphql';
11 |
12 | if (Capacitor.isNative && Capacitor.platform === 'android') {
13 | httpUri = 'http://10.0.2.2:4000/graphql';
14 | wsUri = 'ws://10.0.2.2:4000/graphql';
15 | }
16 |
17 | if (process.env.REACT_APP_URI_FORMAT === 'RELATIVEURI') {
18 | httpUri = "/graphql";
19 | const protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
20 | const port = window.location.port !== "" ? `:${window.location.port}` : "";
21 | wsUri = `${protocol}${window.location.hostname}${port}${httpUri}`
22 | }
23 |
24 | /**
25 | * Create websocket link and
26 | * define websocket link options
27 | */
28 | const wsLink = new WebSocketLink({
29 | uri: wsUri,
30 | options: {
31 | reconnect: true,
32 | lazy: true,
33 | // returns auth header or empty string
34 | connectionParams: async () => (await getAuthHeader())
35 | },
36 | });
37 |
38 | const httpLink = new HttpLink({
39 | uri: httpUri,
40 | });
41 |
42 | /**
43 | * add authorization headers for queries
44 | * to grapqhql backend
45 | *
46 | */
47 | const authLink = setContext(async (_, { headers }) => {
48 | return {
49 | headers: {
50 | ...headers,
51 | // returns auth header or empty string
52 | ...await getAuthHeader()
53 | }
54 | }
55 | });
56 |
57 | /**
58 | * split queries and subscriptions.
59 | * send subscriptions to websocket url &
60 | * queries to http url
61 | *
62 | */
63 | const splitLink = ApolloLink.split(
64 | ({ query }) => {
65 | const { kind, operation }: any = getMainDefinition(query);
66 | return kind === 'OperationDefinition' && operation === 'subscription';
67 | },
68 | wsLink,
69 | httpLink,
70 | );
71 |
72 | const noCache: FetchPolicy = 'no-cache';
73 |
74 | const defaultOptions = {
75 | watchQuery: {
76 | fetchPolicy: noCache,
77 | },
78 | query: {
79 | fetchPolicy: noCache,
80 | },
81 | mutate: {
82 | fetchPolicy: noCache
83 | }
84 | }
85 |
86 | export const clientConfig = {
87 | defaultOptions,
88 | cache: new InMemoryCache(),
89 | link: authLink.concat(splitLink)
90 | };
91 |
--------------------------------------------------------------------------------
/platform/server/src/auth.ts:
--------------------------------------------------------------------------------
1 | import { Express } from "express";
2 | import { config } from './config/config';
3 |
4 | import {
5 | KeycloakTypeDefs,
6 | KeycloakSchemaDirectives,
7 | KeycloakSubscriptionContext,
8 | KeycloakSubscriptionHandler,
9 | KeycloakContext
10 | } from 'keycloak-connect-graphql'
11 |
12 | const session = require('express-session')
13 | const Keycloak = require('keycloak-connect')
14 |
15 | export function buildKeycloakApolloConfig(app: Express, apolloConfig: any) {
16 | const graphqlPath = `/graphql`;
17 | console.log("Using keycloak configuration")
18 |
19 | const memoryStore = new session.MemoryStore()
20 | app.use(session({
21 | secret: process.env.SESSION_SECRET_STRING || 'this should be a long secret',
22 | resave: false,
23 | saveUninitialized: true,
24 | store: memoryStore
25 | }))
26 |
27 | const keycloak = new Keycloak({
28 | store: memoryStore
29 | }, config.keycloakConfig);
30 | const keycloakSubscriptionHandler = new KeycloakSubscriptionHandler({ keycloak })
31 |
32 | app.use(keycloak.middleware())
33 |
34 | // For production we want to protect /graphql endpoint
35 | // For development we want to test our queries using graphql playground
36 | if(process.env.NODE_ENV === 'production'){
37 | app.use(graphqlPath, keycloak.protect());
38 | }
39 |
40 | return {
41 | typeDefs: [KeycloakTypeDefs, apolloConfig.typeDefs], // 1. Add the Keycloak Type Defs
42 | schemaDirectives: KeycloakSchemaDirectives,
43 | resolvers: apolloConfig.resolvers,
44 | playground: apolloConfig.playground,
45 | path: graphqlPath,
46 | context: (context: any) => {
47 | return {
48 | ...apolloConfig.context(context),
49 | kauth: new KeycloakContext({ req: context.req }) // 3. add the KeycloakContext to `kauth`
50 | }
51 | },
52 | subscriptions: {
53 | onConnect: async (connectionParams, websocket, connectionContext) => {
54 | const token = await keycloakSubscriptionHandler.onSubscriptionConnect(connectionParams)
55 | if (!token) {
56 | throw new Error("Cannot build keycloak token. Connection will be terminated")
57 | }
58 | return {
59 | ...apolloConfig.context,
60 | kauth: new KeycloakSubscriptionContext(token)
61 | }
62 | }
63 | },
64 | }
65 | }
66 |
67 |
68 |
--------------------------------------------------------------------------------
/platform/client-admin/src/config/clientConfig.ts:
--------------------------------------------------------------------------------
1 |
2 | import { WebSocketLink } from '@apollo/client/link/ws';
3 | import { setContext } from '@apollo/client/link/context'
4 | import { getMainDefinition } from 'apollo-utilities';
5 | import { getAuthHeader } from '../keycloakAuth';
6 | import { Capacitor } from '@capacitor/core';
7 | import { InMemoryCache, FetchPolicy, ApolloLink, HttpLink } from '@apollo/client';
8 |
9 | let httpUri = 'http://localhost:4000/graphql';
10 | let wsUri = 'ws://localhost:4000/graphql';
11 |
12 | if (Capacitor.isNative && Capacitor.platform === 'android') {
13 | httpUri = 'http://10.0.2.2:4000/graphql';
14 | wsUri = 'ws://10.0.2.2:4000/graphql';
15 | }
16 |
17 | if (process.env.REACT_APP_URI_FORMAT === 'RELATIVEURI') {
18 | httpUri = "/graphql";
19 | const protocol = window.location.protocol === "https:" ? "wss://" : "ws://";
20 | const port = window.location.port !== "" ? `:${window.location.port}` : "";
21 | wsUri = `${protocol}${window.location.hostname}${port}${httpUri}`
22 | }
23 |
24 | /**
25 | * Create websocket link and
26 | * define websocket link options
27 | */
28 | const wsLink = new WebSocketLink({
29 | uri: wsUri,
30 | options: {
31 | reconnect: true,
32 | lazy: true,
33 | // returns auth header or empty string
34 | connectionParams: async () => (await getAuthHeader())
35 | },
36 | });
37 |
38 | const httpLink = new HttpLink({
39 | uri: httpUri,
40 | });
41 |
42 | /**
43 | * add authorization headers for queries
44 | * to grapqhql backend
45 | *
46 | */
47 | const authLink = setContext(async (_, { headers }) => {
48 | return {
49 | headers: {
50 | ...headers,
51 | // returns auth header or empty string
52 | ...await getAuthHeader()
53 | }
54 | }
55 | });
56 |
57 | /**
58 | * split queries and subscriptions.
59 | * send subscriptions to websocket url &
60 | * queries to http url
61 | *
62 | */
63 | const splitLink = ApolloLink.split(
64 | ({ query }) => {
65 | const { kind, operation }: any = getMainDefinition(query);
66 | return kind === 'OperationDefinition' && operation === 'subscription';
67 | },
68 | wsLink,
69 | httpLink,
70 | );
71 |
72 | const noCache: FetchPolicy = 'no-cache';
73 |
74 | const defaultOptions = {
75 | watchQuery: {
76 | fetchPolicy: noCache,
77 | },
78 | query: {
79 | fetchPolicy: noCache,
80 | },
81 | mutate: {
82 | fetchPolicy: noCache
83 | }
84 | }
85 |
86 | export const clientConfig = {
87 | defaultOptions,
88 | cache: new InMemoryCache(),
89 | link: authLink.concat(splitLink)
90 | };
91 |
--------------------------------------------------------------------------------
/website/src/components/Terminal/index.jsx:
--------------------------------------------------------------------------------
1 | import React, { useEffect } from 'react';
2 | import styles from './styles.module.css';
3 |
4 | function Underscore() {
5 |
6 | const underscoreFlash = () => {
7 | const underscore = document.getElementById('underscore');
8 | underscore.classList.toggle('hidden');
9 | };
10 |
11 | useEffect(() => {
12 | // subscribe
13 | const interval = setInterval(underscoreFlash, 400);
14 | // unsubscribe
15 | return () => clearInterval(interval);
16 | });
17 |
18 | return (
19 |
23 | _
24 |
25 | );
26 | }
27 |
28 | function TerminalText({ phrase }) {
29 | let lettercount = 1;
30 | let reverse = false;
31 | let wait = false;
32 |
33 | const typeEffect = async () => {
34 | const text = document.getElementById('text');
35 | text.innerHTML = phrase.substring(0, lettercount);
36 | const callable = !reverse ? typeOutWord : backspace;
37 | await handleReverse();
38 | if (!waiting()) callable();
39 | }
40 |
41 | const waiting = () => {
42 | return (
43 | wait
44 | || (lettercount === phrase.length + 1 && !reverse)
45 | || (lettercount === 0 && reverse)
46 | );
47 | }
48 |
49 | const typeOutWord = () => {
50 | if (lettercount < phrase.length + 1) lettercount++;
51 | };
52 |
53 | const backspace = () => {
54 | if (lettercount > 0) lettercount--;
55 | };
56 |
57 | const handleReverse = async () => {
58 | if (!reverse && lettercount === phrase.length + 1) await toggleReverse();
59 | if (reverse && lettercount === 0) await toggleReverse();
60 | };
61 |
62 | const toggleReverse = () => {
63 | reverse = !reverse;
64 | wait = true;
65 | return new Promise(resolve => {
66 | setTimeout(() => {
67 | wait = false;
68 | resolve();
69 | }, 3000);
70 | });
71 | };
72 |
73 | useEffect(() => {
74 | // subscribe
75 | const interval = setInterval(typeEffect, 120);
76 | // unsubscribe
77 | return () => clearInterval(interval);
78 | });
79 |
80 | return (
81 |
82 | );
83 | }
84 |
85 | export function Terminal() {
86 |
87 | return (
88 |
89 |
92 |
93 | >
94 |
95 |
96 |
97 |
98 | );
99 | }
--------------------------------------------------------------------------------
/platform/client-admin/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "starter-client-admin",
3 | "version": "0.0.1",
4 | "private": true,
5 | "dependencies": {
6 | "@capacitor/core": "2.4.5",
7 | "@ionic/react": "5.3.2",
8 | "@ionic/react-router": "5.3.2",
9 | "@apollo/client": "3.2.0",
10 | "apollo-link-context": "1.0.20",
11 | "apollo-link-ws": "1.0.20",
12 | "google-maps-react": "2.0.6",
13 | "graphql": "15.3.0",
14 | "graphql-tag": "2.11.0",
15 | "humanize-string":"2.1.0",
16 | "ionicons": "5.1.2",
17 | "keycloak-js": "9.0.3",
18 | "moment": "2.27.0",
19 | "react": "16.13.1",
20 | "react-dom": "16.13.1",
21 | "react-router": "5.2.0",
22 | "react-router-dom": "5.2.0",
23 | "simpl-schema": "1.10.0",
24 | "subscriptions-transport-ws": "0.9.18",
25 | "uniforms": "3.0.0-rc.3",
26 | "uniforms-bridge-simple-schema-2": "3.0.0-rc.3",
27 | "uniforms-ionic": "0.1.0"
28 | },
29 | "scripts": {
30 | "start": "npm run build && cap serve",
31 | "dev": "react-scripts start",
32 | "build": "react-scripts build",
33 | "build:generic": "REACT_APP_URI_FORMAT=RELATIVEURI react-scripts build",
34 | "run:android": "cap copy android && cap open android",
35 | "run:ios": "cap copy ios && cap open ios",
36 | "eject": "react-scripts eject"
37 | },
38 | "eslintConfig": {
39 | "extends": "react-app"
40 | },
41 | "browserslist": {
42 | "production": [
43 | ">0.2%",
44 | "not dead",
45 | "not op_mini all"
46 | ],
47 | "development": [
48 | "last 1 chrome version",
49 | "last 1 firefox version",
50 | "last 1 safari version"
51 | ]
52 | },
53 | "resolutions": {
54 | "uniforms": "3.0.0-rc.3"
55 | },
56 | "devDependencies": {
57 | "@capacitor/cli": "2.4.5",
58 | "@graphql-codegen/add": "2.0.1",
59 | "@graphql-codegen/typescript": "1.17.9",
60 | "@graphql-codegen/typescript-operations": "1.17.8",
61 | "@graphql-codegen/typescript-react-apollo": "2.0.6",
62 | "@test-graphql-cli/codegen": "4.0.1-beta.6",
63 | "@testing-library/jest-dom": "5.11.4",
64 | "@testing-library/react": "10.4.9",
65 | "@testing-library/user-event": "10.4.1",
66 | "@types/googlemaps": "3.39.13",
67 | "@types/jest": "25.2.3",
68 | "@types/moment": "2.13.0",
69 | "@types/node": "12.12.55",
70 | "@types/react": "16.9.49",
71 | "@types/react-dom": "16.9.8",
72 | "@types/react-router": "5.1.8",
73 | "@types/react-router-dom": "5.1.5",
74 | "@types/simpl-schema": "0.2.8",
75 | "graphql-cli": "4.0.1-beta.6",
76 | "react-scripts": "3.4.3",
77 | "typescript": "3.9.7"
78 | },
79 | "description": "An Ionic project"
80 | }
81 |
--------------------------------------------------------------------------------