Filtern nach ID

This commit is contained in:
Moritz Utcke
2025-03-19 20:43:47 -03:00
parent 06eb1dff34
commit 2db7508859
9 changed files with 262 additions and 13 deletions

View File

@@ -70,7 +70,7 @@
</ul> </ul>
</details></li> --> </details></li> -->
{#if benutzer.rolle === "ADMIN"} {#if benutzer.rolle === "ADMIN"}
<li><details class="[&_.caret]:open:rotate-180"> <li><details class="[&_.caret]:open:rotate-180" open>
<summary class="button-tab w-full outline-0 hover:outline-0 cursor-pointer"> <summary class="button-tab w-full outline-0 hover:outline-0 cursor-pointer">
<LockClosed width={22} height={22} /> <LockClosed width={22} height={22} />
Admin <CaretDown size={24} class="caret ml-auto transition-transform"></CaretDown></summary> Admin <CaretDown size={24} class="caret ml-auto transition-transform"></CaretDown></summary>
@@ -80,6 +80,11 @@
Ausweise Prüfen Ausweise Prüfen
</a> </a>
</li> </li>
<li>
<a use:ripple={rippleOptions} class="button-tab" href="/dashboard/admin/impersonate-user">
Impersonate User
</a>
</li>
</ul> </ul>
</details></li> </details></li>
{/if} {/if}

View File

@@ -93,6 +93,8 @@
objekte = objekte objekte = objekte
} }
let filters: { name: keyof z.infer<typeof filterAusweise>, type: ZodTypeAny, value: any }[] = [] let filters: { name: keyof z.infer<typeof filterAusweise>, type: ZodTypeAny, value: any }[] = []
export let id: string = "";
</script> </script>
<h1>Gebäudeübersicht</h1> <h1>Gebäudeübersicht</h1>
@@ -100,9 +102,13 @@
<hr /> <hr />
{#if user.rolle === Enums.BenutzerRolle.ADMIN} {#if user.rolle === Enums.BenutzerRolle.ADMIN}
<div class="flex flex-col mb-4"> <!-- <div class="flex flex-col mb-4">
<AusweisePruefenFilter bind:filters={filters}></AusweisePruefenFilter> <AusweisePruefenFilter bind:filters={filters}></AusweisePruefenFilter>
</div> </div> -->
<form action="" class="flex flex-row gap-2 my-2">
<input type="text" bind:value={id} name="id" placeholder="ID">
<button class="button text-sm">Suchen</button>
</form>
{/if} {/if}
<div class="relative mb-6"> <div class="relative mb-6">

View File

@@ -0,0 +1,34 @@
<script lang="ts">
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
$: userRequest = api.user.GET.fetch({
email,
take: 25
}, {
headers: {
"Authorization": `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
})
let email: string = "";
</script>
<input type="email" bind:value={email}>
{#await userRequest}
{:then users}
<div class="flex flex-col gap-2 my-2">
{#each users as user}
<div class="flex flex-row justify-between border p-2 rounded-sm">
<div class="flex flex-col">
<span>{user.vorname} {user.name}</span>
<span class="text-xs">{user.email}</span>
</div>
<a href="/dashboard/admin/impersonate?uid={user.uid}" class="button text-sm">Einloggen</a>
</div>
{/each}
</div>
{/await}

View File

@@ -1,9 +1,10 @@
import { UUidWithPrefix } from "#components/Ausweis/types.js"; import { UUidWithPrefix } from "#components/Ausweis/types.js";
import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { adminMiddleware, authorizationMiddleware } from "#lib/middleware/authorization.js";
import { hashPassword } from "#lib/password.js"; import { hashPassword } from "#lib/password.js";
import { sendRegisterMail } from "#lib/server/mail/registrierung.js"; import { sendRegisterMail } from "#lib/server/mail/registrierung.js";
import { BenutzerSchema, prisma } from "#lib/server/prisma.js"; import { prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { BenutzerSchema } from "src/generated/zod/benutzer.js";
import { z } from "zod"; import { z } from "zod";
export const POST = defineApiRoute({ export const POST = defineApiRoute({
@@ -40,6 +41,39 @@ export const POST = defineApiRoute({
}, },
}) })
export const GET = defineApiRoute({
input: z.object({
uid: UUidWithPrefix
}).or(z.object({
take: z.number(),
email: z.string()
})),
output: z.array(BenutzerSchema),
middleware: adminMiddleware,
async fetch(input, context, admin) {
if ("uid" in input) {
const user = await prisma.benutzer.findUnique({
where: {
uid: input.uid
}
})
return [user];
} else {
const users = await prisma.benutzer.findMany({
where: {
email: {
startsWith: input.email
}
},
take: input.take
})
return users;
}
},
})
export const PUT = defineApiRoute({ export const PUT = defineApiRoute({
input: z.object({ input: z.object({
email: z.string().email(), email: z.string().email(),

View File

@@ -0,0 +1,33 @@
---
import DashboardLayout from "#layouts/DashboardLayout.astro";
import UserLayout from "#layouts/DashboardLayout.astro";
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
import { Enums, prisma } from "#lib/server/prisma";
import { createCaller } from "src/astro-typesafe-api-caller";
import DashboardModule from "#modules/Dashboard/DashboardModule.svelte";
import ImpersonateUserModule from "#modules/ImpersonateUserModule.svelte";
const caller = createCaller(Astro)
const params = Astro.params;
const page = Number(params.page)
const user = await caller.user.self.GET.fetch(undefined, {
headers: {
"Authorization": `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
}
});
if (!user) {
return Astro.redirect("/auth/login")
}
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
return Astro.redirect("/dashboard")
}
---
<DashboardLayout title="Impersonate User" {user}>
<ImpersonateUserModule client:load></ImpersonateUserModule>
</DashboardLayout>

View File

@@ -0,0 +1,66 @@
---
import { encodeToken } from "#lib/auth/token";
import { TokenType } from "#lib/auth/types";
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "#lib/constants";
import { Enums, prisma } from "#lib/server/prisma";
import moment from "moment";
import { createCaller } from "src/astro-typesafe-api-caller";
const caller = createCaller(Astro)
const user = await caller.user.self.GET.fetch(undefined, {
headers: {
"Authorization": `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
}
});
if (!user) {
return Astro.redirect("/auth/login")
}
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
return Astro.redirect("/dashboard")
}
const uid = Astro.url.searchParams.get("uid")
if (!uid) {
return Astro.redirect("/404")
}
const searchedUser = await prisma.benutzer.findUnique({
where: {
uid
}
})
if (!searchedUser) {
return Astro.redirect("/dashboard/impersonate-user")
}
const refreshTokenExpiry = moment().add(30, "days");
const accessToken = encodeToken({
uid: searchedUser.uid,
typ: TokenType.Access,
exp: moment().add(30, "minutes").valueOf(),
});
const refreshToken = encodeToken({
uid: searchedUser.uid,
typ: TokenType.Refresh,
exp: refreshTokenExpiry.valueOf(),
});
Astro.cookies.set(API_REFRESH_TOKEN_COOKIE_NAME, refreshToken, {
domain: `.${Astro.url.hostname}`,
path: "/",
expires: refreshTokenExpiry.toDate()
})
Astro.cookies.set(API_ACCESS_TOKEN_COOKIE_NAME, accessToken, {
domain: `.${Astro.url.hostname}`,
path: "/",
expires: moment().add(30, "minutes").toDate()
})
Astro.cookies.set("uid", searchedUser.uid)
return Astro.redirect("/dashboard")
---

View File

@@ -10,6 +10,9 @@ const caller = createCaller(Astro)
const params = Astro.params; const params = Astro.params;
const page = Number(params.page) const page = Number(params.page)
const id = parseInt(Astro.url.searchParams.get("id") || "")
const user = await caller.user.self.GET.fetch(undefined, { const user = await caller.user.self.GET.fetch(undefined, {
headers: { headers: {
"Authorization": `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}` "Authorization": `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
@@ -32,8 +35,76 @@ const objekte = await prisma.objekt.findMany({
where: user.rolle === Enums.BenutzerRolle.USER ? { where: user.rolle === Enums.BenutzerRolle.USER ? {
benutzer: { benutzer: {
uid: user.uid uid: user.uid
} },
} : {}, } : {
OR: [
{
aufnahmen: {
some: {
verbrauchsausweise_gewerbe: {
some: {
alte_ausweis_id: id
}
},
}
}
},
{
aufnahmen: {
some: {
verbrauchsausweise_wohnen: {
some: {
alte_ausweis_id: id
}
},
}
}
},
{
aufnahmen: {
some: {
bedarfsausweise_wohnen: {
some: {
alte_ausweis_id: id
}
},
}
}
},
{
aufnahmen: {
some: {
verbrauchsausweise_gewerbe: {
some: {
id: id
}
},
}
}
},
{
aufnahmen: {
some: {
verbrauchsausweise_wohnen: {
some: {
id: id
}
},
}
}
},
{
aufnahmen: {
some: {
bedarfsausweise_wohnen: {
some: {
id: id
}
},
}
}
},]
},
orderBy: { orderBy: {
erstellungsdatum: "desc" erstellungsdatum: "desc"
}, },
@@ -53,6 +124,6 @@ const objekte = await prisma.objekt.findMany({
}) })
--- ---
<UserLayout title="Ausweise Prüfen" {user}> <UserLayout title="Objekte" {user}>
<DashboardModule {user} {objekte} totalPages={Math.ceil(totalPages / 25)} page={page} client:load /> <DashboardModule {user} {objekte} totalPages={Math.ceil(totalPages / 25)} page={page} {id} client:load />
</UserLayout> </UserLayout>

View File

@@ -11,7 +11,7 @@ export const GET: APIRoute = async (Astro) => {
const uidAusweis = Astro.url.searchParams.get("uid"); const uidAusweis = Astro.url.searchParams.get("uid");
if (!uidAusweis) { if (!uidAusweis) {
return Astro.redirect("/404") return new Response(null, { status: 404 });
} }
const ausweisart = getAusweisartFromUUID(uidAusweis) const ausweisart = getAusweisartFromUUID(uidAusweis)
@@ -46,7 +46,7 @@ export const GET: APIRoute = async (Astro) => {
if (!ausweis) { if (!ausweis) {
return Astro.redirect("/"); return new Response(null, { status: 404 });
} }
aufnahme = await caller.aufnahme._uid.GET.fetch(undefined, { aufnahme = await caller.aufnahme._uid.GET.fetch(undefined, {

View File

@@ -13,7 +13,7 @@ export const GET: APIRoute = async (Astro) => {
const uidAusweis = Astro.url.searchParams.get("uid"); const uidAusweis = Astro.url.searchParams.get("uid");
if (!uidAusweis) { if (!uidAusweis) {
return Astro.redirect("/404") return new Response(null, { status: 404 });
} }
const ausweisart = getAusweisartFromUUID(uidAusweis) const ausweisart = getAusweisartFromUUID(uidAusweis)
@@ -48,7 +48,7 @@ export const GET: APIRoute = async (Astro) => {
if (!ausweis) { if (!ausweis) {
return Astro.redirect("/"); return new Response(null, { status: 404 });
} }
aufnahme = await caller.aufnahme._uid.GET.fetch(undefined, { aufnahme = await caller.aufnahme._uid.GET.fetch(undefined, {