Spaces:
Sleeping
Sleeping
| from flask import Flask, render_template, request, redirect, url_for, session, flash, g | |
| import sqlite3 | |
| import os | |
| import re | |
| from datetime import datetime | |
| app = Flask(__name__) | |
| app.secret_key = 'student_system_secret_key_2024' | |
| # Database path | |
| DATABASE = os.path.join(os.path.dirname(__file__), 'database.db') | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Database Helpers | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| def get_db(): | |
| """Open a new database connection if not already open for this request.""" | |
| if 'db' not in g: | |
| g.db = sqlite3.connect(DATABASE) | |
| g.db.row_factory = sqlite3.Row # rows behave like dicts | |
| return g.db | |
| def close_db(error): | |
| """Close database connection at end of request.""" | |
| db = g.pop('db', None) | |
| if db is not None: | |
| db.close() | |
| def init_db(): | |
| """Create tables if they don't exist.""" | |
| db = sqlite3.connect(DATABASE) | |
| cursor = db.cursor() | |
| # Users table (admin login) | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS users ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| username TEXT NOT NULL UNIQUE, | |
| password TEXT NOT NULL | |
| ) | |
| ''') | |
| # Students table | |
| cursor.execute(''' | |
| CREATE TABLE IF NOT EXISTS students ( | |
| id INTEGER PRIMARY KEY AUTOINCREMENT, | |
| student_id TEXT NOT NULL UNIQUE, | |
| full_name TEXT NOT NULL, | |
| father_name TEXT NOT NULL, | |
| mother_name TEXT NOT NULL, | |
| gender TEXT NOT NULL, | |
| dob TEXT NOT NULL, | |
| email TEXT NOT NULL UNIQUE, | |
| phone TEXT NOT NULL, | |
| course TEXT NOT NULL, | |
| branch TEXT NOT NULL, | |
| year_sem TEXT NOT NULL, | |
| address TEXT NOT NULL, | |
| city TEXT NOT NULL, | |
| state TEXT NOT NULL, | |
| pin_code TEXT NOT NULL, | |
| created_at TEXT NOT NULL | |
| ) | |
| ''') | |
| # Insert default admin user (password: admin123) | |
| cursor.execute(''' | |
| INSERT OR IGNORE INTO users (username, password) | |
| VALUES (?, ?) | |
| ''', ('admin', 'admin123')) | |
| db.commit() | |
| db.close() | |
| print("Database initialised successfully.") | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Auth helpers | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| def login_required(f): | |
| """Decorator: redirect to login if session missing.""" | |
| from functools import wraps | |
| def decorated(*args, **kwargs): | |
| if 'user' not in session: | |
| flash('Please log in to access this page.', 'warning') | |
| return redirect(url_for('login')) | |
| return f(*args, **kwargs) | |
| return decorated | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Validation helpers | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| def validate_student(data): | |
| """Server-side validation; returns list of error strings.""" | |
| errors = [] | |
| if not data.get('student_id', '').strip(): | |
| errors.append('Student ID is required.') | |
| if not data.get('full_name', '').strip(): | |
| errors.append('Full Name is required.') | |
| if not data.get('father_name', '').strip(): | |
| errors.append('Father Name is required.') | |
| if not data.get('mother_name', '').strip(): | |
| errors.append('Mother Name is required.') | |
| if data.get('gender') not in ('Male', 'Female', 'Other'): | |
| errors.append('Please select a valid Gender.') | |
| # Date of birth | |
| dob = data.get('dob', '').strip() | |
| if not dob: | |
| errors.append('Date of Birth is required.') | |
| else: | |
| try: | |
| datetime.strptime(dob, '%Y-%m-%d') | |
| except ValueError: | |
| errors.append('Date of Birth format is invalid.') | |
| email = data.get('email', '').strip() | |
| if not email: | |
| errors.append('Email is required.') | |
| elif not re.match(r'^[\w.+-]+@[\w-]+\.[a-zA-Z]{2,}$', email): | |
| errors.append('Email address is invalid.') | |
| # Phone (10 digits) | |
| phone = data.get('phone', '').strip() | |
| if not phone: | |
| errors.append('Phone Number is required.') | |
| elif not re.match(r'^\d{10}$', phone): | |
| errors.append('Phone Number must be exactly 10 digits.') | |
| if not data.get('course', '').strip(): | |
| errors.append('Course is required.') | |
| if not data.get('branch', '').strip(): | |
| errors.append('Branch is required.') | |
| if not data.get('year_sem', '').strip(): | |
| errors.append('Year / Semester is required.') | |
| if not data.get('address', '').strip(): | |
| errors.append('Address is required.') | |
| if not data.get('city', '').strip(): | |
| errors.append('City is required.') | |
| if not data.get('state', '').strip(): | |
| errors.append('State is required.') | |
| pin = data.get('pin_code', '').strip() | |
| if not pin: | |
| errors.append('Pin Code is required.') | |
| elif not re.match(r'^\d{6}$', pin): | |
| errors.append('Pin Code must be exactly 6 digits.') | |
| return errors | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Routes | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| def index(): | |
| return redirect(url_for('login')) | |
| # ββ LOGIN ββββββββββββββββββββββββββββββββββ | |
| def login(): | |
| if 'user' in session: | |
| return redirect(url_for('dashboard')) | |
| if request.method == 'POST': | |
| username = request.form.get('username', '').strip() | |
| password = request.form.get('password', '').strip() | |
| db = get_db() | |
| user = db.execute( | |
| 'SELECT * FROM users WHERE username=? AND password=?', | |
| (username, password) | |
| ).fetchone() | |
| if user: | |
| session['user'] = username | |
| flash(f'Welcome back, {username}! π', 'success') | |
| return redirect(url_for('dashboard')) | |
| else: | |
| flash('Invalid username or password.', 'danger') | |
| return render_template('login.html') | |
| # ββ LOGOUT βββββββββββββββββββββββββββββββββ | |
| def logout(): | |
| session.pop('user', None) | |
| flash('You have been logged out.', 'info') | |
| return redirect(url_for('login')) | |
| # ββ DASHBOARD ββββββββββββββββββββββββββββββ | |
| def dashboard(): | |
| db = get_db() | |
| total = db.execute('SELECT COUNT(*) FROM students').fetchone()[0] | |
| male = db.execute("SELECT COUNT(*) FROM students WHERE gender='Male'").fetchone()[0] | |
| female = db.execute("SELECT COUNT(*) FROM students WHERE gender='Female'").fetchone()[0] | |
| courses = db.execute('SELECT COUNT(DISTINCT course) FROM students').fetchone()[0] | |
| # Recent 5 students | |
| recent = db.execute( | |
| 'SELECT student_id, full_name, course, branch FROM students ORDER BY id DESC LIMIT 5' | |
| ).fetchall() | |
| stats = { | |
| 'total': total, | |
| 'male': male, | |
| 'female': female, | |
| 'courses': courses, | |
| } | |
| return render_template('dashboard.html', stats=stats, recent=recent) | |
| # ββ ADD STUDENT ββββββββββββββββββββββββββββ | |
| def add_student(): | |
| if request.method == 'POST': | |
| data = {k: v.strip() for k, v in request.form.items()} | |
| errors = validate_student(data) | |
| if errors: | |
| for e in errors: | |
| flash(e, 'danger') | |
| return render_template('add_student.html', form=data) | |
| db = get_db() | |
| # Check duplicate student_id | |
| dup_id = db.execute('SELECT id FROM students WHERE student_id=?', (data['student_id'],)).fetchone() | |
| if dup_id: | |
| flash('Student ID already exists. Use a unique ID.', 'danger') | |
| return render_template('add_student.html', form=data) | |
| # Check duplicate email | |
| dup_email = db.execute('SELECT id FROM students WHERE email=?', (data['email'],)).fetchone() | |
| if dup_email: | |
| flash('Email address already registered.', 'danger') | |
| return render_template('add_student.html', form=data) | |
| db.execute(''' | |
| INSERT INTO students | |
| (student_id, full_name, father_name, mother_name, gender, dob, | |
| email, phone, course, branch, year_sem, address, city, state, | |
| pin_code, created_at) | |
| VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) | |
| ''', ( | |
| data['student_id'], data['full_name'], data['father_name'], | |
| data['mother_name'], data['gender'], data['dob'], | |
| data['email'], data['phone'], data['course'], data['branch'], | |
| data['year_sem'], data['address'], data['city'], data['state'], | |
| data['pin_code'], datetime.now().strftime('%Y-%m-%d %H:%M:%S') | |
| )) | |
| db.commit() | |
| flash(f'Student "{data["full_name"]}" added successfully! β ', 'success') | |
| return redirect(url_for('view_students')) | |
| return render_template('add_student.html', form={}) | |
| # ββ VIEW STUDENTS ββββββββββββββββββββββββββ | |
| def view_students(): | |
| db = get_db() | |
| q = request.args.get('q', '').strip() | |
| col = request.args.get('col', 'full_name') | |
| allowed_cols = {'full_name', 'student_id', 'course', 'phone'} | |
| if col not in allowed_cols: | |
| col = 'full_name' | |
| if q: | |
| students = db.execute( | |
| f'SELECT * FROM students WHERE {col} LIKE ? ORDER BY id DESC', | |
| (f'%{q}%',) | |
| ).fetchall() | |
| else: | |
| students = db.execute('SELECT * FROM students ORDER BY id DESC').fetchall() | |
| return render_template('view_students.html', students=students, q=q, col=col) | |
| # ββ EDIT STUDENT βββββββββββββββββββββββββββ | |
| def edit_student(sid): | |
| db = get_db() | |
| student = db.execute('SELECT * FROM students WHERE id=?', (sid,)).fetchone() | |
| if not student: | |
| flash('Student not found.', 'danger') | |
| return redirect(url_for('view_students')) | |
| if request.method == 'POST': | |
| data = {k: v.strip() for k, v in request.form.items()} | |
| errors = validate_student(data) | |
| if errors: | |
| for e in errors: | |
| flash(e, 'danger') | |
| return render_template('edit_student.html', student=data, sid=sid) | |
| # Duplicate checks (exclude current record) | |
| dup_id = db.execute( | |
| 'SELECT id FROM students WHERE student_id=? AND id!=?', | |
| (data['student_id'], sid) | |
| ).fetchone() | |
| if dup_id: | |
| flash('Student ID already used by another record.', 'danger') | |
| return render_template('edit_student.html', student=data, sid=sid) | |
| dup_email = db.execute( | |
| 'SELECT id FROM students WHERE email=? AND id!=?', | |
| (data['email'], sid) | |
| ).fetchone() | |
| if dup_email: | |
| flash('Email already used by another record.', 'danger') | |
| return render_template('edit_student.html', student=data, sid=sid) | |
| db.execute(''' | |
| UPDATE students SET | |
| student_id=?, full_name=?, father_name=?, mother_name=?, | |
| gender=?, dob=?, email=?, phone=?, course=?, branch=?, | |
| year_sem=?, address=?, city=?, state=?, pin_code=? | |
| WHERE id=? | |
| ''', ( | |
| data['student_id'], data['full_name'], data['father_name'], | |
| data['mother_name'], data['gender'], data['dob'], | |
| data['email'], data['phone'], data['course'], data['branch'], | |
| data['year_sem'], data['address'], data['city'], data['state'], | |
| data['pin_code'], sid | |
| )) | |
| db.commit() | |
| flash(f'Student "{data["full_name"]}" updated successfully! β ', 'success') | |
| return redirect(url_for('view_students')) | |
| return render_template('edit_student.html', student=student, sid=sid) | |
| # ββ DELETE STUDENT βββββββββββββββββββββββββ | |
| def delete_student(sid): | |
| db = get_db() | |
| student = db.execute('SELECT full_name FROM students WHERE id=?', (sid,)).fetchone() | |
| if student: | |
| db.execute('DELETE FROM students WHERE id=?', (sid,)) | |
| db.commit() | |
| flash(f'Student "{student["full_name"]}" deleted successfully.', 'success') | |
| else: | |
| flash('Student not found.', 'danger') | |
| return redirect(url_for('view_students')) | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| # Entry point | |
| # βββββββββββββββββββββββββββββββββββββββββ | |
| init_db() | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=7860, debug=True) | |