├── .gitignore ├── static ├── kit.png ├── favicon.png ├── KIT-logo.png ├── background.png └── favicon-old.png ├── vercel.json ├── requirements.txt ├── Dockerfile ├── .github └── workflows │ └── deploy.yml ├── LICENSE ├── README.md ├── templates ├── 404.html ├── index.html ├── confirm.html ├── login.html ├── register.html ├── bus_incharge_portal.html └── student_portal.html └── app.py /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .vercel -------------------------------------------------------------------------------- /static/kit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunlorenz/Bus-Pass-System/HEAD/static/kit.png -------------------------------------------------------------------------------- /static/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunlorenz/Bus-Pass-System/HEAD/static/favicon.png -------------------------------------------------------------------------------- /static/KIT-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunlorenz/Bus-Pass-System/HEAD/static/KIT-logo.png -------------------------------------------------------------------------------- /static/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunlorenz/Bus-Pass-System/HEAD/static/background.png -------------------------------------------------------------------------------- /static/favicon-old.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/arunlorenz/Bus-Pass-System/HEAD/static/favicon-old.png -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 2, 3 | "builds": [ 4 | { 5 | "src": "app.py", 6 | "use": "@vercel/python", 7 | "config": { "maxLambdaSize": "1000mb" } 8 | } 9 | ], 10 | "routes": [ 11 | { 12 | "src": "/(.*)", 13 | "dest": "app.py" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | blinker==1.8.2 2 | boto3==1.34.110 3 | botocore==1.34.110 4 | click==8.1.7 5 | DateTime==5.5 6 | dnspython==2.6.1 7 | Flask==3.0.3 8 | itsdangerous==2.2.0 9 | Jinja2==3.1.4 10 | jmespath==1.0.1 11 | MarkupSafe==2.1.5 12 | pymongo==4.7.2 13 | python-dateutil==2.9.0.post0 14 | python-dotenv==1.0.1 15 | pytz==2024.1 16 | s3transfer==0.10.1 17 | six==1.16.0 18 | urllib3==1.26.15 19 | Werkzeug==3.0.3 20 | zope.interface==6.4 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an official Python runtime as a parent image 2 | FROM python:3.8-slim 3 | 4 | # Set the working directory in the container 5 | WORKDIR /app 6 | 7 | # Copy the current directory contents into the container at /app 8 | COPY . /app 9 | 10 | # Install any needed packages specified in requirements.txt 11 | RUN pip install --no-cache-dir -r requirements.txt 12 | 13 | # Make port 5000 available to the world outside this container 14 | EXPOSE 5000 15 | 16 | # Define environment variable 17 | ENV FLASK_APP=app.py 18 | 19 | # Run app.py when the container launches 20 | CMD ["flask", "run", "--host=0.0.0.0"] -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy the app 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | deployment: 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - name: Checkout repository 14 | uses: actions/checkout@v2 15 | 16 | - name: Update package list and install necessary packages 17 | run: | 18 | sudo apt-get update 19 | sudo apt-get upgrade -y 20 | sudo apt-get install -y python3-venv python3-pip 21 | 22 | - name: Set up Python environment 23 | run: | 24 | python3 -m venv venv 25 | source venv/bin/activate 26 | pip install --upgrade pip 27 | 28 | - name: Install requirements 29 | run: | 30 | source venv/bin/activate 31 | pip install -r requirements.txt 32 | 33 | - name: Start the code 34 | run: | 35 | source venv/bin/activate 36 | python app.py 37 | 38 | - name: Keep the job running for testing 39 | run: sleep 1h 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Arunkumar N S 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bus Pass System 2 | 3 | The Bus Pass System is an innovative web application revolutionizing the way students manage their bus passes. With a user-friendly interface, it offers convenient features such as generating and validating bus passes online. By leveraging HTML, CSS, JavaScript, Python, Flask, MongoDB and several AWS services, it ensures a seamless experience for users while maintaining robust backend functionality. This project aims to streamline bus pass management processes, reducing manual efforts and enhancing overall efficiency. With its cloud-based database storage, it guarantees scalability and reliability, making it an ideal solution for educational institutions seeking modernized bus pass management systems. 4 | 5 | ## Features 6 | 7 | - **Buy Bus Pass**: Students can generate a bus pass by entering their roll number and selecting their desired stop. 8 | - **Validate Bus Pass**: Users can validate a bus pass by entering the pass number. 9 | 10 | ## Technologies Used 11 | 12 | - **Frontend**: HTML, CSS, JavaScript, Flask 13 | - **Backend**: Python, Flask 14 | - **Database**: MongoDB (Cloud) 15 | 16 | ## Getting Started 17 | 18 | ### Prerequisites 19 | 20 | - Python 3.x installed on your local machine 21 | - MongoDB Cloud account for database storage 22 | - Git for version control (optional) 23 | 24 | ### Installation 25 | 26 | 1. Clone the repository: 27 | 28 | ```bash 29 | git clone https://github.com/arunlorenz/Bus-Pass-System.git 30 | 31 | 2. Install the required Python dependencies: 32 | 33 | ```bash 34 | pip install -r requirements.txt 35 | ``` 36 | 37 | 3. Set up environment variables for MongoDB connection details. 38 | 39 | 4. Run the Flask application: 40 | ```bash 41 | python app.py 42 | ``` 43 | 44 | 5. Access the application in your web browser at http://localhost:5000. 45 | 46 | ### Usage 47 | - Visit the homepage to buy a bus pass or validate an existing pass. 48 | - Follow the on-screen instructions to complete the desired action. 49 | 50 | 51 | ### Contributing 52 | Contributions are welcome! If you'd like to contribute to this project, please follow these steps: 53 | 54 | 1. Fork the repository 55 | 2. Create a new branch (git checkout -b feature/your-feature-name) 56 | 3. Make your changes 57 | 4. Commit your changes (git commit -am 'Add some feature') 58 | 5. Push to the branch (git push origin feature/your-feature-name) 59 | 6. Create a new Pull Request 60 | 61 | ### License 62 | This project is licensed under the MIT License - see the LICENSE file for details. 63 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | KIT - Transport 7 | 8 | 94 | 95 | 96 |
97 | Centered Image 98 |
99 |
100 |
101 |

404 - Page Not Found

102 |

The page you are looking for does not exist.

103 |

Return to home page

104 | Home 105 |
106 |
107 | 112 |
113 | alpha 114 |
115 | 116 | 117 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | KIT - Transport 7 | 8 | 94 | 95 | 96 |
97 | Centered Image 98 |
99 |
100 |
101 |

Karpagam Institute of Technology

102 |

Coimbatore - 641 105

103 |

Department of Transportation

104 | 108 |
109 |
110 | 115 |
116 | alpha 117 |
118 | 119 | 120 | -------------------------------------------------------------------------------- /templates/confirm.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | KIT - Transport 7 | 8 | 104 | 105 | 106 |
107 | Centered Image 108 |
109 | Home 110 |
111 |
112 |

Confirm Registration

113 |
114 | 115 |
116 | 117 |
118 |
119 |
120 | {% if error %} 121 |

{{ error }}

122 | {% endif %} 123 |
124 | alpha 125 |
126 | 127 | 128 | -------------------------------------------------------------------------------- /templates/login.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | KIT - Transport 5 | 6 | 111 | 112 | 113 |
114 | Centered Image 115 |
116 | Home 117 |
118 |

Login

119 | {% if error %} 120 |

{{ error }}

121 | {% endif %} 122 |
123 |
124 |
125 |
126 |
127 | 128 | Don't have an account? Register here 129 |
130 |
131 |
132 | alpha 133 |
134 | 135 | 136 | -------------------------------------------------------------------------------- /templates/register.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | KIT - Transport 6 | 7 | 112 | 113 | 114 |
115 | Centered Image 116 |
117 | Home 118 |
119 |

Register

120 | {% if error %} 121 |

{{ error }}

122 | {% endif %} 123 |
124 | 125 |
126 | 127 | 128 |
129 | 130 | 131 |
132 | 133 | 134 |
135 | 136 | 137 |
141 | 142 | 143 |
144 |
145 |
146 | alpha 147 |
148 | 149 | 150 | -------------------------------------------------------------------------------- /templates/bus_incharge_portal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | KIT - Transport 7 | 8 | 129 | 130 | 131 |
132 | Centered Image 133 |
134 | Logout 135 |
136 |

Karpagam Institute of Technology

137 |

Bus Incharge Portal

138 |

Validate Bus Pass

139 |
140 | 141 | 142 |
143 |
144 |
145 |
146 | alpha 147 |
148 | 149 | 180 | 181 | 182 | -------------------------------------------------------------------------------- /templates/student_portal.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | KIT - Transport 8 | 9 | 131 | 132 | 133 |
134 | Centered Image 135 |
136 | Logout 137 |
138 |

Karpagam Institute of Technology

139 |

Student Portal

140 |

Generate Bus Pass

141 |
142 | 143 | 144 | 145 | 146 | 152 | 153 | 154 |
155 | 156 | 157 | 158 | 159 |
160 | 161 |
162 |
163 |
164 |
165 | alpha 166 |
167 | 168 | 197 | 198 | 199 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask, render_template, request, redirect, url_for, session, jsonify 2 | import boto3 3 | from botocore.exceptions import ClientError 4 | import hmac 5 | import hashlib 6 | import base64 7 | import os 8 | from dotenv import load_dotenv 9 | from pymongo import MongoClient 10 | import datetime 11 | 12 | app = Flask(__name__) 13 | load_dotenv() 14 | 15 | app.secret_key = os.getenv('FLASK_SECRET_KEY', 'your_secret_key') 16 | 17 | # AWS Cognito Configuration 18 | CLIENT_ID = os.getenv('COGNITO_CLIENT_ID', 'your_app_client_id') 19 | CLIENT_SECRET = os.getenv('COGNITO_CLIENT_SECRET', 'your_app_client_secret') 20 | USER_POOL_ID = os.getenv('COGNITO_USER_POOL_ID', 'your_user_pool_id') 21 | REGION = os.getenv('COGNITO_REGION', 'your_aws_region') 22 | 23 | cognito = boto3.client('cognito-idp', region_name=REGION) 24 | 25 | # MongoDB Configuration 26 | DB_STRING = os.getenv("MONGO_CONN_STRING") 27 | DB_NAME = os.getenv("MONGO_DB_NAME") 28 | client = MongoClient(DB_STRING) 29 | db = client[DB_NAME] 30 | collection = db["buspass"] 31 | 32 | stop_amounts = { 33 | "Stop 1": 50, 34 | "Stop 2": 75, 35 | "Stop 3": 100 36 | } 37 | 38 | def get_secret_hash(username): 39 | message = username + CLIENT_ID 40 | dig = hmac.new(CLIENT_SECRET.encode('utf-8'), message.encode('utf-8'), hashlib.sha256).digest() 41 | return base64.b64encode(dig).decode() 42 | 43 | @app.route('/') 44 | def home(): 45 | if 'username' in session: 46 | return redirect(url_for('student_portal')) if session['role'] == 'student' else redirect(url_for('bus_incharge_portal')) 47 | return render_template('index.html') 48 | 49 | @app.route('/login', methods=['GET', 'POST']) 50 | def login(): 51 | if 'username' in session: 52 | return redirect(url_for('home')) 53 | if request.method == 'POST': 54 | username = request.form['username'] 55 | password = request.form['password'] 56 | secret_hash = get_secret_hash(username) 57 | try: 58 | response = cognito.initiate_auth( 59 | ClientId=CLIENT_ID, 60 | AuthFlow='USER_PASSWORD_AUTH', 61 | AuthParameters={ 62 | 'USERNAME': username, 63 | 'PASSWORD': password, 64 | 'SECRET_HASH': secret_hash 65 | } 66 | ) 67 | session['username'] = username 68 | user_attributes = cognito.get_user( 69 | AccessToken=response['AuthenticationResult']['AccessToken'] 70 | )['UserAttributes'] 71 | role = next((attr['Value'] for attr in user_attributes if attr['Name'] == 'nickname'), None) 72 | session['role'] = role 73 | if 'student' == role: 74 | return redirect(url_for('student_portal')) 75 | elif 'bus_incharge' == role: 76 | return redirect(url_for('bus_incharge_portal')) 77 | else: 78 | return redirect(url_for('home')) 79 | except ClientError as e: 80 | return render_template('login.html', error=e.response['Error']['Message']) 81 | return render_template('login.html') 82 | 83 | @app.route('/logout') 84 | def logout(): 85 | session.pop('username', None) 86 | session.pop('role', None) 87 | return redirect(url_for('home')) 88 | 89 | @app.route('/student_portal') 90 | def student_portal(): 91 | if 'username' in session: 92 | if session['role'] == 'student': 93 | return render_template('student_portal.html', username=session['username']) 94 | else: 95 | return redirect(url_for('home')) 96 | return redirect(url_for('login')) 97 | 98 | @app.route('/bus_incharge_portal') 99 | def bus_incharge_portal(): 100 | if 'username' in session: 101 | if session['role'] == 'bus_incharge': 102 | return render_template('bus_incharge_portal.html', username=session['username']) 103 | else: 104 | return redirect(url_for('home')) 105 | return redirect(url_for('login')) 106 | 107 | @app.route('/register', methods=['GET', 'POST']) 108 | def register(): 109 | if 'username' in session: 110 | return redirect(url_for('home')) 111 | if request.method == 'POST': 112 | username = request.form['username'] 113 | password = request.form['password'] 114 | email = request.form['email'] 115 | full_name = request.form['full_name'] 116 | role = request.form['role'] # Capturing role from the form 117 | secret_hash = get_secret_hash(username) 118 | try: 119 | response = cognito.sign_up( 120 | ClientId=CLIENT_ID, 121 | Username=username, 122 | Password=password, 123 | SecretHash=secret_hash, 124 | UserAttributes=[ 125 | {'Name': 'email', 'Value': email}, 126 | {'Name': 'name', 'Value': full_name}, 127 | {'Name': 'nickname', 'Value': role} # Using nickname to store role 128 | ] 129 | ) 130 | return redirect(url_for('confirm', username=username)) 131 | except ClientError as e: 132 | return render_template('register.html', error=e.response['Error']['Message']) 133 | return render_template('register.html') 134 | 135 | @app.route('/confirm', methods=['GET', 'POST']) 136 | def confirm(): 137 | username = request.args.get('username') 138 | if 'username' in session: 139 | if session['role'] == 'student': 140 | return redirect(url_for('student_portal')) 141 | else: 142 | return redirect(url_for('bus_incharge_portal')) 143 | if request.method == 'POST': 144 | confirmation_code = request.form['confirmation_code'] 145 | try: 146 | response = cognito.confirm_sign_up( 147 | ClientId=CLIENT_ID, 148 | Username=username, 149 | ConfirmationCode=confirmation_code, 150 | SecretHash=get_secret_hash(username) 151 | ) 152 | return redirect(url_for('login')) 153 | except ClientError as e: 154 | return render_template('confirm.html', username=username, error=e.response['Error']['Message']) 155 | return render_template('confirm.html', username=username) 156 | 157 | @app.route('/buy-bus-pass', methods=['POST']) 158 | def buy_bus_pass(): 159 | data = request.json 160 | roll_number = data.get('roll_number') 161 | selected_stop = data.get('selected_stop') 162 | round_trip = data.get('round_trip', 'No') 163 | pass_number, amount = generate_bus_pass(roll_number, selected_stop, round_trip) 164 | collection.insert_one({"roll_number": roll_number, "pass_number": pass_number, "total_amount": amount}) 165 | return jsonify({"message": "Bus pass generated successfully", "pass_number": pass_number, "amount": amount}) 166 | 167 | @app.route('/validate-bus-pass', methods=['POST']) 168 | def validate_bus_pass(): 169 | data = request.json 170 | pass_number = data.get('pass_number') 171 | bus_pass = collection.find_one({"pass_number": pass_number}) 172 | if bus_pass: 173 | return jsonify({"valid": True, "message": "Valid bus pass"}) 174 | else: 175 | return jsonify({"valid": False, "message": "Invalid bus pass number"}) 176 | 177 | @app.errorhandler(404) 178 | def page_not_found(error): 179 | return render_template('404.html'), 404 180 | 181 | def generate_bus_pass(roll_number, selected_stop, round_trip): 182 | timestamp = datetime.datetime.now().strftime("%Y%m%d%H%M%S") 183 | amount = stop_amounts.get(selected_stop, 0) 184 | if round_trip == "Yes": 185 | amount *= 2 186 | pass_number = f"{roll_number}_{selected_stop}_{timestamp}" 187 | return pass_number, amount 188 | 189 | if __name__ == '__main__': 190 | app.run(debug=True) 191 | --------------------------------------------------------------------------------