diff --git a/.gitignore b/.gitignore index 40afa02..43656cb 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ web/env +web/__pycache__ +web/__pycache__ diff --git a/ERD_diagram.drawio b/ERD_diagram.drawio index cb68887..07624ba 100644 --- a/ERD_diagram.drawio +++ b/ERD_diagram.drawio @@ -1,11 +1,11 @@ - + - + @@ -60,7 +60,7 @@ - + @@ -70,7 +70,7 @@ - + @@ -88,7 +88,7 @@ - + @@ -118,7 +118,7 @@ - + @@ -139,12 +139,12 @@ - + - + @@ -242,15 +242,15 @@ - + - + - + @@ -259,21 +259,12 @@ - - - - - - - - - - + - + @@ -283,16 +274,10 @@ - + - - - - - - @@ -312,12 +297,12 @@ - + - + @@ -348,70 +333,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -421,37 +342,8 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + @@ -474,7 +366,7 @@ - + @@ -482,12 +374,12 @@ - + - + @@ -519,96 +411,79 @@ - + - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -617,6 +492,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ERD_diagram.drawio.png b/ERD_diagram.drawio.png new file mode 100644 index 0000000..0166c35 Binary files /dev/null and b/ERD_diagram.drawio.png differ diff --git a/VWA_PROJECT_DOC_Hrachovina-Kirsch.docx b/VWA_PROJECT_DOC_Hrachovina-Kirsch.docx index d898f43..68c86f1 100644 Binary files a/VWA_PROJECT_DOC_Hrachovina-Kirsch.docx and b/VWA_PROJECT_DOC_Hrachovina-Kirsch.docx differ diff --git a/drateny_model.drawio b/drateny_model.drawio index fbdde33..a7a63cd 100644 --- a/drateny_model.drawio +++ b/drateny_model.drawio @@ -1,6 +1,6 @@ - + - + @@ -432,7 +432,7 @@ - + @@ -470,7 +470,7 @@ - + @@ -508,7 +508,7 @@ - + @@ -546,7 +546,7 @@ - + @@ -584,7 +584,7 @@ - + @@ -622,7 +622,7 @@ - + @@ -660,7 +660,7 @@ - + @@ -698,7 +698,7 @@ - + @@ -736,7 +736,7 @@ - + @@ -774,7 +774,7 @@ - + @@ -1119,12 +1119,12 @@ - + - + @@ -1139,7 +1139,7 @@ - + @@ -1162,12 +1162,12 @@ - + - + @@ -1182,7 +1182,7 @@ - + @@ -1205,12 +1205,12 @@ - + - + @@ -1225,7 +1225,7 @@ - + @@ -1248,12 +1248,12 @@ - + - + @@ -1268,7 +1268,7 @@ - + @@ -1291,12 +1291,12 @@ - + - + @@ -1311,7 +1311,7 @@ - + @@ -1334,12 +1334,12 @@ - + - + @@ -1354,7 +1354,7 @@ - + @@ -1377,12 +1377,12 @@ - + - + @@ -1397,7 +1397,7 @@ - + @@ -1420,12 +1420,12 @@ - + - + @@ -1440,7 +1440,7 @@ - + @@ -1463,12 +1463,12 @@ - + - + @@ -1483,7 +1483,7 @@ - + @@ -1506,12 +1506,12 @@ - + - + @@ -1526,7 +1526,7 @@ - + @@ -1617,7 +1617,7 @@ - + @@ -1865,1287 +1865,1767 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/drateny_model.png b/drateny_model.png deleted file mode 100644 index c2ace63..0000000 Binary files a/drateny_model.png and /dev/null differ diff --git a/konzultace_3.txt b/konzultace_3.txt new file mode 100644 index 0000000..e9dabb8 --- /dev/null +++ b/konzultace_3.txt @@ -0,0 +1,8 @@ +smazat stavy, +vazba vozidla - zakaznici +oprava - produkty vazba + +osetrit locking of database when incorrect command issued + + +zakaznici se nemusi prihlasovat :checkmark: \ No newline at end of file diff --git a/poznamky k projektu.txt b/poznamky k projektu.txt deleted file mode 100644 index bea7ab2..0000000 --- a/poznamky k projektu.txt +++ /dev/null @@ -1,16 +0,0 @@ -katalog a sluzeb nemusi byt -procesni model - bpmn prvni cviceni -procesy spojeni s udrzbou rozvojem - napsat to, jakykoliv -model pozadavku - use case -jeden stavovy diagram -diagram casovani - nebudeme delat, numime -scenar - jeden -sekveencni diagram/diagram aktivit - vygenerovat a hezky popsat -diagram nasazeni -ericcson cosi nedelat -zbytek info na dokumentovem serveru - - -bude se prezentovat - -do odevzdavarny diff --git a/web/app.py b/web/app.py index 625bf15..46d02b3 100644 --- a/web/app.py +++ b/web/app.py @@ -1,9 +1,13 @@ -from flask import Flask, render_template, request, redirect, url_for +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 app = Flask(__name__) +app.secret_key = 'aezakmi' +# ----------------- Logging part not related to project requirements ----------------- # Set up custom logging logging.basicConfig(level=logging.DEBUG) @@ -14,9 +18,9 @@ werkzeug_logger.setLevel(logging.ERROR) # Log client IP before each request @app.before_request def log_client_ip(): - # Get client IP address from X-Forwarded-For header or remote_addr client_ip = request.headers.get('X-Forwarded-For', request.remote_addr) client_ip = client_ip.split(',')[0] # Get the first IP if it's a forwarded request + request.client_ip = client_ip # Store the client IP in the request context # Override werkzeug's default logging to show client IP in the access log @app.after_request @@ -25,6 +29,77 @@ def log_request(response): client_ip = client_ip.split(',')[0] # Get the first IP if it's a forwarded request 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') +def logout(): + session.pop('logged_in', None) + session.pop('role_id', None) + session.pop('username', None) + return ''' + + ''' + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if session.get('logged_in'): + flash('Již jste přihlášen.', 'info') + if session.get('role_id') == 1: + return redirect(url_for('administrator')) + else: + return redirect(url_for('home')) + + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + + conn = get_db_connection() + user = conn.execute('SELECT * FROM Zamestnanci WHERE username = ?', (username,)).fetchone() + conn.close() + + if user is None or not check_password(user['heslo'], password): + flash('Nesprávné uživatelské jméno nebo heslo.', 'error') + else: + session['logged_in'] = True + session['role_id'] = user['Role_ID'] + session['username'] = user['Username'] # Store username in session + flash('Úspěšně přihlášen.', 'success') + if user['Role_ID'] == 1: + return redirect(url_for('administrator')) + else: + return redirect(url_for('home')) + + return render_template('login.html') @app.route('/') def home(): @@ -36,11 +111,105 @@ def home(): def about(): return render_template('about.html') +@app.route('/administrator') +def administrator(): + 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')) + users = fetch_users(session.get('role_id')) + return render_template('administrator.html', users=users) + +@app.route('/create_user', methods=['GET', 'POST']) +def create_user(): + 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': + jmeno = request.form['jmeno'] + prijmeni = request.form['prijmeni'] + email = request.form['email'] + role = request.form['role'] + username = request.form['username'] + heslo = encrypt_password(request.form['heslo']) + + conn = get_db_connection() + existing_user = conn.execute('SELECT * FROM Zamestnanci WHERE Username = ?', (username,)).fetchone() + + if existing_user: + conn.close() + return 'exists' + + try: + conn.execute('INSERT INTO Zamestnanci (Jmeno, Prijmeni, Email, Role_ID, Username, Heslo) VALUES (?, ?, ?, ?, ?, ?)', + (jmeno, prijmeni, email, role, username, heslo)) + conn.commit() + return 'success' + except sqlite3.Error as e: + return f'error: {e}' + finally: + conn.close() + + return render_template('create_user.html') + +@app.route('/edit_user/', methods=['GET', 'POST']) +def edit_user(user_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() + user = conn.execute('SELECT * FROM Zamestnanci WHERE ID_Uzivatele = ?', (user_id,)).fetchone() + + if request.method == 'POST': + jmeno = request.form['jmeno'] + prijmeni = request.form['prijmeni'] + email = request.form['email'] + role = request.form['role'] + username = request.form['username'] + heslo = request.form['heslo'] + + if heslo: + heslo = encrypt_password(heslo) + conn.execute('UPDATE Zamestnanci SET Jmeno = ?, Prijmeni = ?, Email = ?, Role_ID = ?, Username = ?, Heslo = ? WHERE ID_Uzivatele = ?', + (jmeno, prijmeni, email, role, username, heslo, user_id)) + else: + conn.execute('UPDATE Zamestnanci SET Jmeno = ?, Prijmeni = ?, Email = ?, Role_ID = ?, Username = ? WHERE ID_Uzivatele = ?', + (jmeno, prijmeni, email, role, username, user_id)) + + conn.commit() + conn.close() + + flash('Uživatel byl úspěšně aktualizován.') + return redirect(url_for('administrator')) + + conn.close() + return render_template('edit_user.html', user=user) + +@app.route('/delete_user/', methods=['POST']) +def delete_user(user_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() + user = conn.execute('SELECT * FROM Zamestnanci WHERE ID_Uzivatele = ?', (user_id,)).fetchone() + + if user and user['Role_ID'] > session.get('role_id'): + conn.execute('DELETE FROM Zamestnanci WHERE ID_Uzivatele = ?', (user_id,)) + conn.commit() + flash('Uživatel byl úspěšně smazán.') + else: + flash('Nemáte oprávnění smazat tohoto uživatele.', 'error') + + conn.close() + return redirect(url_for('administrator')) + # Always redirect back home @app.errorhandler(404) def default_page(e): return redirect(url_for('home')) - +# Run the app if __name__ == "__main__": app.run(debug=True, host="0.0.0.0", port=5005) diff --git a/web/static/css/style.css b/web/static/css/style.css new file mode 100644 index 0000000..178ea82 --- /dev/null +++ b/web/static/css/style.css @@ -0,0 +1,517 @@ +/* Global styles */ +* { + margin: 0; + box-sizing: border-box; +} + +/* Body styling */ +body { + font-family: Arial, sans-serif; + background-color: black; + color: white; + position: relative; +} + +body::before { + content: ""; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-image: url('/static/img/background-1.jpg'); + background-size: cover; + background-position: center; + background-attachment: fixed; + filter: brightness(50%); + z-index: -1; +} + +/* Rounded corners applied directly */ +.about, .map, .service-info, .photos, .directions, .services, .service-item, .review-box { + border-radius: 1em; +} + +/* Header title styling */ +.nazev { + float: left; +} + +/* Flex container class for consistent layout */ +.flex-container { + display: flex; + justify-content: space-between; + align-items: center; +} + +/* Header and Footer background graphics */ +header, footer { + background-color: #333; + padding: 10px; + text-align: center; + width: 75%; + margin: 0 auto; + color: white; +} + +header { + height: 9.5em; +} + +.header { + margin-left: 1em; + margin-right: 1em; +} + +footer { + width: fit-content; /* Change width to auto */ + border-top-left-radius: 1em; + position: fixed; + bottom: 0; + right: 0; +} + +/* Navbar */ +.navbar { + display: flex; + justify-content: space-around; + background-color: #444; + padding: 10px; + margin-bottom: 10px; + width: 75%; + margin: 0 auto; + border-bottom-left-radius: 0.5em; + border-bottom-right-radius: 0.5em; +} + +/* Navbar links */ +.navbar a { + text-decoration: none; + color: white; + padding: 5px 15px; +} + +/* Navbar buttons */ +.navbar button { + background-color: #808080; + color: white; + padding: 10px 20px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: transform 0.3s, box-shadow 0.3s; +} + +.navbar button:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +/* Content layout */ +.container { + margin: auto; + width: 75%; +} + +/* Section styles */ +.about, .service-info, .photos, .directions { + box-sizing: border-box; + padding: 15px; + background-color: #222; + border: 1px solid #555; + color: white; + margin-top: 10px; + margin-bottom: 10px; +} + +.directions { + flex: 1 1 100%; + display: block; +} + +.directions-content { + display: flex; + align-items: center; +} + +.directions-content iframe { + flex: 1 1 50%; +} + +.directions-text { + flex: 1 1 50%; + margin-left: 20px; +} + +/* About and Map are larger sections */ +.about { + flex: 2 1 50%; +} + +.photos, .directions { + flex: 1 1 30%; +} + +/* Service section */ +.services { + margin: 20px 0; + padding: 15px; + background-color: #222; + border: 1px solid #555; + color: white; +} + +.service-list { + display: flex; + justify-content: space-around; + flex-wrap: wrap; +} + +.service-item { + flex: 1 1 200px; + background-color: #333; + width: 200px; + height: 200px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + transition: transform 0.3s, box-shadow 0.3s; + margin: 10px; +} + +.service-item img { + width: 100px; + height: auto; +} + +.service-item:first-child img { + width: 150px; +} + +/* Hover effects for buttons and service items */ +.service-item:hover, +.reservation-button:hover, +.login-button:hover, +.review-box:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +/* Buttons */ +.button, .reservation-button, .login-button, .navbar button { + background-color: #808080; + color: white; + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin-bottom: 10px; + margin-left: 10px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: transform 0.3s, box-shadow 0.3s; +} + +.button:hover, .reservation-button:hover, .login-button:hover, .navbar button:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +/* Flex container for buttons */ +.buttons { + display: flex; + justify-content: flex-end; + align-items: center; + margin-top: 1.7em; +} + +/* Reviews section */ +.reviews { + display: flex; + justify-content: space-around; + margin: 20px; +} + +.review-box { + width: 200px; + min-height: 100px; + background-color: #444; + border: 1px solid #555; + padding: 10px; + text-align: center; + transition: transform 0.3s, box-shadow 0.3s; + color: white; +} + +/* Text alignment for Directions */ +.directions { + text-align: right; +} + +/* Align-right class */ +.align-right { + float: right; + margin-left: 20px; +} + +/* Popup form styles */ +.popup-form { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.5); + z-index: 1; +} + +.form-container { + background-color: #333; + padding: 20px; + border: 1px solid #555; + width: 80%; + max-width: 500px; + border-radius: 1em; + color: white; + margin-top: 5%; + margin-left: auto; + margin-right: auto; + margin-bottom: 1%; +} + +.close-button { + color: white; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close-button:hover, +.close-button:focus { + color: #bbb; + text-decoration: none; + cursor: pointer; +} + +.form-container label { + display: block; + margin: 10px 0 5px; +} + +.form-container input, +.form-container textarea { + width: 100%; + padding: 10px; + margin: 5px 0 20px; + border: none; + border-radius: 5px; + background-color: #555; + color: white; +} + +.form-container button { + background-color: #808080; + color: white; + padding: 10px 20px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: transform 0.3s, box-shadow 0.3s; +} + +.form-container button:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +/* Required field indicator */ +.required { + color: red; +} + +/* Logo styles */ +.logo { + width: 100px; + height: auto; + vertical-align: middle; + text-align: left; +} + +/* About content styles */ +.about-content { + display: flex; + justify-content: space-between; + align-items: center; +} + +.about-text, .about-image { + flex: 1 1 50%; +} + +.about-text { + padding-right: 20px; + text-align: left; +} + +.about-image img { + width: 100%; + height: auto; + border-radius: 0.5em; +} + +/* Service offer section */ +.nabidka-sluzeb { + display: flex; + justify-content: space-around; + flex-wrap: wrap; +} + +/* Table styling */ +table { + width: 100%; + border-collapse: collapse; + margin: 20px 0; + font-size: 18px; + text-align: left; +} + +table th, table td { + padding: 12px 15px; + border: 1px solid #ddd; +} + +table th { + background-color: #333; + color: white; +} + +table td { + background-color: #222; +} + +table tr:nth-child(even) { + background-color: #f2f2f2; +} + +table tr:hover { + background-color: #ddd; +} + +/* Media queries for mobile responsiveness */ +@media (max-width: 768px) { + .navbar, .container, .about, .map, .service-info, .photos, .directions, .services, .service-item, .review-box { + border-radius: 0.5em; + } + + .navbar { + flex-direction: column; + align-items: center; + } + + .navbar a { + padding: 10px; + width: 100%; + text-align: center; + } + + .content { + flex-direction: column; + } + + .about-content, .directions-content { + flex-direction: column; + } + + .directions-content iframe, .directions-text { + width: 100%; + margin: 0; + } + + .buttons { + flex-direction: column; + align-items: center; + } + + .reservation-button, .login-button { + width: 100%; + margin: 5px 0; + } + + .service-list { + flex-direction: column; + align-items: center; + } + + .service-item { + width: 100%; + margin: 10px 0; + } + + .reviews { + flex-direction: column; + align-items: center; + } + + .review-box { + width: 100%; + margin: 10px 0; + } + + .form-container { + width: 90%; + } +} + +/* Button link styles */ +.button-link { + background: none; + border: none; + color: #007bff; + text-decoration: underline; + cursor: pointer; + font-size: 16px; + padding: 0; +} + +.button-link:hover { + color: #0056b3; + text-decoration: underline; +} + +/* Logout button styles */ +.logout-button { + background-color: #808080; + color: white; + padding: 10px 20px; + text-align: center; + text-decoration: none; + display: inline-block; + font-size: 16px; + margin-bottom: 10px; + margin-left: 10px; + border: none; + border-radius: 5px; + cursor: pointer; + transition: transform 0.3s, box-shadow 0.3s; +} + +.logout-button:hover { + transform: scale(1.05); + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2); +} + +/* User info section */ +.user-info { + position: fixed; + top: 0; + right: 0; + background-color: #333; + color: white; + padding: 10px; + border-bottom-left-radius: 1em; + z-index: 1000; +} diff --git a/database/database.sqlite b/web/static/db/db.sqlite similarity index 71% rename from database/database.sqlite rename to web/static/db/db.sqlite index c286c85..3860d58 100644 Binary files a/database/database.sqlite and b/web/static/db/db.sqlite differ diff --git a/web/static/img/atv-icon.png b/web/static/img/atv-icon.png new file mode 100644 index 0000000..7c729f9 Binary files /dev/null and b/web/static/img/atv-icon.png differ diff --git a/web/static/img/autoservis.jpg b/web/static/img/autoservis.jpg new file mode 100644 index 0000000..5a57456 Binary files /dev/null and b/web/static/img/autoservis.jpg differ diff --git a/web/static/img/background-1.jpg b/web/static/img/background-1.jpg new file mode 100644 index 0000000..9164dab Binary files /dev/null and b/web/static/img/background-1.jpg differ diff --git a/web/static/img/background-2.png b/web/static/img/background-2.png new file mode 100644 index 0000000..b68d61a Binary files /dev/null and b/web/static/img/background-2.png differ diff --git a/web/static/img/car-icon.png b/web/static/img/car-icon.png new file mode 100644 index 0000000..9ffc33f Binary files /dev/null and b/web/static/img/car-icon.png differ diff --git a/web/static/img/logo.webp b/web/static/img/logo.webp new file mode 100644 index 0000000..fe1edb3 Binary files /dev/null and b/web/static/img/logo.webp differ diff --git a/web/static/img/motorcycle-icon.png b/web/static/img/motorcycle-icon.png new file mode 100644 index 0000000..da327ba Binary files /dev/null and b/web/static/img/motorcycle-icon.png differ diff --git a/web/static/img/scooter-icon.png b/web/static/img/scooter-icon.png new file mode 100644 index 0000000..67e4127 Binary files /dev/null and b/web/static/img/scooter-icon.png differ diff --git a/web/static/scripts/create_user.js b/web/static/scripts/create_user.js new file mode 100644 index 0000000..2bd882c --- /dev/null +++ b/web/static/scripts/create_user.js @@ -0,0 +1,18 @@ +function handleCreateUser(event) { + event.preventDefault(); + const form = event.target; + fetch(form.action, { + method: form.method, + body: new FormData(form), + }) + .then(response => response.text()) + .then(result => { + if (result === 'exists') { + alert('Uživatel s tímto uživatelským jménem již existuje.'); + } else { + alert('Nový uživatel byl úspěšně vytvořen.'); + window.location.reload(); + } + }) + .catch(error => console.error('Error:', error)); +} \ No newline at end of file diff --git a/web/static/scripts/reservation.js b/web/static/scripts/reservation.js new file mode 100644 index 0000000..d6180f7 --- /dev/null +++ b/web/static/scripts/reservation.js @@ -0,0 +1,8 @@ + +function openReservationForm() { + document.getElementById("reservationForm").style.display = "block"; +} + +function closeReservationForm() { + document.getElementById("reservationForm").style.display = "none"; +} \ No newline at end of file diff --git a/web/static/style.css b/web/static/style.css deleted file mode 100644 index cf2ddad..0000000 --- a/web/static/style.css +++ /dev/null @@ -1,117 +0,0 @@ -body { - font-family: Arial, sans-serif; - margin: 0; - padding: 0; - background-color: #f4f4f4; - } - - header, footer { - background-color: #ccc; - padding: 10px; - text-align: center; - } - - .container { - width: 90%; - max-width: 1200px; - margin: 0 auto; - } - - .contact-info, .buttons { - display: flex; - justify-content: space-between; - padding: 10px 0; - } - - .navbar { - display: flex; - justify-content: space-around; - background-color: #ddd; - padding: 10px; - margin-bottom: 10px; - } - - .navbar a { - text-decoration: none; - color: black; - padding: 5px 15px; - } - - .content { - display: flex; - flex-wrap: wrap; - } - - .about, .map, .service-info, .photos { - box-sizing: border-box; - padding: 15px; - background-color: white; - margin: 10px; - border: 1px solid #ccc; - } - - .about, .map { - flex: 2 1 60%; - } - - .photos, .directions { - flex: 1 1 30%; - } - - .map { - text-align: center; - } - - .services { - margin: 20px 0; - padding: 15px; - background-color: white; - border: 1px solid #ccc; - } - - .service-list { - display: flex; - justify-content: space-around; - flex-wrap: wrap; - } - - .service-item { - flex: 1 1 200px; - text-align: center; - padding: 15px; - } - - .service-item img { - width: 100px; - height: auto; - } - - .footer { - background-color: #ccc; - display: flex; - justify-content: space-around; - padding: 20px; - flex-wrap: wrap; - } - - .footer div { - flex: 1 1 100px; - padding: 10px; - text-align: center; - } - - .reviews { - display: flex; - justify-content: space-around; - margin-top: 20px; - } - - .review-box { - width: 150px; - height: 80px; - background-color: #f9f9f9; - border: 1px solid #ccc; - padding: 10px; - text-align: center; - } - \ No newline at end of file diff --git a/web/templates/about.html b/web/templates/about.html deleted file mode 100644 index 0d4f01e..0000000 --- a/web/templates/about.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - About Us - - -

About Our Flask Application

-

This is a simple Flask application created to demonstrate how to render templates and create routes.

-

Flask is a micro web framework for Python. It is easy to use, lightweight, and flexible for creating web applications.

- -

Our Mission

-

To provide an easy-to-understand tutorial for web development using Flask and Python!

- -

Back to Home

- - diff --git a/web/templates/administrator.html b/web/templates/administrator.html new file mode 100644 index 0000000..384bd02 --- /dev/null +++ b/web/templates/administrator.html @@ -0,0 +1,90 @@ + + + + + + Uživatelská Tabulka + + + + + +
+
+
+ Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz +
+

+ + + + Uživatelská Tabulka +

+ +
+
+ + + +
+
+ {% if not session.get('logged_in') %} +

Musíte se přihlásit, abyste mohli zobrazit tuto stránku.

+ {% elif session.get('role_id') != 1 %} +

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

+ {% else %} + +
+ {% if users %} + + + + + + + + + + + + + + {% for user in users %} + + + + + + + + + + {% endfor %} + +
IDJménoPrijmeniEmailRoleUsernameAkce
{{ user['ID_Uzivatele'] }}{{ user['Jmeno'] }}{{ user['Prijmeni'] }}{{ user['Email'] }}{{ user['Role_ID'] }}{{ user['Username'] }} + Edit + {% if user['Role_ID'] > session.get('role_id') %} + /
+ +
+ {% endif %} +
+ {% else %} +

No users found.

+ {% endif %} +
+ {% endif %} +
+
+
+
Made by Hrachovina
+
+ + + diff --git a/web/templates/create_user.html b/web/templates/create_user.html new file mode 100644 index 0000000..7c8fb1c --- /dev/null +++ b/web/templates/create_user.html @@ -0,0 +1,64 @@ + + + + + + Vytvořit Nového Uživatele + + + + + +
+
+
+ Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz +
+

+ + + + Vytvořit Nového Uživatele +

+ +
+
+ +
+
+ {% if not session.get('logged_in') or session.get('role_id') != 1 %} +

Nemáte oprávnění k přístupu na tuto stránku.

+ {% else %} +
+ + + + + + + + + + + + + + + + + + + +
+ {% endif %} +
+
+ +
+
Made by Hrachovina and Kirsch
+
+ + + \ No newline at end of file diff --git a/web/templates/edit_user.html b/web/templates/edit_user.html new file mode 100644 index 0000000..7c9c9f4 --- /dev/null +++ b/web/templates/edit_user.html @@ -0,0 +1,60 @@ + + + + + + Editovat Uživatele + + + + +
+
+
+ Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz +
+

+ + + + Editovat Uživatele +

+ +
+
+ +
+
+

Editovat Uživatele

+
+ + + + + + + + + + + + + + + + + + + +
+
+
+ +
+
Made by Hrachovina and Kirsch
+
+ + + \ No newline at end of file diff --git a/web/templates/home.html b/web/templates/home.html index c8a5c95..59d9f5d 100644 --- a/web/templates/home.html +++ b/web/templates/home.html @@ -4,88 +4,143 @@ Autoservis - + +
-
-

Autoservis

+
- Kontakt: 123 123 123 - Otevírací doba: 9-18 hod - auto@servis.cz + Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz
+

+ + + + Autoservis +

- - + {% if session.get('logged_in') %} + Administrace + Odhlásit se + {% else %} + Administrace + {% endif %} +
+{% if session.get('logged_in') %} + +{% endif %} +
-

O nás

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla consequat.

-
-
-

Fotografie autoservisu

-
-
-

- -

-
-
-

Jak se k nám dostanete?

-

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+
+
+

O nás

+

Již po mnoho let se staráme o vaše automobily s maximální pečlivostí a odborností. Naše dlouhá historie sahá až do doby, kdy se auta stala nedílnou součástí každodenního života. Od té doby jsme ušli dlouhou cestu a vybudovali jsme si pevnou pověst spolehlivého partnera pro všechny motoristy. + + Proč si vybrat právě nás? + + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed auctor, velit nec ultricies ultricies, nunc libero ultricies nunc, nec ultricies nunc libero nec libero. Sed auctor, velit nec ultricies ultricies, nunc libero ultricies nunc, nec ultricies nunc libero nec libero. Sed auctor, velit nec ultricies ultricies, nunc libero ultricies nunc, nec ultricies nunc libero nec libero. +

+
+
+ Car repair +
+
+
+
+
+
+ +
+

Jak se k nám dostanete?

+

Lorem ipsum dolor sit amet, consectetur adipiscing elit.

+

Začněte na hlavním nádraží a pokračujte po ulici Masarykova. Na konci ulice odbočte doprava na ulici Benešova. Pokračujte rovně, dokud nedosáhnete křižovatky s ulicí Cejl. Zde odbočte doleva a pokračujte po ulici Cejl, dokud nedosáhnete našeho autoservisu, který se nachází na pravé straně ulice.

+
-
-

Nabídka služeb

+

Nabídka služeb

- Car + Car

Oprava osobních vozidel

- ATV + ATV

Oprava čtyřkolek

- Scooter + Scooter

Oprava skútrů

- Motorcycle + Motorcycle

Oprava motorek

-
Recenze 1
-
Recenze 2
-
Recenze 3
-
Recenze 4
+
+

Skvělý servis! Rychlá a profesionální oprava.

+

⭐⭐⭐⭐

+

- Jan Novák

+
+
+

Velmi přátelský personál a kvalitní služby.

+

⭐⭐⭐⭐⭐

+

- Petra Svobodová

+
+
+

Oprava byla hotová dříve, než jsem očekával.

+

⭐⭐⭐

+

- Martin Dvořák

+
+
+

Výborná komunikace a skvělé ceny. Určitě se vrátím.

+

⭐⭐⭐⭐⭐

+

- Eva Černá

+
+
+
+
+
Made by Hrachovina and Kirsch
+
+ + + -
-
Adresa: Cejl 36, Brno-střed
-
Kontakt: 123 123 123
-
Pobočky: Praha, Brno, Ostrava
-
Služby: Oprava klimatizace, Geometrie kol, Diagnostika
-
- diff --git a/web/templates/login.html b/web/templates/login.html new file mode 100644 index 0000000..47f6d5b --- /dev/null +++ b/web/templates/login.html @@ -0,0 +1,31 @@ + + + + + + Přihlášení + + + +
+

Přihlášení

+ {% with messages = get_flashed_messages(with_categories=true) %} + {% if messages %} +
    +
  • {{ messages[-1][1] }}
  • +
+ {% endif %} + {% endwith %} +
+ + + + + +
+
+
+ Domů +
+ + \ No newline at end of file