initial project commit

This commit is contained in:
georg.sinn-schirwitz
2025-08-29 15:07:58 +02:00
parent 38708e6d1d
commit 23a67d7fe1
31 changed files with 3433 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
{% extends 'base.html' %} {% block content %}
<h2>Login</h2>
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<label>Username <input type="text" name="username" required /></label>
<label>Password <input type="password" name="password" /></label>
<button type="submit">Login</button>
</form>
{% endblock %}

View File

@@ -0,0 +1,142 @@
{% extends 'base.html' %} {% block content %}
<h2>Taxonomy</h2>
<section>
<h3>Regions</h3>
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="add_region" />
<input type="text" name="region_name" placeholder="New region" required />
<label for="region_color">Color:</label>
<input type="color" name="region_color" id="region_color" value="#ffffff" />
<button type="submit">Add Region</button>
</form>
<div id="regions-table">
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Rename</th>
<th>Color</th>
</tr>
</thead>
<tbody>
{% for r in regions %}
<tr>
<td>{{ r.region_id }}</td>
<td>{{ r.name }}</td>
<td>
<form
method="post"
style="display: flex; gap: 0.5rem; align-items: center"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="rename_region" />
<input type="hidden" name="region_id" value="{{ r.region_id }}" />
<input
type="text"
name="new_region_name"
placeholder="New name"
required
/>
<button type="submit">Rename</button>
</form>
</td>
<td>
<form
method="post"
style="display: flex; gap: 0.5rem; align-items: center"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="change_region_color" />
<input type="hidden" name="region_id" value="{{ r.region_id }}" />
<input
type="color"
name="new_region_color"
value="{{ r.color }}"
required
/>
<button type="submit">Change Color</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
<section>
<h3>Keywords</h3>
<form method="post">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="add_keyword" />
<input type="text" name="keyword_name" placeholder="New keyword" required />
<label for="keyword_color">Color:</label>
<input
type="color"
name="keyword_color"
id="keyword_color"
value="#ffffff"
/>
<button type="submit">Add Keyword</button>
</form>
<div id="keywords-table">
<table>
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Rename</th>
<th>Color</th>
</tr>
</thead>
<tbody>
{% for k in keywords %}
<tr>
<td>{{ k.keyword_id }}</td>
<td>{{ k.name }}</td>
<td>
<form
method="post"
style="display: flex; gap: 0.5rem; align-items: center"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="rename_keyword" />
<input type="hidden" name="keyword_id" value="{{ k.keyword_id }}" />
<input
type="text"
name="new_keyword_name"
placeholder="New name"
required
/>
<button type="submit">Rename</button>
</form>
</td>
<td>
<form
method="post"
style="display: flex; gap: 0.5rem; align-items: center"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<input type="hidden" name="action" value="change_keyword_color" />
<input type="hidden" name="keyword_id" value="{{ k.keyword_id }}" />
<input
type="color"
name="new_keyword_color"
value="{{ k.color }}"
required
/>
<button type="submit">Change Color</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</section>
{% endblock %} {% block footer_scripts %}
<script src="{{ url_for('static', filename='taxonomy.js') }}"></script>
</script>
{% endblock %}

View File

@@ -0,0 +1,139 @@
{% extends 'base.html' %} {% block content %}
<div id="users">
<h2>Users</h2>
<form id="user-form" method="post" action="{{ url_for('admin_users') }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<table>
<thead>
<tr>
<th>ID</th>
<th>Username</th>
<th>Admin</th>
<th>Active</th>
<th colspan="2">Password</th>
<th>Created</th>
<th>Last Login</th>
<th></th>
</tr>
</thead>
<tbody>
{% for u in users %}
<tr class="user-row" data-user-id="{{ u.user_id }}">
<td>
{{ u.user_id }}<input
type="hidden"
name="user_id"
value="{{ u.user_id }}"
/>
</td>
<td>
<input
type="text"
name="username"
value="{{ u.username }}"
required
/>
</td>
<td>
<input type="checkbox" name="is_admin" {{ 'checked' if u.is_admin
else '' }} />
</td>
<td>
<input type="checkbox" name="is_active" {{ 'checked' if u.is_active
else '' }} />
</td>
<td>{{ '✅' if u.has_password else '❌' }}</td>
<td><input type="password" name="password" /></td>
<td>{{ u.created_at }}</td>
<td>{{ u.last_login or 'never' }}</td>
<td>
<button type="submit" data-user-id="{{ u.user_id }}">Save</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</form>
</div>
<h3>Create / Update User</h3>
<form
id="create-update-user-form"
method="post"
action="{{ url_for('admin_users') }}"
>
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
<label>Username <input type="text" name="username" required /></label>
<label>Password <input type="password" name="password" /></label>
<label>Admin <input type="checkbox" name="is_admin" value="1" /></label>
<label
>Active <input type="checkbox" name="is_active" value="1" checked
/></label>
<button type="submit">Save</button>
</form>
{% endblock %} {% block footer_scripts %}
<script>
function updateUser(userId) {
const row = document.querySelector(`.user-row[data-user-id="${userId}"]`);
const passwordInput = row.querySelector('input[name="password"]');
const hasPassword =
row.querySelector("td:nth-child(5)").textContent.trim() === "✅";
const formData = row.querySelector("form").elements;
const username = formData.username.value;
const password = hasPassword ? passwordInput.value : undefined;
const isAdmin = formData.is_admin.checked;
const isActive = formData.is_active.checked;
fetch("/admin/users", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
user_id: userId,
password: password,
username: username,
is_admin: isAdmin,
is_active: isActive,
csrf_token: formData.csrf_token.value,
}),
})
.then((response) => {
if (response.ok) {
alert("User updated successfully");
// Clear the password field after successful update
passwordInput.value = "";
} else {
alert("Error updating user");
}
})
.catch((error) => {
console.error("Error:", error);
alert("Error updating user");
});
}
function initUserForm() {
const form = document.getElementById("user-form");
const createUpdateForm = document.getElementById("create-update-user-form");
form.addEventListener("submit", function (event) {
const userId = event.target.querySelector('input[name="user_id"]').value;
event.preventDefault(); // Prevent the default form submission
updateUser(userId);
});
form.addEventListener("click", function (event) {
const userId = event.target.closest(".user-row").dataset.userId;
updateUser(userId);
});
createUpdateForm.addEventListener("submit", function (event) {
const passwordInput = createUpdateForm.querySelector(
'input[name="password"]'
);
});
}
initUserForm();
</script>
{% endblock %}