added basic user editing
This commit is contained in:
parent
f0b2e9a818
commit
f18f430c0e
|
|
@ -11,5 +11,5 @@
|
|||
"meta_permissions": {
|
||||
"MANAGE": ["VIEW", "ADD", "DELETE", "EDIT"]
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import Bun from 'bun';
|
||||
|
||||
import { User, get_user_by_name } from "$lib/server/database";
|
||||
import { User, get_user_by_name, update_user_password } from "$lib/server/database";
|
||||
|
||||
export async function authorize_password(username: string, password: string): Promise<User | null> {
|
||||
|
||||
|
|
@ -12,4 +12,8 @@ export async function authorize_password(username: string, password: string): Pr
|
|||
return res ? user : null;
|
||||
}
|
||||
|
||||
export async function change_password(user_id: number, new_password: string): Promise<boolean> {
|
||||
const hash = await Bun.password.hash(new_password, { algorithm: "bcrypt", cost: 11});
|
||||
|
||||
return update_user_password(user_id, hash)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,8 +48,8 @@ const USER_DATABASE_SETUP: string[] = [
|
|||
const USER_DATABASE_ADD_USER: string =
|
||||
"INSERT INTO users (name, gender, address, username, password) VALUES ($name, $gender, $address, $username, $password);";
|
||||
|
||||
const USER_DATABASE_GET_USER: string =
|
||||
"SELECT * FROM users;";
|
||||
const USER_DATABASE_GET_ALL_USER: string =
|
||||
"SELECT id, username, name FROM users;";
|
||||
|
||||
const USER_DATABASE_GET_USER_BY_NAME: string =
|
||||
"SELECT * FROM users WHERE username = $username;"
|
||||
|
|
@ -57,6 +57,9 @@ const USER_DATABASE_GET_USER_BY_NAME: string =
|
|||
const USER_DATABASE_EMPTY: string =
|
||||
"SELECT EXISTS (SELECT 1 FROM users);"
|
||||
|
||||
const USER_DATABASE_UPDATE_PASSWORD: string =
|
||||
"UPDATE users SET password=$password WHERE id=$id;"
|
||||
|
||||
/*const USER_DATABASE_ADD_ACCESS_TOKEN: string =
|
||||
"INSERT INTO access_tokens (user_id, token, expiry_date) VALUES ($user_id, $token, $expiry_date);"
|
||||
|
||||
|
|
@ -83,7 +86,7 @@ const ENTRY_DATABASE_SETUP: string[] = [
|
|||
record_id INTEGER NOT NULL,
|
||||
date VARCHAR(10),
|
||||
start VARCHAR(5),
|
||||
end VARCHAR(5),
|
||||
end V<F52>ARCHAR(5),
|
||||
comment TEXT,
|
||||
modified DATETIME DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
||||
FOREIGN KEY(record_id) REFERENCES records(id)
|
||||
|
|
@ -198,6 +201,19 @@ export class User {
|
|||
this._database = db;
|
||||
}
|
||||
|
||||
toUserEntry(): UserEntry {
|
||||
return {
|
||||
id: this.id,
|
||||
gender: this.gender,
|
||||
name: this.name,
|
||||
address: this.address,
|
||||
username: this.username,
|
||||
password: this.password,
|
||||
permissions: this.permissions,
|
||||
created: this.created,
|
||||
}
|
||||
}
|
||||
|
||||
get_months(): { year: string, month: string }[] {
|
||||
const query = this._database.query(ENTRY_DATABASE_GET_MONTHS);
|
||||
const res = query.all();
|
||||
|
|
@ -381,51 +397,16 @@ export async function create_user(user: { name: string, gender: string, address:
|
|||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function _get_user(): UserEntry | null {
|
||||
export function get_all_user(): { id: number, username: string, name: string }[] {
|
||||
|
||||
try {
|
||||
const statement = user_database.prepare(USER_DATABASE_GET_USER);
|
||||
const result = statement.get() as UserEntry;
|
||||
|
||||
return result;
|
||||
|
||||
} catch (e) {
|
||||
if (e instanceof SQLiteError) {
|
||||
return null;
|
||||
}
|
||||
|
||||
throw e;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function get_user(id: number): User | null {
|
||||
|
||||
const user = _get_user();
|
||||
if (user == null) {
|
||||
return null;
|
||||
}
|
||||
const query = user_database.prepare(USER_DATABASE_GET_ALL_USER)
|
||||
const user = query.all() as { id: number, username: string, name: string }[]
|
||||
|
||||
const db_name = get_user_db_name(user);
|
||||
|
||||
try {
|
||||
|
||||
fs.mkdir(DATABASES_PATH, { recursive: true });
|
||||
|
||||
let userdb = new Database(db_name, { create: true, strict: true });
|
||||
|
||||
if (!is_db_initialized(userdb)) {
|
||||
setup_db(userdb, ENTRY_DATABASE_SETUP);
|
||||
}
|
||||
|
||||
return new User(user, userdb);
|
||||
return user
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
|
||||
return null;
|
||||
throw e
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function get_user_by_name(username: string): User | null {
|
||||
|
|
@ -462,3 +443,25 @@ export function do_users_exist(): any {
|
|||
// sqlite trims the first "SELECT " and ";" from the query string
|
||||
return (answer as any)?.[USER_DATABASE_EMPTY.slice(7, -1)];
|
||||
}
|
||||
|
||||
export function updateUser(data: {id: number, gender?: string, name?: string, address?: string, username?: string }) {
|
||||
let changed: Array<string> = []
|
||||
if (data.gender) changed.push("gender=$gender")
|
||||
if (data.name) changed.push("name=$name")
|
||||
if (data.address) changed.push("address=$address")
|
||||
if (data.username) changed.push("username=$username")
|
||||
|
||||
const update_query = "UPDATE users SET " + changed.join(", ") + " WHERE id=$id;"
|
||||
|
||||
const query = user_database.prepare(update_query)
|
||||
const result = query.run(data)
|
||||
|
||||
return get_user_by_name(data?.name ?? "") // GET USER BY lastRowId from result
|
||||
}
|
||||
|
||||
export function update_user_password(user_id: number, password: string) {
|
||||
const query = user_database.prepare(USER_DATABASE_UPDATE_PASSWORD)
|
||||
const result = query.run({ password: password, id: user_id })
|
||||
|
||||
return result.changes > 0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,6 +104,13 @@ function logout_user_session(token: string): boolean {
|
|||
return true;
|
||||
}
|
||||
|
||||
function reload_user_data(user: User) {
|
||||
const session_info = active_users.get(user.id)
|
||||
if (!session_info) return
|
||||
|
||||
session_info.user = user
|
||||
}
|
||||
|
||||
async function __clean_session_store() {
|
||||
|
||||
let cleaned_user_sessions = 0
|
||||
|
|
@ -135,6 +142,7 @@ export default class SessionStore {
|
|||
static issue_access_token_for_user = issue_access_token_for_user;
|
||||
static get_user_by_access_token = get_user_by_access_token;
|
||||
static logout_user_session = logout_user_session;
|
||||
static reload_user_data = reload_user_data;
|
||||
}
|
||||
|
||||
setInterval(__clean_session_store, 15*60*1000);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
import type { PageServerLoad, Actions } from "./$types"
|
||||
|
||||
import { fail } from "@sveltejs/kit"
|
||||
|
||||
import Permissions from "$lib/permissions"
|
||||
import { toInt } from "$lib/util"
|
||||
|
||||
import SessionStore from "$lib/server/session_store"
|
||||
import { updateUser } from "$lib/server/database"
|
||||
import { change_password } from "$lib/server/auth"
|
||||
|
||||
export const load: PageServerLoad = ({ locals, url }) => {
|
||||
|
||||
if (locals.user == null) {
|
||||
return fail(403, { message: "Unauthorized user" })
|
||||
}
|
||||
|
||||
return {
|
||||
user: locals.user.toUserEntry()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export const actions = {
|
||||
edit: async ({locals, request}) => {
|
||||
|
||||
if (locals.user == null) {
|
||||
Logs.route.warn("An unauthorized user tried to edit an user")
|
||||
return fail(403, { message: "Unauthorized user" })
|
||||
}
|
||||
|
||||
const data = await request.formData();
|
||||
|
||||
const id = toInt((data.get("id") as string|null) ?? "NaN")
|
||||
const name = data.get("name") as string|null
|
||||
const gender = data.get("gender") as string|null
|
||||
const address = data.get("address") as string|null
|
||||
|
||||
const username = data.get("username") as string|null
|
||||
const password1 = data.get("password1") as string|null
|
||||
const password2 = data.get("password2") as string|null
|
||||
|
||||
if (isNaN(id) || name == null || gender == null || address == null || username == null) {
|
||||
return fail(400, { message: "invalid request" })
|
||||
}
|
||||
|
||||
if (locals.user.id != id
|
||||
&& (!Permissions.has(locals.user.permissions, Permissions.USERADMIN.EDIT)
|
||||
|| ((password1 != null || password2 != null) && !Permissions.has(locals.user.permissions, Permissions.USERADMIN.EDIT_PASSWORD)))) {
|
||||
return fail(403, { message: "Unauthorized action" })
|
||||
}
|
||||
|
||||
if ((password1 != null || password2 != null)) {
|
||||
if (password1 != password2) {
|
||||
return fail(400, { message: "Passwörter müssen übereinstimmen" })
|
||||
}
|
||||
const result = change_password(id, password1!)
|
||||
if (!result) {
|
||||
return fail(500, { message: "Database failure"})
|
||||
}
|
||||
}
|
||||
|
||||
const updated_user = updateUser({id, name, gender, address, username})
|
||||
SessionStore.reload_user_data(updated_user ?? locals.user)
|
||||
|
||||
return {}
|
||||
|
||||
}
|
||||
} satisfies Actions
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
<script lang="ts">
|
||||
|
||||
import type { PageProps } from "./$types"
|
||||
import { enhance } from "$app/forms"
|
||||
|
||||
const { data, form }: PageProps = $props()
|
||||
|
||||
</script>
|
||||
|
||||
<form method="POST" id="form_edit" action="?/edit" use:enhance>
|
||||
<input type="hidden" name="id" value={data.user.id} />
|
||||
|
||||
<div class="root">
|
||||
|
||||
<h1>Benutzer</h1>
|
||||
|
||||
<p>{form?.message}</p>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col class="leader2" />
|
||||
<col class="form2" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr><th colspan="2">Persönliche Daten</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td><input type="text" name="name" value={data.user.name} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Geschlecht</td>
|
||||
<td><select name="gender">
|
||||
<option>M</option>
|
||||
<option>W</option></select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Addresse</td>
|
||||
<td><input type="text" name="address" value={data.user.address} /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col class="leader3" />
|
||||
<col class="form3" />
|
||||
<col class="form3" />
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr><th colspan="3">Benutzer</th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Benutzername</td>
|
||||
<td colspan="2"><input type="text" name="username" value={data.user.username} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Passwort ändern</td>
|
||||
<td><input type="password" name="password1" /></td>
|
||||
<td><input type="password" name="password2" placeholder="Wiederholen"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<button type="submit">Speichern</button>
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<style>
|
||||
|
||||
.root {
|
||||
margin: auto;
|
||||
width: 50%;
|
||||
}
|
||||
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.form2 {
|
||||
width: 75%;
|
||||
}
|
||||
.form3 {
|
||||
width: 37.5%
|
||||
}
|
||||
|
||||
input {
|
||||
width: 100%;
|
||||
border: none;
|
||||
border-bottom: solid 1px black;
|
||||
}
|
||||
|
||||
button {
|
||||
width: 15%;
|
||||
margin-left: 85%;
|
||||
}
|
||||
|
||||
</style>
|
||||
Loading…
Reference in New Issue