diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 94ee418..a854c77 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -2,7 +2,7 @@ module.exports = { root: true, env: { browser: true, es2020: true }, extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'plugin:react-hooks/recommended'], - ignorePatterns: ['dist', '.eslintrc.cjs'], + ignorePatterns: ['dist', '.eslintrc.cjs', 'node_modules', 'webpack.config.js', 'webpack.config.prod.js', 'server'], parser: '@typescript-eslint/parser', plugins: ['react-refresh'], rules: { diff --git a/Readme.md b/Readme.md index 3252fc4..ed7b939 100644 --- a/Readme.md +++ b/Readme.md @@ -1,24 +1,107 @@ -# Problem why this project is not possible +![logo](https://i.imgur.com/lU5LxHe.png) -- Web app can't access location in background -- Web app can't access location when screen is off -- Web app can't access location when app is closed -- Web app can't access location when app is not in use -- Web app can't access location when app is not in foreground -- Web app can't access location when app is not in focus +# GeoAttend: Revolutionizing Attendance with Geofencing + +Introducing **GeoAttend**, a cutting-edge Geospatial Attendance System designed to streamline attendance tracking for organizations and events of all sizes. With a robust set of features and a +user-friendly interface, GeoAttend ensures accurate and efficient attendance management through advanced geofencing technology. + +## Screenshots + +![Screenshot 2023-09-02 221546](https://i.imgur.com/nZRuZ2A.png) + +![Screenshot 2023-09-02 221434](https://i.imgur.com/DJ9VjxK.png) + +![Screenshot 2023-09-02 221514](https://i.imgur.com/rlq9m1C.png) + +## Technologies Used: + +- **Frontend:** React, Redux, Material UI, React Router, React Hooks, React Context API, React Leaflet, React Geolocation, React Google Maps, React Google Charts, React Google Login, React Google + +- **Backend:** Node.js, Express.js, MongoDB, Mongoose, JWT, Bcrypt, Nodemailer, Nodemailer Sendgrid Transport, Nodemon, Concurrently, Axios, Dotenv, Cors, Body Parser, Cookie Parser, Multer, Multer + +- **API Testing:** Postman + +- **Development Environment:** VS Code, Git, GitHub, Heroku, Netlify, MongoDB Atlas + +- **Project Management:** Figma, Lucidchart, Google Docs + +- **Version Control:** Git, GitHub + +- **Deployment:** Heroku, Netlify, MongoDB Atlas + +## Installation + +#### Install Client + +```bash + npm install +``` + +#### Install Server + +```bash + cd server + npm install +``` + +## Run Locally + +Open frontend and backend in different terminals. Go to the project directory + +#### Start server + +Install dependencies + +```bash + cd server + npm install +``` + +```bash + npm run start:backend +``` + +#### Start Client + +Install dependencies + +```bash + npm install +``` + +```bash + npm run start:frontend +``` + +## Deployment -# Project Summary (NEVER OVER-ENGINEER) +To deploy this project run + +```bash + npm run prod +``` + +## Environment Variables + +To run this project, you will need to add the following environment variables to your .env file + +#### Server Env + +> put the env inside ./server/.env + +`MONGODB_URI` + +`TOKEN_SECRET` + +`PORT` + +# Project Summary - Automation - Production Ready - Scalable - Maintainable -# GeoAttend: Revolutionizing Attendance with Geofencing - -Introducing **GeoAttend**, a cutting-edge Geospatial Attendance System designed to streamline attendance tracking for organizations and events of all sizes. With a robust set of features and a -user-friendly interface, GeoAttend ensures accurate and efficient attendance management through advanced geofencing technology. - ## Key Features: - **Diverse Organizational Support:** GeoAttend caters to a wide range of organizations, including universities, event halls, classrooms, and more, offering seamless attendance management for @@ -66,48 +149,7 @@ reducing the administrative burden on organizations. GeoAttend also offers a diverse set of features, including event creation, location setting, event scheduling, and user management, empowering administrators to manage events with ease. The platform also caters to a wide range of organizations, including universities, event halls, classrooms, and more, offering seamless attendance management for hundreds of events across different locations. -## Technical Details: - -### Technologies Used: - -- **Frontend:** React, Redux, Material UI, React Router, React Hooks, React Context API, React Leaflet, React Geolocation, React Google Maps, React Google Charts, React Google Login, React Google - Places Autocomplete, React Google Recaptcha, React Google Maps Loader, React Google Maps API, React Google Maps Directions, React Google Maps Loader - -- **Backend:** Node.js, Express.js, MongoDB, Mongoose, JWT, Bcrypt, Nodemailer, Nodemailer Sendgrid Transport, Nodemon, Concurrently, Axios, Dotenv, Cors, Body Parser, Cookie Parser, Multer, Multer - S3, AWS SDK, AWS S3, GeoLib, GeoLib Clean Coordinates, GeoLib Get Center, GeoLib Get Bounding Box, GeoLib Get Distance, GeoLib Get Rhumb Line, GeoLib Get Rhumb Line Between, GeoLib Get Rhumb Line - Point, GeoLib Get Rhumb Line Point Between, GeoLib Get Great Circle, GeoLib Get Great Circle Between, GeoLib Get Great Circle Point, GeoLib Get Great Circle Point Between, GeoLib Get Nearest, - GeoLib Get Nearest Point, GeoLib Get Nearest Point Of Line, GeoLib Get Nearest Point Of Line Segment, GeoLib Get Nearest Point Of Polygon, GeoLib Get Nearest Point Of Polygon Edge, GeoLib Get - Nearest Point Of Polygon Vertex, GeoLib Get Nearest Point Of Polygon - -- **API Testing:** Postman, Jest, Supertest - -- **Development Environment:** VS Code, Git, GitHub, Heroku, Netlify, MongoDB Atlas, AWS S3 - -- **Project Management:** Trello, Figma, Lucidchart, Google Docs, Google Slides, Google Sheets, Google Forms, Google Meet, Google Drive, Google Calendar, Google Maps, Google Places, Google - Recaptcha, Google Analytics, Google Search Console, Google Cloud Platform, Google Cloud Storage, Google Cloud Functions, Google Cloud Run, Google Cloud Build, Google Cloud SQL, Google Cloud - Firestore, Google Cloud Pub/Sub, Google Cloud CDN, Google Cloud IAM, Google Cloud Billing, Google Cloud Logging, Google Cloud Monitoring, Google Cloud Error Reporting, Google Cloud Debugger, - Google Cloud Profiler, Google Cloud Trace, Google Cloud Security Scanner, Google Cloud Web Security Scanner, Google Cloud API Gateway, Google Cloud Endpoints, Google Cloud Memorystore, Google - Cloud Scheduler, Google Cloud Tasks, Google Cloud Secret Manager, Google Cloud Key Management Service, Google Cloud Storage Transfer Service, Google Cloud Data Transfer Service, Google Cloud - BigQuery, Google Cloud Dataflow, Google Cloud Dataproc, Google Cloud Datalab, Google Cloud Data Studio, Google Cloud Data Catalog, Google Cloud Data Fusion, Google Cloud Data Loss Prevention, - Google Cloud Data Labeling Service, Google Cloud Data Migration Service, Google Cloud Data Catalog, Google Cloud Data - -- **Version Control:** Git, GitHub - -- **Deployment:** Heroku, Netlify, MongoDB Atlas, AWS S3 - -### System Architecture: - -![System Architecture](./images/system-architecture.png) - -### Database Schema: - -![Database Schema](./images/database-schema.png) - -### API Routes: - -![API Routes](./images/api-routes.png) - -## Drawbacks to Consider and Handle (CHAT GPT) +## Drawbacks to Consider and Handle 1. **Battery Drain:** Continuous use of geolocation services can lead to increased battery consumption on users' devices. This can be a concern, especially for longer events or when users forget to turn off location services. @@ -182,6 +224,10 @@ GeoAttend is a powerful attendance management system that can be further enhance - **One User Per Device:** Restricting users to one device per account can help prevent unauthorized access and improve attendance accuracy. +# Problem why this project is not possible on Web App (PWA) ? + +- Web app can't access location in background / when screen is off / when app is closed / when app is not in use / when app is not in foreground / when app is not in focus. + # Report a Bug - lishugupta652@gmail.com To report a bug, please [open an issue](https://github.com/LishuGupta652/GeoAttend/issues/new) on GitHub and provide detailed information about the bug, including steps to diff --git a/Server/.env.sample b/Server/.env.sample new file mode 100644 index 0000000..a706cb6 --- /dev/null +++ b/Server/.env.sample @@ -0,0 +1,4 @@ +# MONGODB_URI = mongodb+srv://lishugupta652:mongodc652@firstcluster.76qkd.mongodb.net/geoattend_dev +MONGODB_URI=mongodb://localhost:27017/geoattend_dev +TOKEN_SECRET='thattypescriptguy' +PORT=3001 \ No newline at end of file diff --git a/Server/README.MD b/Server/README.MD deleted file mode 100644 index 8c21c52..0000000 --- a/Server/README.MD +++ /dev/null @@ -1,6 +0,0 @@ -``` -npm install -nodemon index -``` - -https://github.com/LishuGupta652/express-mongoose-auth-api-working diff --git a/Server/controllers/User.js b/Server/controllers/User.js index e581968..0369475 100644 --- a/Server/controllers/User.js +++ b/Server/controllers/User.js @@ -1,100 +1,98 @@ -const User = require("../models/User"); -const bcrypt = require("bcrypt"); -const jwt = require("jsonwebtoken"); -const { loginValidation, registerValidation } = require("../validation"); +const User = require('../models/User'); +const bcrypt = require('bcrypt'); +const jwt = require('jsonwebtoken'); +const { loginValidation, registerValidation } = require('../validation'); exports.homepage = (req, res) => { - return res.status(200).json({ - error: "You are not authorized to access this page.", - message: "Welcome to Gea Attend API v1.0.0", - }); + return res.status(200).json({ + error: 'You are not authorized to access this page.', + message: 'Welcome to Gea Attend API v1.0.0' + }); }; exports.signup = async (req, res) => { - const { warning, value, error } = registerValidation(req.body); - if (error) { - return res.status(400).json({ - error: error.details[0].message, - message: "", - }); - } + const { warning, value, error } = registerValidation(req.body); + if (error) { + return res.status(400).json({ + error: error.details[0].message, + message: '' + }); + } - // Check if the user already exists - const emailExists = await User.findOne({ email: req.body.email }); - if (emailExists) { - return res.status(400).send({ - error: "Email already exists", - message: "", - }); - } + // Check if the user already exists + const emailExists = await User.findOne({ email: req.body.email }); + if (emailExists) { + return res.status(400).send({ + error: 'Email already exists', + message: '' + }); + } - // Hash the password - // Salt must be integer and bcrypt is responding with a string - const salt = bcrypt.genSalt(10); - const hashedPassword = await bcrypt.hash(req.body.password, parseInt(salt)); + // Hash the password + // Salt must be integer and bcrypt is responding with a string + const salt = bcrypt.genSalt(10); + const hashedPassword = await bcrypt.hash(req.body.password, parseInt(salt)); - // Create New User - const user = new User({ - name: req.body.name, - email: req.body.email, - password: hashedPassword, - }); - try { - const savedUser = await user.save(); - res.send({ user: { id: savedUser._id } }); - } catch (err) { - console.log(err); - res.status(404).json({ - error: "Something went wrong. Please try again later.", - message: err.message, + // Create New User + const user = new User({ + name: req.body.name, + email: req.body.email, + password: hashedPassword }); - } + try { + const savedUser = await user.save(); + res.send({ user: { id: savedUser._id } }); + } catch (err) { + console.log(err); + res.status(404).json({ + error: 'Something went wrong. Please try again later.', + message: err.message + }); + } }; exports.login = async (req, res) => { - // Validate the data - try { - const { error } = loginValidation(req.body); - if (error) return res.status(400).send(error.details[0].message); - const { email, password } = req.body; + // Validate the data + try { + const { error } = loginValidation(req.body); + if (error) return res.status(400).send(error.details[0].message); + const { email, password } = req.body; - // Validating the email - const user = await User.findOne({ email: email }); - if (!user) { - return res.status(400).send({ - error: "No User Found", - message: "", - }); - } + // Validating the email + const user = await User.findOne({ email: email }); + if (!user) { + return res.status(400).send({ + error: 'No User Found', + message: '' + }); + } - // Validating the password - const validPass = await bcrypt.compare(password, user.password); - if (!validPass) { - return res.status(400).send({ - error: "Email or password is wrong", - message: "", - }); - } + // Validating the password + const validPass = await bcrypt.compare(password, user.password); + if (!validPass) { + return res.status(400).send({ + error: 'Email or password is wrong', + message: '' + }); + } - const token = jwt.sign( - { - _id: user._id, - email, - name: user.name, - exp: Math.floor(Date.now() / 1000) + 60 * 60, - }, - process.env.TOKEN_SECRET - ); + const token = jwt.sign( + { + _id: user._id, + email, + name: user.name, + exp: Math.floor(Date.now() / 1000) + 60 * 60 + }, + process?.env?.TOKEN_SECRET + ); - res.cookie("auth-token", token, { httpOnly: true }); - return res.header("auth-token", token).json({ user: { token: token } }); - } catch (err) { - console.log( - "Error while logging in: " + err.message + " " + err.details[0].message - ); - res.status(404).json({ - error: "Something went wrong. Please try again later.", - message: err.message, - }); - } + res.cookie('auth-token', token, { httpOnly: true }); + return res.header('auth-token', token).json({ user: { token: token } }); + } catch (err) { + console.log('Error while logging in: ' + err.message + ' ' + err); + res.status(404).json({ + error: 'Something went wrong. Please try again later.', + message: err.message + }); + } }; diff --git a/Server/index.js b/Server/index.js index b92de80..1fe6da2 100644 --- a/Server/index.js +++ b/Server/index.js @@ -1,38 +1,38 @@ -const express = require("express"); +const express = require('express'); const app = express(); const PORT = process.env.PORT || 3001; -const mongoose = require("mongoose"); -const env = require("dotenv").config(); -const userRoutes = require("./routes/User"); -const postRoutes = require("./routes/posts"); -const morgan = require("morgan"); -const cors = require("cors"); +const mongoose = require('mongoose'); +const env = require('dotenv').config(); +const userRoutes = require('./routes/User'); +const postRoutes = require('./routes/posts'); +const morgan = require('morgan'); +const cors = require('cors'); -mongoose.connect(process.env.MONGODB_URI, () => { - console.log("Connected to Db " + process.env.MONGODB_URI); -}); +mongoose + .connect(process.env.MONGODB_URI) + .then(() => { + console.log('MongoDB Server Connected!!', process.env.MONGODB_URI); + app.listen(PORT, () => { + console.log(`Server is running on port http://localhost:${PORT}`); + }); + }) + .catch((err) => { + console.log('Error in connecting to MongoDB Server', err); + }); app.use(cors()); -app.use( - morgan( - ":date :method :url :status :res[content-length] -(Response: :response-time)" - ) -); +app.use(morgan(':date :method :url :status :res[content-length] -(Response: :response-time)')); // MiddleWare to use json app.use(express.json()); app.use(express.urlencoded({ extended: true })); -app.use("/api/user", userRoutes); -app.use("/api/posts", postRoutes); +app.use('/api/user', userRoutes); +app.use('/api/posts', postRoutes); // Index Route -app.get("/", (req, res) => { - res.send({ - msg: "Hello there this app is working totally fine", - route: "/api/user/register", - }); -}); - -app.listen(PORT, () => { - console.log(`Server is running on port http://localhost:${PORT}`); +app.get('/', (req, res) => { + res.send({ + msg: 'Welcome to Geo Attend Server. If you are seeing this. You are at right track.', + route: '/api/user/register' + }); }); diff --git a/Server/package.json b/Server/package.json index e697693..30356b5 100644 --- a/Server/package.json +++ b/Server/package.json @@ -1,23 +1,23 @@ { - "name": "authentication", - "version": "1.0.0", - "description": "app made using express to do login logout jwt etc", - "main": "index.js", - "scripts": { - "start:dev": "npx nodemon index.js", - "start": "node index.js" - }, - "author": "", - "license": "ISC", - "dependencies": { - "bcrypt": "^5.0.1", - "cors": "^2.8.5", - "dotenv": "^10.0.0", - "express": "^4.17.1", - "joi": "^17.4.2", - "jsonwebtoken": "^8.5.1", - "mongoose": "^6.0.13", - "morgan": "^1.10.0", - "nodemon": "^2.0.15" - } + "name": "authentication", + "version": "1.0.0", + "description": "app made using express to do login logout jwt etc", + "main": "index.js", + "scripts": { + "start:dev": "npx nodemon index.js", + "start": "node index.js" + }, + "author": "", + "license": "ISC", + "dependencies": { + "bcrypt": "^5.0.1", + "cors": "^2.8.5", + "dotenv": "^10.0.0", + "express": "^4.17.1", + "joi": "^17.4.2", + "jsonwebtoken": "^8.5.1", + "mongoose": "^6.0.13", + "morgan": "^1.10.0", + "nodemon": "^2.0.15" + } } diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 0000000..6de1673 Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..e3b3650 Binary files /dev/null and b/assets/logo.png differ diff --git a/assets/logo_t66d77lxp.png b/assets/logo_t66d77lxp.png new file mode 100644 index 0000000..e3b3650 Binary files /dev/null and b/assets/logo_t66d77lxp.png differ diff --git a/package.json b/package.json index 66bdf2e..37c7d97 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,6 @@ "start:frontend": "npm run start:dev", "start:backend": "cd server && npm run start:dev", "build": "tsc && vite build", - "prod": "tsc && vite build && npm run lint && npm run release && npm run push:tags", "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 100", "preview": "vite preview", "release": "npx standard-version", @@ -16,7 +15,8 @@ "docker:build": "docker-compose build", "docker:up": "docker-compose up ", "docker:start": "docker-compose build && docker-compose up ", - "docker:build:test": "docker build -t geoattend ." + "docker:build:test": "docker build -t geoattend .", + "prod": "tsc && vite build && npm run lint && npm run release && npm run push:tags" }, "dependencies": { "@emotion/react": "^11.11.1", diff --git a/src/utils/api.ts b/src/utils/api.ts index 697aa91..840d6a3 100644 --- a/src/utils/api.ts +++ b/src/utils/api.ts @@ -9,8 +9,8 @@ const userApiClient = axios.create({ }, }); -const request = ({ ...options }) => { - userApiClient.defaults.headers.common['Authorization'] = `Bearer ${localStorage.getItem('token')}`; +const apiRequest = async ({ ...options }) => { + userApiClient.defaults.headers.common['Authorization'] = `Bearer ${localStorage.getItem('auth_token')}`; const onSuccess = (response: any) => response.data; const onError = (error: any) => { @@ -22,21 +22,21 @@ const request = ({ ...options }) => { export const getApiTest = async (): Promise => { - return await request({ + return await apiRequest({ url: GET_API_TEST, method: 'GET', }); } export const signupUser = async (data: any): Promise => { - return await request({ + return await apiRequest({ url: API_SIGNUP, method: 'POST', data }); } export const loginUser = async (data: any): Promise => { - return await request({ + return await apiRequest({ url: API_LOGIN, method: 'POST', data diff --git a/tsconfig.json b/tsconfig.json index 16c6529..5c59219 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -17,5 +17,6 @@ "noEmit": true, "jsx": "react-jsx" }, - "include": ["src"] + "include": ["src"], + "exclude": ["node_modules","server" ] }