diff --git a/web/app.py b/web/app.py index 46d02b3..66e98d2 100644 --- a/web/app.py +++ b/web/app.py @@ -1,8 +1,10 @@ from flask import Flask, render_template, request, redirect, url_for, flash, session import logging from datetime import datetime -import sqlite3 from werkzeug.security import check_password_hash, generate_password_hash +from db import get_db_connection, fetch_users, fetch_orders, fetch_roles, fetch_repairs, fetch_employees +from auth import encrypt_password, check_password +import random app = Flask(__name__) app.secret_key = 'aezakmi' @@ -30,32 +32,6 @@ def log_request(response): app.logger.info(f"{client_ip} - - [{request.date}] \"{request.method} {request.full_path} {request.environ.get('SERVER_PROTOCOL')}\" {response.status_code}") return response # ----------------- End of logging part ----------------- -# Database connection -def get_db_connection(): - conn = sqlite3.connect('./static/db/db.sqlite') - conn.row_factory = sqlite3.Row - return conn - -# Function to convert row to dictionary -def dict_from_row(row): - return {key: row[key] for key in row.keys()} - -# Function to fetch users from database -def fetch_users(role_id): - conn = get_db_connection() - users = conn.execute('SELECT * FROM Zamestnanci WHERE Role_ID >= ?', (role_id,)).fetchall() - users = [dict_from_row(user) for user in users] - conn.close() - app.logger.debug(f"Fetched users: {users}") - return users - -# Function to encrypt password -def encrypt_password(password): - return generate_password_hash(password) - -# Function to check password -def check_password(stored_password, provided_password): - return check_password_hash(stored_password, provided_password) # Routes @app.route('/logout') @@ -117,7 +93,9 @@ def administrator(): flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error') return redirect(url_for('login')) users = fetch_users(session.get('role_id')) - return render_template('administrator.html', users=users) + orders = fetch_orders() + roles = fetch_roles() + return render_template('administrator.html', users=users, orders=orders, roles=roles) @app.route('/create_user', methods=['GET', 'POST']) def create_user(): @@ -205,6 +183,137 @@ def delete_user(user_id): conn.close() return redirect(url_for('administrator')) +@app.route('/edit_order/', methods=['GET', 'POST']) +def edit_order(order_id): + if not session.get('logged_in') or session.get('role_id') != 1: + flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error') + return redirect(url_for('login')) + + conn = get_db_connection() + order = conn.execute('SELECT * FROM Objednavky WHERE ID_Objednavky = ?', (order_id,)).fetchone() + + if request.method == 'POST': + stav = request.form['stav'] + id_zamestnance = request.form['id_zamestnance'] + popis = request.form['popis'] + datum_konce = request.form['datum_konce'] + + conn.execute('UPDATE Objednavky SET Stav = ?, ID_Zamestnance = ?, Popis = ?, Datum_Konce = ? WHERE ID_Objednavky = ?', + (stav, id_zamestnance, popis, datum_konce, order_id)) + + conn.commit() + conn.close() + + flash('Objednávka byla úspěšně aktualizována.') + return redirect(url_for('administrator')) + + conn.close() + return render_template('edit_order.html', order=order) + +@app.route('/repairs') +def repairs(): + if not session.get('logged_in'): + flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error') + return redirect(url_for('login')) + repairs = fetch_repairs() + return render_template('repairs.html', repairs=repairs) + +@app.route('/create_repair', methods=['GET', 'POST']) +def create_repair(): + if not session.get('logged_in') or session.get('role_id') != 1: + flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error') + return redirect(url_for('login')) + + if request.method == 'POST': + id_zamestnance = request.form['id_zamestnance'] + nazev = request.form['nazev'] + popis = request.form['popis'] + + conn = get_db_connection() + try: + conn.execute('INSERT INTO Opravy (ID_Zamestnance, Nazev, Popis) VALUES (?, ?, ?)', + (id_zamestnance, nazev, popis)) + conn.commit() + flash('Nová oprava byla úspěšně vytvořena.', 'success') + return redirect(url_for('repairs')) + except sqlite3.Error as e: + flash(f'Chyba při vytváření opravy: {e}', 'error') + finally: + conn.close() + + employees = fetch_employees() + return render_template('create_repair.html', employees=employees) + +@app.route('/edit_repair/', methods=['GET', 'POST']) +def edit_repair(repair_id): + if not session.get('logged_in') or session.get('role_id') != 1: + flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error') + return redirect(url_for('login')) + + conn = get_db_connection() + repair = conn.execute('SELECT * FROM Opravy WHERE ID_Opravy = ?', (repair_id,)).fetchone() + + if request.method == 'POST': + id_zamestnance = request.form['id_zamestnance'] + nazev = request.form['nazev'] + popis = request.form['popis'] + + conn.execute('UPDATE Opravy SET ID_Zamestnance = ?, Nazev = ?, Popis = ? WHERE ID_Opravy = ?', + (id_zamestnance, nazev, popis, repair_id)) + conn.commit() + conn.close() + + flash('Oprava byla úspěšně aktualizována.') + return redirect(url_for('repairs')) + + employees = fetch_employees() + conn.close() + return render_template('edit_repair.html', repair=repair, employees=employees) + +@app.route('/delete_repair/', methods=['POST']) +def delete_repair(repair_id): + if not session.get('logged_in') or session.get('role_id') != 1: + flash('Nemáte oprávnění k přístupu na tuto stránku.', 'error') + return redirect(url_for('login')) + + conn = get_db_connection() + conn.execute('DELETE FROM Opravy WHERE ID_Opravy = ?', (repair_id,)) + conn.commit() + conn.close() + + flash('Oprava byla úspěšně smazána.') + return redirect(url_for('repairs')) + +@app.route('/create_reservation', methods=['POST']) +def create_reservation(): + full_name = request.form['fullName'] + email = request.form['email'] + date = request.form['date'] + description = request.form['description'] + + # Convert date to DD.MM.YYYY format + formatted_date = datetime.strptime(date, '%Y-%m-%d').strftime('%d.%m.%Y') + + conn = get_db_connection() + try: + # Fetch a random user with role_id 2 + user = conn.execute('SELECT ID_Uzivatele FROM Zamestnanci WHERE Role_ID = 2 ORDER BY RANDOM() LIMIT 1').fetchone() + if user: + user_id = user['ID_Uzivatele'] + else: + user_id = 1 # Fallback to a default user ID if no user with role_id 2 is found + + conn.execute('INSERT INTO Objednavky (Stav, ID_Zamestnance, Popis, ID_Vozidla, Datum_Zacatku, Cena) VALUES (?, ?, ?, ?, ?, ?)', + ('Nová', user_id, description, 1, formatted_date, 0.0)) # Example values for ID_Vozidla + conn.commit() + flash('Rezervace byla úspěšně vytvořena.', 'success') + except sqlite3.Error as e: + flash(f'Chyba při vytváření rezervace: {e}', 'error') + finally: + conn.close() + + return redirect(url_for('home')) + # Always redirect back home @app.errorhandler(404) def default_page(e): diff --git a/web/auth.py b/web/auth.py new file mode 100644 index 0000000..32db038 --- /dev/null +++ b/web/auth.py @@ -0,0 +1,8 @@ + +from werkzeug.security import check_password_hash, generate_password_hash + +def encrypt_password(password): + return generate_password_hash(password) + +def check_password(stored_password, provided_password): + return check_password_hash(stored_password, provided_password) \ No newline at end of file diff --git a/web/db.py b/web/db.py new file mode 100644 index 0000000..0e7d09a --- /dev/null +++ b/web/db.py @@ -0,0 +1,65 @@ + +import sqlite3 +from flask import current_app as app + +def get_db_connection(): + conn = sqlite3.connect('./static/db/db.sqlite') + conn.row_factory = sqlite3.Row + return conn + +def dict_from_row(row): + return {key: row[key] for key in row.keys()} + +def fetch_users(role_id): + conn = get_db_connection() + users = conn.execute('SELECT * FROM Zamestnanci WHERE Role_ID >= ?', (role_id,)).fetchall() + users = [dict_from_row(user) for user in users] + conn.close() + app.logger.debug(f"Fetched users: {users}") + return users + +def fetch_orders(): + conn = get_db_connection() + orders = conn.execute('SELECT * FROM Objednavky').fetchall() + orders = [dict_from_row(order) for order in orders] + conn.close() + app.logger.debug(f"Fetched orders: {orders}") + return orders + +def fetch_roles(): + conn = get_db_connection() + roles = conn.execute('SELECT * FROM Role').fetchall() + roles = [dict_from_row(role) for role in roles] + conn.close() + app.logger.debug(f"Fetched roles: {roles}") + return roles + +def fetch_repairs(): + conn = get_db_connection() + repairs = conn.execute(''' + SELECT Opravy.ID_Opravy, Zamestnanci.Jmeno, Zamestnanci.Prijmeni, Opravy.Nazev, Opravy.Popis + FROM Opravy + JOIN Zamestnanci ON Opravy.ID_Zamestnance = Zamestnanci.ID_Uzivatele + ''').fetchall() + repairs = [dict_from_row(repair) for repair in repairs] + + for repair in repairs: + products = conn.execute(''' + SELECT Produkty.Nazev, Pouzite_Produkty.Pocet_Produktu + FROM Pouzite_Produkty + JOIN Produkty ON Pouzite_Produkty.ID_Produktu = Produkty.ID_Produktu + WHERE Pouzite_Produkty.ID_Opravy = ? + ''', (repair['ID_Opravy'],)).fetchall() + repair['products'] = [dict_from_row(product) for product in products] + + conn.close() + app.logger.debug(f"Fetched repairs: {repairs}") + return repairs + +def fetch_employees(): + conn = get_db_connection() + employees = conn.execute('SELECT ID_Uzivatele, Jmeno, Prijmeni FROM Zamestnanci').fetchall() + employees = [dict_from_row(employee) for employee in employees] + conn.close() + app.logger.debug(f"Fetched employees: {employees}") + return employees \ No newline at end of file diff --git a/web/static/css/style.css b/web/static/css/style.css index 178ea82..48f77c6 100644 --- a/web/static/css/style.css +++ b/web/static/css/style.css @@ -71,6 +71,26 @@ footer { right: 0; } +.navbar-users-table { + display: flex; + justify-content: space-around; + background-color: #444; + padding: 10px; + margin-top: 1.5em; + border-top-left-radius: 0.5em; + border-top-right-radius: 0.5em; +} + +.navbar-orders-table { + display: flex; + justify-content: space-around; + background-color: #444; + padding: 10px; + margin-top: 1.5em; + border-top-left-radius: 0.5em; + border-top-right-radius: 0.5em; +} + /* Navbar */ .navbar { display: flex; @@ -111,6 +131,7 @@ footer { .container { margin: auto; width: 75%; + text-align: center; } /* Section styles */ @@ -374,9 +395,8 @@ footer { table { width: 100%; border-collapse: collapse; - margin: 20px 0; font-size: 18px; - text-align: left; + text-align: center; } table th, table td { @@ -515,3 +535,28 @@ table tr:hover { border-bottom-left-radius: 1em; z-index: 1000; } + +/* Dropdown menu styles */ +select { + width: 100%; + padding: 10px; + margin: 5px 0 20px; + border: none; + border-radius: 5px; + background-color: #555; + color: white; + font-size: 16px; +} + +select:focus { + outline: none; + box-shadow: 0 0 5px rgba(81, 203, 238, 1); + border: 1px solid rgba(81, 203, 238, 1); +} + +/* Option styles */ +option { + background-color: #333; + color: white; + padding: 10px; +} diff --git a/web/static/db/databaze.txt b/web/static/db/databaze.txt new file mode 100644 index 0000000..6d1622c --- /dev/null +++ b/web/static/db/databaze.txt @@ -0,0 +1,76 @@ +-- Table for Roles +CREATE TABLE Role ( + Role_ID INTEGER PRIMARY KEY, + Nazev TEXT NOT NULL +); + +-- Table for Employees (Zamestnanci) +CREATE TABLE Zamestnanci ( + ID_Uzivatele INTEGER PRIMARY KEY, + Jmeno TEXT NOT NULL, + Prijmeni TEXT NOT NULL, + Role_ID INTEGER NOT NULL, + Heslo TEXT NOT NULL, + Email TEXT, + Username TEXT NOT NULL UNIQUE, + FOREIGN KEY (Role_ID) REFERENCES Role (Role_ID) +); + +-- Table for Vehicles (Vozidla) +CREATE TABLE Vozidla ( + ID_Vozidla INTEGER PRIMARY KEY, + Majitel TEXT NOT NULL, + Barva TEXT NOT NULL, + Typ TEXT NOT NULL +); + +-- Table for Orders (Objednavky) +CREATE TABLE Objednavky ( + ID_Objednavky INTEGER PRIMARY KEY, + Stav TEXT NOT NULL, + ID_Zamestnance INTEGER NOT NULL, + Popis TEXT, + ID_Vozidla INTEGER NOT NULL, + Datum_Zacatku DATE NOT NULL, + Datum_Konce DATE, + Cena REAL NOT NULL, + FOREIGN KEY (ID_Zamestnance) REFERENCES Zamestnanci (ID_Uzivatele), + FOREIGN KEY (ID_Vozidla) REFERENCES Vozidla (ID_Vozidla) +); + +-- Table for Repairs (Opravy) +CREATE TABLE Opravy ( + ID_Opravy INTEGER PRIMARY KEY, + ID_Zamestnance INTEGER NOT NULL, + Nazev TEXT NOT NULL, + Popis TEXT, + FOREIGN KEY (ID_Zamestnance) REFERENCES Zamestnanci (ID_Uzivatele) +); + +-- Linking table for Orders and Repairs (Objednavky_Opravy) +CREATE TABLE Objednavky_Opravy ( + ID_Objednavky_Opravy INTEGER PRIMARY KEY, + ID_Objednavky INTEGER NOT NULL, + ID_Opravy INTEGER NOT NULL, + FOREIGN KEY (ID_Objednavky) REFERENCES Objednavky (ID_Objednavky), + FOREIGN KEY (ID_Opravy) REFERENCES Opravy (ID_Opravy) +); + +-- Table for Products (Produkty) +CREATE TABLE Produkty ( + ID_Produktu INTEGER PRIMARY KEY, + Minimalni_Zasoba INTEGER NOT NULL, + Momentalni_Zasoba INTEGER NOT NULL, + Nazev TEXT NOT NULL, + Popis TEXT +); + +-- Table for Product Usage (Pouzite_Produkty) +CREATE TABLE Pouzite_Produkty ( + ID_Pouziti INTEGER PRIMARY KEY, + ID_Opravy INTEGER NOT NULL, + ID_Produktu INTEGER NOT NULL, + Pocet_Produktu INTEGER NOT NULL, + FOREIGN KEY (ID_Opravy) REFERENCES Opravy (ID_Opravy), + FOREIGN KEY (ID_Produktu) REFERENCES Produkty (ID_Produktu) +); diff --git a/web/static/db/db.sqlite b/web/static/db/db.sqlite index 3860d58..7e617d0 100644 Binary files a/web/static/db/db.sqlite and b/web/static/db/db.sqlite differ diff --git a/web/static/scripts/reservation.js b/web/static/scripts/reservation.js index d6180f7..bd3581a 100644 --- a/web/static/scripts/reservation.js +++ b/web/static/scripts/reservation.js @@ -1,8 +1,10 @@ - function openReservationForm() { - document.getElementById("reservationForm").style.display = "block"; + const now = new Date(); + const formattedDate = now.toLocaleDateString('cs-CZ', { day: '2-digit', month: '2-digit', year: 'numeric' }); + document.getElementById('date').value = formattedDate; + document.getElementById('reservationForm').style.display = 'block'; } function closeReservationForm() { - document.getElementById("reservationForm").style.display = "none"; + document.getElementById('reservationForm').style.display = 'none'; } \ No newline at end of file diff --git a/web/templates/administrator.html b/web/templates/administrator.html index 384bd02..7a9abbc 100644 --- a/web/templates/administrator.html +++ b/web/templates/administrator.html @@ -3,7 +3,7 @@ - Uživatelská Tabulka + Administrativní pracovníci @@ -18,7 +18,7 @@ - Uživatelská Tabulka + Administrativní pracovníci
Zpět na Domovskou Stránku @@ -28,9 +28,7 @@
- +
@@ -39,8 +37,10 @@ {% elif session.get('role_id') != 1 %}

Nemáte oprávnění zobrazit tuto stránku.

{% else %} -
+ {% if users %} @@ -61,7 +61,13 @@ - +
{{ user['Jmeno'] }} {{ user['Prijmeni'] }} {{ user['Email'] }}{{ user['Role_ID'] }} + {% for role in roles %} + {% if role['Role_ID'] == user['Role_ID'] %} + {{ role['Nazev'] }} + {% endif %} + {% endfor %} + {{ user['Username'] }} Edit @@ -79,8 +85,55 @@

No users found.

{% endif %} +
+ + {% if orders %} + + + + + + + + + + + + + + {% for order in orders %} + + + + + + + + + + {% endfor %} + +
Číslo objednávkyDatum začátkuDatum konceStavPřiřazený zaměstnanecPopisAkce
{{ order['ID_Objednavky'] }}{{ order['Datum_Zacatku'] }}{{ order['Datum_Konce'] }}{{ order['Stav'] }} + {% for user in users %} + {% if user['ID_Uzivatele'] == order['ID_Zamestnance'] %} + {{ user['Jmeno'] }} {{ user['Prijmeni'] }} + {% endif %} + {% endfor %} + {{ order['Popis'] }} + Edit +
+ {% else %} + + + + +
Nenalezeny žádné objednávky k zobrazení.
+ {% endif %} +
{% endif %} - +