reupload of project

This commit is contained in:
2024-12-06 09:28:08 +01:00
parent f025364a05
commit ebb3f69a4e
28 changed files with 2031 additions and 735 deletions

View File

@@ -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 '''
<script>
alert('Úspěšně odhlášen.');
window.location.href = '/';
</script>
'''
@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/<int:user_id>', 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/<int:user_id>', 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)

517
web/static/css/style.css Normal file
View File

@@ -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;
}

BIN
web/static/db/db.sqlite Normal file

Binary file not shown.

BIN
web/static/img/atv-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 339 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 781 KiB

BIN
web/static/img/car-icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

BIN
web/static/img/logo.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 717 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB

View File

@@ -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));
}

View File

@@ -0,0 +1,8 @@
function openReservationForm() {
document.getElementById("reservationForm").style.display = "block";
}
function closeReservationForm() {
document.getElementById("reservationForm").style.display = "none";
}

View File

@@ -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;
}

View File

@@ -1,18 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>About Us</title>
</head>
<body>
<h1>About Our Flask Application</h1>
<p>This is a simple Flask application created to demonstrate how to render templates and create routes.</p>
<p>Flask is a micro web framework for Python. It is easy to use, lightweight, and flexible for creating web applications.</p>
<h2>Our Mission</h2>
<p>To provide an easy-to-understand tutorial for web development using Flask and Python!</p>
<p><a href="{{ url_for('home') }}">Back to Home</a></p>
</body>
</html>

View File

@@ -0,0 +1,90 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Uživatelská Tabulka</title>
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
<script src="{{url_for('static', filename='scripts/user_table.js')}}"></script>
</head>
<body>
<header>
<div class="header">
<div class="contact-info">
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
</div>
<h1 class="nazev">
<a href="{{ url_for('home') }}" style="text-decoration: none;">
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
</a>
Uživatelská Tabulka
</h1>
<div class="buttons">
<a href="{{ url_for('home') }}" class="button">Zpět na Domovskou Stránku</a>
<a href="{{ url_for('create_user') }}" class="button">Vytvořit Nového Uživatele</a>
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a> <!-- New Log Out button -->
</div>
</div>
</header>
<nav class="navbar">
<h2 id="users-table">Tabulka Uživatelů</h2>
</nav>
<div class="container">
<div class="content">
{% if not session.get('logged_in') %}
<p>Musíte se přihlásit, abyste mohli zobrazit tuto stránku.</p>
{% elif session.get('role_id') != 1 %}
<p>Nemáte oprávnění zobrazit tuto stránku.</p>
{% else %}
<div class="user-table">
{% if users %}
<table>
<thead>
<tr>
<th>ID</th>
<th>Jméno</th>
<th>Prijmeni</th>
<th>Email</th>
<th>Role</th>
<th>Username</th>
<th>Akce</th> <!-- New column for actions -->
</tr>
</thead>
<tbody>
{% for user in users %}
<tr>
<td>{{ user['ID_Uzivatele'] }}</td>
<td>{{ user['Jmeno'] }}</td>
<td>{{ user['Prijmeni'] }}</td>
<td>{{ user['Email'] }}</td>
<td>{{ user['Role_ID'] }}</td>
<td>{{ user['Username'] }}</td>
<td>
<a href="{{ url_for('edit_user', user_id=user['ID_Uzivatele']) }}">Edit</a>
{% if user['Role_ID'] > session.get('role_id') %}
/ <form action="{{ url_for('delete_user', user_id=user['ID_Uzivatele']) }}" method="post" style="display:inline;" onsubmit="return confirm('Opravdu chcete smazat tohoto uživatele?');">
<button type="submit" class="button-link">Delete</button>
</form>
{% endif %}
</td> <!-- Edit and Delete buttons -->
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No users found.</p>
{% endif %}
</div>
{% endif %}
</div>
</div>
<footer class="footer" id="kontakt">
<div>Made by Hrachovina</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,64 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Vytvořit Nového Uživatele</title>
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
<script src="{{url_for('static', filename='scripts/create_user.js')}}"></script>
</head>
<body>
<header>
<div class="header">
<div class="contact-info">
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
</div>
<h1 class="nazev">
<a href="{{ url_for('home') }}" style="text-decoration: none;">
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
</a>
Vytvořit Nového Uživatele
</h1>
<div class="buttons">
<a href="{{ url_for('administrator') }}" class="button">Zpět na Uživatelskou Tabulku</a>
</div>
</div>
</header>
<div class="container">
<div class="content">
{% if not session.get('logged_in') or session.get('role_id') != 1 %}
<p>Nemáte oprávnění k přístupu na tuto stránku.</p>
{% else %}
<form action="{{ url_for('create_user') }}" method="post" class="form-container" onsubmit="handleCreateUser(event)">
<label for="jmeno">Jméno:</label>
<input type="text" id="jmeno" name="jmeno" required>
<label for="prijmeni">Příjmení:</label>
<input type="text" id="prijmeni" name="prijmeni" required>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
<label for="role">Role:</label>
<input type="text" id="role" name="role" required>
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<label for="heslo">Heslo:</label>
<input type="password" id="heslo" name="heslo" required>
<button type="submit" class="button">Vytvořit</button>
</form>
{% endif %}
</div>
</div>
<footer class="footer" id="kontakt">
<div>Made by Hrachovina and Kirsch</div>
</footer>
</body>
</html>

View File

@@ -0,0 +1,60 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editovat Uživatele</title>
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
</head>
<body>
<header>
<div class="header">
<div class="contact-info">
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
</div>
<h1 class="nazev">
<a href="{{ url_for('home') }}" style="text-decoration: none;">
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
</a>
Editovat Uživatele
</h1>
<div class="buttons">
<a href="{{ url_for('administrator') }}" class="button">Zpět na Uživatelskou Tabulku</a>
</div>
</div>
</header>
<div class="container">
<div class="content">
<h2>Editovat Uživatele</h2>
<form action="{{ url_for('edit_user', user_id=user['ID_Uzivatele']) }}" method="post" class="form-container">
<label for="jmeno">Jméno:</label>
<input type="text" id="jmeno" name="jmeno" value="{{ user['Jmeno'] }}" required>
<label for="prijmeni">Příjmení:</label>
<input type="text" id="prijmeni" name="prijmeni" value="{{ user['Prijmeni'] }}" required>
<label for="email">Email:</label>
<input type="email" id="email" name="email" value="{{ user['Email'] }}" required>
<label for="role">Role:</label>
<input type="text" id="role" name="role" value="{{ user['Role_ID'] }}" required>
<label for="username">Username:</label>
<input type="text" id="username" name="username" value="{{ user['Username'] }}" required>
<label for="heslo">Heslo (ponechte prázdné, pokud nechcete měnit):</label>
<input type="password" id="heslo" name="heslo">
<button type="submit" class="button">Aktualizovat</button>
</form>
</div>
</div>
<footer class="footer" id="kontakt">
<div>Made by Hrachovina and Kirsch</div>
</footer>
</body>
</html>

View File

@@ -4,88 +4,143 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Autoservis</title>
<link rel="stylesheet" href="{{url_for('static', filename='style.css')}}">
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
<script src="{{url_for('static', filename='scripts/reservation.js')}}"></script>
</head>
<body>
<header>
<div class="container">
<h1>Autoservis</h1>
<div class="header">
<div class="contact-info">
<span>Kontakt: 123 123 123</span>
<span>Otevírací doba: 9-18 hod</span>
<span>auto@servis.cz</span>
<span>Kontakt: 123 123 123 | Otevírací doba: 9-18 hod | auto@servis.cz </span>
</div>
<h1 class="nazev">
<a href="{{ url_for('home') }}" style="text-decoration: none;">
<img src="{{url_for('static', filename='img/logo.webp')}}" alt="Logo" class="logo">
</a>
Autoservis
</h1>
<div class="buttons">
<button>Přihlásit se</button>
<button>Objednat se</button>
{% if session.get('logged_in') %}
<a href="{{ url_for('administrator') }}" class="button">Administrace</a>
<a href="{{ url_for('logout') }}" class="button">Odhlásit se</a>
{% else %}
<a href="{{ url_for('login') }}" class="button">Administrace</a>
{% endif %}
<button class="button" onclick="openReservationForm()">Objednat se</button>
</div>
</div>
</header>
{% if session.get('logged_in') %}
<div class="user-info">
<span>Logged in: {{ session.get('username') }}</span>
</div>
{% endif %}
<nav class="navbar">
<a href="#o-nas">O nás</a>
<a href="#nabidka-sluzeb">Nabídka služeb</a>
<a href="#recenze">Recenze</a>
<a href="#kontakt">Kontakt</a>
<button class="button" onclick="location.href='#about-header'">O nás</button>
<button class="button" onclick="location.href='#directions'">K nám</button>
<button class="button" onclick="location.href='#nabidka-sluzeb'">Služby</button>
<button class="button" onclick="location.href='#recenze'">Recenze</button>
</nav>
<div class="container">
<div class="content">
<div class="about">
<h2 id="o-nas">O nás</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla consequat.</p>
</div>
<div class="photos">
<h2>Fotografie autoservisu</h2>
</div>
<div class="map">
<h2>
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2607.057050033818!2d16.625835399999996!3d49.19947729999999!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x471294f40ffa3c2b%3A0x6ceee968235c0272!2sCejl%2036%2F64%2C%20602%2000%20Brno-st%C5%99ed!5e0!3m2!1scs!2scz!4v1731501763892!5m2!1scs!2scz" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
</h2>
</div>
<div class="directions">
<h2>Jak se k nám dostanete?</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<div class="about-content">
<div class="about-text">
<h2 id="about-header">O nás</h2>
<p>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.
</p>
</div>
<div class="about-image">
<img src="{{url_for('static', filename='img/autoservis.jpg')}}" alt="Car repair">
</div>
</div>
</div>
</div>
<div id="directions" class="directions">
<div class="directions-content">
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2607.057050033818!2d16.625835399999996!3d49.19947729999999!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x471294f40ffa3c2b%3A0x6ceee968235c0272!2sCejl%2036%2F64%2C%20602%2000%20Brno-st%C5%99ed!5e0!3m2!1scs!2scz!4v1731501763892!5m2!1scs!2scz" width="50%" height="450" style="border:0; border-radius: 0.5em;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
<div class="directions-text">
<h2 class="directions-header">Jak se k nám dostanete?</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<p>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.</p>
</div>
</div>
</div>
<div class="services">
<h2 id="nabidka-sluzeb">Nabídka služeb</h2>
<h2 id="nabidka-sluzeb" class="nabidka-sluzeb">Nabídka služeb</h2>
<div class="service-list">
<div class="service-item">
<img src="car-icon.png" alt="Car">
<img src="{{url_for('static', filename='img/car-icon.png')}}" alt="Car">
<p>Oprava osobních vozidel</p>
</div>
<div class="service-item">
<img src="atv-icon.png" alt="ATV">
<img src="{{url_for('static', filename='img/atv-icon.png')}}" alt="ATV">
<p>Oprava čtyřkolek</p>
</div>
<div class="service-item">
<img src="scooter-icon.png" alt="Scooter">
<img src="{{url_for('static', filename='img/scooter-icon.png')}}" alt="Scooter">
<p>Oprava skútrů</p>
</div>
<div class="service-item">
<img src="motorcycle-icon.png" alt="Motorcycle">
<img src="{{url_for('static', filename='img/motorcycle-icon.png')}}" alt="Motorcycle">
<p>Oprava motorek</p>
</div>
</div>
</div>
<div class="reviews" id="recenze">
<div class="review-box">Recenze 1</div>
<div class="review-box">Recenze 2</div>
<div class="review-box">Recenze 3</div>
<div class="review-box">Recenze 4</div>
<div class="review-box">
<p>Skvělý servis! Rychlá a profesionální oprava.</p>
<p>⭐⭐⭐⭐</p>
<p>- Jan Novák</p>
</div>
<div class="review-box">
<p>Velmi přátelský personál a kvalitní služby.</p>
<p>⭐⭐⭐⭐⭐</p>
<p>- Petra Svobodová</p>
</div>
<div class="review-box">
<p>Oprava byla hotová dříve, než jsem očekával.</p>
<p>⭐⭐⭐</p>
<p>- Martin Dvořák</p>
</div>
<div class="review-box">
<p>Výborná komunikace a skvělé ceny. Určitě se vrátím.</p>
<p>⭐⭐⭐⭐⭐</p>
<p>- Eva Černá</p>
</div>
</div>
</div>
<footer class="footer" id="kontakt">
<div>Made by Hrachovina and Kirsch</div>
</footer>
<!-- Reservation Form Popup -->
<div id="reservationForm" class="popup-form">
<div class="form-container">
<span class="close-button" onclick="closeReservationForm()">&times;</span>
<h2>Rezervace</h2>
<form>
<label for="fullName">Celé jméno: <span class="required">*</span></label>
<input type="text" id="fullName" name="fullName" required>
<label for="email">Email: <span class="required">*</span></label>
<input type="email" id="email" name="email" required>
<label for="date">Datum: <span class="required">*</span></label>
<input type="date" id="date" name="date" required>
<label for="description">Popis: <span class="required">*</span></label>
<textarea id="description" name="description" rows="4" required></textarea>
<button type="submit" class="button">Odeslat</button>
</form>
</div>
</div>
<footer class="footer" id="kontakt">
<div>Adresa: Cejl 36, Brno-střed</div>
<div>Kontakt: 123 123 123</div>
<div>Pobočky: Praha, Brno, Ostrava</div>
<div>Služby: Oprava klimatizace, Geometrie kol, Diagnostika</div>
</footer>
</body>
</html>

31
web/templates/login.html Normal file
View File

@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Přihlášení</title>
<link rel="stylesheet" href="{{url_for('static', filename='css/style.css')}}">
</head>
<body>
<div class="form-container">
<h2> Přihlášení </h2>
{% with messages = get_flashed_messages(with_categories=true) %}
{% if messages %}
<ul class="flashes">
<li class="{{ messages[-1][0] }}">{{ messages[-1][1] }}</li> <!-- Show only the last message -->
</ul>
{% endif %}
{% endwith %}
<form method="POST" action="{{ url_for('login') }}">
<label for="username">Uživatelské jméno: <span class="required">*</span></label>
<input type="text" id="username" name="username" required>
<label for="password">Heslo: <span class="required">*</span></label>
<input type="password" id="password" name="password" required>
<button type="submit" class="button">Přihlásit se</button>
</form>
</div>
<div style="text-align: center;">
<a href="{{ url_for('home') }}" class="button">Domů</a>
</div>
</body>
</html>