├── dronesym-frontend ├── src │ ├── assets │ │ ├── .gitkeep │ │ ├── img │ │ │ ├── red.png │ │ │ ├── blue.png │ │ │ ├── dronesym_logo.png │ │ │ └── apple-touch-192.png │ │ └── icons │ │ │ ├── icon-72x72.png │ │ │ ├── icon-96x96.png │ │ │ ├── icon-128x128.png │ │ │ ├── icon-144x144.png │ │ │ ├── icon-152x152.png │ │ │ ├── icon-192x192.png │ │ │ ├── icon-384x384.png │ │ │ └── icon-512x512.png │ ├── app │ │ ├── app.component.css │ │ ├── breadcrumb │ │ │ ├── breadcrumb.component.css │ │ │ ├── breadcrumb.ts │ │ │ ├── breadcrumb.component.html │ │ │ ├── breadcrumb.component.spec.ts │ │ │ └── breadcrumb.component.ts │ │ ├── drone-list │ │ │ ├── drone-list.component.css │ │ │ ├── drone-list.component.spec.ts │ │ │ ├── drone-list.component.html │ │ │ └── drone-list.component.ts │ │ ├── drone-groups │ │ │ ├── drone-groups.component.css │ │ │ ├── drone-groups.component.spec.ts │ │ │ ├── drone-groups.component.html │ │ │ └── drone-groups.component.ts │ │ ├── user-management │ │ │ ├── user-management.component.css │ │ │ ├── user-management.component.spec.ts │ │ │ ├── user-management.component.html │ │ │ └── user-management.component.ts │ │ ├── app.component.html │ │ ├── new-password-dialog │ │ │ ├── new-password-dialog.component.css │ │ │ ├── new-password-dialog.component.spec.ts │ │ │ ├── new-password-dialog.component.html │ │ │ └── new-password-dialog.component.ts │ │ ├── drones-box │ │ │ ├── drones-box.component.css │ │ │ ├── drones-box.component.spec.ts │ │ │ ├── drones-box.component.html │ │ │ └── drones-box.component.ts │ │ ├── confirm-dialog │ │ │ ├── confirm-dialog.component.css │ │ │ ├── confirm-dialog.component.spec.ts │ │ │ ├── confirm-dialog.component.html │ │ │ └── confirm-dialog.component.ts │ │ ├── reset-code-dialog │ │ │ ├── reset-code-dialog.component.css │ │ │ ├── reset-code-dialog.component.spec.ts │ │ │ ├── reset-code-dialog.component.html │ │ │ └── reset-code-dialog.component.ts │ │ ├── user-view │ │ │ ├── user-view.component.css │ │ │ ├── user-view.component.html │ │ │ ├── user-view.component.spec.ts │ │ │ └── user-view.component.ts │ │ ├── cursor-tooltip │ │ │ ├── cursor-tooltip.component.html │ │ │ ├── cursor-tooltip.component.css │ │ │ ├── cursor-tooltip.component.spec.ts │ │ │ └── cursor-tooltip.component.ts │ │ ├── dashboard │ │ │ ├── dashboard.component.css │ │ │ ├── dashboard.component.spec.ts │ │ │ └── dashboard.component.html │ │ ├── drone-option-box │ │ │ ├── drone-option-box.component.css │ │ │ ├── drone-option-box.component.spec.ts │ │ │ ├── drone-option-box.component.ts │ │ │ └── drone-option-box.component.html │ │ ├── user-signup │ │ │ ├── user-signup.component.css │ │ │ ├── user-signup.component.spec.ts │ │ │ ├── user-signup.component.html │ │ │ └── user-signup.component.ts │ │ ├── user-service │ │ │ └── user.service.spec.ts │ │ ├── auth-http │ │ │ ├── auth-http.service.spec.ts │ │ │ └── auth-http.service.ts │ │ ├── drone-service │ │ │ ├── drone-data.service.spec.ts │ │ │ └── drone-data.service.ts │ │ ├── route-guard │ │ │ ├── route-guard.service.spec.ts │ │ │ └── route-guard.service.ts │ │ ├── admin-authorize │ │ │ ├── admin-authorize.service.spec.ts │ │ │ └── admin-authorize.service.ts │ │ ├── user-dashboard │ │ │ ├── user-dashboard.component.ts │ │ │ ├── user-dashboard.component.html │ │ │ ├── user-dashboard.component.spec.ts │ │ │ └── user-dashboard.component.css │ │ ├── app.component.ts │ │ ├── login │ │ │ ├── login.component.spec.ts │ │ │ ├── login.component.ts │ │ │ ├── login.component.html │ │ │ └── login.component.css │ │ ├── signup │ │ │ ├── signup.component.spec.ts │ │ │ ├── signup.component.css │ │ │ ├── signup.component.html │ │ │ └── signup.component.ts │ │ ├── forgot-password │ │ │ ├── forgot-password.component.spec.ts │ │ │ ├── forgot-password.component.html │ │ │ ├── forgot-password.component.css │ │ │ └── forgot-password.component.ts │ │ ├── app.component.spec.ts │ │ ├── app-router.ts │ │ └── app.module.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── example.environment.ts │ ├── favicon.ico │ ├── typings.d.ts │ ├── tsconfig.app.json │ ├── main.ts │ ├── tsconfig.spec.json │ ├── ngsw-config.json │ ├── index.html │ ├── styles.css │ ├── test.ts │ ├── manifest.json │ └── polyfills.ts ├── .dockerignore ├── .bowerrc ├── e2e │ ├── conf.js │ ├── tsconfig.e2e.json │ ├── app.po.ts │ ├── app.e2e-spec.ts │ ├── Login │ │ ├── login.e2e-spec.ts │ │ └── login.po.ts │ └── test.ts ├── Dockerfile ├── .editorconfig ├── bower.json ├── tsconfig.json ├── .gitignore ├── README.md ├── protractor.conf.js ├── karma.conf.js ├── package.json ├── tslint.json └── angular.json ├── dronesym-python ├── .cache │ └── v │ │ └── cache │ │ └── lastfailed ├── flask-api │ ├── src │ │ ├── config.ini │ │ ├── threadrunner.py │ │ ├── node.py │ │ ├── mavparser.py │ │ └── main.py │ └── tests │ │ ├── test_default.py │ │ ├── mocks.py │ │ └── test_dronepool.py ├── requirements.txt └── Dockerfile ├── dronesym-node ├── .dockerignore ├── .env ├── config │ ├── example.mongoconfig.js │ ├── jwtconfig.js │ └── passportconfig.js ├── Dockerfile ├── tests │ ├── test.js │ ├── drone_tests.js │ ├── user_models.js │ └── group_models.js ├── websocket.js ├── .eslintrc.json ├── Models │ ├── group.js │ ├── drone.js │ └── user.js ├── index.js ├── package.json └── Routers │ ├── userRouter.js │ └── droneRouter.js ├── dronedb └── dronesym │ ├── users.bson │ ├── groups.bson │ ├── users.metadata.json │ └── groups.metadata.json ├── docs ├── src │ ├── images │ │ ├── drone_logo.png │ │ ├── gatsby-icon.png │ │ └── gatsby-astronaut.png │ ├── pages │ │ └── 404.js │ └── components │ │ ├── header.js │ │ ├── image.js │ │ ├── layout.js │ │ └── seo.js ├── .prettierrc ├── gatsby-node.js ├── gatsby-browser.js ├── gatsby-ssr.js ├── gatsby-config.js ├── LICENSE ├── .gitignore └── package.json ├── initScripts ├── instructions.md └── start.sh ├── .dependabot └── config.yml ├── .github ├── dependabot.yml ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE │ └── ISSUE_TEMPLATE.md └── CONTRIBUTING.md ├── docker-compose.yaml ├── .editorconfig ├── .travis.yml ├── CODE_OF_CONDUCT.md ├── .gitignore └── README.md /dronesym-frontend/src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/app.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-python/.cache/v/cache/lastfailed: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /dronesym-node/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /dronesym-frontend/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/breadcrumb/breadcrumb.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-list/drone-list.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-groups/drone-groups.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-node/.env: -------------------------------------------------------------------------------- 1 | MONGO_URL= mongodb://localhost:27017/dronesym 2 | -------------------------------------------------------------------------------- /dronesym-frontend/.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "src/assets" 3 | } 4 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-management/user-management.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/new-password-dialog/new-password-dialog.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drones-box/drones-box.component.css: -------------------------------------------------------------------------------- 1 | .list-items{ 2 | padding: 6px; 3 | } -------------------------------------------------------------------------------- /dronedb/dronesym/users.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronedb/dronesym/users.bson -------------------------------------------------------------------------------- /docs/src/images/drone_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/docs/src/images/drone_logo.png -------------------------------------------------------------------------------- /dronedb/dronesym/groups.bson: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronedb/dronesym/groups.bson -------------------------------------------------------------------------------- /docs/src/images/gatsby-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/docs/src/images/gatsby-icon.png -------------------------------------------------------------------------------- /dronesym-frontend/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /dronedb/dronesym/users.metadata.json: -------------------------------------------------------------------------------- 1 | {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"dronesym.users"}]} -------------------------------------------------------------------------------- /dronesym-frontend/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/favicon.ico -------------------------------------------------------------------------------- /dronesym-python/flask-api/src/config.ini: -------------------------------------------------------------------------------- 1 | [firebase] 2 | db_url: DB_URL 3 | db_secret: DB_SECRET 4 | db_email: DB_EMAIL 5 | -------------------------------------------------------------------------------- /docs/src/images/gatsby-astronaut.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/docs/src/images/gatsby-astronaut.png -------------------------------------------------------------------------------- /dronedb/dronesym/groups.metadata.json: -------------------------------------------------------------------------------- 1 | {"options":{},"indexes":[{"v":1,"key":{"_id":1},"name":"_id_","ns":"dronesym.groups"}]} -------------------------------------------------------------------------------- /dronesym-frontend/src/app/confirm-dialog/confirm-dialog.component.css: -------------------------------------------------------------------------------- 1 | .modal .modal-footer .btn{ 2 | margin-left: 10px; 3 | } -------------------------------------------------------------------------------- /dronesym-node/config/example.mongoconfig.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | dbUri: 'mongodb://localhost:27017/dronesym', 3 | }; 4 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/reset-code-dialog/reset-code-dialog.component.css: -------------------------------------------------------------------------------- 1 | .modal .modal-footer .btn{ 2 | margin-left: 10px; 3 | } -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/img/red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/img/red.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/img/blue.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/img/blue.png -------------------------------------------------------------------------------- /dronesym-python/requirements.txt: -------------------------------------------------------------------------------- 1 | dronekit_sitl==3.2.0 2 | dronekit==2.9.2 3 | Flask==1.0.2 4 | pymavlink==2.3.3 5 | requests==2.20.0 6 | -------------------------------------------------------------------------------- /dronesym-node/config/jwtconfig.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | secret: 'YOUR_JWT_SECRET', 3 | expiresIn: '1h', 4 | issuer: 'dronesym', 5 | }; 6 | -------------------------------------------------------------------------------- /docs/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "endOfLine": "lf", 3 | "semi": false, 4 | "singleQuote": false, 5 | "tabWidth": 2, 6 | "trailingComma": "es5" 7 | } 8 | -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-72x72.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-96x96.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/img/dronesym_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/img/dronesym_logo.png -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-view/user-view.component.css: -------------------------------------------------------------------------------- 1 | .nav-button{ 2 | display: inline-flex; 3 | } 4 | 5 | .brand-logo{ 6 | padding-left: 6px; 7 | } -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-128x128.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-144x144.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-152x152.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-192x192.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-384x384.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-384x384.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/icons/icon-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/icons/icon-512x512.png -------------------------------------------------------------------------------- /dronesym-frontend/src/assets/img/apple-touch-192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/scorelab/DroneSym/HEAD/dronesym-frontend/src/assets/img/apple-touch-192.png -------------------------------------------------------------------------------- /dronesym-frontend/src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/breadcrumb/breadcrumb.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Breadcrumb model. 3 | */ 4 | export interface Breadcrumb { 5 | label: string; 6 | url: string; 7 | } 8 | 9 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/cursor-tooltip/cursor-tooltip.component.html: -------------------------------------------------------------------------------- 1 |
2 | Lat: {{ latitude | number:'2.2-4' }} | Lon: {{ longitude | number:'2.2-4'}} 3 |
-------------------------------------------------------------------------------- /docs/gatsby-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/node-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/cursor-tooltip/cursor-tooltip.component.css: -------------------------------------------------------------------------------- 1 | .cursortip{ 2 | position: absolute; 3 | background-color: #212121; 4 | color: white; 5 | border-radius: 6px; 6 | padding: 10px; 7 | } -------------------------------------------------------------------------------- /dronesym-python/flask-api/tests/test_default.py: -------------------------------------------------------------------------------- 1 | # TODO: Write unit tests for actual methods in the class 2 | 3 | def add_one(x): 4 | return x+1 5 | 6 | def test_add_one(): 7 | assert add_one(3) == 4 8 | -------------------------------------------------------------------------------- /docs/gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/dashboard/dashboard.component.css: -------------------------------------------------------------------------------- 1 | agm-map{ 2 | height: 100vh; 3 | } 4 | 5 | .control-buttons{ 6 | position: absolute; 7 | bottom: 35px; 8 | right: 35px; 9 | z-index: 2; 10 | } -------------------------------------------------------------------------------- /docs/gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /dronesym-frontend/e2e/conf.js: -------------------------------------------------------------------------------- 1 | exports.config = { 2 | seleniumAddress: "http://localhost:4444/wd/hub", 3 | specs: ["test.ts"], 4 | framework: "jasmine", 5 | capabilities: { 6 | browserName: "chrome" 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /dronesym-node/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM node:11 3 | RUN mkdir -p /usr/src/app 4 | WORKDIR /usr/src/app 5 | COPY package.json /usr/src/app 6 | RUN npm install 7 | COPY . /usr/src/app 8 | EXPOSE 3000 9 | CMD ["npm", "start"] 10 | -------------------------------------------------------------------------------- /dronesym-frontend/Dockerfile: -------------------------------------------------------------------------------- 1 | 2 | FROM node:11 3 | RUN mkdir -p /usr/src/app 4 | WORKDIR /usr/src/app 5 | COPY package.json /usr/src/app 6 | RUN npm install 7 | COPY . /usr/src/app 8 | EXPOSE 4200 9 | CMD ["npm", "start"] 10 | -------------------------------------------------------------------------------- /initScripts/instructions.md: -------------------------------------------------------------------------------- 1 | Simple bash script to start the application. 2 | Make sure to run mongodb server first. 3 | Open up a terminal, navigate to the directory initScripts/ and run chmod a+x start.sh 4 | Then run "./start.sh" (without double quotes) 5 | -------------------------------------------------------------------------------- /dronesym-python/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3 2 | RUN mkdir -p /usr/src/app 3 | WORKDIR /usr/src/app 4 | COPY requirements.txt /usr/src/app 5 | RUN pip3 install -r requirements.txt 6 | COPY ./flask-api/src /usr/src/app 7 | EXPOSE 5000 8 | CMD ["python3", "main.py"] 9 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-option-box/drone-option-box.component.css: -------------------------------------------------------------------------------- 1 | .drone-box{ 2 | margin: 6px; 3 | } 4 | 5 | .info-box{ 6 | border-radius: 3px; 7 | background-color: #e6e6e6; 8 | color: #484747; 9 | padding: 5px; 10 | font-size: 1.1rem; 11 | } -------------------------------------------------------------------------------- /dronesym-frontend/e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /dronesym-frontend/e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class DronesymFrontendPage { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /dronesym-frontend/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /dronesym-frontend/.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-signup/user-signup.component.css: -------------------------------------------------------------------------------- 1 | .signup-background{ 2 | background-color: #f5f5f5; 3 | } 4 | 5 | .signup-header{ 6 | display: flex; 7 | flex-direction: row; 8 | } 9 | 10 | .logo-badge{ 11 | height: 60px; 12 | width: 60px; 13 | } 14 | 15 | #signupmodal{ 16 | width : 30%; 17 | overflow: hidden; 18 | } -------------------------------------------------------------------------------- /dronesym-frontend/src/app/breadcrumb/breadcrumb.component.html: -------------------------------------------------------------------------------- 1 |
2 | 10 |
11 | -------------------------------------------------------------------------------- /dronesym-node/tests/test.js: -------------------------------------------------------------------------------- 1 | // const https = require('http'); 2 | 3 | 4 | // try { 5 | // // eslint-disable-next-line no-unused-vars 6 | // const request = https.get({host: 'http://localhost:3000/feed'}, function(response) { 7 | // Console.log(response.statusCode); 8 | // }); 9 | // } catch (e) { 10 | // Console.error(e.message); 11 | // } 12 | -------------------------------------------------------------------------------- /docs/src/pages/404.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | 3 | import Layout from "../components/layout" 4 | import SEO from "../components/seo" 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ) 13 | 14 | export default NotFoundPage 15 | -------------------------------------------------------------------------------- /dronesym-node/websocket.js: -------------------------------------------------------------------------------- 1 | const io = require('socket.io'); 2 | const socketIoJwt = require('socketio-jwt'); 3 | const config = require('./config/jwtconfig'); 4 | 5 | exports.init = function(http) { 6 | const ioConn = io(http).of('/feed'); 7 | ioConn.use(socketIoJwt.authorize({ 8 | secret: config.secret, 9 | handshake: true, 10 | })); 11 | exports.connection = ioConn; 12 | }; 13 | -------------------------------------------------------------------------------- /initScripts/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | mongo --eval "db.stats()" 3 | 4 | RESULT=$? # returns 0 if mongo eval succeeds 5 | 6 | if [ $RESULT -ne 0 ]; then 7 | echo "mongodb not running /n please run mongodb first!" 8 | exit 1 9 | else 10 | ((cd ../dronesym-node/ && npm start & python3 ../dronesym-python/flask-api/src/main.py)&);(sleep 5 && cd ../dronesym-frontend/ && ng serve )& 11 | fi 12 | -------------------------------------------------------------------------------- /.dependabot/config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | update_configs: 4 | - package_manager: "javascript" 5 | directory: "/dronesym-node" 6 | update_schedule: "monthly" 7 | 8 | - package_manager: "javascript" 9 | directory: "/dronesym-frontend" 10 | update_schedule: "monthly" 11 | 12 | - package_manager: "python" 13 | directory: "/dronesym-python" 14 | update_schedule: "monthly" 15 | -------------------------------------------------------------------------------- /dronesym-frontend/src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule); 12 | -------------------------------------------------------------------------------- /dronesym-node/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "commonjs": true, 4 | "es6": true, 5 | "node": true 6 | }, 7 | "extends": "google", 8 | "globals": { 9 | "Atomics": "readonly", 10 | "SharedArrayBuffer": "readonly" 11 | }, 12 | "parserOptions": { 13 | "ecmaVersion": 2018 14 | }, 15 | "rules": { 16 | "valid-jsdoc":"off" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /dronesym-frontend/src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts", 15 | "polyfills.ts" 16 | ], 17 | "include": [ 18 | "**/*.spec.ts", 19 | "**/*.d.ts" 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-service/user.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { UserService } from './user.service'; 4 | 5 | describe('UserService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [UserService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([UserService], (service: UserService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /dronesym-frontend/e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { DronesymFrontendPage } from './app.po'; 2 | 3 | describe('dronesym-frontend App', () => { 4 | let page: DronesymFrontendPage; 5 | 6 | beforeEach(() => { 7 | page = new DronesymFrontendPage(); 8 | }); 9 | 10 | // FIXME: This test is redundant, we should delete it 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getParagraphText()).toEqual('Welcome to app!!'); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/auth-http/auth-http.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AuthHttpService } from './auth-http.service'; 4 | 5 | describe('AuthHttpService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AuthHttpService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([AuthHttpService], (service: AuthHttpService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-service/drone-data.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { DroneDataService } from './drone-data.service'; 4 | 5 | describe('DroneDataService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [DroneDataService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([DroneDataService], (service: DroneDataService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/route-guard/route-guard.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { RouteGuardService } from './route-guard.service'; 4 | 5 | describe('RouteGuardService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [RouteGuardService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([RouteGuardService], (service: RouteGuardService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /dronesym-frontend/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "DroneSym", 3 | "description": "Realtime drone fleet tracker", 4 | "main": "", 5 | "authors": [ 6 | "Hasanga Somaratne " 7 | ], 8 | "license": "MIT", 9 | "homepage": "https://github.com/hasa93/DroneSym", 10 | "ignore": [ 11 | "**/.*", 12 | "node_modules", 13 | "bower_components", 14 | "app/bower_components", 15 | "test", 16 | "tests" 17 | ], 18 | "dependencies": { 19 | "materialize": "^0.98.2" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /dronesym-node/Models/group.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const groupSchema = new mongoose.Schema({ 4 | name: { 5 | type: String, 6 | required: true, 7 | }, 8 | userId: { 9 | type: String, 10 | required: true, 11 | }, 12 | drones: { 13 | type: [String], 14 | default: [], 15 | }, 16 | users: { 17 | type: [{ 18 | userId: String, 19 | userName: String, 20 | }], 21 | default: [], 22 | }, 23 | }); 24 | 25 | module.exports = mongoose.model('Groups', groupSchema); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/admin-authorize/admin-authorize.service.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, inject } from '@angular/core/testing'; 2 | 3 | import { AdminAuthorizeService } from './admin-authorize.service'; 4 | 5 | describe('AdminAuthorizeService', () => { 6 | beforeEach(() => { 7 | TestBed.configureTestingModule({ 8 | providers: [AdminAuthorizeService] 9 | }); 10 | }); 11 | 12 | it('should be created', inject([AdminAuthorizeService], (service: AdminAuthorizeService) => { 13 | expect(service).toBeTruthy(); 14 | })); 15 | }); 16 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "monthly" 12 | -------------------------------------------------------------------------------- /dronesym-frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "importHelpers": true, 5 | "outDir": "./dist/out-tsc", 6 | "baseUrl": "src", 7 | "sourceMap": true, 8 | "declaration": false, 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "target": "es5", 13 | "typeRoots": [ 14 | "node_modules/@types" 15 | ], 16 | "lib": [ 17 | "es2016", 18 | "dom" 19 | ], 20 | "module": "es2015" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | services: 3 | mongo: 4 | image: mongo 5 | expose: 6 | - 27017 7 | ports: 8 | - 27017:27017 9 | restart: always 10 | entrypoint: ["/usr/bin/mongod", "--bind_ip_all","--replSet", "rs"] 11 | node: 12 | build: './dronesym-node' 13 | ports: 14 | - "3000:3000" 15 | environment: 16 | - MONGO_URL=mongodb://mongo:27017/dronesym 17 | angular: 18 | build: './dronesym-frontend' 19 | ports: 20 | - "4200:4200" 21 | flask: 22 | build: './dronesym-python' 23 | ports: 24 | - "5000:5000" 25 | 26 | -------------------------------------------------------------------------------- /dronesym-frontend/e2e/Login/login.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { LoginPage } from './login.po'; 2 | 3 | describe('Dronesym Login Page', () => { 4 | let page: LoginPage; 5 | 6 | beforeEach(() => { 7 | page = new LoginPage(); 8 | }); 9 | 10 | it('Should display Login Form With The title "Login"', () => { 11 | page.navigateTo(); 12 | expect(page.getLoginFormTitle()).toEqual('Login'); 13 | }); 14 | 15 | it('Should Login User', async () => { 16 | await page.loginUser(); 17 | const loggedUrl = await page.getUrl(); 18 | expect(loggedUrl).toContain('/dashboard'); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /dronesym-frontend/src/environments/example.environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `.angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false, 8 | mapsApiKey: 'YOUR_GOOLE_MAPS_API_KEY', 9 | nodeApiURL: 'http://localhost:3000/dronesym/api/node', 10 | feedURL: 'http://localhost:3000/feed' 11 | }; 12 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-dashboard/user-dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { UserService } from '../user-service/user.service'; 3 | 4 | @Component({ 5 | selector: 'app-user-dashboard', 6 | templateUrl: './user-dashboard.component.html', 7 | styleUrls: ['./user-dashboard.component.css'] 8 | }) 9 | export class UserDashboardComponent implements OnInit { 10 | 11 | public userRole: string; 12 | 13 | constructor(private userService: UserService) { 14 | userService.getUserRole().then((role) => { 15 | this.userRole = role; 16 | }); 17 | } 18 | 19 | ngOnInit() { 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /dronesym-frontend/src/ngsw-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "index": "/index.html", 3 | "assetGroups": [ 4 | { 5 | "name": "app", 6 | "installMode": "prefetch", 7 | "resources": { 8 | "files": [ 9 | "/favicon.ico", 10 | "/index.html", 11 | "/*.css", 12 | "/*.js" 13 | ] 14 | } 15 | }, { 16 | "name": "assets", 17 | "installMode": "lazy", 18 | "updateMode": "prefetch", 19 | "resources": { 20 | "files": [ 21 | "/assets/**", 22 | "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)" 23 | ] 24 | } 25 | } 26 | ] 27 | } 28 | -------------------------------------------------------------------------------- /dronesym-node/Models/drone.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | mongoose.set('useFindAndModify', false); 3 | const groupSchema = new mongoose.Schema({ 4 | description: { 5 | type: String, 6 | required: true, 7 | }, 8 | flying_time: { 9 | type: String, 10 | }, 11 | name: { 12 | type: String, 13 | required: true, 14 | }, 15 | location: { 16 | lat: Number, 17 | lon: Number, 18 | }, 19 | users: [{ 20 | userId: String, 21 | groupId: String, 22 | }], 23 | timestamp: { 24 | type: Number, 25 | }, 26 | waypoints: [{ 27 | lat: Number, 28 | lon: Number, 29 | }], 30 | 31 | },{strict: false}); 32 | 33 | module.exports = mongoose.model('Drone', groupSchema); 34 | -------------------------------------------------------------------------------- /dronesym-frontend/.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | 8 | # dependencies 9 | /node_modules 10 | 11 | # IDEs and editors 12 | /.idea 13 | .project 14 | .classpath 15 | .c9/ 16 | *.launch 17 | .settings/ 18 | *.sublime-workspace 19 | 20 | # IDE - VSCode 21 | .vscode/* 22 | !.vscode/settings.json 23 | !.vscode/tasks.json 24 | !.vscode/launch.json 25 | !.vscode/extensions.json 26 | 27 | # misc 28 | /.sass-cache 29 | /connect.lock 30 | /coverage 31 | /libpeerconnection.log 32 | npm-debug.log 33 | testem.log 34 | /typings 35 | 36 | # e2e 37 | /e2e/*.js 38 | /e2e/*.map 39 | 40 | # System Files 41 | .DS_Store 42 | Thumbs.db 43 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ViewChild, AfterViewInit, NgZone } from '@angular/core'; 2 | import { DecimalPipe } from '@angular/common'; 3 | import { DroneDataService } from './drone-service/drone-data.service'; 4 | 5 | import { CursorTooltipComponent } from './cursor-tooltip/cursor-tooltip.component'; 6 | import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component'; 7 | import { DroneOptionBoxComponent } from './drone-option-box/drone-option-box.component'; 8 | 9 | declare var google: any; 10 | 11 | @Component({ 12 | selector: 'app-root', 13 | templateUrl: './app.component.html', 14 | styleUrls: ['./app.component.css'] 15 | }) 16 | 17 | export class AppComponent { } 18 | -------------------------------------------------------------------------------- /dronesym-frontend/e2e/Login/login.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class LoginPage { 4 | navigateTo() { 5 | return browser.get('/login'); 6 | } 7 | 8 | getLoginFormTitle() { 9 | return element(by.className('card-title')).getText(); 10 | } 11 | 12 | async loginUser() { 13 | const usernameInput = element(by.id('username')); 14 | const passwordInput = element(by.id('password')); 15 | const submitButton = element(by.css('button.btn')); 16 | 17 | await usernameInput.sendKeys('admin'); 18 | await passwordInput.sendKeys('admin'); 19 | return submitButton.click(); 20 | } 21 | 22 | async getUrl() { 23 | return await browser.getCurrentUrl(); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | DronesymFrontend 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /dronesym-frontend/README.md: -------------------------------------------------------------------------------- 1 | # DroneSym Frontend 2 | 3 | The frontend app written in angular2 for DroneSym project 4 | 5 | ### Installation 6 | 7 | Install AngularCLI 8 | 9 | ```sh 10 | $ npm install -g @angular/cli 11 | ``` 12 | Set environmental variable in `./dronesym-frontend/src/environments/environment.ts` 13 | 14 | ```sh 15 | mapsApiKey: 'YOUR_GOOGLE_MAPS_API_KEY', 16 | nodeApiURL: 'http://localhost:3000/dronesym/api/node', 17 | feedURL: 'http://localhost:3000/feed' 18 | ``` 19 | _Note: Dronesym Node server (`./dronesym-node/`) and DroneSym Flask server (`./dronesym-python/flask-api/src`) should be running before starting the frontend server_ 20 | 21 | Starting the Angular2 development server 22 | 23 | ```sh 24 | $ npm install 25 | $ ng serve 26 | ``` 27 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | root = true 3 | 4 | # Unix-style newlines with a newline ending every file 5 | [*] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | 9 | # Matches multiple files with brace expansion notation 10 | # Set default charset 11 | [*.{js,py}] 12 | charset = utf-8 13 | 14 | # 4 space indentation 15 | [*.py] 16 | indent_style = space 17 | indent_size = 4 18 | 19 | # Tab indentation (no size specified) 20 | [Makefile] 21 | indent_style = tab 22 | 23 | # Indentation override for all JS under lib directory 24 | [lib/**.js] 25 | indent_style = space 26 | indent_size = 2 27 | 28 | # Matches the exact files either package.json or .travis.yml 29 | [{package.json,.travis.yml}] 30 | indent_style = space 31 | indent_size = 2 32 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: required 2 | dist: trusty 3 | matrix: 4 | include: 5 | - language: python 6 | python: 7 | - 3.5 8 | install: "pip3 install -r dronesym-python/requirements.txt" 9 | script: pytest dronesym-python 10 | 11 | - language: node_js 12 | node_js: 13 | - "10" 14 | before_script: 15 | - cd dronesym-node 16 | - npm install 17 | - virtualenv -p python3 ../flask_env 18 | - source ../flask_env/bin/activate 19 | 20 | cache: 21 | directories: 22 | - "node_modules" 23 | script: 24 | - ((npm start;python3 ../dronesym-python/flask-api/src/main.py)&);(sleep 5 && npm test --timeout 10000 --exit)& 25 | services: 26 | - mongodb 27 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/login/login.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LoginComponent } from './login.component'; 4 | 5 | describe('LoginComponent', () => { 6 | let component: LoginComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LoginComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LoginComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/signup/signup.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { SignupComponent } from './signup.component'; 4 | 5 | describe('SignupComponent', () => { 6 | let component: SignupComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ SignupComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(SignupComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-view/user-view.component.html: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-view/user-view.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserViewComponent } from './user-view.component'; 4 | 5 | describe('UserViewComponent', () => { 6 | let component: UserViewComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserViewComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserViewComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/dashboard/dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DashboardComponent } from './dashboard.component'; 4 | 5 | describe('DashboardComponent', () => { 6 | let component: DashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DashboardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-list/drone-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DroneListComponent } from './drone-list.component'; 4 | 5 | describe('DroneListComponent', () => { 6 | let component: DroneListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DroneListComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DroneListComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drones-box/drones-box.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DronesBoxComponent } from './drones-box.component'; 4 | 5 | describe('DronesBoxComponent', () => { 6 | let component: DronesBoxComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DronesBoxComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DronesBoxComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-python/flask-api/src/threadrunner.py: -------------------------------------------------------------------------------- 1 | from threading import Thread, Lock 2 | from queue import Queue 3 | import threading 4 | 5 | q = Queue(maxsize=0) 6 | mq = Queue(maxsize=0) 7 | 8 | 9 | def execute_next(): 10 | global q, lock 11 | while True: 12 | (fn, args) = q.get() 13 | fn(args) 14 | q.task_done() 15 | 16 | 17 | def execute_mq(): 18 | global mq, lock 19 | while True: 20 | (fn, args) = mq.get() 21 | fn(args) 22 | mq.task_done() 23 | 24 | 25 | def initialize(thread_count=4): 26 | for i in range(thread_count - 1): 27 | worker = Thread(target=execute_next) 28 | worker.daemon = True 29 | worker.start() 30 | 31 | mq_worker = Thread(target=execute_mq) 32 | mq_worker.daemon = True 33 | mq_worker.start() 34 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/breadcrumb/breadcrumb.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { BreadcrumbComponent } from './breadcrumb.component'; 4 | 5 | describe('BreadcrumbComponent', () => { 6 | let component: BreadcrumbComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ BreadcrumbComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(BreadcrumbComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-signup/user-signup.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserSignupComponent } from './user-signup.component'; 4 | 5 | describe('UserSignupComponent', () => { 6 | let component: UserSignupComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserSignupComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserSignupComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-groups/drone-groups.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DroneGroupsComponent } from './drone-groups.component'; 4 | 5 | describe('DroneGroupsComponent', () => { 6 | let component: DroneGroupsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DroneGroupsComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DroneGroupsComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-dashboard/user-dashboard.component.html: -------------------------------------------------------------------------------- 1 | 14 | 15 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/confirm-dialog/confirm-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ConfirmDialogComponent } from './confirm-dialog.component'; 4 | 5 | describe('ConfirmDialogComponent', () => { 6 | let component: ConfirmDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ConfirmDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ConfirmDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/cursor-tooltip/cursor-tooltip.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { CursorTooltipComponent } from './cursor-tooltip.component'; 4 | 5 | describe('CursorTooltipComponent', () => { 6 | let component: CursorTooltipComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ CursorTooltipComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(CursorTooltipComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-dashboard/user-dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserDashboardComponent } from './user-dashboard.component'; 4 | 5 | describe('UserDashboardComponent', () => { 6 | let component: UserDashboardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserDashboardComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserDashboardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-node/config/passportconfig.js: -------------------------------------------------------------------------------- 1 | const JwtStrategy = require('passport-jwt').Strategy; 2 | const ExtractJwt = require('passport-jwt').ExtractJwt; 3 | const jwtConfig = require('./jwtconfig'); 4 | const User = require('../Models/user'); 5 | 6 | const jwtOptions = { 7 | jwtFromRequest: ExtractJwt.fromAuthHeaderWithScheme('jwt'), 8 | secretOrKey: jwtConfig.secret, 9 | }; 10 | 11 | const jwtAuthenticate = new JwtStrategy(jwtOptions, function(payload, done) { 12 | User.findById(payload.id, function(err, user) { 13 | if (err) { 14 | done(err); 15 | return; 16 | } 17 | 18 | if (user) { 19 | done(null, user); 20 | } else { 21 | console.log('User not found'); 22 | done(null, false); 23 | } 24 | }); 25 | }); 26 | 27 | module.exports = function(passport) { 28 | passport.use(jwtAuthenticate); 29 | }; 30 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/forgot-password/forgot-password.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ForgotPasswordComponent } from './forgot-password.component'; 4 | 5 | describe('ForgotPasswordComponent', () => { 6 | let component: ForgotPasswordComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ForgotPasswordComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ForgotPasswordComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-view/user-view.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, AfterViewInit } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { UserService } from '../user-service/user.service'; 4 | 5 | @Component({ 6 | selector: 'app-user-view', 7 | templateUrl: './user-view.component.html', 8 | styleUrls: ['./user-view.component.css'] 9 | }) 10 | export class UserViewComponent implements AfterViewInit { 11 | userRole: string; 12 | 13 | constructor(private router: Router, private userService: UserService) { 14 | this.userService.getUserRole().then((role) => { 15 | this.userRole = role; 16 | }); 17 | } 18 | 19 | ngAfterViewInit() { 20 | this.router.navigate(['dashboard/map']); 21 | } 22 | 23 | logout() { 24 | this.userService.logout(); 25 | this.router.navigate(['login']); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-option-box/drone-option-box.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { DroneOptionBoxComponent } from './drone-option-box.component'; 4 | 5 | describe('DroneOptionBoxComponent', () => { 6 | let component: DroneOptionBoxComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ DroneOptionBoxComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(DroneOptionBoxComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-management/user-management.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserManagementComponent } from './user-management.component'; 4 | 5 | describe('UserManagementComponent', () => { 6 | let component: UserManagementComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ UserManagementComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(UserManagementComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should be created', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/reset-code-dialog/reset-code-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ResetCodeDialogComponent } from './reset-code-dialog.component'; 4 | 5 | describe('ResetCodeDialogComponent', () => { 6 | let component: ResetCodeDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ ResetCodeDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(ResetCodeDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/reset-code-dialog/reset-code-dialog.component.html: -------------------------------------------------------------------------------- 1 | 21 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/route-guard/route-guard.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { CanActivate, Router } from '@angular/router'; 3 | import { UserService } from '../user-service/user.service'; 4 | 5 | @Injectable() 6 | export class RouteGuardService implements CanActivate { 7 | 8 | constructor(private userService: UserService, private router: Router) { } 9 | 10 | canActivate() { 11 | return this.isAuthenticated(); 12 | } 13 | 14 | private isAuthenticated(): Promise { 15 | return this.userService.isAuthenticated() 16 | .then((res) => { 17 | if (res) { 18 | return true; 19 | } else { 20 | this.router.navigate(['login']); 21 | return false; 22 | } 23 | }) 24 | .catch((err) => { 25 | this.router.navigate(['login']); 26 | return false; 27 | }); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/new-password-dialog/new-password-dialog.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { NewPasswordDialogComponent } from './new-password-dialog.component'; 4 | 5 | describe('NewPasswordDialogComponent', () => { 6 | let component: NewPasswordDialogComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ NewPasswordDialogComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(NewPasswordDialogComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/cursor-tooltip/cursor-tooltip.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input, ViewChild, OnChanges } from '@angular/core'; 2 | import { DecimalPipe } from '@angular/common'; 3 | 4 | @Component({ 5 | selector: 'app-cursor-tooltip', 6 | templateUrl: './cursor-tooltip.component.html', 7 | styleUrls: ['./cursor-tooltip.component.css'] 8 | }) 9 | export class CursorTooltipComponent implements OnInit { 10 | @ViewChild('tooltip') tooltip; 11 | @Input('latitude') latitude: number; 12 | @Input('longitude') longitude: number; 13 | 14 | @Input() 15 | set x(x: number) { 16 | const el = this.tooltip.nativeElement; 17 | el.style.left = `${x + 5}px`; 18 | } 19 | 20 | @Input() 21 | set y(y: number) { 22 | const el = this.tooltip.nativeElement; 23 | el.style.top = `${y + 5}px`; 24 | } 25 | 26 | 27 | constructor() { } 28 | 29 | ngOnInit() { 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /docs/src/components/header.js: -------------------------------------------------------------------------------- 1 | import { Link } from "gatsby" 2 | import PropTypes from "prop-types" 3 | import React from "react" 4 | const Header = ({ siteTitle }) => ( 5 |
11 |
18 |

19 | 26 | {siteTitle} 27 | 28 |

29 |
30 |
31 | ) 32 | 33 | Header.propTypes = { 34 | siteTitle: PropTypes.string, 35 | } 36 | 37 | Header.defaultProps = { 38 | siteTitle: ``, 39 | } 40 | 41 | export default Header 42 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-dashboard/user-dashboard.component.css: -------------------------------------------------------------------------------- 1 | .side-nav{ 2 | width: 12%; 3 | box-shadow: none; 4 | background-color: #efefef 5 | } 6 | 7 | .brand-logo{ 8 | padding-left: 6px; 9 | } 10 | 11 | .collection{ 12 | margin-top: 0; 13 | border: none; 14 | } 15 | 16 | .dashboard-button{ 17 | color: #01579b !important; 18 | text-transform: uppercase; 19 | height: 10%; 20 | border-radius: 0; 21 | background-color: inherit; 22 | border: none; 23 | text-align : center; 24 | } 25 | 26 | .dashboard-button:hover{ 27 | color: #01579b !important; 28 | } 29 | 30 | .dashboard-button.dash-yellow:hover{ 31 | color: #f9a825 !important; 32 | border-left: 5px solid #fdd835; 33 | } 34 | 35 | .dashboard-button.dash-green:hover{ 36 | color: #4caf50 !important; 37 | border-left: 5px solid #4caf50; 38 | } 39 | 40 | .dashboard-button.dash-blue:hover { 41 | color : #01579b !important; 42 | border-left: 5px solid #01579b; 43 | } -------------------------------------------------------------------------------- /dronesym-frontend/src/app/admin-authorize/admin-authorize.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router, CanActivate } from '@angular/router'; 3 | import { UserService } from '../user-service/user.service'; 4 | 5 | @Injectable() 6 | export class AdminAuthorizeService implements CanActivate { 7 | 8 | constructor(private router: Router, private userService: UserService) { } 9 | 10 | 11 | canActivate() { 12 | return this.userService.getUserRole() 13 | .then((role) => { 14 | if (role === 'admin') { 15 | return true; 16 | } else { 17 | this.router.navigate(['dashboard']); 18 | return false; 19 | } 20 | }, (err) => { 21 | console.log(err); 22 | this.router.navigate(['dashboard']); 23 | return false; 24 | }); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /dronesym-python/flask-api/tests/mocks.py: -------------------------------------------------------------------------------- 1 | from dronekit import VehicleMode 2 | 3 | class MockVehicle: 4 | class Commands: 5 | def __init__(self): 6 | self.cmds = [] 7 | 8 | def wait_ready(self): 9 | return True 10 | 11 | def clear(self): 12 | return True 13 | 14 | 15 | class Location: 16 | class GlobalRelativeFrame: 17 | def __init__(self): 18 | self.alt = 0 19 | 20 | def __init__(self): 21 | self.global_relative_frame = self.GlobalRelativeFrame() 22 | 23 | def setAltitude(self, altitude): 24 | self.global_relative_frame.alt = altitude 25 | 26 | def __init__(self): 27 | self.mode = VehicleMode('GUIDED') 28 | self.armed = False 29 | self.commands = self.Commands() 30 | self.location = self.Location() 31 | 32 | def setAltitude(self, altitude): 33 | self.location.setAltitude(altitude) 34 | 35 | class MockMavParser: 36 | def __init__(self): 37 | pass 38 | 39 | def create_mission(self, drone, waypoints): 40 | return True -------------------------------------------------------------------------------- /dronesym-frontend/src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | body{ 3 | margin: 0; 4 | } 5 | 6 | .info-pane{ 7 | position:relative; 8 | left: 12%; 9 | padding-left: 2%; 10 | } 11 | 12 | .info-header{ 13 | font-weight: thin; 14 | } 15 | 16 | .half-bar{ 17 | display: inline-block; 18 | height: 2px; 19 | } 20 | .breadcrumb { 21 | margin-bottom:-3px; 22 | list-style: none ; 23 | list-style-type: none; 24 | background-color: #eee; 25 | } 26 | .breadcrumb li { 27 | display: inline; 28 | font-size: 16px; 29 | padding-left:2px; 30 | } 31 | .breadcrumb li+li:before { 32 | padding: 8px; 33 | color:#22459C; 34 | content: ">\00a0"; 35 | } 36 | .breadcrumb li a { 37 | color: #0275d8; 38 | text-decoration: none; 39 | } 40 | ol.breadcrumb li a:hover { 41 | color: #01447e; 42 | text-decoration: underline; 43 | } 44 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drones-box/drones-box.component.html: -------------------------------------------------------------------------------- 1 | 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please do not create a Pull Request without creating an issue first. 2 | Any change needs to be discussed before proceeding. 3 | Failure to do so may result in the rejection of the pull request. 4 | 5 | Please provide enough information so that others can review your pull request: 6 | 7 | 8 | 9 | Explain the **details** for making this change. What existing problem does the pull request solve? 10 | 11 | 12 | 13 | **Test plan (required)** 14 | 15 | Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. 16 | 17 | 18 | 19 | **Code formatting** 20 | 21 | 22 | 23 | **Closing issues** 24 | 25 | Put `closes #XXXX` in your comment to auto-close the issue that your PR fixes (if such). 26 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/new-password-dialog/new-password-dialog.component.html: -------------------------------------------------------------------------------- 1 | 25 | -------------------------------------------------------------------------------- /dronesym-frontend/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, 'coverage'), reports: [ 'html', 'lcovonly' ], 20 | fixWebpackSourcePaths: true 21 | }, 22 | 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false 30 | }); 31 | }; 32 | -------------------------------------------------------------------------------- /docs/src/components/image.js: -------------------------------------------------------------------------------- 1 | import React from "react" 2 | import { useStaticQuery, graphql } from "gatsby" 3 | import Img from "gatsby-image" 4 | 5 | /* 6 | * This component is built using `gatsby-image` to automatically serve optimized 7 | * images with lazy loading and reduced file sizes. The image is loaded using a 8 | * `useStaticQuery`, which allows us to load the image from directly within this 9 | * component, rather than having to pass the image data down from pages. 10 | * 11 | * For more information, see the docs: 12 | * - `gatsby-image`: https://gatsby.dev/gatsby-image 13 | * - `useStaticQuery`: https://www.gatsbyjs.org/docs/use-static-query/ 14 | */ 15 | 16 | const Image = () => { 17 | const data = useStaticQuery(graphql` 18 | query { 19 | placeholderImage: file(relativePath: { eq: "drone_logo.png" }) { 20 | childImageSharp { 21 | fluid(maxWidth: 300) { 22 | ...GatsbyImageSharpFluid 23 | } 24 | } 25 | } 26 | } 27 | `) 28 | 29 | return 30 | } 31 | 32 | export default Image 33 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-list/drone-list.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Manage Drones

4 |
5 |
6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 |
14 |
15 | {{ drone.name }} - {{drone.description}} 16 | 17 | 18 | 19 |
20 |
21 | -------------------------------------------------------------------------------- /docs/gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `DroneSym - Documentation`, 4 | description: `Project Documentation about project DroneSym`, 5 | author: `@gatsbyjs`, 6 | }, 7 | plugins: [ 8 | `gatsby-plugin-react-helmet`, 9 | `gatsby-plugin-mdx`, 10 | { 11 | resolve: `gatsby-source-filesystem`, 12 | options: { 13 | name: `images`, 14 | path: `${__dirname}/src/images`, 15 | }, 16 | }, 17 | `gatsby-transformer-sharp`, 18 | `gatsby-plugin-sharp`, 19 | { 20 | resolve: `gatsby-plugin-manifest`, 21 | options: { 22 | name: `gatsby-starter-default`, 23 | short_name: `starter`, 24 | start_url: `/`, 25 | background_color: `#663399`, 26 | theme_color: `#663399`, 27 | display: `minimal-ui`, 28 | icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site. 29 | }, 30 | }, 31 | // this (optional) plugin enables Progressive Web App + Offline functionality 32 | // To learn more, visit: https://gatsby.dev/offline 33 | // `gatsby-plugin-offline`, 34 | ], 35 | } 36 | -------------------------------------------------------------------------------- /docs/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed, async } from '@angular/core/testing'; 2 | 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async(() => { 7 | TestBed.configureTestingModule({ 8 | declarations: [ 9 | AppComponent 10 | ], 11 | }).compileComponents(); 12 | })); 13 | 14 | it('should create the app', async(() => { 15 | const fixture = TestBed.createComponent(AppComponent); 16 | const app = fixture.debugElement.componentInstance; 17 | expect(app).toBeTruthy(); 18 | })); 19 | 20 | it(`should have as title 'app'`, async(() => { 21 | const fixture = TestBed.createComponent(AppComponent); 22 | const app = fixture.debugElement.componentInstance; 23 | expect(app.title).toEqual('app'); 24 | })); 25 | 26 | it('should render title in a h1 tag', async(() => { 27 | const fixture = TestBed.createComponent(AppComponent); 28 | fixture.detectChanges(); 29 | const compiled = fixture.debugElement.nativeElement; 30 | expect(compiled.querySelector('h1').textContent).toContain('Welcome to app!!'); 31 | })); 32 | }); 33 | -------------------------------------------------------------------------------- /dronesym-python/flask-api/src/node.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | import json 3 | import time 4 | import requests 5 | 6 | 7 | apiUrl = 'http://localhost:3000/dronesym/api/node' 8 | 9 | 10 | def update_drone(id, status): 11 | try: 12 | response = requests.post( 13 | apiUrl + '/update/' + str(id), 14 | json=status, 15 | headers={ 16 | 'Content-Type': 'application/json'}) 17 | return response.json() 18 | except requests.ConnectionError: 19 | print("Retrying...") 20 | time.sleep(0.1) 21 | return update_drone(id, status) 22 | 23 | 24 | def get_drone_by_id(id): 25 | try: 26 | response = requests.get(apiUrl + '/get/' + id) 27 | return response.json() 28 | except requests.ConnectionError: 29 | print("Retrying...") 30 | time.sleep(1) 31 | return get_drone_by_id(id) 32 | 33 | 34 | def get_drones(): 35 | try: 36 | response = requests.get(apiUrl + '/get') 37 | return response.json() 38 | except requests.ConnectionError: 39 | print("Retrying...") 40 | time.sleep(1) 41 | return get_drones() 42 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | 3 | Please answer the following questions for yourself before submitting an issue. **YOU MAY DELETE THE PREREQUISITES SECTION.** 4 | 5 | - [ ] I am running the latest version 6 | - [ ] I checked the documentation and found no answer 7 | - [ ] I checked to make sure that this issue has not already been filed 8 | - [ ] I'm reporting the issue to the correct repository (for multi-repository projects) 9 | 10 | # Expected Behavior 11 | 12 | Please describe the behavior you are expecting 13 | 14 | # Current Behavior 15 | 16 | What is the current behavior? 17 | 18 | # Failure Information (for bugs) 19 | 20 | Please help provide information about the failure if this is a bug. If it is not a bug, please remove the rest of this template. 21 | 22 | ## Steps to Reproduce 23 | 24 | Please provide detailed steps for reproducing the issue. 25 | 26 | 1. step 1 27 | 2. step 2 28 | 3. you get it... 29 | 30 | ## Context 31 | 32 | Please provide any relevant information about your setup. This is important in case the issue is not reproducible except for under certain conditions. 33 | 34 | 35 | ## Failure Logs 36 | 37 | Please include any relevant log snippets or files here. 38 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/confirm-dialog/confirm-dialog.component.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /dronesym-frontend/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | import 'zone.js/dist/jasmine-patch'; 7 | import 'zone.js/dist/async-test'; 8 | import 'zone.js/dist/fake-async-test'; 9 | import { getTestBed } from '@angular/core/testing'; 10 | import { 11 | BrowserDynamicTestingModule, 12 | platformBrowserDynamicTesting 13 | } from '@angular/platform-browser-dynamic/testing'; 14 | 15 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 16 | declare const __karma__: any; 17 | declare const require: any; 18 | 19 | // Prevent Karma from running prematurely. 20 | __karma__.loaded = function () {}; 21 | 22 | // First, initialize the Angular testing environment. 23 | getTestBed().initTestEnvironment( 24 | BrowserDynamicTestingModule, 25 | platformBrowserDynamicTesting() 26 | ); 27 | // Then we find all the tests. 28 | const context = require.context('./', true, /\.spec\.ts$/); 29 | // And load the modules. 30 | context.keys().map(context); 31 | // Finally, start Karma to run the tests. 32 | __karma__.start(); 33 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/login/login.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | import { MaterializeAction } from 'angular2-materialize'; 4 | import { Router } from '@angular/router'; 5 | import { UserService } from '../user-service/user.service'; 6 | 7 | declare var Materialize: any; 8 | 9 | @Component({ 10 | selector: 'app-login', 11 | templateUrl: './login.component.html', 12 | styleUrls: ['./login.component.css'] 13 | }) 14 | export class LoginComponent { 15 | private user: any = {}; 16 | 17 | constructor(private router: Router, private userService: UserService) { 18 | this.user.username = ''; 19 | this.user.password = ''; 20 | } 21 | 22 | setUsername($event) { 23 | this.user.username = $event.target.value; 24 | } 25 | 26 | setPassword($event) { 27 | this.user.password = $event.target.value; 28 | } 29 | 30 | onLogin($event) { 31 | $event.preventDefault(); 32 | this.userService.login(this.user.username, this.user.password) 33 | .then((res) => { 34 | if (res.status === 'OK') { 35 | this.router.navigate(['dashboard/map']); 36 | } else { 37 | Materialize.toast(res.msg, 4000); 38 | } 39 | }); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variables file 55 | .env 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /docs/src/components/layout.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Layout component that queries for data 3 | * with Gatsby's useStaticQuery component 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import { useStaticQuery, graphql } from "gatsby" 11 | 12 | import Header from "./header" 13 | import "./layout.css" 14 | 15 | const Layout = ({ children }) => { 16 | const data = useStaticQuery(graphql` 17 | query SiteTitleQuery { 18 | site { 19 | siteMetadata { 20 | title 21 | } 22 | } 23 | } 24 | `) 25 | 26 | return ( 27 | <> 28 |
29 |
37 |
{children}
38 |
39 | © {new Date().getFullYear()}, Built with 40 | {` `} 41 | Gatsby 42 |
43 |
44 | 45 | ) 46 | } 47 | 48 | Layout.propTypes = { 49 | children: PropTypes.node.isRequired, 50 | } 51 | 52 | export default Layout 53 | -------------------------------------------------------------------------------- /dronesym-frontend/src/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dronesym-frontend", 3 | "short_name": "dronesym-frontend", 4 | "theme_color": "#1976d2", 5 | "background_color": "#fafafa", 6 | "display": "standalone", 7 | "scope": "/", 8 | "start_url": "/", 9 | "icons": [ 10 | { 11 | "src": "assets/icons/icon-72x72.png", 12 | "sizes": "72x72", 13 | "type": "image/png" 14 | }, 15 | { 16 | "src": "assets/icons/icon-96x96.png", 17 | "sizes": "96x96", 18 | "type": "image/png" 19 | }, 20 | { 21 | "src": "assets/icons/icon-128x128.png", 22 | "sizes": "128x128", 23 | "type": "image/png" 24 | }, 25 | { 26 | "src": "assets/icons/icon-144x144.png", 27 | "sizes": "144x144", 28 | "type": "image/png" 29 | }, 30 | { 31 | "src": "assets/icons/icon-152x152.png", 32 | "sizes": "152x152", 33 | "type": "image/png" 34 | }, 35 | { 36 | "src": "assets/icons/icon-192x192.png", 37 | "sizes": "192x192", 38 | "type": "image/png" 39 | }, 40 | { 41 | "src": "assets/icons/icon-384x384.png", 42 | "sizes": "384x384", 43 | "type": "image/png" 44 | }, 45 | { 46 | "src": "assets/icons/icon-512x512.png", 47 | "sizes": "512x512", 48 | "type": "image/png" 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /dronesym-frontend/src/app/reset-code-dialog/reset-code-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, EventEmitter, Output, Input } from '@angular/core'; 2 | import { MaterializeAction } from 'angular2-materialize'; 3 | 4 | @Component({ 5 | selector: 'app-reset-code-dialog', 6 | templateUrl: './reset-code-dialog.component.html', 7 | styleUrls: ['./reset-code-dialog.component.css'] 8 | }) 9 | export class ResetCodeDialogComponent implements OnInit { 10 | modalActions = new EventEmitter(); 11 | code: string; 12 | codes:string; 13 | @Output('onResponse') onResponse = new EventEmitter(); 14 | @Input('message') message: string; 15 | @Input('inputEnabled') inputEnabled: boolean; 16 | @Input() 17 | 18 | set show(show: boolean) { 19 | if (show) { 20 | this.modalActions.emit({ action: 'modal', params: ['open']}); 21 | } else { 22 | this.modalActions.emit({ action: 'modal', params: ['close']}); 23 | } 24 | } 25 | 26 | constructor() { 27 | this.code = ''; 28 | } 29 | 30 | ngOnInit() { 31 | this.code = ''; 32 | } 33 | 34 | public setCode($event) { 35 | this.code = $event.target.value; 36 | } 37 | public cancel() { 38 | this.onResponse.emit('DIALOG_CANCEL'); 39 | } 40 | 41 | public confirm() { 42 | this.onResponse.emit({'message' : 'DIALOG_CONFIRM', 'code' : this.code}); 43 | } 44 | 45 | 46 | } 47 | -------------------------------------------------------------------------------- /dronesym-node/Models/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | const bcrypt = require('bcrypt'); 3 | 4 | const userSchema = new mongoose.Schema({ 5 | uname: { 6 | type: String, 7 | required: true, 8 | }, 9 | 10 | password: { 11 | type: String, 12 | required: true, 13 | }, 14 | role: { 15 | type: String, 16 | enum: ['user', 'admin'], 17 | lowercase: true, 18 | required: true, 19 | default: 'user', 20 | }, 21 | email: { 22 | type: String, 23 | required: true, 24 | }, 25 | groups: { 26 | type: [{ 27 | groupId: String, 28 | groupName: String, 29 | }], 30 | default: [], 31 | }, 32 | 33 | }, {timestamps: true}); 34 | 35 | userSchema.pre('save', function(next) { 36 | const user = this; 37 | const SALT_FACTOR = 5; 38 | 39 | bcrypt.genSalt(SALT_FACTOR, function(err, salt) { 40 | if (err) { 41 | return next(err); 42 | } 43 | 44 | bcrypt.hash(user.password, salt, null, function(err, hash) { 45 | if (err) { 46 | return next(err); 47 | } 48 | 49 | user.password = hash; 50 | next(); 51 | }); 52 | }); 53 | }); 54 | 55 | userSchema.methods.comparePassword = function(password, callBack) { 56 | bcrypt.compare(password, this.password, function(err, isMatch) { 57 | if (err) { 58 | callBack(err, null); 59 | return; 60 | } 61 | callBack(null, isMatch); 62 | }); 63 | }; 64 | 65 | module.exports = mongoose.model('User', userSchema); 66 | -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-default", 3 | "private": true, 4 | "description": "A simple starter to get up and developing quickly with Gatsby", 5 | "version": "0.1.0", 6 | "author": "Kyle Mathews ", 7 | "dependencies": { 8 | "@mdx-js/mdx": "^1.1.5", 9 | "@mdx-js/react": "^1.1.5", 10 | "gatsby": "^2.13.31", 11 | "gatsby-image": "^2.2.6", 12 | "gatsby-plugin-manifest": "^2.2.3", 13 | "gatsby-plugin-mdx": "^1.0.22", 14 | "gatsby-plugin-offline": "^2.2.4", 15 | "gatsby-plugin-react-helmet": "^3.1.2", 16 | "gatsby-plugin-sharp": "^2.2.8", 17 | "gatsby-source-filesystem": "^2.1.5", 18 | "gatsby-transformer-sharp": "^2.2.4", 19 | "prop-types": "^15.7.2", 20 | "react": "^16.8.6", 21 | "react-dom": "^16.8.6", 22 | "react-helmet": "^5.2.1" 23 | }, 24 | "devDependencies": { 25 | "prettier": "^1.18.2" 26 | }, 27 | "keywords": [ 28 | "gatsby" 29 | ], 30 | "license": "MIT", 31 | "scripts": { 32 | "build": "gatsby build", 33 | "develop": "gatsby develop", 34 | "format": "prettier --write src/**/*.{js,jsx}", 35 | "start": "npm run develop", 36 | "serve": "gatsby serve", 37 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\"" 38 | }, 39 | "repository": { 40 | "type": "git", 41 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 42 | }, 43 | "bugs": { 44 | "url": "https://github.com/gatsbyjs/gatsby/issues" 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/forgot-password/forgot-password.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 35 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/new-password-dialog/new-password-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, EventEmitter, Output, Input } from '@angular/core'; 2 | import { MaterializeAction } from 'angular2-materialize'; 3 | 4 | @Component({ 5 | selector: 'app-new-password-dialog', 6 | templateUrl: './new-password-dialog.component.html', 7 | styleUrls: ['./new-password-dialog.component.css'] 8 | }) 9 | export class NewPasswordDialogComponent implements OnInit { 10 | modalActions = new EventEmitter(); 11 | pass: any; 12 | @Output('onResponse') onResponse = new EventEmitter(); 13 | @Input('message') message: string; 14 | @Input('inputEnabled') inputEnabled: boolean; 15 | @Input() 16 | 17 | set show(show: boolean) { 18 | if (show) { 19 | this.modalActions.emit({ action: 'modal', params: ['open']}); 20 | } else { 21 | this.modalActions.emit({ action: 'modal', params: ['close']}); 22 | } 23 | } 24 | 25 | constructor() { 26 | this.pass = { password: '', retype: ''}; 27 | } 28 | 29 | ngOnInit() { 30 | } 31 | public setPassword($event) { 32 | this.pass.password = $event.target.value; 33 | } 34 | 35 | public setRetype($event) { 36 | this.pass.retype = $event.target.value; 37 | } 38 | 39 | public cancel() { 40 | this.onResponse.emit('DIALOG_CANCEL'); 41 | } 42 | 43 | public confirm() { 44 | if (this.pass.password === this.pass.retype) { 45 | this.onResponse.emit({'message' : 'DIALOG_CONFIRM', 'pass' : this.pass.password, 'retype' : this.pass.retype}); 46 | } 47 | 48 | } 49 | 50 | 51 | } 52 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/login/login.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 42 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-option-box/drone-option-box.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core'; 2 | import { DecimalPipe } from '@angular/common'; 3 | import { MaterializeAction } from 'angular2-materialize'; 4 | 5 | @Component({ 6 | selector: 'app-drone-option-box', 7 | templateUrl: './drone-option-box.component.html', 8 | styleUrls: ['./drone-option-box.component.css'] 9 | }) 10 | export class DroneOptionBoxComponent implements OnInit { 11 | 12 | droneState: string; 13 | droneHeading: number; 14 | droneSpeed: number; 15 | droneAlt: number; 16 | 17 | @Output('onSelected') onSelected = new EventEmitter(); 18 | @Input('name') droneName: string; 19 | @Input('description') droneDescription: string; 20 | 21 | @Input() 22 | set state(state: string) { 23 | this.droneState = state || 'FINISHED'; 24 | } 25 | @Input() 26 | set altitude(value: number) { 27 | this.droneAlt = value || 0; 28 | } 29 | @Input() 30 | set heading(value: number) { 31 | this.droneHeading = value || 0; 32 | } 33 | @Input() 34 | set airspeed(value: number) { 35 | this.droneSpeed = value || 0; 36 | } 37 | 38 | constructor() { 39 | this.droneState = 'FINISHED'; 40 | } 41 | 42 | ngOnInit() { 43 | } 44 | 45 | public onWaypoints() { 46 | this.onSelected.emit('SELECT_WAYPOINTS'); 47 | } 48 | 49 | public onTakeoff() { 50 | this.onSelected.emit('SELECT_TAKEOFF'); 51 | } 52 | 53 | public onResume() { 54 | this.onSelected.emit('SELECT_RESUME'); 55 | } 56 | 57 | public onCancel() { 58 | this.onSelected.emit('SELECT_CANCEL'); 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drones-box/drones-box.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; 2 | import { MaterializeAction } from 'angular2-materialize'; 3 | 4 | @Component({ 5 | selector: 'app-drones-box', 6 | templateUrl: './drones-box.component.html', 7 | styleUrls: ['./drones-box.component.css'] 8 | }) 9 | export class DronesBoxComponent { 10 | 11 | modalActions = new EventEmitter(); 12 | selectedItems: any; 13 | 14 | @Input() 15 | set show(show: boolean) { 16 | if (show) { 17 | this.modalActions.emit({ action: 'modal', params: ['open']}); 18 | } else { 19 | this.modalActions.emit({ action: 'modal', params: ['close']}); 20 | } 21 | } 22 | 23 | @Input('drones') drones: any; 24 | @Input('message') message: string; 25 | @Output('onResponse') response = new EventEmitter(); 26 | 27 | constructor() { 28 | 29 | this.selectedItems = []; 30 | } 31 | 32 | toggleDrone(droneId) { 33 | // console.log(droneId); 34 | // console.log(this.drones); 35 | if (this.selectedItems.indexOf(droneId) === -1) { 36 | this.selectedItems.push(droneId); 37 | } else { 38 | this.selectedItems = this.selectedItems.filter((id) => id !== droneId); 39 | } 40 | } 41 | 42 | isSelected(droneId) { 43 | return this.selectedItems.indexOf(droneId) > -1; 44 | } 45 | 46 | confirm() { 47 | this.response.emit({ action : 'DRONES_BOX_CONFIRM' , items : this.selectedItems }); 48 | this.selectedItems = []; 49 | } 50 | 51 | cancel() { 52 | this.selectedItems = []; 53 | this.response.emit({ actions : 'DRONES_BOX_CANCEL'}); 54 | } 55 | 56 | } 57 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/auth-http/auth-http.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { Http, Headers, RequestOptions } from '@angular/http'; 4 | import { Observable , Operator } from 'rxjs'; 5 | // import 'rxjs/operator/map'; 6 | import 'rxjs/operator/share'; 7 | import { map, filter, catchError, mergeMap } from 'rxjs/operators'; 8 | import { from } from 'rxjs'; 9 | @Injectable() 10 | export class AuthHttpService { 11 | 12 | constructor(private http: Http, private router: Router) { } 13 | 14 | private getAuthHeader(): Headers { 15 | const token = localStorage.getItem('token'); 16 | const headers = new Headers(); 17 | headers.append('Authorization', token); 18 | 19 | return headers; 20 | } 21 | 22 | private checkAuthorization(request: Observable): Observable { 23 | request.pipe(map((res) => { 24 | const json = res.json(); 25 | if (json === 'Unauthorized') { 26 | this.router.navigate(['login']); 27 | return request; 28 | } else { 29 | return request; 30 | } 31 | }, (err) => { 32 | console.log(err); 33 | this.router.navigate(['login']); 34 | return request; 35 | })); 36 | 37 | return request; 38 | } 39 | 40 | public get(url: string): Observable { 41 | const authHeader = this.getAuthHeader(); 42 | const request = this.http.get(url, { 'headers': authHeader }); 43 | return this.checkAuthorization(request); 44 | } 45 | 46 | public post(url: string, data: any): Observable { 47 | const authHeader = this.getAuthHeader(); 48 | const request = this.http.post(url, data, { 'headers': authHeader }); 49 | return this.checkAuthorization(request); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/confirm-dialog/confirm-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; 2 | import { MaterializeAction } from 'angular2-materialize'; 3 | 4 | @Component({ 5 | selector: 'app-confirm-dialog', 6 | templateUrl: './confirm-dialog.component.html', 7 | styleUrls: ['./confirm-dialog.component.css'] 8 | }) 9 | export class ConfirmDialogComponent implements OnInit { 10 | 11 | modalActions = new EventEmitter(); 12 | name: string; 13 | description: string; 14 | flying_time: string; 15 | 16 | @Output('onResponse') onResponse = new EventEmitter(); 17 | @Input('message') message: string; 18 | @Input('inputEnabled') inputEnabled: boolean; 19 | @Input('newDrone') newDrone: boolean; 20 | @Input() 21 | set show(show: boolean) { 22 | if (show) { 23 | this.modalActions.emit({ action: 'modal', params: ['open']}); 24 | } else { 25 | this.modalActions.emit({ action: 'modal', params: ['close']}); 26 | } 27 | } 28 | 29 | constructor() { 30 | this.name = ''; 31 | this.description = ''; 32 | this.flying_time = ''; 33 | } 34 | 35 | ngOnInit() { 36 | } 37 | 38 | public setName($event) { 39 | this.name = $event.target.value; 40 | } 41 | public setDescription($event) { 42 | this.description = $event.target.value; 43 | } 44 | public setFlyingTime($event) { 45 | this.flying_time = $event.target.value; 46 | } 47 | public cancel() { 48 | this.onResponse.emit('DIALOG_CANCEL'); 49 | } 50 | 51 | public confirm() { 52 | this.onResponse.emit({'message' : 'DIALOG_CONFIRM', 'name' : 53 | this.name , 'description': this.description, 'flying_time': this.flying_time}); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-management/user-management.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Manage Users

4 |
5 |
6 | 7 |
8 | 9 | 12 | 13 | 14 | 15 | 16 |
17 |
    18 |
  • 19 | 20 |
    {{ user.uname }}
    21 | 22 |
    23 | add Add Groups 24 | 25 |
      26 |
    • {{ group.groupName }}clear
    • 27 |
    28 |
    29 |
  • 30 |
31 |
32 | 33 | 34 |
35 | 36 | -------------------------------------------------------------------------------- /dronesym-python/flask-api/src/mavparser.py: -------------------------------------------------------------------------------- 1 | from __future__ import print_function 2 | from dronekit import Vehicle, Command 3 | from pymavlink import mavutil 4 | 5 | 6 | def create_mission(drone, waypoints): 7 | cmds = drone.commands 8 | cmds.wait_ready() 9 | cmds.clear() 10 | 11 | cmds.add( 12 | Command( 13 | 0, 14 | 0, 15 | 0, 16 | mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT, 17 | mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 18 | 0, 19 | 0, 20 | 0, 21 | 0, 22 | 0, 23 | 0, 24 | waypoints[0]['lat'], 25 | waypoints[0]['lon'], 26 | 10)) 27 | 28 | for (i, wp) in enumerate(waypoints): 29 | cmds.add( 30 | Command( 31 | 0, 32 | 0, 33 | 0, 34 | mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT, 35 | mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 36 | 0, 37 | 0, 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | wp['lat'], 43 | wp['lon'], 44 | 10)) 45 | 46 | cmds.add(Command(0, 47 | 0, 48 | 0, 49 | mavutil.mavlink.MAV_FRAME_GLOBAL_RELATIVE_ALT, 50 | mavutil.mavlink.MAV_CMD_NAV_WAYPOINT, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 0, 57 | waypoints[-1]['lat'], 58 | waypoints[-1]['lon'], 59 | 10)) 60 | print('uploading mission...') 61 | 62 | cmds.upload() 63 | 64 | print('mission uploaded') 65 | 66 | return 67 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-signup/user-signup.component.html: -------------------------------------------------------------------------------- 1 | 48 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/signup/signup.component.css: -------------------------------------------------------------------------------- 1 | .login-background{ 2 | background-color: #f5f5f5; 3 | } 4 | 5 | .login-card{ 6 | margin-top: 2%; 7 | margin-bottom: 20%; 8 | } 9 | 10 | .logo-container{ 11 | height: 200px; 12 | width: 200px; 13 | margin-left: 26%; 14 | margin-right: auto; 15 | } 16 | 17 | .footer-label{ 18 | font-style: italic; 19 | color: #5e5e5e; 20 | } 21 | .card .card-image img { 22 | width:100%; 23 | align-items: center; 24 | } 25 | .card { 26 | min-width: 310px; 27 | } 28 | @media screen and (min-width:1500px) and (max-width: 2561px) { 29 | .card .card-image img { 30 | width: 100%; 31 | margin-left:100px; 32 | } 33 | } 34 | @media screen and (max-width: 1024px) { 35 | .card .card-image img { 36 | padding-right: 30px; 37 | } 38 | } 39 | 40 | @media screen and (max-width: 780px) { 41 | .row .col.offset-s4 { 42 | margin-left: 29%; 43 | } 44 | .card .card-image img { 45 | padding-right: 40px; 46 | } 47 | } 48 | 49 | .footer-label[_ngcontent-c1] { 50 | margin-left:70px; 51 | width:200px; 52 | } 53 | @media screen and (max-width: 560px) { 54 | .row .col.offset-s4 { 55 | margin-left: 18%; 56 | } 57 | } 58 | @media screen and (max-width: 530px) { 59 | .row .col.offset-s4 { 60 | margin-left: 16%; 61 | } 62 | .card .card-image img { 63 | padding-right: 30px; 64 | } 65 | } 66 | 67 | @media screen and (max-width: 470px) { 68 | .row .col.offset-s4 { 69 | margin-left: 10%; 70 | } 71 | .card .card-image img { 72 | padding-right: 35px; 73 | } 74 | } 75 | @media screen and (max-width: 400px) { 76 | .row .col.offset-s4 { 77 | margin-left: 6%; 78 | } 79 | .card .card-image img { 80 | padding-right: 40px; 81 | } 82 | } 83 | 84 | @media screen and (max-width: 330px) { 85 | .row .col.offset-s4 { 86 | margin-left: 4%; 87 | } 88 | .card { 89 | min-width: 270px; 90 | } 91 | .card .card-image img { 92 | padding-right: 50px; 93 | } 94 | } 95 | .btnn{ 96 | text-align: center 97 | } -------------------------------------------------------------------------------- /dronesym-node/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | let express = require('express'); 4 | let logger = require('morgan'); 5 | let mongoose = require('mongoose'); 6 | let passport = require('passport'); 7 | let bodyParser = require('body-parser'); 8 | let cors = require('cors'); 9 | let app = express(); 10 | let http = require('http'); 11 | require('dotenv').config(); 12 | // You can change the port to any other, if 3000 is busy or being used by any other service. 13 | let port = 3000; 14 | 15 | http = http.Server(app); 16 | let sockConn = require('./websocket').init(http); 17 | 18 | let droneRouter = require('./Routers/droneRouter'); 19 | let userRouter = require('./Routers/userRouter'); 20 | let mongoConfig = require('./config/example.mongoconfig'); 21 | 22 | app.use(logger('dev')); 23 | app.use(bodyParser.json()); 24 | app.use(bodyParser.urlencoded({extended: true})); 25 | app.use(cors()); 26 | 27 | // passport configuration 28 | let passportConfig = require('./config/passportconfig')(passport); 29 | app.use(passport.initialize()); 30 | 31 | // mongodb connection 32 | mongoose.connect(process.env.MONGO_URL, {useNewUrlParser: true}); 33 | 34 | mongoose.connection.on('error', function(err) { 35 | console.log(err); 36 | }); 37 | 38 | mongoose.connection.on('open', function() { 39 | console.log('Userbase connected...'); 40 | }); 41 | 42 | 43 | app.use('/dronesym/api/node', droneRouter); 44 | app.use('/dronesym/api/node/user', userRouter); 45 | 46 | // catch 404 and forward to error handler 47 | app.use(function(req, res, next) { 48 | let err = new Error('Not Found'); 49 | err.status = 404; 50 | next(err); 51 | }); 52 | 53 | app.use(function(err, req, res, next) { 54 | res.status(err.status || 500); 55 | res.json({ 56 | message: err.message, 57 | error: err, 58 | }); 59 | }); 60 | 61 | 62 | http.listen(port, function() { 63 | // eslint-disable-next-line no-console 64 | console.log('Listening on ' + port + '..'); 65 | }); 66 | 67 | module.exports = app; 68 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-groups/drone-groups.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

Manage Groups

4 |
5 |
6 | 7 |
8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
    19 |
  • 20 | 21 |
    {{ group.name }} {{ group.drones.length }}
    22 | 23 |
    24 | add Add Drones 25 | 26 |
      27 |
    • {{ getName(drone) }}clear
    • 28 |
    29 |
    30 |
  • 31 |
32 |
33 |
34 | -------------------------------------------------------------------------------- /dronesym-node/tests/drone_tests.js: -------------------------------------------------------------------------------- 1 | 2 | const assert = require('assert'); 3 | const randomstring = require('randomstring'); 4 | const {createUser} = require('../Controllers/userCtrl'); 5 | const user = ['', '', ''];// User Array 6 | // eslint-disable-next-line require-jsdoc 7 | function newUser(leng = 10, user) { 8 | // takes variable argument length, default is 10 9 | user[0] = randomstring.generate(leng);// Username 10 | user[1] = randomstring.generate(leng);// Password 11 | user[2] = 'User';// User 12 | user[3] = 'test@test.com'; // Email 13 | } 14 | 15 | describe('USER CONTROLLER', () => { 16 | describe('New User', () => { 17 | describe('Successfully Created', () => { 18 | before(() => { 19 | newUser(10, user); 20 | }); 21 | it('No Missing Requirements. Success.', (done) => { 22 | createUser(user[0], user[3], user[1], user[2], function(response) { 23 | assert.strictEqual(response.status, 'OK'); 24 | done(); 25 | }); 26 | }); 27 | }); 28 | describe('Throws Errors', () => { 29 | newUser(10, user); 30 | it('Username and Password Missing', (done) => { 31 | createUser('', user[3], '', user[2], function(response) { 32 | assert.strictEqual(response.status, 'ERROR'); 33 | done(); 34 | }); 35 | }); 36 | it('Username Missing', (done) => { 37 | createUser('', user[3], user[1], user[2], function(response) { 38 | assert.strictEqual(response.status, 'ERROR'); 39 | done(); 40 | }); 41 | }); 42 | it('Password Missing', (done) => { 43 | createUser(user[0], user[3], '', user[2], function(response) { 44 | assert.strictEqual(response.status, 'ERROR'); 45 | done(); 46 | }); 47 | it('Email Missing', (done) => { 48 | createUser(user[0], '', user[1], user[2], function(response) { 49 | assert.strictEqual(response.status, 'ERROR'); 50 | done(); 51 | }); 52 | }); 53 | }); 54 | }); 55 | }); 56 | }); 57 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/login/login.component.css: -------------------------------------------------------------------------------- 1 | .login-background{ 2 | background-color: #f5f5f5; 3 | } 4 | 5 | .login-card{ 6 | margin-top: 2%; 7 | margin-bottom: 20%; 8 | } 9 | 10 | .logo-container{ 11 | height: 200px; 12 | width: 200px; 13 | margin-left: 26%; 14 | margin-right: auto; 15 | } 16 | 17 | .footer-label{ 18 | font-style: italic; 19 | color: #5e5e5e; 20 | } 21 | .card .card-image img { 22 | width:100%; 23 | align-items: center; 24 | } 25 | .card { 26 | min-width: 310px; 27 | } 28 | @media screen and (min-width:1500px) and (max-width: 2561px) { 29 | .card .card-image img { 30 | width: 100%; 31 | margin-left:100px; 32 | } 33 | } 34 | @media screen and (max-width: 1024px) { 35 | .card .card-image img { 36 | padding-right: 30px; 37 | } 38 | } 39 | 40 | @media screen and (max-width: 780px) { 41 | .row .col.offset-s4 { 42 | margin-left: 29%; 43 | } 44 | .card .card-image img { 45 | padding-right: 40px; 46 | } 47 | } 48 | 49 | .footer-label[_ngcontent-c1] { 50 | margin-left:70px; 51 | width:200px; 52 | } 53 | 54 | #forgetLink { 55 | margin-top: 25px; 56 | } 57 | 58 | @media screen and (max-width: 560px) { 59 | .row .col.offset-s4 { 60 | margin-left: 18%; 61 | } 62 | } 63 | @media screen and (max-width: 530px) { 64 | .row .col.offset-s4 { 65 | margin-left: 16%; 66 | } 67 | .card .card-image img { 68 | padding-right: 30px; 69 | } 70 | } 71 | 72 | @media screen and (max-width: 470px) { 73 | .row .col.offset-s4 { 74 | margin-left: 10%; 75 | } 76 | .card .card-image img { 77 | padding-right: 35px; 78 | } 79 | } 80 | @media screen and (max-width: 400px) { 81 | .row .col.offset-s4 { 82 | margin-left: 6%; 83 | } 84 | .card .card-image img { 85 | padding-right: 40px; 86 | } 87 | } 88 | 89 | @media screen and (max-width: 330px) { 90 | .row .col.offset-s4 { 91 | margin-left: 4%; 92 | } 93 | .card { 94 | min-width: 270px; 95 | } 96 | .card .card-image img { 97 | padding-right: 50px; 98 | } 99 | } 100 | .btnn{ 101 | text-align: center 102 | } -------------------------------------------------------------------------------- /dronesym-node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "drone-sym", 3 | "version": "1.0.0", 4 | "description": "DroneSym NodeJS API", 5 | "keywords": [ 6 | "npm", 7 | "nodejs", 8 | "mongodb", 9 | "firebase", 10 | "drone", 11 | "python", 12 | "angularjs", 13 | "googlemaps" 14 | ], 15 | "main": "index.js", 16 | "scripts": { 17 | "test": "better-npm-run test", 18 | "start": "nodemon index.js" 19 | }, 20 | "betterScripts": { 21 | "test": { 22 | "command": "mocha ./tests", 23 | "env": { 24 | "NODE_ENV": "test" 25 | } 26 | } 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git+https://github.com/hasa93/DroneSym.git" 31 | }, 32 | "author": "SCoRe Community", 33 | "contributors": [ 34 | "dilinade", 35 | "hasa93", 36 | "rhperera", 37 | "malithsen", 38 | "charithccmc", 39 | "iammosespaulr" 40 | ], 41 | "license": "ISC", 42 | "bugs": { 43 | "url": "https://github.com/hasa93/DroneSym/issues" 44 | }, 45 | "homepage": "https://github.com/hasa93/DroneSym#readme", 46 | "engines": {}, 47 | "dependencies": { 48 | "bcrypt": "^3.0.6", 49 | "body-parser": "^1.18.3", 50 | "cookie-parser": "^1.4.4", 51 | "cors": "^2.8.5", 52 | "dotenv": "^8.1.0", 53 | "eslint": "^5.16.0", 54 | "eslint-config-google": "^0.13.0", 55 | "eslint-utils": "^1.4.2", 56 | "express": "^4.16.4", 57 | "http": "0.0.0", 58 | "is-ci": "^2.0.0", 59 | "jsonwebtoken": "^8.5.0", 60 | "mixin-deep": "^2.0.1", 61 | "mongoose": "^5.5.12", 62 | "morgan": "^1.9.1", 63 | "nodemailer": "^6.4.11", 64 | "nodemon": "^1.18.10", 65 | "passport": "^0.4.0", 66 | "passport-jwt": "^4.0.0", 67 | "request": "^2.88.0", 68 | "socket.io": "^2.2.0", 69 | "sinon": "^7.1.1", 70 | "sinon-mongoose": "^2.2.1", 71 | "socketio-jwt": "^4.5.0" 72 | }, 73 | "devDependencies": { 74 | "better-npm-run": "^0.1.1", 75 | "chai": "^4.2.0", 76 | "mocha": "^6.0.2", 77 | "random-location": "^1.0.12", 78 | "randomstring": "^1.1.5" 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-option-box/drone-option-box.component.html: -------------------------------------------------------------------------------- 1 |
2 | {{ droneName }} - {{ droneDescription}}
3 | terrain Altitude - {{ droneAlt | number:'1.2' }}
4 | navigation Heading - {{ droneHeading | number: '1.0-2' }}
5 | play_arrow Airspeed - {{ droneSpeed | number: '1.2'}} 6 |
7 | 8 |
9 |
10 | near_me 13 |
14 | 15 |
16 | explore 18 |
19 | 20 |
21 | replay 23 |
24 | 25 |
26 | clear 28 |
29 |
30 | -------------------------------------------------------------------------------- /docs/src/components/seo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * SEO component that queries for data with 3 | * Gatsby's useStaticQuery React hook 4 | * 5 | * See: https://www.gatsbyjs.org/docs/use-static-query/ 6 | */ 7 | 8 | import React from "react" 9 | import PropTypes from "prop-types" 10 | import Helmet from "react-helmet" 11 | import { useStaticQuery, graphql } from "gatsby" 12 | 13 | function SEO({ description, lang, meta, title }) { 14 | const { site } = useStaticQuery( 15 | graphql` 16 | query { 17 | site { 18 | siteMetadata { 19 | title 20 | description 21 | author 22 | } 23 | } 24 | } 25 | ` 26 | ) 27 | 28 | const metaDescription = description || site.siteMetadata.description 29 | 30 | return ( 31 | 72 | ) 73 | } 74 | 75 | SEO.defaultProps = { 76 | lang: `en`, 77 | meta: [], 78 | description: ``, 79 | } 80 | 81 | SEO.propTypes = { 82 | description: PropTypes.string, 83 | lang: PropTypes.string, 84 | meta: PropTypes.arrayOf(PropTypes.object), 85 | title: PropTypes.string.isRequired, 86 | } 87 | 88 | export default SEO 89 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-list/drone-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { DroneDataService } from '../drone-service/drone-data.service'; 3 | 4 | declare var Materialize; 5 | 6 | @Component({ 7 | selector: 'app-drone-list', 8 | templateUrl: './drone-list.component.html', 9 | styleUrls: ['./drone-list.component.css'] 10 | }) 11 | 12 | 13 | export class DroneListComponent { 14 | 15 | drones: any; 16 | showRenameConfirmation: boolean; 17 | showDeleteConfirmation: boolean; 18 | 19 | currDrone: any; 20 | 21 | constructor(private droneFeed: DroneDataService) { 22 | this.showDeleteConfirmation = false; 23 | this.showRenameConfirmation = false; 24 | 25 | this.drones = []; 26 | 27 | this.droneFeed.getDroneFeed() 28 | .subscribe((drones) => { 29 | // console.log(drones); 30 | if (this.drones.length !== drones.length) { 31 | this.drones = drones; 32 | } 33 | }); 34 | } 35 | 36 | showDeleteConfirmationDialog(drone) { 37 | this.currDrone = drone; 38 | // console.log(drone._id); 39 | this.showDeleteConfirmation = true; 40 | } 41 | 42 | showRenameConfirmationDialog(drone) { 43 | this.currDrone = drone; 44 | this.showRenameConfirmation = true; 45 | } 46 | 47 | deleteResponse($event) { 48 | if ($event.message === 'DIALOG_CONFIRM') { 49 | this.droneFeed.removeDrone(this.currDrone._id, this.currDrone.status) 50 | .then((res) => { 51 | console.log(res); 52 | 53 | if (res.status === 'ERROR') { 54 | Materialize.toast(`Can't Delete : ${res.msg}`, 4000); 55 | return; 56 | } else if (res.status === 'OK') { 57 | Materialize.toast('Drone removed from fleet', 4000); 58 | } 59 | }) 60 | .catch((err) => { 61 | console.log(err); 62 | }); 63 | } 64 | 65 | 66 | this.showDeleteConfirmation = false; 67 | } 68 | 69 | renameResponse($event) { 70 | if ($event.message === 'DIALOG_CONFIRM') { 71 | this.droneFeed.updateName(this.currDrone._id, $event.name) 72 | .then((res) => { 73 | console.log(res); 74 | this.currDrone.name = res.update.name; 75 | }); 76 | } 77 | 78 | this.showRenameConfirmation = false; 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/signup/signup.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 61 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/forgot-password/forgot-password.component.css: -------------------------------------------------------------------------------- 1 | .login-background{ 2 | background-color: #f5f5f5; 3 | } 4 | 5 | .login-card{ 6 | margin-top: 2%; 7 | margin-bottom: 20%; 8 | } 9 | 10 | .logo-container{ 11 | height: 200px; 12 | width: 200px; 13 | margin-left: 26%; 14 | margin-right: auto; 15 | } 16 | 17 | .footer-label{ 18 | font-style: italic; 19 | color: #5e5e5e; 20 | } 21 | .card .card-image img { 22 | width:100%; 23 | align-items: center; 24 | } 25 | .card { 26 | min-width: 310px; 27 | } 28 | @media screen and (min-width:1500px) and (max-width: 2561px) { 29 | .card .card-image img { 30 | width: 100%; 31 | margin-left:100px; 32 | } 33 | } 34 | @media screen and (max-width: 1024px) { 35 | .card .card-image img { 36 | padding-right: 30px; 37 | } 38 | } 39 | 40 | @media screen and (max-width: 780px) { 41 | .row .col.offset-s4 { 42 | margin-left: 29%; 43 | } 44 | .card .card-image img { 45 | padding-right: 40px; 46 | } 47 | } 48 | @media screen and (max-width: 660px) { 49 | .row .col.offset-s4 { 50 | margin-left: 25%; 51 | } 52 | .row .btn { 53 | float:left; 54 | margin-right:34% 55 | } 56 | } 57 | @media screen and (max-width: 630px) { 58 | .row .col.offset-s4 { 59 | margin-left: 24%; 60 | } 61 | .row .btn { 62 | float:right; 63 | margin-right:34% 64 | } 65 | } 66 | @media screen and (max-width: 630px) { 67 | .row .col.offset-s4 { 68 | margin-left: 22%; 69 | } 70 | .row .btn { 71 | float:right; 72 | margin-right:33% 73 | } 74 | .footer-label[_ngcontent-c1] { 75 | margin-left:70px; 76 | width:200px; 77 | } 78 | } 79 | @media screen and (max-width: 560px) { 80 | .row .col.offset-s4 { 81 | margin-left: 18%; 82 | } 83 | } 84 | @media screen and (max-width: 530px) { 85 | .row .col.offset-s4 { 86 | margin-left: 16%; 87 | } 88 | .card .card-image img { 89 | padding-right: 30px; 90 | } 91 | } 92 | 93 | @media screen and (max-width: 470px) { 94 | .row .col.offset-s4 { 95 | margin-left: 10%; 96 | } 97 | .card .card-image img { 98 | padding-right: 35px; 99 | } 100 | } 101 | @media screen and (max-width: 400px) { 102 | .row .col.offset-s4 { 103 | margin-left: 6%; 104 | } 105 | .card .card-image img { 106 | padding-right: 40px; 107 | } 108 | } 109 | 110 | @media screen and (max-width: 330px) { 111 | .row .col.offset-s4 { 112 | margin-left: 4%; 113 | } 114 | .card { 115 | min-width: 270px; 116 | } 117 | .card .card-image img { 118 | padding-right: 50px; 119 | } 120 | } 121 | .btnn{ 122 | text-align: center 123 | } 124 | -------------------------------------------------------------------------------- /dronesym-frontend/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dronesym-frontend", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "ng": "ng", 7 | "start": "ng serve", 8 | "build": "ng build", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e" 12 | }, 13 | "description": "Application For Controlling Drone Systems Remotely", 14 | "keywords": [ 15 | "npm", 16 | "nodejs", 17 | "mongodb", 18 | "firebase", 19 | "drone", 20 | "python", 21 | "angularjs", 22 | "googlemaps" 23 | ], 24 | "bugs": "https://github.com/scorelab/DroneSym/issues", 25 | "author": "SCoRe Community", 26 | "contributors": [ 27 | "dilinade", 28 | "hasa93", 29 | "rhperera", 30 | "malithsen", 31 | "charithccmc", 32 | "iammosespaulr" 33 | ], 34 | "repository": "https://github.com/scorelab/DroneSym", 35 | "homepage": "http://www.scorelab.org/", 36 | "engines": {}, 37 | "private": true, 38 | "dependencies": { 39 | "@agm/core": "^1.0.0-beta.5", 40 | "@angular/animations": "^7.2.8", 41 | "@angular/common": "^7.2.8", 42 | "@angular/compiler": "^7.2.8", 43 | "@angular/core": "^7.2.8", 44 | "@angular/forms": "^7.2.8", 45 | "@angular/http": "^7.2.8", 46 | "@angular/platform-browser": "^7.2.8", 47 | "@angular/platform-browser-dynamic": "^7.2.8", 48 | "@angular/pwa": "^0.12.4", 49 | "@angular/router": "^7.2.8", 50 | "@angular/service-worker": "^7.2.8", 51 | "angular2-materialize": "^15.1.10", 52 | "core-js": "^2.6.5", 53 | "hammerjs": "^2.0.8", 54 | "jquery": "^3.3.1", 55 | "materialize-css": "^0.100.2", 56 | "mixin-deep": "^2.0.1", 57 | "rxjs": "^6.4.0", 58 | "rxjs-compat": "^6.4.0", 59 | "socket.io-client": "^2.2.0", 60 | "tslib": "^1.9.3", 61 | "tslint": "^5.16.0", 62 | "zone.js": "^0.8.29" 63 | }, 64 | "devDependencies": { 65 | "@angular-devkit/build-angular": "^0.13.5", 66 | "@angular/cli": "^7.3.5", 67 | "@angular/compiler-cli": "^7.2.8", 68 | "@angular/language-service": "^7.2.8", 69 | "@types/jasmine": "^3.3.9", 70 | "@types/node": "^11.10.5", 71 | "codelyzer": "^4.5.0", 72 | "jasmine-core": "^3.3.0", 73 | "jasmine-spec-reporter": "^4.2.1", 74 | "karma": "^4.0.1", 75 | "karma-chrome-launcher": "^2.2.0", 76 | "karma-cli": "^2.0.0", 77 | "karma-coverage-istanbul-reporter": "^2.0.5", 78 | "karma-jasmine": "^2.0.1", 79 | "karma-jasmine-html-reporter": "^1.4.0", 80 | "protractor": "^5.4.2", 81 | "ts-node": "^8.0.3", 82 | "typescript": "3.1.6" 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /dronesym-node/tests/user_models.js: -------------------------------------------------------------------------------- 1 | var sinon = require('sinon'); 2 | var chai = require('chai'); 3 | var expect = chai.expect; 4 | 5 | var mongoose = require('mongoose'); 6 | require('sinon-mongoose'); 7 | var Todo = require('../Models/user'); 8 | 9 | /*-----GET ALL GROUPS-------------*/ 10 | describe("Get all User", function(){ 11 | it("should return all user field", function(done){ 12 | var TodoMock = sinon.mock(Todo); 13 | var expectedResult = {status: true, todo: []}; 14 | TodoMock.expects('find').yields(null, expectedResult); 15 | Todo.find(function (err, result) { 16 | TodoMock.verify(); 17 | TodoMock.restore(); 18 | expect(result.status).to.be.true; 19 | done(); 20 | }); 21 | }); 22 | 23 | it("should return error", function(done){ 24 | var TodoMock = sinon.mock(Todo); 25 | var expectedResult = {status: false, error: "Something went wrong"}; 26 | TodoMock.expects('find').yields(expectedResult, null); 27 | Todo.find(function (err, result) { 28 | TodoMock.verify(); 29 | TodoMock.restore(); 30 | expect(err.status).to.not.be.true; 31 | done(); 32 | }); 33 | }); 34 | }); 35 | 36 | /*----POSTING NEW GROUP------------*/ 37 | describe("Post a new user of drones", function(){ 38 | it("should create new user", function(done){ 39 | var TodoMock = sinon.mock(new Todo({ todo: 'Save new user from mock'})); 40 | var todo = TodoMock.object; 41 | var expectedResult = { status: true }; 42 | TodoMock.expects('save').yields(null, expectedResult); 43 | todo.save(function (err, result) { 44 | TodoMock.verify(); 45 | TodoMock.restore(); 46 | expect(result.status).to.be.true; 47 | done(); 48 | }); 49 | }); 50 | // Test will pass if the todo is not saved 51 | it("should return error, if user not saved", function(done){ 52 | var TodoMock = sinon.mock(new Todo({ todo: 'Save new user from mock'})); 53 | var todo = TodoMock.object; 54 | var expectedResult = { status: false }; 55 | TodoMock.expects('save').yields(expectedResult, null); 56 | todo.save(function (err, result) { 57 | TodoMock.verify(); 58 | TodoMock.restore(); 59 | expect(err.status).to.not.be.true; 60 | done(); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /dronesym-node/tests/group_models.js: -------------------------------------------------------------------------------- 1 | var sinon = require('sinon'); 2 | var chai = require('chai'); 3 | var expect = chai.expect; 4 | 5 | var mongoose = require('mongoose'); 6 | require('sinon-mongoose'); 7 | var Todo = require('../Models/group'); 8 | 9 | /*-----GET ALL GROUPS-------------*/ 10 | describe("Get all Groups", function(){ 11 | it("should return all groups field", function(done){ 12 | var TodoMock = sinon.mock(Todo); 13 | var expectedResult = {status: true, todo: []}; 14 | TodoMock.expects('find').yields(null, expectedResult); 15 | Todo.find(function (err, result) { 16 | TodoMock.verify(); 17 | TodoMock.restore(); 18 | expect(result.status).to.be.true; 19 | done(); 20 | }); 21 | }); 22 | 23 | it("should return error", function(done){ 24 | var TodoMock = sinon.mock(Todo); 25 | var expectedResult = {status: false, error: "Something went wrong"}; 26 | TodoMock.expects('find').yields(expectedResult, null); 27 | Todo.find(function (err, result) { 28 | TodoMock.verify(); 29 | TodoMock.restore(); 30 | expect(err.status).to.not.be.true; 31 | done(); 32 | }); 33 | }); 34 | }); 35 | 36 | /*----POSTING NEW GROUP------------*/ 37 | describe("Post a new group of drones", function(){ 38 | it("should create new post", function(done){ 39 | var TodoMock = sinon.mock(new Todo({ todo: 'Save new group from mock'})); 40 | var todo = TodoMock.object; 41 | var expectedResult = { status: true }; 42 | TodoMock.expects('save').yields(null, expectedResult); 43 | todo.save(function (err, result) { 44 | TodoMock.verify(); 45 | TodoMock.restore(); 46 | expect(result.status).to.be.true; 47 | done(); 48 | }); 49 | }); 50 | // Test will pass if the todo is not saved 51 | it("should return error, if post not saved", function(done){ 52 | var TodoMock = sinon.mock(new Todo({ todo: 'Save new group from mock'})); 53 | var todo = TodoMock.object; 54 | var expectedResult = { status: false }; 55 | TodoMock.expects('save').yields(expectedResult, null); 56 | todo.save(function (err, result) { 57 | TodoMock.verify(); 58 | TodoMock.restore(); 59 | expect(err.status).to.not.be.true; 60 | done(); 61 | }); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /dronesym-python/flask-api/tests/test_dronepool.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import mocks 3 | from dronekit import VehicleMode 4 | import unittest 5 | from inspect import getsourcefile 6 | import os.path 7 | import sys 8 | 9 | current_path = os.path.abspath(getsourcefile(lambda:0)) 10 | current_dir = os.path.dirname(current_path) 11 | parent_dir = current_dir[:current_dir.rfind(os.path.sep)] 12 | source_dir = os.path.join(parent_dir, 'src') 13 | 14 | sys.path.insert(0, source_dir) 15 | 16 | import dronepool 17 | 18 | class TestDronePool(unittest.TestCase): 19 | def setUp(self): 20 | dronepool.env_test = True 21 | dronepool.instance_count = 0 22 | 23 | def tearDown(self): 24 | dronepool.instance_count = 0 25 | dronepool.drone_pool = {} 26 | 27 | def test_create_new_drone(self): 28 | res = dronepool.create_new_drone( { "db_key" : "test" }) 29 | self.assertEqual(res['status'], "OK") 30 | self.assertEqual(res['id'], "test") 31 | self.assertEqual("test" in dronepool.drone_pool, True) 32 | 33 | def test_remove_drone(self): 34 | vehicle = mocks.MockVehicle() 35 | dronepool.drone_pool["test"] = vehicle 36 | 37 | res = dronepool.remove_drone({ "drone_id" : "test" }) 38 | self.assertEqual(res['status'], "OK") 39 | self.assertEqual(res['id'], "test") 40 | self.assertEqual("test" in dronepool.drone_pool, False) 41 | 42 | def test_remove_in_flight_drone(self): 43 | vehicle = mocks.MockVehicle() 44 | vehicle.mode = VehicleMode('AUTO') 45 | 46 | dronepool.drone_pool["test"] = vehicle 47 | res = dronepool.remove_drone({ "drone_id" : "test" }) 48 | self.assertEqual(res['status'], "ERROR") 49 | self.assertEqual("test" in dronepool.drone_pool, True) 50 | 51 | def test_remove_drone_with_invalid_key(self): 52 | res = dronepool.remove_drone({ "drone_id" : "test" }) 53 | self.assertEqual(res['status'], "ERROR") 54 | 55 | def test_land_drone_armed(self): 56 | vehicle = mocks.MockVehicle() 57 | vehicle.armed = True 58 | dronepool.drone_pool = { "test" : vehicle } 59 | res = dronepool.land_drone({ "drone_id" : "test" }) 60 | self.assertEqual(res, True) 61 | self.assertEqual(vehicle.mode, VehicleMode('LAND')) 62 | 63 | def test_land_drone_unarmed(self): 64 | vehicle = mocks.MockVehicle() 65 | vehicle.armed = False 66 | dronepool.drone_pool = { "test" : vehicle} 67 | res = dronepool.land_drone({ "drone_id" : "test" }) 68 | self.assertEqual(res, False) 69 | 70 | def test_run_mission(self): 71 | vehicle = mocks.MockVehicle() 72 | mavparser = mocks.MockMavParser() 73 | vehicle.setAltitude(10) 74 | dronepool.mavparser = mavparser 75 | dronepool.run_mission(vehicle, 10, waypoints=[]) 76 | self.assertEqual(vehicle.mode, VehicleMode('AUTO')) 77 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/signup/signup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { UserService } from '../user-service/user.service'; 4 | import { MaterializeAction } from 'angular2-materialize'; 5 | 6 | declare var Materialize; 7 | 8 | @Component({ 9 | selector: 'app-signup', 10 | templateUrl: './signup.component.html', 11 | styleUrls: ['./signup.component.css'] 12 | }) 13 | export class SignupComponent implements OnInit { 14 | 15 | private user: any; 16 | /** Regular expression for email validation */ 17 | regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/); 18 | 19 | constructor(private userService: UserService, private router: Router) { 20 | this.user = { uname: '', email: '', password: '', retype: '', role: '' }; 21 | } 22 | 23 | ngOnInit() { 24 | } 25 | public setUsername($event) { 26 | this.user.uname = $event.target.value; 27 | } 28 | public setEmail($event) { 29 | this.user.email = $event.target.value; 30 | } 31 | 32 | public setPassword($event) { 33 | this.user.password = $event.target.value; 34 | } 35 | 36 | public setRetype($event) { 37 | this.user.retype = $event.target.value; 38 | } 39 | public onRoleSelect($event) { 40 | const role = $event.target.value.toLowerCase(); 41 | this.user.role = role; 42 | } 43 | public onSignup($event) { 44 | $event.preventDefault(); 45 | 46 | if (this.user.uname === '' || this.user.password === '' || this.user.retype === '') { 47 | Materialize.toast('All fields must be specified', 3000); 48 | return; 49 | } 50 | 51 | if (!this.regexp.test(this.user.email)) { 52 | Materialize.toast('Please enter a valid Email Address', 3000); 53 | return; 54 | } 55 | 56 | if (this.user.role === '') { 57 | Materialize.toast('Please specify a user role', 3000); 58 | return; 59 | } 60 | 61 | if (this.user.password !== this.user.retype) { 62 | Materialize.toast('Retype password does not match', 3000); 63 | return; 64 | } 65 | 66 | this.userService.createUserFromSignup(this.user.uname, this.user.password, this.user.role, this.user.email) 67 | .then((status) => { 68 | if (status.status === 'OK') { 69 | Materialize.toast('User created successfully', 4000); 70 | 71 | } else if (status.status === 'ERROR') { 72 | Materialize.toast(status.msg, 4000); 73 | } 74 | }, (err) => { 75 | Materialize.toast('Oops something went wrong...', 4000); 76 | console.log(err); 77 | }); 78 | // console.log(this.user); 79 | } 80 | 81 | } 82 | 83 | -------------------------------------------------------------------------------- /dronesym-node/Routers/userRouter.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = new express.Router(); 3 | const userCtrl = require('../Controllers/userCtrl'); 4 | const passport = require('passport'); 5 | 6 | const authorize = userCtrl.authorizeUser; 7 | const authenticate = passport.authenticate('jwt', {session: false}); 8 | 9 | router.post('/login', function(req, res) { 10 | userCtrl.loginUser(req.body.uname, req.body.password, function(status) { 11 | res.json(status); 12 | }); 13 | }); 14 | router.post('/sendEmail', function(req, res) { 15 | userCtrl.sendEmail(req.body.code, function(status) { 16 | res.json(status); 17 | }); 18 | }); 19 | router.post('/updatePass', function(req, res) { 20 | userCtrl.updatePass(req.body.uname, req.body.password, function(status) { 21 | res.json(status); 22 | }); 23 | }); 24 | router.post('/check', function(req, res) { 25 | userCtrl.check(req.body.uname, function(status) { 26 | res.json(status); 27 | }); 28 | }); 29 | router.post('/create', authenticate, authorize(['admin']), function(req, res) { 30 | userCtrl.createUser(req.body.uname, req.body.email, 31 | req.body.password, req.body.role, 32 | function(status) { 33 | res.json(status); 34 | }); 35 | }); 36 | router.post('/createuser', function(req, res) { 37 | userCtrl.createUserFromSignup(req.body.uname, req.body.password, 38 | req.body.role, req.body.email, function(status) { 39 | res.json(status); 40 | }); 41 | }); 42 | 43 | router.get('/role', authenticate, function(req, res) { 44 | res.json({status: 'OK', role: req.user.role}); 45 | }); 46 | 47 | router.get('/authenticate', authenticate, function(req, res) { 48 | res.json('Authorized'); 49 | }); 50 | 51 | router.post('/:groupId/add', authenticate, authorize(['admin']), 52 | function(req, res) { 53 | userCtrl.updateUserGroups(req.body.userId, req.params.groupId, 54 | insert=true, function(status) { 55 | res.json(status); 56 | }); 57 | }); 58 | 59 | router.post('/:groupId/updategroup', authenticate, authorize(['admin']), 60 | function(req, res) { 61 | userCtrl.updateUserInGroup(req.body.userId, req.params.groupId, 62 | insert=true, 63 | function(status) { 64 | res.json(status); 65 | }); 66 | }); 67 | 68 | router.post('/:groupId/remove', authenticate, authorize(['admin']), 69 | function(req, res) { 70 | userCtrl.updateUserGroups(req.body.userId, req.params.groupId, 71 | insert=false, function(status) { 72 | res.json(status); 73 | }); 74 | }); 75 | 76 | router.get('/list', authenticate, authorize(['admin']), function(req, res) { 77 | userCtrl.getUserList(req.user.id, function(status) { 78 | res.json(status); 79 | }); 80 | }); 81 | 82 | module.exports = router; 83 | -------------------------------------------------------------------------------- /dronesym-frontend/src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/weak-map'; 35 | // import 'core-js/es6/set'; 36 | 37 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 38 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 39 | 40 | /** IE10 and IE11 requires the following to support `@angular/animation`. */ 41 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 42 | 43 | 44 | /** Evergreen browsers require these. **/ 45 | import 'core-js/es6/reflect'; 46 | 47 | 48 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/ 49 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 50 | 51 | 52 | 53 | /*************************************************************************************************** 54 | * Zone JS is required by Angular itself. 55 | */ 56 | import 'zone.js/dist/zone'; // Included with Angular CLI. 57 | 58 | 59 | 60 | /*************************************************************************************************** 61 | * APPLICATION IMPORTS 62 | */ 63 | 64 | /** 65 | * Date, currency, decimal and percent pipes. 66 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 67 | */ 68 | // import 'intl'; // Run `npm install --save intl`. 69 | /** 70 | * Need to import at least one locale-data with intl. 71 | */ 72 | // import 'intl/locale-data/jsonp/en'; 73 | -------------------------------------------------------------------------------- /dronesym-frontend/e2e/test.ts: -------------------------------------------------------------------------------- 1 | describe('End to End test for Login feature and check for possible vulnerabilities in DroneSym', function() { 2 | browser.driver.get('http:localhost:4200/dashboard'); 3 | console.log('\x1b[32m', 'E2E for Login & URL redirection vulnerability Started!'); 4 | it('Checking Login vulnerabilities', function() { 5 | browser.sleep(2000); 6 | expect(browser.driver.getCurrentUrl()).toMatch('http://localhost:4200/login'); 7 | console.log('\x1b[36m', '[Status: PASS!] No URL redirection vulnerability found'); 8 | }); 9 | it('Confirming page rendering', function() { 10 | browser.driver.get('http:localhost:4200'); 11 | // Checking the current url 12 | const path = browser.driver.getCurrentUrl(); 13 | expect(path).toMatch('http://localhost:4200/'); 14 | console.log('\x1b[32m', '[Status: PASS!] Server Accessibility is present.'); 15 | }); 16 | it('Confirming Sign In through Admin\'s account [submition through clicking the button]', function() { 17 | 18 | // Find page elements 19 | const NameField = browser.driver.findElement(By.id('username')); 20 | const PassField = browser.driver.findElement(By.id('password')); 21 | const LoginBtn = browser.driver.findElement(By.css('.btn')); 22 | 23 | // Fill input fields 24 | NameField.sendKeys('admin'); 25 | PassField.sendKeys('admin'); 26 | 27 | // Ensure fields contain what we've entered 28 | expect(NameField.getAttribute('value')).toEqual('admin'); 29 | expect(PassField.getAttribute('value')).toEqual('admin'); 30 | 31 | // Click to sign in - waiting for Angular as it is manually bootstrapped. 32 | LoginBtn.click().then(function() { 33 | browser.waitForAngular(); 34 | expect(browser.driver.getCurrentUrl()).toMatch('http://localhost:4200/dashboard/map'); 35 | }); 36 | }); 37 | console.log('\x1b[32m', '[Status: PASS!] Login activity using correct admin credentials is redirected to Maps page'); 38 | it('Confirming Login through user\'s account [submition through Enter button]', function() { 39 | browser.driver.get('http:localhost:4200/login'); 40 | // Checking the current url 41 | const path = browser.driver.getCurrentUrl(); 42 | expect(path).toMatch('http://localhost:4200/'); 43 | console.log('\x1b[36m', '[Status: PASS!] Login system through User\'s account is working properly'); 44 | const NameField = browser.driver.findElement(By.id('username')); 45 | const PassField = browser.driver.findElement(By.id('password')); 46 | const LoginBtn = browser.driver.findElement(By.css('.btn')); 47 | NameField.sendKeys('icarus'); 48 | PassField.sendKeys('icarus'); 49 | expect(NameField.getAttribute('value')).toEqual('icarus'); 50 | expect(PassField.getAttribute('value')).toEqual('icarus'); 51 | browser.actions().sendKeys(protractor.Key.ENTER).perform(); 52 | }); 53 | }); 54 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/app-router.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes, RouterStateSnapshot } from '@angular/router'; 3 | import { RouteGuardService } from './route-guard/route-guard.service'; 4 | import { AdminAuthorizeService } from './admin-authorize/admin-authorize.service'; 5 | 6 | import { AppComponent } from './app.component'; 7 | import { LoginComponent } from './login/login.component'; 8 | import { DashboardComponent } from './dashboard/dashboard.component'; 9 | import { UserSignupComponent } from './user-signup/user-signup.component'; 10 | import { UserViewComponent } from './user-view/user-view.component'; 11 | import { UserDashboardComponent } from './user-dashboard/user-dashboard.component'; 12 | import { DroneGroupsComponent } from './drone-groups/drone-groups.component'; 13 | import { DroneListComponent } from './drone-list/drone-list.component'; 14 | import { UserManagementComponent } from './user-management/user-management.component'; 15 | import { SignupComponent } from './signup/signup.component'; 16 | import { ForgotPasswordComponent } from './forgot-password/forgot-password.component'; 17 | 18 | const appRoutes: Routes = [ 19 | { 20 | path: 'login', 21 | component: LoginComponent 22 | }, 23 | { 24 | path: 'signup', 25 | component: SignupComponent 26 | }, 27 | { 28 | path: 'resetpassword', 29 | component: ForgotPasswordComponent 30 | }, 31 | { 32 | path: 'dashboard', 33 | data: { 34 | breadcrumb: 'Dashboard' 35 | }, 36 | component: UserViewComponent, 37 | canActivate: [ 38 | RouteGuardService 39 | ], 40 | children: [ 41 | { 42 | path: 'map', 43 | data: { 44 | breadcrumb: 'Map' 45 | }, 46 | component: DashboardComponent, 47 | canActivate: [RouteGuardService] 48 | }, 49 | { 50 | path: 'user', 51 | data: { 52 | breadcrumb: 'User' 53 | }, 54 | component: UserDashboardComponent, 55 | canActivate: [RouteGuardService], 56 | children: [ 57 | { 58 | path: 'groups', 59 | data: { 60 | breadcrumb: 'Manage Groups' 61 | }, 62 | component: DroneGroupsComponent, 63 | canActivate: [RouteGuardService] 64 | }, 65 | { 66 | path: 'list', 67 | data: { 68 | breadcrumb: 'Manage Drones' 69 | }, 70 | component: DroneListComponent, 71 | canActivate: [RouteGuardService] 72 | }, 73 | { 74 | path: 'users', 75 | data: { 76 | breadcrumb: 'Manage Users' 77 | }, 78 | component: UserManagementComponent, 79 | canActivate: [RouteGuardService] 80 | } 81 | ] 82 | } 83 | ] 84 | }, 85 | { 86 | path: '', 87 | component: LoginComponent 88 | }, 89 | { 90 | path: '**', 91 | component: LoginComponent 92 | } 93 | ]; 94 | 95 | @NgModule({ 96 | imports: [ 97 | RouterModule.forRoot(appRoutes) 98 | ], 99 | exports: [ 100 | RouterModule 101 | ] 102 | }) 103 | 104 | export class AppRouter {} 105 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at info@scorelab.org. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /dronesym-python/flask-api/src/main.py: -------------------------------------------------------------------------------- 1 | """ 2 | Main entry point for the Flask API. The API will provide 3 | """ 4 | # an interface to communicate with Dronekit instances 5 | from flask import jsonify, Flask 6 | from flask import abort, request 7 | from flask import make_response 8 | import dronepool 9 | import threadrunner 10 | 11 | app = Flask(__name__) 12 | api_base_url = '/dronesym/api/flask' 13 | 14 | 15 | # response.headers['X-Content-Type-Options'] = 'nosniff' 16 | # response.headers['X-Frame-Options'] = 'SAMEORIGIN' 17 | @app.after_request 18 | def apply_caching(response): 19 | response.headers["X-Frame-Options"] = "SAMEORIGIN" 20 | response.headers['X-Content-Type-Options'] = 'nosniff' 21 | return response 22 | 23 | @app.errorhandler(404) 24 | def send_not_found(error): 25 | return make_response(jsonify({"message": "Resource not found"}), 404) 26 | 27 | 28 | @app.errorhandler(400) 29 | def send_bad_request(error): 30 | return make_response(jsonify({"message": "Bad request"}), 400) 31 | 32 | 33 | @app.route(api_base_url + '/spawn', methods=['POST']) 34 | def create_new_drone(): 35 | 36 | # This routes creates a new Dronekit SITL in the Drone Pool. 37 | # The initial position needs to be send along the request as a JSON 38 | global q 39 | # response.headers['X-Content-Type-Options'] = 'nosniff' 40 | # response.headers['X-Frame-Options'] = 'SAMEORIGIN' 41 | if not request.json or not 'location'in request.json or 'droneId' not in request.json: 42 | abort(400) 43 | print(request.json) 44 | home = request.json['location'] 45 | drone_id = request.json['droneId'] 46 | q.put((dronepool.create_new_drone, {"db_key": drone_id, "home": home})) 47 | 48 | return jsonify({"status": "OK", "message": "Created new drone"}) 49 | 50 | 51 | @app.route(api_base_url + '/remove/', methods=['POST']) 52 | def remove_drone(drone_id): 53 | global q 54 | q.put((dronepool.remove_drone, {"drone_id": drone_id})) 55 | return jsonify({"status": "OK", "message": "Removed drone"}) 56 | 57 | 58 | @app.route(api_base_url + '//takeoff', methods=['POST']) 59 | def send_takeoff(drone_id): 60 | # This route issues a takeoff command to a specific drone 61 | global q 62 | if request.json and request.json['waypoints'] and len( 63 | request.json['waypoints']) > 0: 64 | q.put( 65 | (dronepool.takeoff_drone, { 66 | "drone_id": drone_id, "waypoints": request.json['waypoints']})) 67 | else: 68 | q.put((dronepool.takeoff_drone, {"drone_id": drone_id})) 69 | return jsonify({"status": "taking_off", "drone_id": drone_id}) 70 | 71 | 72 | @app.route(api_base_url + '//land', methods=['POST']) 73 | def send_land(drone_id): 74 | global q 75 | q.put((dronepool.land_drone, {"drone_id": drone_id})) 76 | return jsonify({"status": "landing", "drone_id": drone_id}) 77 | 78 | 79 | @app.route(api_base_url + '//resume', methods=['POST']) 80 | def send_resume(drone_id): 81 | global q 82 | q.put((dronepool.resume_flight, {"drone_id": drone_id})) 83 | return jsonify({"status": "resuming", "drone_id": drone_id}) 84 | 85 | 86 | if __name__ == '__main__': 87 | threadrunner.initialize() 88 | q = threadrunner.q 89 | dronepool.initialize() 90 | app.run(debug=True, use_reloader=False) 91 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-groups/drone-groups.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { DroneDataService } from '../drone-service/drone-data.service'; 3 | import { UserService } from '../user-service/user.service'; 4 | import { DronesBoxComponent } from '../drones-box/drones-box.component'; 5 | 6 | declare var Materialize: any; 7 | 8 | @Component({ 9 | selector: 'app-drone-groups', 10 | templateUrl: './drone-groups.component.html', 11 | styleUrls: ['./drone-groups.component.css'] 12 | }) 13 | export class DroneGroupsComponent { 14 | userRole: string; 15 | groups: any; 16 | showGroupDialog: boolean; 17 | showDronesDialog: boolean; 18 | drones: any; 19 | currGroup: string; 20 | 21 | constructor(private droneFeed: DroneDataService, private userService: UserService) { 22 | this.userRole = ''; 23 | this.showGroupDialog = false; 24 | this.showDronesDialog = false; 25 | this.drones = []; 26 | 27 | this.initialize(); 28 | } 29 | 30 | private initialize() { 31 | this.userService.getUserRole() 32 | .then((role) => this.userRole = role) 33 | .catch((err) => console.log(err)); 34 | 35 | this.droneFeed.getGroups() 36 | .then((res) => { 37 | this.groups = res.groups; 38 | // console.log(this.groups); 39 | }) 40 | .catch((err) => console.log(err)); 41 | 42 | this.droneFeed.getDroneFeed() 43 | .subscribe((drones) => { this.drones = drones; }); 44 | } 45 | 46 | 47 | createGroup($event) { 48 | if ($event.message === 'DIALOG_CONFIRM') { 49 | this.droneFeed.createGroup($event.name) 50 | .then((res) => { 51 | if (res.status === 'ERROR') { 52 | Materialize.toast(res.msg, 4000); 53 | return; 54 | } 55 | this.groups.push(res.group); 56 | }); 57 | } 58 | this.showGroupDialog = false; 59 | } 60 | 61 | showCreateGroupDialog() { 62 | this.showGroupDialog = true; 63 | } 64 | 65 | showSelectDronesDialog(groupId) { 66 | this.showDronesDialog = true; 67 | this.currGroup = groupId; 68 | } 69 | 70 | addDronesToGroup($event) { 71 | if ($event.action === 'DRONES_BOX_CONFIRM' && $event.items.length > 0) { 72 | this.droneFeed.addToGroup(this.currGroup, $event.items) 73 | .then((res) => { 74 | // console.log(res.group); 75 | const newGroup = res.group; 76 | this.groups = this.groups.map((group) => group._id === newGroup._id ? newGroup : group); 77 | }); 78 | } 79 | this.showDronesDialog = false; 80 | this.currGroup = ''; 81 | } 82 | 83 | removeGroup(groupId) { 84 | this.droneFeed.removeGroup(groupId) 85 | .then((res) => { 86 | console.log(res); 87 | Materialize.toast(`Deleted group ${res.group.name}`, 4000); 88 | this.groups = this.groups.filter((group) => group._id !== res.group._id); 89 | }) 90 | .catch((err) => { 91 | console.log(err); 92 | }); 93 | } 94 | 95 | removeFromGroup(groupId, droneId) { 96 | this.droneFeed.removeFromGroup(groupId, droneId) 97 | .then((res) => { 98 | console.log(res); 99 | const newGroup = res.group; 100 | this.groups = this.groups.map((group) => group._id === newGroup._id ? newGroup : group); 101 | }); 102 | } 103 | 104 | getName(droneId) { 105 | return this.drones.filter((drone) => drone._id === droneId) 106 | .map((drone) => drone.name); 107 | } 108 | 109 | 110 | } 111 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { environment } from '../environments/environment'; 4 | 5 | import { MaterializeModule } from 'angular2-materialize'; 6 | import { HttpModule } from '@angular/http'; 7 | import { AuthHttpService } from './auth-http/auth-http.service'; 8 | import { RouterModule, Routes} from '@angular/router'; 9 | import { AppRouter } from './app-router'; 10 | 11 | import { AppComponent } from './app.component'; 12 | import { AgmCoreModule } from '@agm/core'; 13 | import { DroneDataService } from './drone-service/drone-data.service'; 14 | import { UserService } from './user-service/user.service'; 15 | import { RouteGuardService } from './route-guard/route-guard.service'; 16 | import { AdminAuthorizeService } from './admin-authorize/admin-authorize.service'; 17 | import { CursorTooltipComponent } from './cursor-tooltip/cursor-tooltip.component'; 18 | import { ConfirmDialogComponent } from './confirm-dialog/confirm-dialog.component'; 19 | import { DroneOptionBoxComponent } from './drone-option-box/drone-option-box.component'; 20 | import { DashboardComponent } from './dashboard/dashboard.component'; 21 | import { LoginComponent } from './login/login.component'; 22 | import { UserSignupComponent } from './user-signup/user-signup.component'; 23 | import { UserViewComponent } from './user-view/user-view.component'; 24 | import { UserDashboardComponent } from './user-dashboard/user-dashboard.component'; 25 | import { DroneGroupsComponent } from './drone-groups/drone-groups.component'; 26 | import { DroneListComponent } from './drone-list/drone-list.component'; 27 | import { DronesBoxComponent } from './drones-box/drones-box.component'; 28 | import { UserManagementComponent } from './user-management/user-management.component'; 29 | import { SignupComponent } from './signup/signup.component'; 30 | import { BreadcrumbComponent } from './breadcrumb/breadcrumb.component'; 31 | import { ForgotPasswordComponent } from './forgot-password/forgot-password.component'; 32 | import { ResetCodeDialogComponent } from './reset-code-dialog/reset-code-dialog.component'; 33 | import { NewPasswordDialogComponent } from './new-password-dialog/new-password-dialog.component'; 34 | import { ServiceWorkerModule } from '@angular/service-worker'; 35 | 36 | @NgModule({ 37 | declarations: [ 38 | AppComponent, 39 | CursorTooltipComponent, 40 | ConfirmDialogComponent, 41 | DroneOptionBoxComponent, 42 | DashboardComponent, 43 | LoginComponent, 44 | UserSignupComponent, 45 | UserViewComponent, 46 | UserDashboardComponent, 47 | DroneGroupsComponent, 48 | DroneListComponent, 49 | DronesBoxComponent, 50 | UserManagementComponent, 51 | SignupComponent, 52 | BreadcrumbComponent, 53 | ForgotPasswordComponent, 54 | ResetCodeDialogComponent, 55 | NewPasswordDialogComponent 56 | ], 57 | imports: [ 58 | BrowserModule, 59 | MaterializeModule, 60 | HttpModule, 61 | AgmCoreModule.forRoot({ 62 | apiKey: environment.mapsApiKey 63 | }), 64 | AppRouter, 65 | ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }) 66 | ], 67 | providers: [ 68 | DroneDataService, 69 | UserService, 70 | AuthHttpService, 71 | RouteGuardService, 72 | AdminAuthorizeService 73 | ], 74 | bootstrap: [AppComponent] 75 | }) 76 | export class AppModule { } 77 | -------------------------------------------------------------------------------- /dronesym-frontend/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "arrow-return-shorthand": true, 7 | "callable-types": true, 8 | "class-name": true, 9 | "comment-format": [ 10 | true, 11 | "check-space" 12 | ], 13 | "curly": true, 14 | "eofline": true, 15 | "forin": true, 16 | "import-blacklist": [ 17 | true 18 | ], 19 | "import-spacing": true, 20 | "indent": [ 21 | true, 22 | "spaces" 23 | ], 24 | "interface-over-type-literal": true, 25 | "label-position": true, 26 | "max-line-length": [ 27 | true, 28 | 140 29 | ], 30 | "member-access": false, 31 | "member-ordering": [ 32 | true, 33 | "static-before-instance" 34 | ], 35 | "no-arg": true, 36 | "no-bitwise": true, 37 | "no-console": [ 38 | true, 39 | "debug", 40 | "info", 41 | "time", 42 | "timeEnd", 43 | "trace" 44 | ], 45 | "no-construct": true, 46 | "no-debugger": true, 47 | "no-duplicate-super": true, 48 | "no-empty": false, 49 | "no-empty-interface": true, 50 | "no-eval": true, 51 | "no-inferrable-types": [ 52 | true, 53 | "ignore-params" 54 | ], 55 | "no-misused-new": true, 56 | "no-non-null-assertion": true, 57 | "no-shadowed-variable": true, 58 | "no-string-literal": false, 59 | "no-string-throw": true, 60 | "no-switch-case-fall-through": true, 61 | "no-trailing-whitespace": true, 62 | "no-unnecessary-initializer": true, 63 | "no-unused-expression": true, 64 | "no-use-before-declare": true, 65 | "no-var-keyword": true, 66 | "object-literal-sort-keys": false, 67 | "one-line": [ 68 | true, 69 | "check-open-brace", 70 | "check-catch", 71 | "check-else", 72 | "check-whitespace" 73 | ], 74 | "prefer-const": true, 75 | "quotemark": [ 76 | true, 77 | "single" 78 | ], 79 | "radix": true, 80 | "semicolon": [ 81 | true 82 | ], 83 | "triple-equals": [ 84 | true, 85 | "allow-null-check" 86 | ], 87 | "typedef-whitespace": [ 88 | true, 89 | { 90 | "call-signature": "nospace", 91 | "index-signature": "nospace", 92 | "parameter": "nospace", 93 | "property-declaration": "nospace", 94 | "variable-declaration": "nospace" 95 | } 96 | ], 97 | "typeof-compare": true, 98 | "unified-signatures": true, 99 | "variable-name": false, 100 | "whitespace": [ 101 | true, 102 | "check-branch", 103 | "check-decl", 104 | "check-operator", 105 | "check-separator", 106 | "check-type" 107 | ], 108 | "directive-selector": [ 109 | true, 110 | "attribute", 111 | "app", 112 | "camelCase" 113 | ], 114 | "component-selector": [ 115 | true, 116 | "element", 117 | "app", 118 | "kebab-case" 119 | ], 120 | "use-input-property-decorator": true, 121 | "use-output-property-decorator": true, 122 | "use-host-property-decorator": true, 123 | "no-input-rename": false, 124 | "no-output-rename": false, 125 | "use-life-cycle-interface": true, 126 | "use-pipe-transform-interface": true, 127 | "component-class-suffix": true, 128 | "directive-class-suffix": true, 129 | "no-access-missing-member": true, 130 | "templates-use-public": true, 131 | "invoke-injectable": true 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-management/user-management.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { UserSignupComponent } from '../user-signup/user-signup.component'; 3 | import { UserService } from '../user-service/user.service'; 4 | import { DroneDataService } from '../drone-service/drone-data.service'; 5 | import { DronesBoxComponent } from '../drones-box/drones-box.component'; 6 | 7 | @Component({ 8 | selector: 'app-user-management', 9 | templateUrl: './user-management.component.html', 10 | styleUrls: ['./user-management.component.css'] 11 | }) 12 | export class UserManagementComponent implements OnInit { 13 | 14 | public showUserSignUpDialog: boolean; 15 | public showDroneGroupsDialog: boolean; 16 | public userRole; 17 | public users; 18 | public groups; 19 | public currUser; 20 | 21 | constructor(private userService: UserService, private droneService: DroneDataService) { 22 | this.showUserSignUpDialog = false; 23 | this.showDroneGroupsDialog = false; 24 | this.groups = []; 25 | this.users = []; 26 | this.currUser = ''; 27 | 28 | userService.getUserRole().then((role) => { 29 | this.userRole = role; 30 | }); 31 | 32 | userService.getUserList().then((users) => { 33 | this.users = users.users; 34 | // console.log(this.users); 35 | }); 36 | 37 | droneService.getGroups().then((groups) => { 38 | // console.log(groups); 39 | this.groups = groups.groups.map((group) => { 40 | return { 41 | name : group.name, 42 | _id : group._id 43 | }; 44 | }); 45 | }); 46 | } 47 | 48 | ngOnInit() { 49 | } 50 | 51 | private updateUser(userData) { 52 | this.users = this.users.map((user) => { 53 | // console.log(user); 54 | // console.log(userData); 55 | if (user._id === userData.id) { 56 | return userData; 57 | } else { 58 | return user; 59 | } 60 | }); 61 | } 62 | private updateGroup(groupData) { 63 | this.groups = this.groups.map((groups) => { 64 | if (groups._id === groupData.id) { 65 | return groupData; 66 | } else { 67 | return groups; 68 | } 69 | }); 70 | } 71 | 72 | public showCreateUserDialog() { 73 | this.showUserSignUpDialog = true; 74 | } 75 | 76 | public showGroupsDialog(userId) { 77 | this.showDroneGroupsDialog = true; 78 | this.currUser = userId; 79 | } 80 | 81 | public onDronesBoxResponse($event) { 82 | const groups = $event.items; 83 | // console.log(groups); 84 | 85 | groups.forEach((groupId) => { 86 | this.userService.addUserToGroup(this.currUser, groupId) 87 | .then((res) => { 88 | // console.log(res); 89 | this.updateUser(res.user); 90 | }); 91 | }); 92 | groups.forEach((groupId) => { 93 | this.userService.updateUserToGroup(this.currUser, groupId) 94 | .then((res) => { 95 | // console.log(res); 96 | this.updateGroup(res.user); 97 | }); 98 | }); 99 | 100 | this.showDroneGroupsDialog = false; 101 | this.currUser = ''; 102 | } 103 | 104 | public onUserSignupResponse() { 105 | this.userService.getUserList().then((users) => { 106 | this.users = users.users; 107 | }); 108 | this.showUserSignUpDialog = false; 109 | } 110 | 111 | public removeFromGroup(userId, groupId) { 112 | this.userService.removeUserFromGroup(userId, groupId) 113 | .then((res) => { 114 | this.updateUser(res.user); 115 | }); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 | menu 32 | 33 | 41 |
42 | 43 |
44 | done 45 |
46 | 47 |
48 | close 49 |
50 |
51 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/breadcrumb/breadcrumb.component.ts: -------------------------------------------------------------------------------- 1 | 2 | import { Component, OnInit } from '@angular/core'; 3 | import { ActivatedRoute, Router, NavigationEnd } from '@angular/router'; 4 | 5 | /** rxjs Imports */ 6 | import { filter } from 'rxjs/operators'; 7 | 8 | /** Custom Model */ 9 | import { Breadcrumb } from './breadcrumb'; 10 | 11 | 12 | const routeDataBreadcrumb = 'breadcrumb'; 13 | 14 | const routeParamBreadcrumb = 'routeParamBreadcrumb'; 15 | 16 | const routeResolveBreadcrumb = 'routeResolveBreadcrumb'; 17 | 18 | const routeAddBreadcrumbLink = 'addBreadcrumbLink'; 19 | 20 | @Component({ 21 | selector: 'app-breadcrumb', 22 | templateUrl: './breadcrumb.component.html', 23 | styleUrls: ['./breadcrumb.component.css'], 24 | 25 | }) 26 | export class BreadcrumbComponent implements OnInit { 27 | 28 | /** Array of breadcrumbs. */ 29 | breadcrumbs: Breadcrumb[]; 30 | 31 | 32 | constructor(private activatedRoute: ActivatedRoute, 33 | private router: Router) { 34 | this.generateBreadcrumbs(); 35 | } 36 | 37 | ngOnInit() { 38 | } 39 | 40 | /** 41 | * Generates the array of breadcrumbs for the visited route. 42 | */ 43 | generateBreadcrumbs() { 44 | const onNavigationEnd = this.router.events.pipe(filter(event => event instanceof NavigationEnd)); 45 | 46 | onNavigationEnd.subscribe(() => { 47 | this.breadcrumbs = []; 48 | let currentRoute = this.activatedRoute.root; 49 | let currentUrl = ''; 50 | 51 | while (currentRoute.children.length > 0) { 52 | const childrenRoutes = currentRoute.children; 53 | let breadcrumbLabel: any; 54 | let url: any; 55 | 56 | childrenRoutes.forEach(route => { 57 | currentRoute = route; 58 | breadcrumbLabel = false; 59 | 60 | if (route.outlet !== 'primary') { 61 | return; 62 | } 63 | 64 | const routeURL = route.snapshot.url.map(segment => segment.path).join('/'); 65 | currentUrl += `/${routeURL}`; 66 | 67 | if (currentUrl === '/') { 68 | breadcrumbLabel = 'Home'; 69 | } 70 | 71 | const hasData = (route.routeConfig && route.routeConfig.data); 72 | 73 | if (hasData) { 74 | if (route.snapshot.data.hasOwnProperty(routeResolveBreadcrumb) && route.snapshot.data[routeResolveBreadcrumb]) { 75 | breadcrumbLabel = route.snapshot.data; 76 | route.snapshot.data[routeResolveBreadcrumb].forEach((property: any) => { 77 | breadcrumbLabel = breadcrumbLabel[property]; 78 | }); 79 | } else if (route.snapshot.data.hasOwnProperty(routeParamBreadcrumb) && 80 | route.snapshot.paramMap.get(route.snapshot.data[routeParamBreadcrumb])) { 81 | breadcrumbLabel = route.snapshot.paramMap.get(route.snapshot.data[routeParamBreadcrumb]); 82 | } else if (route.snapshot.data.hasOwnProperty(routeDataBreadcrumb)) { 83 | breadcrumbLabel = route.snapshot.data[routeDataBreadcrumb]; 84 | } 85 | 86 | if (route.snapshot.data.hasOwnProperty(routeAddBreadcrumbLink)) { 87 | url = route.snapshot.data[routeAddBreadcrumbLink]; 88 | } else { 89 | url = currentUrl; 90 | } 91 | } 92 | 93 | const breadcrumb: Breadcrumb = { 94 | label: breadcrumbLabel, 95 | url: url 96 | }; 97 | if (breadcrumbLabel) { 98 | this.breadcrumbs.push(breadcrumb); 99 | } 100 | }); 101 | } 102 | }); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/forgot-password/forgot-password.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import { map } from 'rxjs/operators'; 3 | import { UserService } from '../user-service/user.service'; 4 | import { Router } from '@angular/router'; 5 | 6 | declare var Materialize: any; 7 | @Component({ 8 | selector: 'app-forgot-password', 9 | templateUrl: './forgot-password.component.html', 10 | styleUrls: ['./forgot-password.component.css'] 11 | }) 12 | export class ForgotPasswordComponent implements OnInit { 13 | private user: any = {}; 14 | http: any; 15 | baseUrl: any; 16 | userRole: any; 17 | genCode: string; 18 | dialogParams = { 19 | codeDialog: { show: false }, 20 | passDialog: {show: false} 21 | }; 22 | validUser: boolean; 23 | 24 | constructor(private router: Router, private userService: UserService) { 25 | this.user.username = ''; 26 | } 27 | setUsername($event) { 28 | this.user.username = $event.target.value; 29 | } 30 | generateCode() { 31 | // const min = 0; 32 | // const max = 9; 33 | // let rand; 34 | // let num = ''; 35 | const length = 10; 36 | let result = ''; 37 | const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; 38 | const charactersLength = characters.length; 39 | for ( let i = 0; i < length; i++ ) { 40 | result += characters.charAt(Math.floor(Math.random() * charactersLength)); 41 | } 42 | console.log(result); 43 | return result; 44 | 45 | 46 | } 47 | ngOnInit() { 48 | } 49 | 50 | sendEmail(code){ 51 | this.userService.sendEmail(code) 52 | .then((res) => { 53 | 54 | }); 55 | } 56 | checkUser($event) { 57 | this.genCode = this.generateCode(); 58 | $event.preventDefault(); 59 | this.userService.checkUser(this.user.username) 60 | .then((res) => { 61 | if (res.status === 'OK') { 62 | this.validUser = true; 63 | this.sendEmail(this.genCode); 64 | this.dialogParams.codeDialog.show = true; 65 | } else { 66 | Materialize.toast(res.msg, 4000); 67 | } 68 | }); 69 | } 70 | public processDialogResponse($data) { 71 | console.log('Generated :' + this.genCode); 72 | // ($data); 73 | if (this.validUser === true) { 74 | if ($data.message === 'DIALOG_CONFIRM') { 75 | if ($data.code === this.genCode) { 76 | this.dialogParams.passDialog.show = true; 77 | } else { 78 | Materialize.toast('Invalid code', 4000); 79 | } 80 | } else { 81 | Materialize.toast('Dialog canceled!', 4000); 82 | this.router.navigate(['/resetpassword']); 83 | } 84 | this.dialogParams.codeDialog.show = false; 85 | } 86 | } 87 | public processPassDialogResponse($data) { 88 | console.log($data); 89 | if ($data.pass !== $data.retype) { 90 | Materialize.toast('Retype password does not match', 3000); 91 | return; 92 | } else { 93 | console.log($data.pass); 94 | this.userService.updatePass(this.user.username, $data.pass) 95 | .then((status) => { 96 | if (status.status === 'OK') { 97 | Materialize.toast('Password updated successfully', 4000); 98 | this.router.navigate(['/login']); 99 | } else if (status.status === 'ERROR') { 100 | Materialize.toast(status.msg, 4000); 101 | } 102 | }, (err) => { 103 | Materialize.toast('Oops something went wrong...', 4000); 104 | console.log(err); 105 | }); 106 | } 107 | 108 | 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/user-signup/user-signup.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Output, Input, EventEmitter } from '@angular/core'; 2 | import { Router } from '@angular/router'; 3 | import { UserService } from '../user-service/user.service'; 4 | import { MaterializeAction } from 'angular2-materialize'; 5 | 6 | declare var Materialize; 7 | 8 | @Component({ 9 | selector: 'app-user-signup', 10 | templateUrl: './user-signup.component.html', 11 | styleUrls: ['./user-signup.component.css'] 12 | }) 13 | export class UserSignupComponent implements OnInit { 14 | 15 | modalActions = new EventEmitter(); 16 | 17 | /** Regular expression for email validation */ 18 | // tslint:disable-next-line: max-line-length 19 | regexp = new RegExp(/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/); 20 | 21 | @Output('onResponse') onResponse = new EventEmitter(); 22 | @Input() 23 | set show(show: boolean) { 24 | if (show) { 25 | this.modalActions.emit({ action: 'modal', params: ['open']}); 26 | } else { 27 | this.modalActions.emit({ action: 'modal', params: ['close']}); 28 | this.onResponse.emit({ status : 'CLOSED' }); 29 | } 30 | } 31 | 32 | 33 | private user: any; 34 | 35 | constructor(private userService: UserService, private router: Router) { 36 | this.user = { uname: '', email: '', password: '', retype: '', role: '' }; 37 | } 38 | 39 | ngOnInit() { } 40 | 41 | public setUsername($event) { 42 | this.user.uname = $event.target.value; 43 | } 44 | 45 | public setEmail($event) { 46 | this.user.email = $event.target.value; 47 | } 48 | 49 | public setPassword($event) { 50 | this.user.password = $event.target.value; 51 | } 52 | 53 | public setRetype($event) { 54 | this.user.retype = $event.target.value; 55 | } 56 | 57 | public onSignup($event) { 58 | $event.preventDefault(); 59 | 60 | if (this.user.uname === '' || this.user.password === '' || this.user.retype === '') { 61 | Materialize.toast('All fields must be specified', 3000); 62 | return; 63 | } 64 | 65 | if (!this.regexp.test(this.user.email)) { 66 | Materialize.toast('Please enter a valid Email Address', 3000); 67 | return; 68 | } 69 | 70 | if (this.user.role === '') { 71 | Materialize.toast('Please specify a user role', 3000); 72 | return; 73 | } 74 | 75 | if (this.user.password !== this.user.retype) { 76 | Materialize.toast('Retype password does not match', 3000); 77 | return; 78 | } 79 | 80 | this.userService.createUser(this.user.uname, this.user.email, this.user.password, this.user.role) 81 | .then((status) => { 82 | if (status.status === 'OK') { 83 | Materialize.toast('User created successfully', 4000); 84 | this.modalActions.emit({ action: 'modal', params: ['close']}); 85 | this.onResponse.emit({ status : 'CLOSED' }); 86 | } else if (status.status === 'ERROR') { 87 | Materialize.toast(status.msg, 4000); 88 | this.onResponse.emit({ status : 'ERROR', msg : status.msg }); 89 | } 90 | }, (err) => { 91 | Materialize.toast('Oops something went wrong...', 4000); 92 | this.onResponse.emit({ status : 'ERROR', msg : err }); 93 | console.log(err); 94 | }); 95 | // console.log(this.user); 96 | } 97 | 98 | public onRoleSelect($event) { 99 | const role = $event.target.value.toLowerCase(); 100 | this.user.role = role; 101 | // console.log(this.user); 102 | } 103 | 104 | public cancel() { 105 | this.onResponse.emit({ status : 'CANCEL' }); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /dronesym-node/Routers/droneRouter.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const passport = require('passport'); 3 | const drones = require('../Controllers/droneCtrl'); 4 | const userCtrl = require('../Controllers/userCtrl'); 5 | const router = new express.Router(); 6 | 7 | const authenticate = passport.authenticate('jwt', {session: false}); 8 | const authorize = userCtrl.authorizeUser; 9 | 10 | router.post('/create', authenticate, authorize(['admin']), function(req, res) { 11 | const drone = req.body; 12 | drones.createDrone(drone.name, drone.description, 13 | drone.flying_time, drone.location, req.user.id, function(response) { 14 | res.json(response); 15 | }); 16 | }); 17 | 18 | router.post('/remove/:id', authenticate, authorize(['admin']), 19 | function(req, res) { 20 | const drone = req.body; 21 | // console.log(drone); 22 | 23 | drones.removeDrone(req.params.id, drone.status, function(status) { 24 | res.json(status); 25 | }); 26 | }); 27 | 28 | router.get('/get', function(req, res) { 29 | drones.getDroneIds(function(ids) { 30 | res.json({'status': 'OK', 'drones': ids}); 31 | }); 32 | }); 33 | 34 | router.get('/get/:id', function(req, res) { 35 | drones.getDroneById(req.params.id, function(drone) { 36 | // console.log(drone); 37 | res.json(drone); 38 | }); 39 | }); 40 | 41 | router.post('/update/:id', function(req, res) { 42 | drones.updateDroneStatus(req.params.id, req.body, function(status) { 43 | res.json(status); 44 | }); 45 | }); 46 | 47 | router.post('/takeoff/:id', authenticate, authorize(['admin', 'user']), 48 | function(req, res) { 49 | const waypoints = req.body.waypoints; 50 | 51 | drones.takeoffDrone(req.params.id, waypoints, function(status) { 52 | res.json(status); 53 | }); 54 | }); 55 | 56 | router.post('/land/:id', authenticate, authorize(['admin', 'user']), 57 | function(req, res) { 58 | const droneId = req.params.id; 59 | 60 | drones.landDrone(droneId, function(status) { 61 | res.json(status); 62 | }); 63 | }); 64 | 65 | router.post('/update/waypoints/:id', authenticate, authorize(['admin', 'user']), 66 | function(req, res) { 67 | const droneId = req.params.id; 68 | const waypoints = req.body.waypoints; 69 | 70 | drones.updateWaypoints(droneId, waypoints, function(status) { 71 | // console.log(status); 72 | res.json(status); 73 | }); 74 | }); 75 | 76 | router.post('/resume/:id', authenticate, authorize(['admin', 'user']), 77 | function(req, res) { 78 | const droneId = req.params.id; 79 | drones.resumeFlight(droneId, function(status) { 80 | res.json(status); 81 | }); 82 | }); 83 | 84 | router.post('/groups/create', authenticate, authorize(['admin']), 85 | function(req, res) { 86 | drones.createGroup(req.body.name, req.user.id, function(status) { 87 | res.json(status); 88 | }); 89 | }); 90 | 91 | router.post('/groups/remove/:id', authenticate, authorize(['admin']), 92 | function(req, res) { 93 | drones.removeGroup(req.params.id, function(status) { 94 | res.json(status); 95 | }); 96 | }); 97 | 98 | router.get('/groups', authenticate, function(req, res) { 99 | drones.getGroups(req.user.id, function(status) { 100 | res.json(status); 101 | }); 102 | }); 103 | 104 | 105 | router.post('/groups/:id/add', authenticate, function(req, res) { 106 | drones.addToGroup(req.params.id, req.body.drones, function(status) { 107 | res.json(status); 108 | }); 109 | }); 110 | 111 | router.post('/groups/:id/remove/:droneId', authenticate, function(req, res) { 112 | drones.removeFromGroup(req.params.id, req.params.droneId, function(status) { 113 | res.json(status); 114 | }); 115 | }); 116 | 117 | module.exports = router; 118 | -------------------------------------------------------------------------------- /dronesym-frontend/src/app/drone-service/drone-data.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { AuthHttpService } from '../auth-http/auth-http.service'; 3 | import { environment } from '../../environments/environment'; 4 | import * as io from 'socket.io-client'; 5 | 6 | import { Observable } from 'rxjs'; 7 | import { map } from 'rxjs/operators'; 8 | 9 | import 'rxjs/add/operator/toPromise'; 10 | 11 | @Injectable() 12 | export class DroneDataService { 13 | 14 | private baseUrl: string; 15 | private drones: any; 16 | private droneObserver: any; 17 | 18 | feed: any; 19 | 20 | constructor(private http: AuthHttpService) { 21 | this.baseUrl = environment.nodeApiURL; 22 | this.drones = []; 23 | } 24 | 25 | public createDrone(name: string, description: string, flying_time: string, location: any): Promise { 26 | return this.http.post(`${this.baseUrl}/create`, 27 | { 'location' : location, 'name' : name, 'description': description, 'flying_time': flying_time}) 28 | .pipe(map((res) => res.json())) 29 | .toPromise(); 30 | } 31 | 32 | public removeDrone(droneId: string, droneStatus: string) { 33 | return this.http.post(`${this.baseUrl}/remove/${droneId}`, { 'status' : droneStatus }) 34 | .pipe(map((res) => res.json())) 35 | .toPromise(); 36 | } 37 | 38 | public getDroneFeed(): Observable { 39 | const feedObservable = new Observable((observer) => { 40 | const token = localStorage.getItem('token').slice(4); 41 | this.feed = io(environment.feedURL, { 'query' : `token=${token}`}); 42 | this.droneObserver = observer; 43 | 44 | this.feed.on('SOCK_FEED_UPDATE', (data) => { 45 | // console.log(data); 46 | this.drones = data; 47 | observer.next(this.drones); 48 | }); 49 | 50 | return () => { 51 | this.feed.disconnect(); 52 | }; 53 | }); 54 | 55 | return feedObservable; 56 | } 57 | 58 | public updateDroneWaypoints(droneId: string, waypoints: [any]) { 59 | return this.http.post(`${this.baseUrl}/update/waypoints/${droneId}`, { 'waypoints': waypoints}) 60 | .pipe(map((res) => res.json())) 61 | .toPromise(); 62 | } 63 | 64 | public takeOffDrone(droneId: string, waypoints: [any]) { 65 | return this.http.post(`${this.baseUrl}/takeoff/${droneId}`, {'waypoints': waypoints}) 66 | .pipe(map((res) => res.json())) 67 | .toPromise(); 68 | } 69 | 70 | public landDrone(droneId: string) { 71 | return this.http.post(`${this.baseUrl}/land/${droneId}`, {}) 72 | .pipe(map((res) => res.json())) 73 | .toPromise(); 74 | } 75 | 76 | public resumeFlight(droneId: string) { 77 | return this.http.post(`${this.baseUrl}/resume/${droneId}`, {}) 78 | .pipe(map((res) => res.json())) 79 | .toPromise(); 80 | } 81 | 82 | public createGroup(name: string) { 83 | return this.http.post(`${this.baseUrl}/groups/create`, { 'name' : name }) 84 | .pipe(map((res) => res.json())) 85 | .toPromise(); 86 | } 87 | 88 | public getGroups() { 89 | return this.http.get(`${this.baseUrl}/groups`) 90 | .pipe(map((res) => res.json())) 91 | .toPromise(); 92 | } 93 | 94 | public addToGroup(groupId: string, drones: [string]) { 95 | return this.http.post(`${this.baseUrl}/groups/${groupId}/add`, { 'drones' : drones }) 96 | .pipe(map((res) => res.json())) 97 | .toPromise(); 98 | } 99 | 100 | public removeFromGroup(groupId: string, droneId: string) { 101 | return this.http.post(`${this.baseUrl}/groups/${groupId}/remove/${droneId}`, {}) 102 | .pipe(map((res) => res.json())) 103 | .toPromise(); 104 | } 105 | 106 | public removeGroup(groupId: string) { 107 | return this.http.post(`${this.baseUrl}/groups/remove/${groupId}`, {}) 108 | .pipe(map((res) => res.json())) 109 | .toPromise(); 110 | } 111 | 112 | public updateName(droneId: string, newName: string) { 113 | return this.http.post(`${this.baseUrl}/update/${droneId}`, { 'name' : newName }) 114 | .pipe(map((res) => res.json())) 115 | .toPromise(); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | When contributing to this repository, please first discuss the change you wish to make via issue, 4 | email, or any other method with the owners of this repository before making a change. 5 | 6 | Please note we have a code of conduct, please follow it in all your interactions with the project. 7 | 8 | ## Pull Request Process 9 | 10 | 1. Ensure any install or build dependencies are removed before the end of the layer when doing a 11 | build. 12 | 2. Update the README.md with details of changes to the interface, this includes new environment 13 | variables, exposed ports, useful file locations and container parameters. 14 | 3. Increase the version numbers in any examples files and the README.md to the new version that this 15 | Pull Request would represent. The versioning scheme we use is [SemVer](http://semver.org/). 16 | 4. You may merge the Pull Request in once you have the sign-off of two other developers, or if you 17 | do not have permission to do that, you may request the second reviewer to merge it for you. 18 | 19 | ## Code of Conduct 20 | 21 | ### Our Pledge 22 | 23 | In the interest of fostering an open and welcoming environment, we as 24 | contributors and maintainers pledge to making participation in our project and 25 | our community a harassment-free experience for everyone, regardless of age, body 26 | size, disability, ethnicity, gender identity and expression, level of experience, 27 | nationality, personal appearance, race, religion, or sexual identity and 28 | orientation. 29 | 30 | ### Our Standards 31 | 32 | Examples of behavior that contributes to creating a positive environment 33 | include: 34 | 35 | * Using welcoming and inclusive language 36 | * Being respectful of differing viewpoints and experiences 37 | * Gracefully accepting constructive criticism 38 | * Focusing on what is best for the community 39 | * Showing empathy towards other community members 40 | 41 | Examples of unacceptable behavior by participants include: 42 | 43 | * The use of sexualized language or imagery and unwelcome sexual attention or 44 | advances 45 | * Trolling, insulting/derogatory comments, and personal or political attacks 46 | * Public or private harassment 47 | * Publishing others' private information, such as a physical or electronic 48 | address, without explicit permission 49 | * Other conduct which could reasonably be considered inappropriate in a 50 | professional setting 51 | 52 | ### Our Responsibilities 53 | 54 | Project maintainers are responsible for clarifying the standards of acceptable 55 | behavior and are expected to take appropriate and fair corrective action in 56 | response to any instances of unacceptable behavior. 57 | 58 | Project maintainers have the right and responsibility to remove, edit, or 59 | reject comments, commits, code, wiki edits, issues, and other contributions 60 | that are not aligned to this Code of Conduct, or to ban temporarily or 61 | permanently any contributor for other behaviors that they deem inappropriate, 62 | threatening, offensive, or harmful. 63 | 64 | ### Scope 65 | 66 | This Code of Conduct applies both within project spaces and in public spaces 67 | when an individual is representing the project or its community. Examples of 68 | representing a project or community include using an official project e-mail 69 | address, posting via an official social media account, or acting as an appointed 70 | representative at an online or offline event. Representation of a project may be 71 | further defined and clarified by project maintainers. 72 | 73 | ### Enforcement 74 | 75 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 76 | reported by contacting the project team at [INSERT EMAIL ADDRESS]. All 77 | complaints will be reviewed and investigated and will result in a response that 78 | is deemed necessary and appropriate to the circumstances. The project team is 79 | obligated to maintain confidentiality with regard to the reporter of an incident. 80 | Further details of specific enforcement policies may be posted separately. 81 | 82 | Project maintainers who do not follow or enforce the Code of Conduct in good 83 | faith may face temporary or permanent repercussions as determined by other 84 | members of the project's leadership. 85 | 86 | ### Attribution 87 | 88 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 89 | available at [http://contributor-covenant.org/version/1/4][version] 90 | 91 | [homepage]: http://contributor-covenant.org 92 | [version]: http://contributor-covenant.org/version/1/4/ 93 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/git,node,linux,python,angular,mongo 3 | 4 | ### Angular ### 5 | ## Angular ## 6 | # compiled output 7 | /dist 8 | /tmp 9 | /app/**/*.js 10 | /app/**/*.js.map 11 | 12 | # dependencies 13 | /node_modules 14 | /bower_components 15 | 16 | # IDEs and editors 17 | /.idea 18 | 19 | # misc 20 | /.sass-cache 21 | /connect.lock 22 | /coverage/* 23 | /libpeerconnection.log 24 | npm-debug.log 25 | testem.log 26 | /typings 27 | 28 | # e2e 29 | /e2e/*.js 30 | /e2e/*.map 31 | 32 | #System Files 33 | .DS_Store 34 | 35 | ### Git ### 36 | *.orig 37 | 38 | ### Linux ### 39 | *~ 40 | 41 | # temporary files which can be created if a process still has a handle open of a deleted file 42 | .fuse_hidden* 43 | 44 | # KDE directory preferences 45 | .directory 46 | 47 | # Linux trash folder which might appear on any partition or disk 48 | .Trash-* 49 | 50 | # .nfs files are created when an open file is removed but is still being accessed 51 | .nfs* 52 | 53 | ### Node ### 54 | # Logs 55 | logs 56 | *.log 57 | npm-debug.log* 58 | yarn-debug.log* 59 | yarn-error.log* 60 | 61 | # Runtime data 62 | pids 63 | *.pid 64 | *.seed 65 | *.pid.lock 66 | 67 | # Directory for instrumented libs generated by jscoverage/JSCover 68 | lib-cov 69 | 70 | # Coverage directory used by tools like istanbul 71 | coverage 72 | 73 | # nyc test coverage 74 | .nyc_output 75 | 76 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 77 | .grunt 78 | 79 | # Bower dependency directory (https://bower.io/) 80 | bower_components 81 | 82 | # node-waf configuration 83 | .lock-wscript 84 | 85 | # Compiled binary addons (http://nodejs.org/api/addons.html) 86 | build/Release 87 | 88 | # Dependency directories 89 | node_modules 90 | jspm_packages 91 | 92 | # Typescript v1 declaration files 93 | typings/ 94 | 95 | # Optional npm cache directory 96 | .npm 97 | 98 | # Optional eslint cache 99 | .eslintcache 100 | 101 | # Optional REPL history 102 | .node_repl_history 103 | 104 | # Output of 'npm pack' 105 | *.tgz 106 | 107 | # Yarn Integrity file 108 | .yarn-integrity 109 | 110 | ### Python ### 111 | # Byte-compiled / optimized / DLL files 112 | __pycache__/ 113 | *.py[cod] 114 | *$py.class 115 | 116 | # C extensions 117 | *.so 118 | 119 | # Distribution / packaging 120 | .Python 121 | build/ 122 | develop-eggs/ 123 | dist/ 124 | downloads/ 125 | eggs/ 126 | .eggs/ 127 | lib/ 128 | lib64/ 129 | parts/ 130 | sdist/ 131 | var/ 132 | wheels/ 133 | *.egg-info/ 134 | .installed.cfg 135 | *.egg 136 | 137 | # PyInstaller 138 | # Usually these files are written by a python script from a template 139 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 140 | *.manifest 141 | *.spec 142 | 143 | # Installer logs 144 | pip-log.txt 145 | pip-delete-this-directory.txt 146 | 147 | # Unit test / coverage reports 148 | htmlcov/ 149 | .tox/ 150 | .coverage 151 | .coverage.* 152 | .cache 153 | nosetests.xml 154 | coverage.xml 155 | *.cover 156 | .hypothesis/ 157 | 158 | # Translations 159 | *.mo 160 | *.pot 161 | 162 | # Django stuff: 163 | local_settings.py 164 | 165 | # Flask stuff: 166 | instance/ 167 | .webassets-cache 168 | 169 | # Scrapy stuff: 170 | .scrapy 171 | 172 | # Sphinx documentation 173 | docs/_build/ 174 | 175 | # PyBuilder 176 | target/ 177 | 178 | # Jupyter Notebook 179 | .ipynb_checkpoints 180 | 181 | # pyenv 182 | .python-version 183 | 184 | # celery beat schedule file 185 | celerybeat-schedule 186 | 187 | # SageMath parsed files 188 | *.sage.py 189 | 190 | # Environments 191 | .venv 192 | env/ 193 | venv/ 194 | ENV/ 195 | env.bak/ 196 | venv.bak/ 197 | 198 | # Spyder project settings 199 | .spyderproject 200 | .spyproject 201 | 202 | # Rope project settings 203 | .ropeproject 204 | 205 | # mkdocs documentation 206 | /site 207 | 208 | # mypy 209 | .mypy_cache/ 210 | 211 | #Python virtualenv directories 212 | *.pyc 213 | dronesym-python/flask-api/bin 214 | dronesym-python/flask-api/include 215 | dronesym-python/flask-api/lib 216 | dronesym-python/flask-api/pip-selfcheck.json 217 | 218 | #Config files 219 | dronesym-frontend/src/environments/environment.ts 220 | dronesym-node/db.js 221 | dronesym-node/config/mongoconfig.js 222 | dronesym-node/dronesym-d5898-5e6e2d94c38d.json 223 | dronesym-node/example.db.js 224 | #py.test caches 225 | dronesym-python/flask-api/tests/__pycache__ 226 | 227 | #.bak python 228 | *.bak 229 | 230 | # End of https://www.gitignore.io/api/git,node,linux,python,angular,firebase 231 | -------------------------------------------------------------------------------- /dronesym-frontend/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "dronesym-frontend": { 7 | "root": "", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "architect": { 11 | "build": { 12 | "builder": "@angular-devkit/build-angular:browser", 13 | "options": { 14 | "outputPath": "dist", 15 | "index": "src/index.html", 16 | "main": "src/main.ts", 17 | "tsConfig": "src/tsconfig.app.json", 18 | "polyfills": "src/polyfills.ts", 19 | "assets": [ 20 | "src/assets", 21 | "src/favicon.ico", 22 | "src/manifest.json" 23 | ], 24 | "styles": [ 25 | "src/styles.css", 26 | "./node_modules/materialize-css/dist/css/materialize.css" 27 | ], 28 | "scripts": [ 29 | "node_modules/jquery/dist/jquery.js", 30 | "node_modules/hammerjs/hammer.js", 31 | "./node_modules/materialize-css/dist/js/materialize.js" 32 | ] 33 | }, 34 | "configurations": { 35 | "production": { 36 | "optimization": true, 37 | "outputHashing": "all", 38 | "sourceMap": false, 39 | "extractCss": true, 40 | "namedChunks": false, 41 | "aot": true, 42 | "extractLicenses": true, 43 | "vendorChunk": false, 44 | "buildOptimizer": true, 45 | "fileReplacements": [ 46 | { 47 | "replace": "src/environments/environment.ts", 48 | "with": "src/environments/environment.prod.ts" 49 | } 50 | ], 51 | "serviceWorker": true, 52 | "ngswConfigPath": "src/ngsw-config.json" 53 | } 54 | } 55 | }, 56 | "serve": { 57 | "builder": "@angular-devkit/build-angular:dev-server", 58 | "options": { 59 | "browserTarget": "dronesym-frontend:build" 60 | }, 61 | "configurations": { 62 | "production": { 63 | "browserTarget": "dronesym-frontend:build:production" 64 | } 65 | } 66 | }, 67 | "extract-i18n": { 68 | "builder": "@angular-devkit/build-angular:extract-i18n", 69 | "options": { 70 | "browserTarget": "dronesym-frontend:build" 71 | } 72 | }, 73 | "test": { 74 | "builder": "@angular-devkit/build-angular:karma", 75 | "options": { 76 | "main": "src/test.ts", 77 | "karmaConfig": "./karma.conf.js", 78 | "polyfills": "src/polyfills.ts", 79 | "tsConfig": "src/tsconfig.spec.json", 80 | "scripts": [ 81 | "node_modules/jquery/dist/jquery.js", 82 | "node_modules/hammerjs/hammer.js", 83 | "node_modules/materialize-css/dist/js/materialize.js" 84 | ], 85 | "styles": [ 86 | "src/styles.css", 87 | "node_modules/materialize-css/dist/css/materialize.css" 88 | ], 89 | "assets": [ 90 | "src/assets", 91 | "src/favicon.ico", 92 | "src/manifest.json" 93 | ] 94 | } 95 | }, 96 | "lint": { 97 | "builder": "@angular-devkit/build-angular:tslint", 98 | "options": { 99 | "tsConfig": [ 100 | "src/tsconfig.app.json", 101 | "src/tsconfig.spec.json" 102 | ], 103 | "exclude": [] 104 | } 105 | } 106 | } 107 | }, 108 | "dronesym-frontend-e2e": { 109 | "root": "e2e", 110 | "sourceRoot": "e2e", 111 | "projectType": "application", 112 | "architect": { 113 | "e2e": { 114 | "builder": "@angular-devkit/build-angular:protractor", 115 | "options": { 116 | "protractorConfig": "./protractor.conf.js", 117 | "devServerTarget": "dronesym-frontend:serve" 118 | } 119 | }, 120 | "lint": { 121 | "builder": "@angular-devkit/build-angular:tslint", 122 | "options": { 123 | "tsConfig": [ 124 | "e2e/tsconfig.e2e.json" 125 | ], 126 | "exclude": [] 127 | } 128 | } 129 | } 130 | } 131 | }, 132 | "defaultProject": "dronesym-frontend", 133 | "schematics": { 134 | "@schematics/angular:component": { 135 | "prefix": "app", 136 | "styleext": "css" 137 | }, 138 | "@schematics/angular:directive": { 139 | "prefix": "app" 140 | } 141 | } 142 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![dronesym_logo](https://user-images.githubusercontent.com/17242746/47440055-18d8e280-d7cb-11e8-984c-8a495e281275.png) 2 | 3 | # DroneSym 4 | 5 | [![Build Status](https://travis-ci.org/scorelab/DroneSym.svg?branch=develop)](https://travis-ci.org/scorelab/DroneSym) 6 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/f21c3a60c4ec4c0caaf4ebdf60df0b26)](https://www.codacy.com/app/hcktheheaven/DroneSym?utm_source=github.com&utm_medium=referral&utm_content=scorelab/DroneSym&utm_campaign=Badge_Grade) 7 | [![Gitter](https://img.shields.io/gitter/room/nwjs/nw.js.svg)](https://gitter.im/scorelab/DroneSym) 8 | 9 | ### Setting Up the Project 10 | 11 | ### Prerequisites 12 | 13 | 1. Install Node.js 6.x (or higher) 14 | 2. Python version 2.7 (or higher) 15 | 3. MongoDB version 3.6 (or higher) 16 | 17 | ### Part 1 - Setting up the Node environment 18 | 19 | 1. After cloning the repo navigate to `dronesym-node` folder 20 | 2. Run `npm install` to pull the dependencies 21 | 3. To avoid the error : `exception in initAndListen: NonExistentPath: Data directory C:\data\db\ not found., terminating"(Windows) or "Error: dbpath (/data/db) doesn't exist"(Linux)`, create the dbpath as follows before running mongodb with replica set. 22 | **For Windows Users :** 23 | Create a folder C:\data\db 24 | **For Linux Users :** 25 | Run the following commands : 26 | To create the directory **/data/db** directory where **data** directory is in the **root** directory run: 27 | ```sh 28 | $ sudo mkdir -p /data/db 29 | ``` 30 | As the owner and the group of '/data' directory are root, we need to change ownership of the directory to the current user to access it. 31 | We can change the ownership of the directory as follows: 32 | ```sh 33 | $ sudo chown -R username:group/data 34 | $ sudo chmod 0755 /data/db 35 | ``` 36 | If one wants to change the MongoDB default data path i.e. "C:\data\db" (Windows) or "/data/db" (Linux) to some other directory then use: 37 | `mongod --dbpath new_dbpath` 38 | where **new_dbpath** is the path of the new data store directory. Ex : new_dbpath = /usr/local/var/mongodb-data 39 | 4. Run `mongod --replSet rs` to start running Mongo with a Replica Set. 40 | 5. Open another terminal without disturbing the terminal running mongod, then import the database with `mongorestore --db dronesym dronedb/dronesym` 41 | 6. Run `npm start` to start the Node server 42 | **Note: Make sure you have an admin account in the database under user collection. (Refer the schema in Models folder)** 43 | 44 | ### Part 2 - Setting up Python environment 45 | 46 | 1. After cloning the repo, navigate to the folder dronesym-python 47 | 2. Run `sudo pip install -r requirements.txt` to pull the dependencies 48 | 3. Navigate to `dronsym-python/flask-api/src` folder 49 | 4. Run `python main.py` to start the Flask server 50 | **Note: Node server should be running when starting up the Flask server** 51 | 52 | ### Part 3 - Setting up the Angular front-end 53 | 54 | **Make sure that you have Node6.x or higher version installed** 55 | 56 | Install AngularCLI 57 | 58 | ```sh 59 | $ npm install -g @angular/cli 60 | ``` 61 | 62 | Set environmental variable in `./dronesym-frontend/src/environments/environment.ts` 63 | 64 | **_Note:_** You will have to rename the `example.environment.ts` to `environment.ts` or create new file, for example by copying the example file: 65 | 66 | ```sh 67 | $ cp src/environments/example.environment.ts src/environments/environment.ts` 68 | ``` 69 | Edit the environment.ts as follows 70 | ```sh 71 | mapsApiKey: 'YOUR_GOOGLE_MAPS_API_KEY', 72 | nodeApiURL: 'http://localhost:3000/dronesym/api/node', 73 | feedURL: 'http://localhost:3000/feed' 74 | ``` 75 | 76 | **Note: Dronesym Node server (`./dronesym-node/`) and DroneSym Flask server (`./dronesym-python/flask-api/src`) should be running before starting the frontend server\_** 77 | 78 | **Note: You should enable Google Maps JavaScript API before using API key** 79 | 80 | Starting the Angular development server 81 | 82 | ```sh 83 | $ npm install 84 | $ ng serve 85 | ``` 86 | ### Runing tests 87 | 1.Navigate to `dronesym-node` folder and run `npm install http` 88 | 89 | 2.Then run yarn test 90 | 91 | ### Default login credentials 92 | 93 | #### Admin 94 | 95 | ``` 96 | username: admin 97 | password: admin 98 | ``` 99 | 100 | #### User 101 | 102 | ``` 103 | username: icarus 104 | password: icarus 105 | ``` 106 | 107 | ### Part 4 - Running with Docker (Optional) 108 | 109 | Checkout to docker branch 110 | 111 | ```sh 112 | $ git checkout docker 113 | ``` 114 | 115 | Navigate to the root folder 116 | 117 | Run 118 | 119 | ```sh 120 | $ docker-compose up 121 | ``` 122 | 123 | ### Run Unit Tests Node 124 | 125 | For node unit tests - **both the flask server and node server have to be running.** 126 | 127 | Navigate to `dronesym-node` 128 | Run `npm test` --------------------------------------------------------------------------------