epinspectiontool/app.py

285 lines
No EOL
11 KiB
Python

import os
from flask import Flask, render_template, request, redirect, url_for, send_from_directory, flash, session
from datetime import datetime
import sqlite3
import uuid
from werkzeug.security import generate_password_hash, check_password_hash
app = Flask(__name__)
app.secret_key = 'your_secret_key_here'
DB_PATH = '/home/jimmy/inspectiontool/db.sqlite3'
# Initialize database
def init_db():
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("CREATE TABLE IF NOT EXISTS inspections (id INTEGER PRIMARY KEY AUTOINCREMENT, inspector_name TEXT NOT NULL, location TEXT NOT NULL, inspection_date TEXT NOT NULL, installation_name TEXT NOT NULL, created_at TEXT DEFAULT CURRENT_TIMESTAMP, updated_at TEXT DEFAULT CURRENT_TIMESTAMP)")
cursor.execute("CREATE TABLE IF NOT EXISTS checklist_items (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL)")
cursor.execute("INSERT OR IGNORE INTO checklist_items (name) VALUES ('Check electrical wiring'), ('Check plumbing'), ('Check fire safety'), ('Check electrical safety'), ('Check water pressure'), ('Check drainage'), ('Check structural integrity'), ('Check emergency exits'), ('Check fire extinguishers'), ('Check ventilation')")
cursor.execute("CREATE TABLE IF NOT EXISTS inspection_photos (id INTEGER PRIMARY KEY AUTOINCREMENT, inspection_id INTEGER NOT NULL, photo_path TEXT NOT NULL, comment TEXT, resolved INTEGER DEFAULT 0, uploaded_at TEXT DEFAULT CURRENT_TIMESTAMP)")
cursor.execute("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, username TEXT UNIQUE NOT NULL, password_hash TEXT NOT NULL, role TEXT NOT NULL DEFAULT 'user', logo_path TEXT)")
# Add default admin user
hashed_password = generate_password_hash('admin')
cursor.execute("INSERT OR IGNORE INTO users (username, password_hash, role) VALUES ('admin', ?, 'admin')", (hashed_password,))
conn.commit()
conn.close()
init_db()
# Set up static folders
app.config['UPLOAD_FOLDER'] = os.path.join(app.root_path, 'static', 'uploads')
app.config['PDF_FOLDER'] = os.path.join(app.root_path, 'static', 'pdf')
app.config['LOGO_FOLDER'] = os.path.join(app.root_path, 'static', 'logo')
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
os.makedirs(app.config['PDF_FOLDER'], exist_ok=True)
os.makedirs(app.config['LOGO_FOLDER'], exist_ok=True)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
user = cursor.fetchone()
if user and check_password_hash(user[2], password):
session['user_id'] = user[0]
session['username'] = user[1]
session['role'] = user[3]
# Store logo path for current user in session
cursor.execute("SELECT logo_path FROM users WHERE username = ?", (username,))
logo_path = cursor.fetchone()[0] if cursor.fetchone() else None
session['user_logo_path'] = logo_path
return redirect(url_for('index'))
else:
flash('Invalid username or password')
return render_template('login.html')
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form['username']
password = request.form['password']
role = request.form.get('role', 'user')
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users WHERE username = ?", (username,))
if cursor.fetchone():
flash('Username already exists')
return redirect(url_for('register'))
hashed_password = generate_password_hash(password)
cursor.execute("INSERT INTO users (username, password_hash, role) VALUES (?, ?, ?)", (username, hashed_password, role))
conn.commit()
conn.close()
flash('Registration successful!')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/logout')
def logout():
session.pop('user_id', None)
session.pop('username', None)
session.pop('role', None)
session.pop('user_logo_path', None)
return redirect(url_for('index'))
@app.route('/admin')
def admin():
if 'user_id' not in session:
return redirect(url_for('login'))
return render_template('admin.html')
@app.route('/admin/users')
def admin_users():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('index'))
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM users")
users = cursor.fetchall()
conn.close()
return render_template('admin_users.html', users=users)
@app.route('/admin/users/<int:user_id>', methods=['DELETE'])
def delete_user(user_id):
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('index'))
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("DELETE FROM users WHERE id = ?", (user_id,))
conn.commit()
conn.close()
return redirect(url_for('admin_users'))
@app.route('/admin/logo', methods=['GET', 'POST'])
def admin_logo():
if 'user_id' not in session or session['role'] != 'admin':
return redirect(url_for('index'))
if request.method == 'POST':
if 'logo' in request.files:
file = request.files['logo']
if file.filename == '':
flash('No selected file')
return redirect(url_for('admin_users'))
filename = f'logo_{uuid.uuid4().hex}.png'
logo_path = os.path.join(app.config['LOGO_FOLDER'], filename)
file.save(logo_path)
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("UPDATE users SET logo_path = ? WHERE username = 'admin'", (logo_path,))
conn.commit()
conn.close()
flash('Logo uploaded successfully')
return redirect(url_for('admin_users'))
return render_template('admin_logo.html')
@app.route('/')
def index():
conn = sqlite3.connect(DB_PATH)
inspections = conn.execute("SELECT * FROM inspections ORDER BY inspection_date DESC").fetchall()
conn.close()
return render_template('index.html', inspections=inspections)
@app.route('/new', methods=['GET', 'POST'])
def new_inspection():
if 'user_id' not in session:
return redirect(url_for('login'))
if request.method == 'POST':
inspector_name = request.form['inspector_name']
location = request.form['location']
inspection_date = request.form['inspection_date']
installation_name = request.form['installation_name']
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT INTO inspections (inspector_name, location, inspection_date, installation_name) VALUES (?, ?, ?, ?)",
(inspector_name, location, inspection_date, installation_name))
conn.commit()
conn.close()
return redirect(url_for('view_inspection', id=cursor.lastrowid))
return render_template('new_inspection.html')
@app.route('/view/<int:id>')
def view_inspection(id):
if 'user_id' not in session:
return redirect(url_for('login'))
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM inspections WHERE id = ?", (id,))
inspection = cursor.fetchone()
cursor.execute("SELECT * FROM inspection_photos WHERE inspection_id = ?", (id,))
photos = cursor.fetchall()
cursor.execute("SELECT * FROM checklist_items")
checklist_items = cursor.fetchall()
conn.close()
return render_template('inspection.html', inspection=inspection, photos=photos, checklist_items=checklist_items)
@app.route('/upload/<int:id>', methods=['POST'])
def upload_photo(id):
if 'user_id' not in session:
return redirect(url_for('login'))
if 'photo' not in request.files:
flash('No file part')
return redirect(url_for('view_inspection', id=id))
file = request.files['photo']
if file.filename == '':
flash('No selected file')
return redirect(url_for('view_inspection', id=id))
filename = f'photo_{uuid.uuid4().hex}.jpg'
photo_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(photo_path)
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("INSERT INTO inspection_photos (inspection_id, photo_path, comment) VALUES (?, ?, ?)",
(id, filename, request.form.get('comment', '')))
conn.commit()
conn.close()
flash('Photo uploaded successfully')
return redirect(url_for('view_inspection', id=id))
@app.route('/generate_pdf/<int:id>', methods=['GET'])
def generate_pdf(id):
if 'user_id' not in session:
return redirect(url_for('login'))
conn = sqlite3.connect(DB_PATH)
cursor = conn.cursor()
cursor.execute("SELECT * FROM inspections WHERE id = ?", (id,))
inspection = cursor.fetchone()
cursor.execute("SELECT * FROM inspection_photos WHERE inspection_id = ?", (id,))
photos = cursor.fetchall()
cursor.execute("SELECT * FROM checklist_items")
checklist_items = cursor.fetchall()
conn.close()
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
from reportlab.lib import utils
from reportlab.lib.utils import ImageReader
pdf_path = os.path.join(app.config['PDF_FOLDER'], f'report_{id}.pdf')
doc = SimpleDocTemplate(pdf_path, pagesize=letter)
styles = getSampleStyleSheet()
elements = []
elements.append(Paragraph(f"Inspection Report - {inspection[1]}", styles['Heading1']))
elements.append(Spacer(1, 12))
elements.append(Paragraph(f"Inspector: {inspection[1]}", styles['Normal']))
elements.append(Paragraph(f"Location: {inspection[2]}", styles['Normal']))
elements.append(Paragraph(f"Date: {inspection[3]}", styles['Normal']))
elements.append(Paragraph(f"Installation: {inspection[4]}", styles['Normal']))
elements.append(Spacer(1, 12))
elements.append(Paragraph("Checklist", styles['Heading2']))
for item in checklist_items:
elements.append(Paragraph(f"- {item[1]}", styles['Normal']))
elements.append(Spacer(1, 12))
elements.append(Paragraph("Photos", styles['Heading2']))
for photo in photos:
elements.append(Paragraph(f"Photo {photo[0]}: {photo[2]}", styles['Normal']))
elements.append(Spacer(1, 4))
# Add logo if available
logo_path = session.get('user_logo_path')
if logo_path:
try:
logo = ImageReader(logo_path)
logo_width = 100
logo_height = 100
elements.append(Paragraph(f"Logo: {logo_path}", styles['Normal']))
# Add logo to PDF
doc.build(elements)
except Exception as e:
print(f"Error adding logo: {e}")
else:
doc.build(elements)
return send_from_directory(app.config['PDF_FOLDER'], f'report_{id}.pdf', as_attachment=True)
if __name__ == '__main__':
app.run(debug=True)