16 Commits

Author SHA1 Message Date
807f1de774 test
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-02-01 17:41:56 +01:00
677874a0e1 left version
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:35:41 +01:00
81fc7ade5f test
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:34:28 +01:00
b941819b73 test
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:27:43 +01:00
dcc1336d62 test
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:22:08 +01:00
99bd1841cb try
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:21:30 +01:00
16f8c23c38 round
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:11:43 +01:00
cb84e3cdc0 table consistant
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:06:30 +01:00
ca734fda32 version left
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 17:03:29 +01:00
4f6d3de79c search
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 16:57:01 +01:00
bf245e215a fix
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 16:49:50 +01:00
443eb9ef00 fix
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 16:48:54 +01:00
ce38d6cf24 delete in db
Some checks failed
ci/woodpecker/push/woodpecker Pipeline failed
2024-02-01 16:43:31 +01:00
5c8f057843 button color
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 16:34:54 +01:00
85afd501ce version id, 2
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/tag/woodpecker Pipeline was successful
2024-02-01 09:55:40 +01:00
4dbc156439 version id
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
2024-02-01 09:48:54 +01:00
6 changed files with 178 additions and 79 deletions

View File

@ -10,6 +10,9 @@ steps:
from_secret: container_registry_username
password:
from_secret: container_registry_password
build_args:
- VERSION_ID1=${CI_COMMIT_SHA}
- VERSION_ID2=${CI_COMMIT_TAG}
dockerfile: Dockerfile
when:
- event: [push, tag]

View File

@ -1,6 +1,8 @@
FROM python:3.12-alpine3.19
ARG APP_DIR="/opt/app"
ARG VERSION_ID1="x"
ARG VERSION_ID2="alpha"
COPY ./src/ ${APP_DIR}/
COPY start.sh ${APP_DIR}/
@ -9,7 +11,10 @@ WORKDIR ${APP_DIR}
RUN \
apk add --no-cache build-base libpq-dev && \
pip install -r requirements.txt
pip install -r requirements.txt && \
if [ "${VERSION_ID2}" != "" ]; then VERSION_ID=${VERSION_ID2}; else VERSION_ID=${VERSION_ID1}; fi && \
sed -i -e 's/VERSION_ID/'$VERSION_ID'/' ${APP_DIR}/templates/index.html && \
sed -i -e 's/VERSION_ID/'"$VERSION_ID"'/' ${APP_DIR}/templates/nutrition.html
EXPOSE 8080

View File

@ -175,8 +175,30 @@ def get_database_entries():
if conn:
conn.close()
@app.route('/delete_nutrition', methods=['POST'])
@oidc.accept_token(['openid'])
def delete_nutrition():
data = request.get_json()
foodNames = data['foodNames']
if not foodNames:
return jsonify({'error': 'Keine Lebensmittel zum Löschen angegeben'}), 400
try:
conn = psycopg2.connect()
with conn.cursor() as cursor:
query = "DELETE FROM nutrition_table WHERE name = ANY(%s)"
cursor.execute(query, (foodNames,))
conn.commit()
return jsonify({'message': 'Erfolgreich gelöscht'}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500
finally:
if conn:
conn.close()
exposed_app = ProxyFix(app, x_for=1, x_host=1)

View File

@ -46,13 +46,30 @@ button#remove-button:not(:disabled):hover {
background-color: #490000; /* Dunkleres Rot */
}
table {
width: 100%;
border-collapse: collapse;
border-collapse: separate; /* Erlaubt die Anwendung von border-radius */
border-spacing: 0;
border-radius: 10px;
}
table th:first-child {
border-top-left-radius: 10px;
}
table th:last-child {
border-top-right-radius: 10px;
}
table tr:last-child td:first-child {
border-bottom-left-radius: 10px;
}
table tr:last-child td:last-child {
border-bottom-right-radius: 10px;
}
table, th, td {
border: 1px solid #ddd;
}
@ -89,9 +106,20 @@ tr:hover:not(.selected) {
border-radius: 10px;
}
#navbar .navbar-header {
display: flex;
align-items: center;
}
#navbar h1 {
margin: 0;
font-size: 24px;
display: inline-block;
}
#navbar .versionid {
margin-left: 20px;
display: inline-block;
}
#navbar ul {
@ -113,13 +141,10 @@ tr:hover:not(.selected) {
transition: background-color 0.3s;
}
#navbar a:hover {
#navbar a:hover, #navbar a.active {
background-color: #007344; /* Etwas helleres Grün */
}
#navbar a.active {
background-color: #008C50; /* Mittleres Grün */
}
.content {
@ -130,10 +155,8 @@ tr:hover:not(.selected) {
}
#nutrition-input-table {
width: 100%; /* Tabelle nimmt die volle Breite ein */
border-collapse: collapse; /* Entfernt doppelte Ränder */
}
#nutrition-input-table th, #nutrition-input-table td {
border: 1px solid #ddd; /* Fügt Ränder hinzu */
@ -153,16 +176,17 @@ tr:hover:not(.selected) {
}
}
#table-container {
.table-container {
overflow-y: auto;
max-height: 400px; /* Passen Sie die Höhe nach Bedarf an */
max-height: 500px; /* Passen Sie die Höhe nach Bedarf an */
border-radius: 10px;
margin-top: 20px;
}
#database-nutrition-table {
width: 100%;
border-collapse: collapse;
border-collapse: separate; /* Erlaubt die Anwendung von border-radius */
border-spacing: 0;
}
#database-nutrition-table th, #database-nutrition-table td {
@ -183,34 +207,28 @@ tr:hover:not(.selected) {
justify-content: center;
}
#password-prompt input[type="password"] {
padding: 8px;
margin-right: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
#password-prompt button {
padding: 8px 15px;
margin-right: 10px;
border: none;
border-radius: 4px;
cursor: pointer;
color: white;
}
#password-prompt button[type="submit"] {
background-color: #008C50; /* Helles Grün */
}
#password-prompt button[type="submit"]:hover {
background-color: #007344; /* Dunkleres Grün */
}
#password-prompt button[type="button"] {
button#delete-row-button {
background-color: #640000; /* Helles Rot */
}
#password-prompt button[type="button"]:hover {
button#delete-row-button:disabled {
background-color: #cccccc;
color: #666666;
}
button#delete-row-button:not(:disabled):hover {
background-color: #490000; /* Dunkleres Rot */
}
button#cancel-button {
background-color: #640000; /* Helles Rot */
}
button#cancel-button:disabled {
background-color: #cccccc;
color: #666666;
}
button#cancel-button:not(:disabled):hover {
background-color: #490000; /* Dunkleres Rot */
}

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Nährwertberechnungs-App</title>
<title>Elo's Rezept Rechner</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<link rel="shortcut icon" href="../static/images/favicon.ico">
@ -175,7 +175,10 @@ function updateTotalNutrition() {
</head>
<body>
<nav id="navbar">
<h1>Elo's Rezept Rechner</h1>
<div class="navbar-header">
<h1>Elo's Rezept Rechner</h1>
<li class="versionid">VERSION_ID</li>
</div>
<ul>
<li><a href="/" class="active">Rechner</a></li>
<li><a href="/nutrition">Neue Lebensmittel</a></li>
@ -232,4 +235,4 @@ function updateTotalNutrition() {
</table>
</div>
</body>
</html>
</html>

View File

@ -2,7 +2,7 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Neue Lebensmittel hinzufügen</title>
<title>Elo's Rezept Rechner</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
<link rel="shortcut icon" href="../static/images/favicon.ico">
@ -70,14 +70,34 @@
function deleteSelectedRows() {
const table = document.getElementById('database-nutrition-table');
Array.from(table.rows).forEach(row => {
if (row.classList.contains('selected')) {
// Logik zum Löschen der Zeile aus der Datenbank
table.deleteRow(row.rowIndex);
}
});
const selectedRows = Array.from(table.querySelectorAll('tr.selected'));
const foodNames = selectedRows.map(row => row.cells[0].innerText); // Annahme, der Name des Lebensmittels befindet sich in der ersten Zelle
if (foodNames.length > 0) {
// Holen des Tokens und Senden einer Anfrage an das Backend, um die Einträge zu löschen
getBearerToken(token => {
fetch('/delete_nutrition', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + token
},
body: JSON.stringify({foodNames: foodNames})
}).then(response => {
if (response.ok) {
// Erfolgreich gelöscht, entferne Zeilen aus der Tabelle
selectedRows.forEach(row => {
table.deleteRow(row.rowIndex);
});
} else {
console.error('Fehler beim Löschen der Datenbank-Einträge');
}
}).catch(error => console.error('Fehler:', error));
});
}
}
function showPasswordPrompt() {
document.getElementById('delete-row-button').style.display = 'none';
document.getElementById('password-prompt').style.display = 'block';
@ -90,7 +110,7 @@
function deleteRowsIfPasswordCorrect() {
const password = document.getElementById('password-input').value;
if (password === 'wowmuchsecurity') {
if (password === 'geheim') {
deleteSelectedRows(); // Funktion, die die ausgewählten Zeilen löscht
hidePasswordPrompt();
} else {
@ -131,46 +151,74 @@
.catch(error => console.error('Fehler:', error));
}
document.addEventListener('DOMContentLoaded', loadDatabaseEntries);
document.addEventListener('DOMContentLoaded', loadDatabaseEntries);
function filterTable() {
const searchInput = document.getElementById('search-input');
const filterText = searchInput.value.toUpperCase();
const table = document.getElementById('database-nutrition-table');
const rows = table.getElementsByTagName('tr');
for (let i = 1; i < rows.length; i++) { // Beginnen bei 1, um die Kopfzeile auszulassen
const cell = rows[i].getElementsByTagName('td')[0]; // Angenommen, der zu suchende Text befindet sich in der ersten Spalte
if (cell) {
const textValue = cell.textContent || cell.innerText;
if (textValue.toUpperCase().indexOf(filterText) > -1) {
rows[i].style.display = ""; // Zeile anzeigen
} else {
rows[i].style.display = "none"; // Zeile verstecken
}
}
}
}
</script>
</head>
<body>
<nav id="navbar">
<h1>Elo's Rezept Rechner</h1>
<div class="navbar-header">
<h1>Elo's Rezept Rechner</h1>
<li class="versionid">VERSION_ID</li>
</div>
<ul>
<li><a href="/">Rechner</a></li>
<li><a href="/nutrition" class="active">Neue Lebensmittel</a></li>
</ul>
</nav>
<div class="content">
<form onsubmit="event.preventDefault(); addNutritionEntry();" method="POST" id="nutrition-form">
<table id="nutrition-input-table">
<tr>
<th>Lebensmittel</th>
<th>kcal</th>
<th>EW</th>
<th>Fett</th>
<th>KH</th>
<th>BST</th>
<th>CA</th>
</tr>
<tr>
<td><input type="text" name="food" placeholder="Lebensmittel" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="kcal" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="ew" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="fett" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="kh" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="bst" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="ca" pattern="\d+([.,]\d{1,2})?" placeholder="mg" oninput="updateSubmitButtonState()"></td>
</tr>
</table>
<table id="nutrition-input-table">
<tr>
<th>Lebensmittel</th>
<th>kcal</th>
<th>EW</th>
<th>Fett</th>
<th>KH</th>
<th>BST</th>
<th>CA</th>
</tr>
<tr>
<td><input type="text" name="food" placeholder="Lebensmittel" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="kcal" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="ew" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="fett" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="kh" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="bst" pattern="\d+([.,]\d{1,2})?" placeholder="g" oninput="updateSubmitButtonState()"></td>
<td><input <input type="text" name="ca" pattern="\d+([.,]\d{1,2})?" placeholder="mg" oninput="updateSubmitButtonState()"></td>
</tr>
</table>
<button type="submit" id="submit-button" disabled>Hinzufügen</button>
</form>
<div id="table-container">
<div class="search-container">
<input type="text" id="search-input" placeholder="Lebensmittel suchen..." oninput="filterTable()">
</div>
<div class="table-container">
<table id="database-nutrition-table">
<thead>
<tr>
@ -192,8 +240,8 @@ document.addEventListener('DOMContentLoaded', loadDatabaseEntries);
<div id="password-prompt" style="display: none;">
<input type="password" id="password-input" placeholder="Passwort">
<button onclick="deleteRowsIfPasswordCorrect()">OK</button>
<button onclick="hidePasswordPrompt()">Abbrechen</button>
<button id="ok-button" onclick="deleteRowsIfPasswordCorrect()">OK</button>
<button id="cancel-button" onclick="hidePasswordPrompt()">Abbrechen</button>
</div>