API Verbessert - Verbrauchsausweis Funktioniert
This commit is contained in:
@@ -51,7 +51,7 @@
|
||||
"trpc-openapi": "^1.2.0",
|
||||
"uuid": "^9.0.0",
|
||||
"vite-tsconfig-paths": "^4.2.0",
|
||||
"zod": "^3.21.4"
|
||||
"zod": "^3.22.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/js-cookie": "^3.0.6",
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
</HelpLabel>
|
||||
<div>
|
||||
<select
|
||||
name="energietraeger_einheit_heizquelle_1"
|
||||
name="einheit_1"
|
||||
required
|
||||
bind:value={ausweis.einheit_1}
|
||||
>
|
||||
@@ -140,7 +140,7 @@
|
||||
<Label>Einheit *</Label>
|
||||
<div>
|
||||
<select
|
||||
name="energietraeger_einheit_heizquelle_2"
|
||||
name="einheit_2"
|
||||
disabled={!ausweis.zusaetzliche_heizquelle}
|
||||
bind:value={ausweis.einheit_2}
|
||||
required
|
||||
|
||||
@@ -1,297 +0,0 @@
|
||||
<script lang="ts">
|
||||
import HorizontalDots from "#components/Icons/HorizontalDots.svelte";
|
||||
import type { Verbrauchsausweis } from "#lib/Ausweis/Verbrauchsausweis";
|
||||
import moment from "moment";
|
||||
import Cross from "#components/Icons/Cross.svelte";
|
||||
import { Dachgeschoss } from "#lib/Ausweis/types";
|
||||
|
||||
interface Service {
|
||||
name: string;
|
||||
url: string;
|
||||
}
|
||||
|
||||
export let ausweis: Verbrauchsausweis;
|
||||
export let services: Service[];
|
||||
export let hidden: boolean;
|
||||
|
||||
export let i: number;
|
||||
|
||||
let left: string = "";
|
||||
$: {
|
||||
if (i == 0 || i % 3 == 0) {
|
||||
left = "0";
|
||||
} else if (i % 2 == 0) {
|
||||
left = "-50%";
|
||||
} else {
|
||||
left = "-100%";
|
||||
}
|
||||
}
|
||||
|
||||
$: energieverbrauchDaten = [
|
||||
moment(ausweis.energieverbrauch_zeitraum),
|
||||
moment(ausweis.energieverbrauch_zeitraum).add("1", "year"),
|
||||
moment(ausweis.energieverbrauch_zeitraum).add("2", "years"),
|
||||
moment(ausweis.energieverbrauch_zeitraum).add("3", "years"),
|
||||
];
|
||||
|
||||
let showDropdown: boolean = false;
|
||||
</script>
|
||||
|
||||
<div class="rounded-lg bg-white shadow-sm border px-4 py-1 relative">
|
||||
<div class="flex flex-row justify-between items-center cursor-pointer">
|
||||
<h3>
|
||||
{ausweis.objekt_strasse}, {ausweis.objekt_plz}
|
||||
{ausweis.objekt_ort}
|
||||
</h3>
|
||||
<button
|
||||
class="cursor-pointer relative hover:bg-gray-100 rounded-lg p-1"
|
||||
on:click={() => {
|
||||
showDropdown = !showDropdown;
|
||||
}}
|
||||
>
|
||||
<HorizontalDots width={20} height={20} />
|
||||
<div
|
||||
class="absolute right-0 top-full w-[150px] border shadow-md rounded-lg bg-white z-50"
|
||||
hidden={!showDropdown}
|
||||
>
|
||||
<button
|
||||
class="cursor-pointer hover:bg-gray-100 w-full p-1"
|
||||
on:click={() => {
|
||||
hidden = !hidden;
|
||||
}}>Berechnung</button
|
||||
>
|
||||
<button
|
||||
class="cursor-pointer hover:bg-gray-100 w-full p-1"
|
||||
on:click={() => {}}>Gebäudeansicht</button
|
||||
>
|
||||
<button
|
||||
class="cursor-pointer hover:bg-gray-100 w-full p-1"
|
||||
on:click={() => {}}>Ausweis Ansehen</button
|
||||
>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<a href="/ausweis/{ausweis.uid}/cad">Gebäudeansicht</a>
|
||||
<div
|
||||
class="absolute top-[calc(100%+16px)] left-0 w-[200%] rounded-lg z-50 bg-white border p-2"
|
||||
style="left: {left};"
|
||||
{hidden}
|
||||
>
|
||||
<div class="flex flex-row justify-between">
|
||||
<h4 class="px-2 py-1 bg-violet-50 rounded-lg">
|
||||
Datenprüfung Verbrauchsausweis - ID {ausweis.id} - {ausweis.objekt_strasse},
|
||||
{ausweis.objekt_plz}
|
||||
{ausweis.objekt_ort}
|
||||
</h4>
|
||||
<Cross
|
||||
on:click={() => (hidden = true)}
|
||||
className="p-1 hover:bg-gray-100 cursor-pointer w-[25px] h-[25px] rounded-lg"
|
||||
/>
|
||||
</div>
|
||||
<h5>Abschnitt A,B,C,D und E</h5>
|
||||
<div class="grid grid-cols-4 gap-4">
|
||||
<div class="border rounded-lg p-1">
|
||||
<table>
|
||||
<tr>
|
||||
<td>AL</td><td>:</td>
|
||||
<td>{ausweis.ausstellgrund}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BH</td><td>:</td>
|
||||
<td>{ausweis.baujahr_anlage}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>BG</td><td>:</td>
|
||||
<td>{ausweis.baujahr_gebaeude}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AW</td><td>:</td>
|
||||
<td>{ausweis.anzahl_einheiten}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ST</td><td>:</td>
|
||||
<td>{ausweis.objekt_saniert}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="border rounded-lg p-1">
|
||||
<table>
|
||||
<tr>
|
||||
<td>WF</td><td>:</td>
|
||||
<td>{ausweis.wohnflaeche}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>F</td><td>:</td>
|
||||
<td>{ausweis.baujahr_anlage}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AN</td><td>:</td>
|
||||
<td>{ausweis.baujahr_gebaeude}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>KB</td><td>:</td>
|
||||
<td>{ausweis.keller_beheizt}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DB</td><td>:</td>
|
||||
<td>{ausweis.dachgeschoss == Dachgeschoss.BEHEIZT ? "Ja" : "Nein"}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="border rounded-lg p-1">
|
||||
<table>
|
||||
<tr>
|
||||
<td>WWE</td><td>:</td>
|
||||
<td>{ausweis.warmwasser_enthalten}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WWA</td><td>:</td>
|
||||
<td>{ausweis.anteil_warmwasser_1}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WWAZH</td><td>:</td>
|
||||
<td>{ausweis.anteil_warmwasser_2}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AEVS</td><td>:</td>
|
||||
<td />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSWW</td><td>:</td>
|
||||
<td>{ausweis.dachgeschoss}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="border rounded-lg p-1">
|
||||
<table>
|
||||
<tr>
|
||||
<td>GT</td><td>:</td>
|
||||
<td>{ausweis.objekt_gebaeudeteil}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GTL</td><td>:</td>
|
||||
<td />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>L</td><td>:</td>
|
||||
<td>{ausweis.lueftungskonzept}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>AK</td><td>:</td>
|
||||
<td />
|
||||
</tr>
|
||||
<tr>
|
||||
<td>LS</td><td>:</td>
|
||||
<td>{ausweis.leerstand}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="border rounded-lg p-1 gap-2 grid grid-cols-4 justify-between">
|
||||
<table>
|
||||
<tr>
|
||||
<td>{energieverbrauchDaten[0].format("MMMM YYYY")}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{energieverbrauchDaten[0].format("MM.YYYY")} - {energieverbrauchDaten[1].format(
|
||||
"MM.YYYY"
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{energieverbrauchDaten[1].format("MM.YYYY")} - {energieverbrauchDaten[2].format(
|
||||
"MM.YYYY"
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{energieverbrauchDaten[2].format("MM.YYYY")} - {energieverbrauchDaten[3].format(
|
||||
"MM.YYYY"
|
||||
)}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Faktoren Hi / PF / COE</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Primäre Heizquelle (1)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{ausweis.energieverbrauch_1_heizquelle_1}
|
||||
{ausweis.energietraeger_einheit_heizquelle_1}
|
||||
{ausweis.energietraeger_1}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{ausweis.energieverbrauch_2_heizquelle_1}
|
||||
{ausweis.energietraeger_einheit_heizquelle_1}
|
||||
{ausweis.energietraeger_1}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{ausweis.energieverbrauch_3_heizquelle_1}
|
||||
{ausweis.energietraeger_einheit_heizquelle_1}
|
||||
{ausweis.energietraeger_1}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>10 / 1.1 / 2.5</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Sekundäre Heizquelle (2)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{ausweis.energieverbrauch_1_heizquelle_2}
|
||||
{ausweis.energietraeger_einheit_heizquelle_2}
|
||||
{ausweis.energietraeger_2}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{ausweis.energieverbrauch_2_heizquelle_2}
|
||||
{ausweis.energietraeger_einheit_heizquelle_2}
|
||||
{ausweis.energietraeger_2}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td
|
||||
>{ausweis.energieverbrauch_3_heizquelle_2}
|
||||
{ausweis.energietraeger_einheit_heizquelle_2}
|
||||
{ausweis.energietraeger_2}</td
|
||||
>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>10 / 1.1 / 2.5</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td>Klimafaktoren</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1.12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1.15</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>1.12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -56,17 +56,17 @@ const loggedIn = isLoggedIn(Astro);
|
||||
>Energieausweis erstellen</a
|
||||
>
|
||||
<a class="headerButton" href="/energieausweis-kontakt.php"
|
||||
>{t("header.kontakt")}</a
|
||||
>Kontakt</a
|
||||
>
|
||||
<a class="headerButton" href="/agb">AGB</a>
|
||||
{
|
||||
loggedIn ? (
|
||||
<a class="headerButton" href="/user">
|
||||
{t("header.profil")}
|
||||
Profil
|
||||
</a>
|
||||
) : (
|
||||
<a class="headerButton" href="/login">
|
||||
{t("header.login")}
|
||||
Login
|
||||
</a>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
VerbrauchsausweisWohnen,
|
||||
} from "@ibcornelsen/database";
|
||||
import moment from "moment";
|
||||
import trpc from "src/trpc";
|
||||
import { client } from "src/trpc";
|
||||
|
||||
export function energetischeNutzflaecheVerbrauchsausweisWohnen_2016(
|
||||
ausweis: VerbrauchsausweisWohnen & {
|
||||
@@ -28,7 +28,7 @@ export async function endEnergieVerbrauchVerbrauchsausweis_2016(
|
||||
return null
|
||||
}
|
||||
|
||||
const klimafaktoren = await trpc.klimafaktoren.query({
|
||||
const klimafaktoren = await client.v1.klimafaktoren.query({
|
||||
plz: ausweis.gebaeude_stammdaten.plz,
|
||||
genauigkeit: "years",
|
||||
startdatum: ausweis.startdatum,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getKlimafaktoren } from "#lib/Klimafaktoren";
|
||||
import { getKlimafaktoren } from "#lib/getKlimafaktoren";
|
||||
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor";
|
||||
import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
|
||||
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import jwt from "jwt-simple";
|
||||
|
||||
export function encodeToken(data: Record<string, any>) {
|
||||
type TokenData = { uid: string, exp: number }
|
||||
|
||||
export function encodeToken(data: TokenData) {
|
||||
const token = jwt.encode(data, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4", "HS256");
|
||||
return token;
|
||||
}
|
||||
|
||||
export function decodeToken<T>(token: string): Partial<T> {
|
||||
export function decodeToken(token: string): Partial<TokenData> {
|
||||
return jwt.decode(token, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4");
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
import moment from "moment";
|
||||
import { memoize } from "./Memoization";
|
||||
import trpc from "src/trpc";
|
||||
import { client } from "src/trpc";
|
||||
|
||||
export const getKlimafaktoren = memoize(async (date: Date, plz: string) => {
|
||||
if (!plz || !date) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const response = await trpc.klimafaktoren.query({
|
||||
const response = await client.v1.klimafaktoren.query({
|
||||
plz,
|
||||
genauigkeit: "years",
|
||||
startdatum: date,
|
||||
|
||||
@@ -69,33 +69,4 @@ export class User {
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
public static async create(user: UserType): Promise<{uid: string, id: number} | null> {
|
||||
if (!user || UserRegisterValidator.safeParse(user).success == false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const uid = uuid();
|
||||
const hashedPassword = hashPassword(user.passwort);
|
||||
|
||||
const result = await prisma.benutzer.create({
|
||||
data: {
|
||||
email: user.email,
|
||||
passwort: hashedPassword,
|
||||
uid: uid
|
||||
},
|
||||
select: {
|
||||
id: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
uid,
|
||||
id: result.id
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import {
|
||||
endEnergieVerbrauchVerbrauchsausweis_2016,
|
||||
energetischeNutzflaecheVerbrauchsausweisWohnen_2016,
|
||||
} from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016";
|
||||
import { getKlimafaktoren } from "#lib/Klimafaktoren";
|
||||
import { getKlimafaktoren } from "#lib/getKlimafaktoren";
|
||||
import { getHeizwertfaktor } from "#lib/server/Heizwertfaktor";
|
||||
import {
|
||||
GebaeudeStammdaten,
|
||||
@@ -28,6 +28,11 @@ export async function xmlVerbrauchsausweisWohnen_2016(
|
||||
let postleitzahl = gebaeude.plz?.substring(0, 3) + "XX";
|
||||
|
||||
const result = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis);
|
||||
|
||||
if (!result) {
|
||||
throw new Error("Verbrauchsausweis konnte nicht zur Berechnung verarbeitet werden.");
|
||||
}
|
||||
|
||||
const berechnungen = new AusweisBerechnungen2016(
|
||||
ausweis,
|
||||
ausweis.gebaeude_stammdaten,
|
||||
@@ -79,12 +84,12 @@ export async function xmlVerbrauchsausweisWohnen_2016(
|
||||
: "true";
|
||||
|
||||
let heizwertfaktor_1 = getHeizwertfaktor(
|
||||
ausweis.brennstoff_1,
|
||||
ausweis.einheit_1
|
||||
ausweis.brennstoff_1 as string,
|
||||
ausweis.einheit_1 as string
|
||||
);
|
||||
let heizwertfaktor_2 = getHeizwertfaktor(
|
||||
ausweis.brennstoff_2,
|
||||
ausweis.einheit_2
|
||||
ausweis.brennstoff_2 as string,
|
||||
ausweis.einheit_2 as string
|
||||
);
|
||||
|
||||
let warmWasserErmittlung =
|
||||
@@ -158,12 +163,12 @@ export async function xmlVerbrauchsausweisWohnen_2016(
|
||||
);
|
||||
|
||||
let energieTraeger = berechnungen.getEnergietraegerBezeichnung(
|
||||
ausweis.brennstoff_1,
|
||||
ausweis.einheit_1
|
||||
ausweis.brennstoff_1 as string,
|
||||
ausweis.einheit_1 as string
|
||||
);
|
||||
let energieTraeger_2 = berechnungen.getEnergietraegerBezeichnung(
|
||||
ausweis.brennstoff_2,
|
||||
ausweis.einheit_2
|
||||
ausweis.brennstoff_2 as string,
|
||||
ausweis.einheit_2 as string
|
||||
);
|
||||
|
||||
let warmwasserZuschlag = Math.round(result.energieVerbrauchWarmwasser_1);
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
export async function getKlimafaktorenServer(date: Date, zip: string, accuracy: "months" | "years" = "months"): Promise<number[] | null> {
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
|
||||
/**
|
||||
* Dies ist die Server-Side Implementierung von fetch, die Daten werden direkt vom Server abgerufen.
|
||||
* Dadurch können unnötige Requests vermieden werden.
|
||||
* @date 9/20/2023 - 11:33:30 AM
|
||||
*
|
||||
* @export
|
||||
* @async
|
||||
* @param {string} resourceUri
|
||||
* @param {?RequestInit} [options]
|
||||
* @returns {Promise<any>}
|
||||
*/
|
||||
export async function fetch(resourceUri: string, options?: RequestInit): Promise<any> {
|
||||
const response = await fetch(`http://localhost:3000/api/${resourceUri}`, options);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error("Fehler beim Abrufen der Daten.");
|
||||
}
|
||||
|
||||
return response.json();
|
||||
}
|
||||
@@ -1,10 +1,15 @@
|
||||
import { TRPCError, initTRPC } from "@trpc/server";
|
||||
import { initTRPC } from "@trpc/server";
|
||||
import { ZodError } from "zod";
|
||||
import { OpenApiMeta } from "trpc-openapi";
|
||||
|
||||
type Context = { uid?: string };
|
||||
type Context = {
|
||||
authorization: string | null;
|
||||
ip: string;
|
||||
req: Request;
|
||||
}
|
||||
|
||||
export const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({
|
||||
|
||||
errorFormatter(opts) {
|
||||
const { shape, error } = opts;
|
||||
return {
|
||||
@@ -18,17 +23,4 @@ export const t = initTRPC.context<Context>().meta<OpenApiMeta>().create({
|
||||
},
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export const publicProcedure = t.procedure
|
||||
|
||||
export const privateProcedure = t.procedure.use((opts) => {
|
||||
if (!opts.ctx.uid) {
|
||||
throw new TRPCError({
|
||||
code: 'FORBIDDEN',
|
||||
message: "Diese Ressource benötigt eine UID, welche im 'Authorization' Header gegeben sein muss.",
|
||||
});
|
||||
}
|
||||
|
||||
return opts.next();
|
||||
});
|
||||
0
src/lib/trpc/middlewares/adminProcedure.ts
Normal file
0
src/lib/trpc/middlewares/adminProcedure.ts
Normal file
26
src/lib/trpc/middlewares/loggedProcedure.ts
Normal file
26
src/lib/trpc/middlewares/loggedProcedure.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import { privateProcedure } from "./privateProcedure";
|
||||
|
||||
// NOTE: Muss noch mit der Datenbank eingebunden werden.
|
||||
export const loggedProcedure = privateProcedure.use(async (opts) => {
|
||||
const start = Date.now();
|
||||
|
||||
const result = await opts.next();
|
||||
|
||||
const durationMs = Date.now() - start;
|
||||
|
||||
await prisma.apiRequests.create({
|
||||
data: {
|
||||
ip: opts.ctx.ip,
|
||||
method: opts.type,
|
||||
path: opts.path,
|
||||
responseSize: JSON.stringify(result).length,
|
||||
responseTime: durationMs,
|
||||
userAgent: opts.ctx.req.headers["user-agent"] || "",
|
||||
status: result.ok ? 200 : 500,
|
||||
user_id: opts.ctx.user.id
|
||||
}
|
||||
})
|
||||
|
||||
return result;
|
||||
});
|
||||
44
src/lib/trpc/middlewares/privateProcedure.ts
Normal file
44
src/lib/trpc/middlewares/privateProcedure.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { publicProcedure } from "./publicProcedure";
|
||||
import { decodeToken } from "#lib/JsonWebToken";
|
||||
import { User } from "#lib/User";
|
||||
|
||||
export const privateProcedure = publicProcedure.use(async (opts) => {
|
||||
const { ctx } = opts;
|
||||
|
||||
if (!ctx.authorization) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Für diese Action ist ein Bearer Token verpflichtend." });
|
||||
}
|
||||
|
||||
const [authorizationType, value] = ctx.authorization.split(" ");
|
||||
|
||||
if (authorizationType != "Bearer") {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Für diese Action ist ein Bearer Token verpflichtend." });
|
||||
}
|
||||
|
||||
const stringToken = Buffer.from(value, "base64").toString();
|
||||
try {
|
||||
const token = decodeToken(
|
||||
stringToken
|
||||
);
|
||||
const uid = token.uid;
|
||||
|
||||
if (!uid) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Der gegebene Token ist fehlerhaft." });
|
||||
}
|
||||
|
||||
const user = await User.fromUID(uid);
|
||||
|
||||
if (!user) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Der gegebene Token ist fehlerhaft." });
|
||||
}
|
||||
|
||||
return opts.next({
|
||||
ctx: {
|
||||
user,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Der gegebene Token ist fehlerhaft." });
|
||||
}
|
||||
});
|
||||
3
src/lib/trpc/middlewares/publicProcedure.ts
Normal file
3
src/lib/trpc/middlewares/publicProcedure.ts
Normal file
@@ -0,0 +1,3 @@
|
||||
import { t } from "#lib/trpc/context";
|
||||
|
||||
export const publicProcedure = t.procedure;
|
||||
0
src/lib/trpc/procedures/v1/benutzer/entfernen.ts
Normal file
0
src/lib/trpc/procedures/v1/benutzer/entfernen.ts
Normal file
64
src/lib/trpc/procedures/v1/benutzer/erstellen.ts
Normal file
64
src/lib/trpc/procedures/v1/benutzer/erstellen.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
import { z } from "zod";
|
||||
import moment from "moment";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
|
||||
import { encodeToken } from "#lib/JsonWebToken";
|
||||
import { hashPassword } from "#lib/Password";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
export const tRPC_V1_BenutzerErstellenProcedure = publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
email: z.string().email(),
|
||||
passwort: z.string().min(8).max(100),
|
||||
vorname: z.string().min(1).max(100),
|
||||
name: z.string().min(1).max(100),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
uid: z.string().uuid(),
|
||||
token: z.string(),
|
||||
exp: z.number(),
|
||||
})
|
||||
)
|
||||
.query(async (opts) => {
|
||||
const hashedPassword = hashPassword(opts.input.passwort);
|
||||
|
||||
// Vielleicht existiert der Benutzer ja schon?
|
||||
const existingUser = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
email: opts.input.email
|
||||
}
|
||||
})
|
||||
|
||||
if (existingUser) {
|
||||
throw new TRPCError({ code: "CONFLICT", message: "Der Benutzer existiert bereits." });
|
||||
}
|
||||
|
||||
const user = await prisma.benutzer.create({
|
||||
data: {
|
||||
email: opts.input.email,
|
||||
passwort: hashedPassword,
|
||||
vorname: opts.input.vorname,
|
||||
name: opts.input.name
|
||||
},
|
||||
select: {
|
||||
id: true,
|
||||
uid: true
|
||||
}
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
throw new TRPCError({ code: "INTERNAL_SERVER_ERROR", message: "Der Benutzer konnte nicht erstellt werden." });
|
||||
}
|
||||
|
||||
const expiry = moment().add(2, "days").unix();
|
||||
const token = encodeToken({ uid: user.uid, exp: expiry })
|
||||
|
||||
return {
|
||||
uid: user.uid,
|
||||
token: token,
|
||||
exp: expiry
|
||||
}
|
||||
});
|
||||
31
src/lib/trpc/procedures/v1/benutzer/fromPrivateId.ts
Normal file
31
src/lib/trpc/procedures/v1/benutzer/fromPrivateId.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { z } from "zod";
|
||||
import { BenutzerSchema, prisma } from "@ibcornelsen/database";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { loggedProcedure } from "#lib/trpc/middlewares/loggedProcedure";
|
||||
|
||||
export const tRPC_V1_BenutzerFromPrivateIdProcedure = loggedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
BenutzerSchema
|
||||
)
|
||||
.query(async (opts) => {
|
||||
if (opts.ctx.user.id !== opts.input.id) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Sie sind nicht dazu authorisiert die Daten dieses Benutzers einzusehen." });
|
||||
}
|
||||
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
id: opts.input.id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht." });
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
31
src/lib/trpc/procedures/v1/benutzer/fromPublicId.ts
Normal file
31
src/lib/trpc/procedures/v1/benutzer/fromPublicId.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { z } from "zod";
|
||||
import { BenutzerSchema, prisma } from "@ibcornelsen/database";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { loggedProcedure } from "#lib/trpc/middlewares/loggedProcedure";
|
||||
|
||||
export const tRPC_V1_BenutzerFromPublicIdProcedure = loggedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
uid: z.string().uuid(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
BenutzerSchema
|
||||
)
|
||||
.query(async (opts) => {
|
||||
if (opts.ctx.user.uid !== opts.input.uid) {
|
||||
throw new TRPCError({ code: "UNAUTHORIZED", message: "Sie sind nicht dazu authorisiert die Daten dieses Benutzers einzusehen." });
|
||||
}
|
||||
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
uid: opts.input.uid,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht." });
|
||||
}
|
||||
|
||||
return user;
|
||||
});
|
||||
50
src/lib/trpc/procedures/v1/benutzer/tokenErneuern.ts
Normal file
50
src/lib/trpc/procedures/v1/benutzer/tokenErneuern.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { z } from "zod";
|
||||
import moment from "moment";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
|
||||
import { encodeToken } from "#lib/JsonWebToken";
|
||||
import { hashPassword } from "#lib/Password";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
|
||||
export const tRPC_V1_BenutzerTokenErneuernProcedure = publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
email: z.string().email(),
|
||||
passwort: z.string().min(8).max(100),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
uid: z.string().uuid(),
|
||||
token: z.string(),
|
||||
exp: z.number(),
|
||||
})
|
||||
)
|
||||
.query(async (opts) => {
|
||||
const hashedPassword = hashPassword(opts.input.passwort);
|
||||
|
||||
// Falls der Nutzer nicht existiert, wird eine Fehlermeldung zurückgegeben.
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
email: opts.input.email
|
||||
}
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht oder das Password ist falsch." });
|
||||
}
|
||||
|
||||
// Falls das Passwort nicht stimmt, wird eine Fehlermeldung zurückgegeben.
|
||||
if (user.passwort !== hashedPassword) {
|
||||
throw new TRPCError({ code: "BAD_REQUEST", message: "Der gesuchte Benutzer existiert nicht oder das Password ist falsch." });
|
||||
}
|
||||
|
||||
const expiry = moment().add(2, "days").unix();
|
||||
const token = encodeToken({ uid: user.uid, exp: expiry })
|
||||
|
||||
return {
|
||||
uid: user.uid,
|
||||
token: token,
|
||||
exp: expiry
|
||||
}
|
||||
});
|
||||
49
src/lib/trpc/procedures/v1/benutzer/tokenValidieren.ts
Normal file
49
src/lib/trpc/procedures/v1/benutzer/tokenValidieren.ts
Normal file
@@ -0,0 +1,49 @@
|
||||
import { z } from "zod";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
|
||||
import { decodeToken } from "#lib/JsonWebToken";
|
||||
|
||||
export const tRPC_V1_BenutzerTokenValidierenProcedure = publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
token: z.string(),
|
||||
})
|
||||
)
|
||||
.output(
|
||||
z.object({
|
||||
uid: z.string().uuid(),
|
||||
valid: z.boolean(),
|
||||
exp: z.number()
|
||||
})
|
||||
)
|
||||
.query(async (opts) => {
|
||||
const decodedToken = decodeToken(opts.input.token);
|
||||
|
||||
if (!decodedToken || !decodedToken.uid || !decodedToken.exp) {
|
||||
return {
|
||||
uid: "",
|
||||
valid: false,
|
||||
exp: 0,
|
||||
};
|
||||
}
|
||||
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
uid: decodedToken.uid,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
return {
|
||||
uid: "",
|
||||
valid: false,
|
||||
exp: 0,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
uid: decodedToken.uid,
|
||||
valid: true,
|
||||
exp: decodedToken.exp
|
||||
};
|
||||
});
|
||||
45
src/lib/trpc/procedures/v1/index.ts
Normal file
45
src/lib/trpc/procedures/v1/index.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { t } from "#lib/trpc/context";
|
||||
import { tRPC_V1_KlimafaktorenProcedure } from "./klimafaktoren";
|
||||
import { VerbrauchsausweisWohnen2016Erstellen } from "./verbrauchsausweis-wohnen/2016/erstellen";
|
||||
import { tRPC_V1_BenutzerErstellenProcedure } from "./benutzer/erstellen";
|
||||
import { tRPC_V1_BenutzerTokenErneuernProcedure } from "./benutzer/tokenErneuern";
|
||||
import { tRPC_V1_BenutzerTokenValidierenProcedure } from "./benutzer/tokenValidieren";
|
||||
import { tRPC_V1_BenutzerFromPublicIdProcedure } from "./benutzer/fromPublicId";
|
||||
import { tRPC_V1_BenutzerFromPrivateIdProcedure } from "./benutzer/fromPrivateId";
|
||||
|
||||
const router = t.router;
|
||||
|
||||
export const v1Router = router({
|
||||
verbrauchsausweisWohnen: router({
|
||||
2016: router({
|
||||
erstellen: VerbrauchsausweisWohnen2016Erstellen
|
||||
}),
|
||||
2023: router({
|
||||
|
||||
})
|
||||
}),
|
||||
verbrauchsausweisGewerbe: router({
|
||||
2016: router({
|
||||
|
||||
}),
|
||||
2023: router({
|
||||
|
||||
})
|
||||
}),
|
||||
bedarfsausweisWohen: router({
|
||||
2016: router({
|
||||
|
||||
}),
|
||||
2023: router({
|
||||
|
||||
})
|
||||
}),
|
||||
klimafaktoren: tRPC_V1_KlimafaktorenProcedure,
|
||||
benutzer: router({
|
||||
erstellen: tRPC_V1_BenutzerErstellenProcedure,
|
||||
tokenErneuern: tRPC_V1_BenutzerTokenErneuernProcedure,
|
||||
tokenValidieren: tRPC_V1_BenutzerTokenValidierenProcedure,
|
||||
fromPublicId: tRPC_V1_BenutzerFromPublicIdProcedure,
|
||||
fromPrivateId: tRPC_V1_BenutzerFromPrivateIdProcedure
|
||||
})
|
||||
})
|
||||
@@ -1,10 +1,10 @@
|
||||
import { z } from "zod";
|
||||
import { t } from "../../context";
|
||||
import moment from "moment";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
|
||||
|
||||
export const tRPCKlimafaktorenProcedure = t.procedure
|
||||
export const tRPC_V1_KlimafaktorenProcedure = publicProcedure
|
||||
.input(
|
||||
z.object({
|
||||
plz: z.string().min(4).max(5),
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ZodSchema, z } from "zod";
|
||||
import { publicProcedure } from "../../../../context";
|
||||
import { GebaeudeStammdaten, VerbrauchsausweisWohnen, prisma } from "@ibcornelsen/database";
|
||||
import { z } from "zod";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
import { publicProcedure } from "#lib/trpc/middlewares/publicProcedure";
|
||||
|
||||
export const VerbrauchsausweisWohnen2016Erstellen = publicProcedure
|
||||
.meta({
|
||||
@@ -16,11 +16,11 @@ export const VerbrauchsausweisWohnen2016Erstellen = publicProcedure
|
||||
baujahr_heizung: z.array(z.number()).optional(),
|
||||
zusaetzliche_heizquelle: z.boolean().optional(),
|
||||
brennstoff_1: z.string().max(50).optional(),
|
||||
einheit_1: z.string().max(10).optional(),
|
||||
einheit_1: z.string().max(50).optional(),
|
||||
brennstoff_2: z.string().max(50).optional(),
|
||||
einheit_2: z.string().max(10).optional(),
|
||||
startdatum: z.date().optional(),
|
||||
enddatum: z.date().optional(),
|
||||
einheit_2: z.string().max(50).optional(),
|
||||
startdatum: z.coerce.date().optional(),
|
||||
enddatum: z.coerce.date().optional(),
|
||||
verbrauch_1: z.number().optional(),
|
||||
verbrauch_2: z.number().optional(),
|
||||
verbrauch_3: z.number().optional(),
|
||||
@@ -86,8 +86,8 @@ export const VerbrauchsausweisWohnen2016Erstellen = publicProcedure
|
||||
aussenwand_min_12cm_gedaemmt: z.boolean().optional(),
|
||||
dachgeschoss_min_12cm_gedaemmt: z.boolean().optional(),
|
||||
oberste_geschossdecke_min_12cm_gedaemmt: z.boolean().optional(),
|
||||
} satisfies ZodSchema<GebaeudeStammdaten>))
|
||||
} satisfies ZodSchema<VerbrauchsausweisWohnen>))
|
||||
}))
|
||||
}))
|
||||
.output(
|
||||
z.object({
|
||||
uid: z.string().uuid(),
|
||||
@@ -121,7 +121,23 @@ export const VerbrauchsausweisWohnen2016Erstellen = publicProcedure
|
||||
});
|
||||
|
||||
return { uid: verbrauchsausweis.uid };
|
||||
}
|
||||
} else {
|
||||
// Gebäude existiert noch nicht
|
||||
const gebaeude = await prisma.gebaeudeStammdaten.create({
|
||||
data: opts.input.gebaeude_stammdaten
|
||||
});
|
||||
|
||||
return { uid: "" };
|
||||
const verbrauchsausweis = await prisma.verbrauchsausweisWohnen.create({
|
||||
data: {
|
||||
...opts.input,
|
||||
gebaeude_stammdaten: {
|
||||
connect: {
|
||||
uid: gebaeude.uid
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return { uid: verbrauchsausweis.uid };
|
||||
}
|
||||
});
|
||||
@@ -15,13 +15,14 @@
|
||||
import { auditBedarfsausweisBenoetigt } from "#components/Verbrauchsausweis/audits/BedarfsausweisBenoetigt";
|
||||
import { auditVerbrauchAbweichung } from "#components/Verbrauchsausweis/audits/VerbrauchAbweichung";
|
||||
import { GebaeudeStammdaten, VerbrauchsausweisWohnen } from "@ibcornelsen/database";
|
||||
import trpc from "src/trpc";
|
||||
import { client } from "src/trpc";
|
||||
|
||||
export let uid: string = "";
|
||||
|
||||
let gebaeude: GebaeudeStammdaten = {} as GebaeudeStammdaten;
|
||||
let ausweis: VerbrauchsausweisWohnen = {} as VerbrauchsausweisWohnen;
|
||||
if (uid) {
|
||||
// NOTE: Funktioniert nicht mehr
|
||||
async () => {
|
||||
const result = await fetch(`/api/verbrauchsausweis?uid=${uid}`, {
|
||||
method: "GET",
|
||||
@@ -62,11 +63,16 @@
|
||||
|
||||
|
||||
async function ausweisAbschicken() {
|
||||
console.log(ausweis);
|
||||
|
||||
overlay.ariaHidden = "false";
|
||||
const response = await trpc.v1.verbrauchsausweisWohnen[2016].erstellen.mutate({
|
||||
const response = await client.v1.verbrauchsausweisWohnen[2016].erstellen.mutate({
|
||||
...ausweis,
|
||||
gebaeude_stammdaten: gebaeude
|
||||
})
|
||||
|
||||
console.log(response.uid);
|
||||
|
||||
}
|
||||
|
||||
let overlay: HTMLDivElement;
|
||||
|
||||
@@ -1,34 +1,18 @@
|
||||
<script lang="ts">
|
||||
import Cookies from "js-cookie"
|
||||
import { addNotification } from "@ibcornelsen/ui";
|
||||
import { client } from "src/trpc";
|
||||
|
||||
let email: string;
|
||||
let password: string;
|
||||
let passwort: string;
|
||||
|
||||
async function login() {
|
||||
const response = await fetch("/api/login", {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
email,
|
||||
password,
|
||||
}),
|
||||
});
|
||||
|
||||
const json = await response.json();
|
||||
|
||||
if (json.success == true) {
|
||||
const options = {
|
||||
domain: `.${window.location.hostname}`,
|
||||
path: "/",
|
||||
expires: json.data.expires
|
||||
}
|
||||
Cookies.set("token", json.data.token, options);
|
||||
Cookies.set("expires", json.data.expires, options);
|
||||
localStorage.setItem("token", json.data.token);
|
||||
localStorage.setItem("expires", json.data.expires);
|
||||
window.location.href = "/user";
|
||||
} else {
|
||||
const response = await client.v1.benutzer.tokenErneuern.query({
|
||||
email,
|
||||
passwort
|
||||
})
|
||||
|
||||
if (!response.token || !response.exp) {
|
||||
addNotification({
|
||||
message: "Ups...",
|
||||
subtext: "Das hat leider nicht geklappt, haben sie ihr Passwort und ihre Email Adresse richtig eingegeben?",
|
||||
@@ -36,7 +20,16 @@
|
||||
timeout: 6000,
|
||||
dismissable: true
|
||||
})
|
||||
return;
|
||||
}
|
||||
|
||||
const options = {
|
||||
domain: `.${window.location.hostname}`,
|
||||
path: "/",
|
||||
expires: response.exp
|
||||
}
|
||||
Cookies.set("token", response.token, options);
|
||||
window.location.href = "/user";
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -61,7 +54,7 @@
|
||||
type="password"
|
||||
placeholder="********"
|
||||
name="password"
|
||||
bind:value={password}
|
||||
bind:value={passwort}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,20 +1,28 @@
|
||||
<script lang="ts">
|
||||
import { addNotification } from "@ibcornelsen/ui";
|
||||
import Cookies from "js-cookie";
|
||||
import {client} from "src/trpc";
|
||||
|
||||
let passwort: string;
|
||||
let email: string;
|
||||
let vorname: string;
|
||||
let name: string;
|
||||
|
||||
async function login() {
|
||||
const response = await fetch("/api/user", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
passwort, email
|
||||
})
|
||||
const response = await client.v1.benutzer.erstellen.query({
|
||||
email,
|
||||
passwort,
|
||||
vorname,
|
||||
name
|
||||
})
|
||||
|
||||
const json = await response.json()
|
||||
|
||||
if (json.success == true) {
|
||||
if (response.token) {
|
||||
const options = {
|
||||
domain: `.${window.location.hostname}`,
|
||||
path: "/",
|
||||
expires: response.exp
|
||||
}
|
||||
Cookies.set("token", response.token, options);
|
||||
window.location.href = "/login";
|
||||
} else {
|
||||
addNotification({
|
||||
@@ -31,6 +39,28 @@
|
||||
<div style="width:50%;margin: 0 auto">
|
||||
<h1>Registrieren:</h1>
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="flex flex-row gap-4 w-full">
|
||||
<div class="w-1/2">
|
||||
<h4>Vorname</h4>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Vorname"
|
||||
class="px-2.5 py-1.5 rounded-lg border bg-gray-50"
|
||||
bind:value={vorname}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="w-1/2">
|
||||
<h4>Nachname</h4>
|
||||
<input
|
||||
type="text"
|
||||
placeholder="Nachname"
|
||||
class="px-2.5 py-1.5 rounded-lg border bg-gray-50"
|
||||
bind:value={name}
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h4>Email</h4>
|
||||
<input
|
||||
|
||||
42
src/pages/api/[trpc].ts
Normal file
42
src/pages/api/[trpc].ts
Normal file
@@ -0,0 +1,42 @@
|
||||
// NOTE: Öffentliche API benötigt OpenApiMeta. Das Package bräuchte momentan noch einen extra Server, deshalb nehmen wir es momentan noch nicht mit rein.
|
||||
//import { OpenApiMeta } from "trpc-openapi";
|
||||
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
||||
import { APIRoute } from "astro";
|
||||
import { t } from "../../lib/trpc/context";
|
||||
import { v1Router } from "#lib/trpc/procedures/v1";
|
||||
|
||||
export const appRouter = t.router({
|
||||
v1: v1Router,
|
||||
});
|
||||
|
||||
export const all: APIRoute = ({ request }) => {
|
||||
return fetchRequestHandler({
|
||||
req: request,
|
||||
endpoint: "/api",
|
||||
router: appRouter,
|
||||
createContext: async ({ req }) => {
|
||||
const ip = req.headers.get("x-forwarded-for");
|
||||
const authorization = req.headers.get("authorization") || null;
|
||||
|
||||
return {
|
||||
authorization,
|
||||
ip: ip?.toString() || "",
|
||||
req: req,
|
||||
};
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export function tRPCCaller(request: Request) {
|
||||
const { authorization } = {
|
||||
authorization: request.headers.get("authorization") || "",
|
||||
};
|
||||
const createCaller = t.createCallerFactory(appRouter);
|
||||
return createCaller({
|
||||
authorization,
|
||||
req: request,
|
||||
ip: request.headers.get("x-forwarded-for") || "",
|
||||
});
|
||||
}
|
||||
|
||||
export type AppRouter = typeof appRouter;
|
||||
@@ -1,34 +0,0 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, error } from "../../lib/APIResponse";
|
||||
import { validatePassword } from "../../lib/Password";
|
||||
import { User } from "../../lib/User";
|
||||
import moment from "moment";
|
||||
import { encodeToken } from "../../lib/JsonWebToken";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
|
||||
*/
|
||||
export const post: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
|
||||
if (!body.hasOwnProperty("email") || !body.hasOwnProperty("password")) {
|
||||
return MissingPropertyError(["email", "password"]);
|
||||
}
|
||||
|
||||
const user = await User.fromEmail(body.email);
|
||||
|
||||
if (!user) {
|
||||
return error(["Invalid email or password."]);
|
||||
}
|
||||
|
||||
// Validate Password
|
||||
if (!validatePassword(user.passwort, body.password)) {
|
||||
return error(["Invalid email or password."]);
|
||||
}
|
||||
|
||||
const expiry = moment().add(2, "days").unix();
|
||||
const token = encodeToken({ id: user.id, uid: user.uid, exp: expiry })
|
||||
|
||||
return success({ token, expires: expiry });
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, error } from "../../lib/APIResponse";
|
||||
import { validatePassword, hashPassword } from "../../lib/Password";
|
||||
import { User } from "../../lib/User";
|
||||
import moment from "moment";
|
||||
import { encodeToken } from "../../lib/JsonWebToken";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
|
||||
*/
|
||||
export const post: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
|
||||
if (!body.hasOwnProperty("email") || !body.hasOwnProperty("password")) {
|
||||
return MissingPropertyError(["email", "password"]);
|
||||
}
|
||||
|
||||
const user = await User.fromEmail(body.email);
|
||||
|
||||
if (!user) {
|
||||
return error(["Invalid email or password."]);
|
||||
}
|
||||
|
||||
// Validate Password
|
||||
if (!validatePassword(user.passwort, body.password)) {
|
||||
return error(["Invalid email or password."]);
|
||||
}
|
||||
|
||||
const expiry = moment().add(2, "days").unix();
|
||||
const token = encodeToken({ id: user.id, uid: user.uid, exp: expiry })
|
||||
|
||||
return success({ token, expires: expiry });
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// NOTE: Öffentliche API benötigt OpenApiMeta. Das Package bräuchte momentan noch einen extra Server, deshalb nehmen wir es momentan noch nicht mit rein.
|
||||
//import { OpenApiMeta } from "trpc-openapi";
|
||||
import { fetchRequestHandler } from "@trpc/server/adapters/fetch";
|
||||
import { APIRoute } from "astro";
|
||||
import { t } from "./context";
|
||||
import { v1Router } from "./procedures/v1";
|
||||
|
||||
export const AppRouter = t.router({
|
||||
v1: v1Router,
|
||||
})
|
||||
|
||||
export const all: APIRoute = ({ request }) => {
|
||||
console.log(request);
|
||||
|
||||
return fetchRequestHandler({
|
||||
req: request,
|
||||
endpoint: "/api/trpc",
|
||||
router: AppRouter,
|
||||
createContext: async ({ req }) => {
|
||||
return { uid: req.headers.get("X-Session") ?? undefined };
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
export function tRPCCaller(request: Request) {
|
||||
const { uid } = { uid: request.headers.get("Authorization") || "" };
|
||||
const createCaller = t.createCallerFactory(AppRouter);
|
||||
return createCaller({ uid });
|
||||
}
|
||||
|
||||
export type AppRouter = typeof AppRouter;
|
||||
@@ -1,42 +0,0 @@
|
||||
import { z } from "zod";
|
||||
import { t } from "../../context";
|
||||
import { tRPCKlimafaktorenProcedure } from "./klimafaktoren";
|
||||
import { VerbrauchsausweisWohnen2016Erstellen } from "./verbrauchsausweis-wohnen/2016/erstellen";
|
||||
|
||||
const router = t.router;
|
||||
|
||||
export const v1Router = router({
|
||||
verbrauchsausweisWohnen: router({
|
||||
2016: router({
|
||||
erstellen: VerbrauchsausweisWohnen2016Erstellen
|
||||
}),
|
||||
2023: router({
|
||||
|
||||
})
|
||||
}),
|
||||
verbrauchsausweisGewerbe: router({
|
||||
2016: router({
|
||||
|
||||
}),
|
||||
2023: router({
|
||||
|
||||
})
|
||||
}),
|
||||
bedarfsausweisWohen: router({
|
||||
2016: router({
|
||||
|
||||
}),
|
||||
2023: router({
|
||||
|
||||
})
|
||||
}),
|
||||
klimafaktoren: tRPCKlimafaktorenProcedure,
|
||||
test: t.procedure.meta({
|
||||
openapi: {
|
||||
method: "GET",
|
||||
path: "/v1/test",
|
||||
}
|
||||
}).input(z.void({})).output(z.string()).query(async (opts) => {
|
||||
return "Hello World!";
|
||||
})
|
||||
})
|
||||
@@ -1,50 +0,0 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, MissingEntityError, ActionFailedError, InvalidDataError, error } from "../../lib/APIResponse";
|
||||
import { User } from "../../lib/User";
|
||||
import { UserRegisterValidator, UserType } from "../../lib/User/type";
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
|
||||
*/
|
||||
export const get: APIRoute = async ({ request }) => {
|
||||
const body = await request.json();
|
||||
|
||||
if (!body.hasOwnProperty("uid")) {
|
||||
return MissingPropertyError(["uid"]);
|
||||
}
|
||||
|
||||
const user = User.fromUID(body.uid);
|
||||
|
||||
if (!user) {
|
||||
return MissingEntityError("user");
|
||||
}
|
||||
|
||||
return success(user);
|
||||
}
|
||||
|
||||
export const put: APIRoute = async ({ request }) => {
|
||||
const body: z.infer<typeof UserRegisterValidator> = await request.json();
|
||||
|
||||
const validate = UserRegisterValidator.safeParse(body);
|
||||
|
||||
if (validate.success == false) {
|
||||
return InvalidDataError(validate.error);
|
||||
}
|
||||
|
||||
const user = await User.fromEmail(body.email);
|
||||
|
||||
if (user) {
|
||||
return error(["Diese Email Adresse wird bereits verwendet."]);
|
||||
}
|
||||
|
||||
const result = await User.create(body as UserType);
|
||||
|
||||
if (!result) {
|
||||
return ActionFailedError();
|
||||
}
|
||||
|
||||
return success({ uid: result.uid, id: result.id });
|
||||
}
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
import type { APIRoute } from "astro";
|
||||
import { success, MissingPropertyError, MissingEntityError, error } from "../../lib/APIResponse";
|
||||
import { validateAuthorizationHeader } from "src/lib/server/Authorization";
|
||||
import { prisma } from "@ibcornelsen/database";
|
||||
|
||||
/**
|
||||
* Ruft einen Nutzer anhand seiner uid aus der Datenbank ab.
|
||||
* @param param0 Die Request mit dem request body. Dieser enthält entweder eine uid mit der der Benutzer identifiziert werden kann.
|
||||
*/
|
||||
export const get: APIRoute = async ({ request }) => {
|
||||
const user = await validateAuthorizationHeader(request, ["Bearer", "Basic"]);
|
||||
|
||||
if (!user) {
|
||||
return error(["Invalid authentication credentials!"]);
|
||||
}
|
||||
|
||||
const body = Object.fromEntries(new URLSearchParams(request.url.split("?")[1]))
|
||||
|
||||
let result;
|
||||
if (body.zip) {
|
||||
result = await prisma.postleitzahlen.findUnique({
|
||||
where: {
|
||||
plz: body.zip,
|
||||
},
|
||||
})
|
||||
} else if (body.city) {
|
||||
result = await prisma.postleitzahlen.findMany({
|
||||
where: {
|
||||
stadt: body.city,
|
||||
},
|
||||
})
|
||||
} else if (body.state) {
|
||||
result = await prisma.postleitzahlen.findMany({
|
||||
where: {
|
||||
bundesland: body.state,
|
||||
},
|
||||
})
|
||||
} else {
|
||||
return MissingPropertyError(["Either 'state', 'city' or 'zip' have to exist in request body."])
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
return MissingEntityError("zip info")
|
||||
}
|
||||
|
||||
return success(result);
|
||||
}
|
||||
@@ -1,28 +1,27 @@
|
||||
---
|
||||
import { changeLanguage } from "i18next";
|
||||
import moment from "moment";
|
||||
import { decodeToken } from "#lib/JsonWebToken";
|
||||
import { User } from "#lib/User";
|
||||
import UserLayout from "#layouts/UserLayout.astro";
|
||||
import AusweisCard from "#components/AusweisCard.svelte";
|
||||
import { Verbrauchsausweis } from "#lib/Ausweis/Verbrauchsausweis";
|
||||
|
||||
changeLanguage("de");
|
||||
import { User } from "#lib/User";
|
||||
import { tRPCCaller } from "../api/[trpc]";
|
||||
|
||||
const token = Astro.cookies.get("token").value;
|
||||
const expires = Astro.cookies.get("expires").number();
|
||||
const now = moment().unix();
|
||||
if (!token || now > expires) {
|
||||
Astro.cookies.delete("token");
|
||||
Astro.cookies.delete("expires");
|
||||
return Astro.redirect(`/login`);
|
||||
|
||||
if (!token) {
|
||||
Astro.cookies.delete("token");
|
||||
return Astro.redirect(`/login`);
|
||||
}
|
||||
const parsed = decodeToken(token);
|
||||
const user = await User.fromUID(parsed.uid);
|
||||
|
||||
const response = await tRPCCaller(Astro.request).v1.benutzer.tokenValidieren({ token });
|
||||
|
||||
if (!response.valid) {
|
||||
Astro.cookies.delete("token");
|
||||
return Astro.redirect(`/login`);
|
||||
}
|
||||
|
||||
const user = await User.fromUID(response.uid);
|
||||
|
||||
if (!user) {
|
||||
Astro.cookies.delete("token");
|
||||
Astro.cookies.delete("expires");
|
||||
return Astro.redirect(`/login`);
|
||||
Astro.cookies.delete("token");
|
||||
return Astro.redirect(`/login`);
|
||||
}
|
||||
---
|
||||
|
||||
@@ -31,8 +30,5 @@ if (!user) {
|
||||
|
||||
<h2>Ihre Ausweise</h2>
|
||||
<div class="grid grid-flow-row grid-cols-1 md:grid-cols-2 xl:grid-cols-3 gap-4">
|
||||
<AusweisCard client:load hidden={true} i={0} ausweis={new Verbrauchsausweis()}></AusweisCard>
|
||||
<AusweisCard client:load hidden={true} i={1} ausweis={new Verbrauchsausweis()}></AusweisCard>
|
||||
<AusweisCard client:load hidden={true} i={2} ausweis={new Verbrauchsausweis()}></AusweisCard>
|
||||
</div>
|
||||
</UserLayout>
|
||||
@@ -1,11 +1,11 @@
|
||||
import { createTRPCProxyClient, httpBatchLink } from '@trpc/client';
|
||||
import cookies from 'js-cookie';
|
||||
import type { AppRouter } from 'src/pages/api/trpc/[trpc]';
|
||||
import type { AppRouter } from 'src/pages/api/[trpc]';
|
||||
|
||||
export default createTRPCProxyClient<AppRouter>({
|
||||
export const client = createTRPCProxyClient<AppRouter>({
|
||||
links: [
|
||||
httpBatchLink({
|
||||
url: 'http://localhost:3000/api/trpc',
|
||||
url: 'http://localhost:3000/api',
|
||||
headers() {
|
||||
return {
|
||||
'Authorization': `Bearer ${cookies.get('uid')}`,
|
||||
|
||||
Reference in New Issue
Block a user