WIP on dev-moritz
This commit is contained in:
@@ -5,12 +5,13 @@ import tailwind from "@astrojs/tailwind";
|
||||
import node from "@astrojs/node";
|
||||
import mdx from "@astrojs/mdx";
|
||||
import dsv from "@rollup/plugin-dsv"
|
||||
import astroTypesafeAPI from "astro-typesafe-api"
|
||||
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [svelte(), tailwind(), mdx()],
|
||||
integrations: [svelte(), tailwind(), mdx(), astroTypesafeAPI()],
|
||||
outDir: "./dist",
|
||||
output: "server",
|
||||
vite: {
|
||||
|
||||
1
openapi.json
Normal file
1
openapi.json
Normal file
@@ -0,0 +1 @@
|
||||
{"openapi":"3.0.3","info":{"title":"Title","version":"1.0.0","description":""},"paths":{"[id]":{"patch":{"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{}}}}}}},"index":{"post":{"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{}}}}}}}}}
|
||||
29
package.json
29
package.json
@@ -25,40 +25,41 @@
|
||||
"@ibcornelsen/database": "link:@ibcornelsen/database",
|
||||
"@ibcornelsen/ui": "^0.0.2",
|
||||
"@mollie/api-client": "^3.7.0",
|
||||
"@pdfme/common": "^5.1.7",
|
||||
"@pdfme/generator": "^5.2.11",
|
||||
"@pdfme/ui": "^5.1.7",
|
||||
"@pdfme/common": "^5.2.16",
|
||||
"@pdfme/generator": "^5.2.16",
|
||||
"@pdfme/ui": "^5.2.16",
|
||||
"@trpc/client": "^10.45.2",
|
||||
"@trpc/server": "^10.45.2",
|
||||
"astro": "^4.16.10",
|
||||
"astro": "^4.16.18",
|
||||
"body-scroll-lock": "^4.0.0-beta.0",
|
||||
"buffer": "^6.0.3",
|
||||
"bun": "^1.1.34",
|
||||
"bun": "^1.1.45",
|
||||
"csvtojson": "^2.0.10",
|
||||
"express": "^4.21.1",
|
||||
"express": "^4.21.2",
|
||||
"flag-icons": "^6.15.0",
|
||||
"fontkit": "^2.0.4",
|
||||
"js-cookie": "^3.0.5",
|
||||
"js-interpolate": "^1.3.2",
|
||||
"jsonwebtoken": "^9.0.2",
|
||||
"moment": "^2.30.1",
|
||||
"moment-timezone": "^0.5.46",
|
||||
"pdf-lib": "^1.17.1",
|
||||
"postcss-nested": "^7.0.2",
|
||||
"radix-svelte-icons": "^1.0.0",
|
||||
"sass": "^1.80.6",
|
||||
"sass": "^1.83.4",
|
||||
"svelte": "^3.59.2",
|
||||
"svelte-dialogs": "^1.2.2",
|
||||
"svelte-preprocess": "^5.1.4",
|
||||
"svelte-ripple-action": "^1.0.6",
|
||||
"tailwindcss": "^3.4.14",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"trpc-openapi": "^1.2.0",
|
||||
"uuid": "^9.0.1",
|
||||
"zod": "^3.23.8"
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@faker-js/faker": "^8.4.1",
|
||||
"@rollup/plugin-dsv": "^3.0.5",
|
||||
"@tailwindcss/typography": "^0.5.15",
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@types/body-scroll-lock": "^3.1.2",
|
||||
"@types/express": "^5.0.0",
|
||||
"@types/fontkit": "^2.0.7",
|
||||
@@ -67,13 +68,13 @@
|
||||
"@typescript-eslint/eslint-plugin": "^5.62.0",
|
||||
"@typescript-eslint/parser": "^5.62.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"bun-types": "^1.1.34",
|
||||
"cypress": "^13.15.2",
|
||||
"bun-types": "^1.1.45",
|
||||
"cypress": "^13.17.0",
|
||||
"cypress-file-upload": "^5.0.8",
|
||||
"daisyui": "^4.12.14",
|
||||
"daisyui": "^4.12.23",
|
||||
"eslint": "~8.15.0",
|
||||
"eslint-config-prettier": "8.1.0",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss": "^8.5.1",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-nesting": "^13.0.1",
|
||||
"prettier": "^2.8.8",
|
||||
|
||||
16
src/astro-typesafe-api-caller.ts
Normal file
16
src/astro-typesafe-api-caller.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { createCallerFactory } from "astro-typesafe-api/server";
|
||||
import { type AstroGlobal } from "astro";
|
||||
|
||||
export const createCaller = createCallerFactory({
|
||||
"aufnahme/[id]": await import("../src/pages/api/aufnahme/[id].ts"),
|
||||
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
|
||||
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
|
||||
"auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"),
|
||||
"user/self": await import("../src/pages/api/user/self.ts"),
|
||||
"bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"),
|
||||
"objekt/[id]": await import("../src/pages/api/objekt/[id].ts"),
|
||||
"objekt": await import("../src/pages/api/objekt/index.ts"),
|
||||
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),
|
||||
"verbrauchsausweis-wohnen/[id]": await import("../src/pages/api/verbrauchsausweis-wohnen/[id].ts"),
|
||||
"verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"),
|
||||
})
|
||||
@@ -22,6 +22,8 @@ export async function verbrauchsausweisWohnenSpeichern(
|
||||
// Anscheinend wurde der Ausweis bereits erstellt und hat eine UID.
|
||||
// Jetzt müssen wir ihn nun nur noch abspeichern.
|
||||
try {
|
||||
await client.v1.objekt.speichern.mutate()
|
||||
|
||||
await client.v1.verbrauchsausweisWohnen[2016].speichern.mutate({
|
||||
...ausweis,
|
||||
gebaeude_aufnahme_allgemein: {
|
||||
@@ -41,7 +43,6 @@ export async function verbrauchsausweisWohnenSpeichern(
|
||||
|
||||
return { uid: ausweis.uid, gebaeude_uid: gebaeude.uid, gebaeude_aufnahme_uid: gebaeude_aufnahme_allgemein.uid };
|
||||
} catch (e) {
|
||||
// TODO: Ticket mit Fehldermeldung abschicken.
|
||||
}
|
||||
} else {
|
||||
// Wir speichern den Ausweis ab und leiten auf die "ausweis-gespeichert" Seite weiter.
|
||||
@@ -69,7 +70,6 @@ export async function verbrauchsausweisWohnenSpeichern(
|
||||
ausweis,
|
||||
}),
|
||||
});
|
||||
// TODO: Ticket mit Fehldermeldung abschicken.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
|
||||
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
//import Label from "#components/Label.svelte";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
import HeizungImage from "./HeizungImage.svelte";
|
||||
import AusweisPreviewContainer from "./AusweisPreviewContainer.svelte";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
import ZipSearch from "#components/PlzSuche.svelte";
|
||||
import { Enums } from "@ibcornelsen/database/client"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
export let gebaeude_aufnahme_allgemein: GebaeudeAufnahmeClient;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
|
||||
export let checked: boolean | null | undefined;
|
||||
export let name: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
import FensterImage from "./FensterImage.svelte";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
import HeizungImage from "./HeizungImage.svelte";
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
import DaemmungImage from "./DaemmungImage.svelte";
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<script lang="ts">
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import Verbrauchslabel from "#labels/VerbrauchsLabel.svelte";
|
||||
import VerbrauchsHelpLabel from "#labels/VerbrauchsHelpLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
import Verbrauchslabel from "#components/labels/VerbrauchsLabel.svelte";
|
||||
import VerbrauchsHelpLabel from "#components/labels/VerbrauchsHelpLabel.svelte";
|
||||
|
||||
import Label from "../Label.svelte";
|
||||
|
||||
@@ -44,12 +44,12 @@
|
||||
];
|
||||
|
||||
const startDate = moment(
|
||||
ausweis.gebaeude_aufnahme_allgemein.erstellungsdatum || Date.now()
|
||||
ausweis.aufnahme.erstellungsdatum || Date.now()
|
||||
)
|
||||
.subtract(4, "years")
|
||||
.subtract(6, "months");
|
||||
const endDate = moment(
|
||||
ausweis.gebaeude_aufnahme_allgemein.erstellungsdatum || Date.now()
|
||||
ausweis.aufnahme.erstellungsdatum || Date.now()
|
||||
).subtract(3, "years");
|
||||
|
||||
for (let m = moment(startDate); m.isBefore(endDate); m.add(1, "month")) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
|
||||
import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#labels/InputLabel.svelte";
|
||||
import HelpLabel from "#components/labels/HelpLabel.svelte";
|
||||
import Inputlabel from "#components/labels/InputLabel.svelte";
|
||||
|
||||
export let ausweis;
|
||||
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { get_current_component } from "svelte/internal";
|
||||
|
||||
const component = get_current_component();
|
||||
|
||||
export let image: string;
|
||||
export let name: string;
|
||||
export let description: string;
|
||||
@@ -25,10 +21,6 @@
|
||||
<div class="join">
|
||||
<button class="p-3.5 border rounded-lg" disabled={!removable && quantity == 1} on:click={() => {
|
||||
quantity--
|
||||
|
||||
if ((quantity == 0) && removable) {
|
||||
component.$destroy();
|
||||
}
|
||||
}}>-</button>
|
||||
<button class="p-3.5 border rounded-lg">{quantity}</button>
|
||||
<button class="p-3.5 border rounded-lg" disabled={quantity <= maxQuantity} on:click={() => quantity++}>+</button>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import HeaderLogin from "#header/HeaderLogin.svelte";
|
||||
import HeaderLogin from "#components/design/header/HeaderLogin.svelte";
|
||||
---
|
||||
|
||||
<header id="header">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
import HeaderLogin from "#header/HeaderLogin.svelte";
|
||||
import HeaderLogin from "#components/design/header/HeaderLogin.svelte";
|
||||
---
|
||||
|
||||
<header id="header">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { loginClient } from "#lib/login";
|
||||
import { loginClient } from "#lib/login.js";
|
||||
import { CrossCircled } from "radix-svelte-icons";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import CardNavigation from "#sidebarCards/cardNavigation.svelte";
|
||||
import CardPriceiInfo from "#sidebarCards/cardPriceiInfo.svelte";
|
||||
import CardProduktSidebar from "#sidebarCards/CardProduktSidebar.svelte";
|
||||
import CardNavigation from "#components/design/sidebars/cards/cardNavigation.svelte";
|
||||
import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.svelte";
|
||||
import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte";
|
||||
|
||||
import { PRICES } from "#lib/constants";
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import CardContact from "#sidebarCards/cardContact.svelte";
|
||||
import CardPriceiInfo from "#sidebarCards/cardPriceiInfo.svelte";
|
||||
import CardProduktSidebar from "#sidebarCards/CardProduktSidebar.svelte";
|
||||
import CardContact from "#components/design/sidebars/cards/cardContact.svelte";
|
||||
import CardPriceiInfo from "#components/design/sidebars/cards/cardPriceiInfo.svelte";
|
||||
import CardProduktSidebar from "#components/design/sidebars/cards/CardProduktSidebar.svelte";
|
||||
|
||||
import { PRICES } from "#lib/constants";
|
||||
---
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
---
|
||||
import Login from "#sidebarCards/cardlogin_1.svelte";
|
||||
import Contact from "#sidebarCards/cardcontact.svelte";
|
||||
import Review from "#sidebarCards/cardreview.svelte";
|
||||
import VApromo from "#sidebarCards/cardVApromo.svelte";
|
||||
import VAGpromo from "#sidebarCards/cardVAGpromo.svelte";
|
||||
import BApromo from "#sidebarCards/cardBApromo.svelte";
|
||||
import BAGpromo from "#sidebarCards/cardBAGpromo.svelte";
|
||||
import Login from "#components/design/sidebars/cards/cardlogin_1.svelte";
|
||||
import Contact from "#components/design/sidebars/cards/cardcontact.svelte";
|
||||
import Review from "#components/design/sidebars/cards/cardreview.svelte";
|
||||
import VApromo from "#components/design/sidebars/cards/cardVApromo.svelte";
|
||||
import VAGpromo from "#components/design/sidebars/cards/cardVAGpromo.svelte";
|
||||
import BApromo from "#components/design/sidebars/cards/cardBApromo.svelte";
|
||||
import BAGpromo from "#components/design/sidebars/cards/cardBAGpromo.svelte";
|
||||
---
|
||||
|
||||
<div class="hidden
|
||||
|
||||
4
src/env.d.ts
vendored
4
src/env.d.ts
vendored
@@ -1,7 +1,11 @@
|
||||
/// <reference path="../.astro/types.d.ts" />
|
||||
/// <reference types="astro/client" />
|
||||
/// <reference types="../.astro/astro-typesafe-api.d.ts" />
|
||||
|
||||
|
||||
/// <reference path="../.astro-i18n/generated.d.ts" />
|
||||
/// <reference path="../.astro/astro-typesafe-api.d.ts" />
|
||||
|
||||
|
||||
declare module "*.csv" {
|
||||
export default <{ [key: string]: any }>Array;
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
import "../style/global.css";
|
||||
import "../style/formular.css";
|
||||
import "../../svelte-dialogs.config"
|
||||
import Header from "#header/AusweisHeader.astro";
|
||||
import Footer from "#footer/Footer.astro";
|
||||
import SidebarLeft from "#sidebarLeft/SidebarLeft.astro";
|
||||
import Header from "#components/design/header/AusweisHeader.astro";
|
||||
import Footer from "#components/design/footer/Footer.astro";
|
||||
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro";
|
||||
import { NotificationWrapper } from "@ibcornelsen/ui";
|
||||
|
||||
export interface Props {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
import "../style/global.css";
|
||||
import "../../svelte-dialogs.config"
|
||||
import Header from "#header/Header.astro";
|
||||
import Footer from "#footer/Footer.astro";
|
||||
import SidebarLeft from "#sidebarLeft/SidebarLeft.astro";
|
||||
import SidebarRight from "#sidebarRight/SidebarRight.astro";
|
||||
import Header from "#components/design/header/Header.astro";
|
||||
import Footer from "#components/design/footer/Footer.astro";
|
||||
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro";
|
||||
import SidebarRight from "#components/design/sidebars/right/SidebarRight.astro";
|
||||
import { NotificationWrapper } from "@ibcornelsen/ui";
|
||||
|
||||
export interface Props {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
import "../style/global.css";
|
||||
import "../../svelte-dialogs.config"
|
||||
import Header from "#header/Header_1.astro";
|
||||
import Footer from "#footer/Footer.astro";
|
||||
import SidebarLeft from "#sidebarLeft/SidebarLeft.astro";
|
||||
import SidebarRight from "#sidebarRight/SidebarRight_1.astro";
|
||||
import Header from "#components/design/header/Header_1.astro";
|
||||
import Footer from "#components/design/footer/Footer.astro";
|
||||
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro";
|
||||
import SidebarRight from "#components/design/sidebars/right/SidebarRight_1.astro";
|
||||
import { NotificationWrapper } from "@ibcornelsen/ui";
|
||||
|
||||
export interface Props {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
---
|
||||
import "../style/global.css";
|
||||
import "../../svelte-dialogs.config"
|
||||
import Header from "#header/Header.astro";
|
||||
import Footer from "#footer/Footer.astro";
|
||||
import SidebarLeft from "#sidebarLeft/SidebarLeft.astro";
|
||||
import SidebarRight from "#sidebarRight/SidebarRight.astro";
|
||||
import Header from "#components/design/header/Header.astro";
|
||||
import Footer from "#components/design/footer/Footer.astro";
|
||||
import SidebarLeft from "#components/design/sidebars/left/SidebarLeft.astro";
|
||||
import SidebarRight from "#components/design/sidebars/right/SidebarRight.astro";
|
||||
import { NotificationWrapper } from "@ibcornelsen/ui";
|
||||
|
||||
export interface Props {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { BedarfsausweisWohnenClient, GebaeudeAufnahmeClient } from "#components/Ausweis/types.js";
|
||||
import { berechnungNutzenergiebedarfTrinkwasser } from "./BerechnungNutzenergiebedarfTrinkwarmwasser.js";
|
||||
import { berechnungNutzenergiebedarfTrinkwarmwasser } from "./BerechnungNutzenergiebedarfTrinkwarmwasser.js";
|
||||
import { FixedLengthArray } from "./types.js";
|
||||
|
||||
export function berechnungWaermequellenAusAnlagentechnikTrinkwasser(ausweis: BedarfsausweisWohnenClient, gebaeude_aufnahme: GebaeudeAufnahmeClient) {
|
||||
const trinkwasserWaermebedarf = berechnungNutzenergiebedarfTrinkwasser(ausweis, gebaeude_aufnahme);
|
||||
const trinkwasserWaermebedarf = berechnungNutzenergiebedarfTrinkwarmwasser(ausweis, gebaeude_aufnahme);
|
||||
|
||||
const result = new Array(12).fill(0) as unknown as FixedLengthArray<number, 12>
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// Funktion zur Berechnung der Bilanzinnentemperatur aus Tabelle 8 EFH oder Tabelle 10 MFH
|
||||
|
||||
import { cubicSplineInterpolation, nevillePolynomialInterpolation } from "js-interpolate";
|
||||
import { any } from "node_modules/cypress/types/bluebird/index.js";
|
||||
import { cubicSplineInterpolation } from "js-interpolate";
|
||||
|
||||
// aus Eingabeformular
|
||||
let wohneinheiten = 3;
|
||||
|
||||
22
src/lib/auth/token.ts
Normal file
22
src/lib/auth/token.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import jwt from "jsonwebtoken";
|
||||
|
||||
export enum TokenType {
|
||||
Refresh,
|
||||
Access,
|
||||
Reset
|
||||
}
|
||||
|
||||
export type TokenData = { uid: string, typ: TokenType, exp: number }
|
||||
|
||||
export function encodeToken(data: TokenData) {
|
||||
const token = jwt.sign(data, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4", {
|
||||
algorithm: "HS256"
|
||||
});
|
||||
return token;
|
||||
}
|
||||
|
||||
export function decodeToken(token: string): Partial<TokenData> {
|
||||
return jwt.verify(token, "yIvbgS$k7Bfc+mpV%TWDZAhje9#uJad4", {
|
||||
algorithms: ["HS256"]
|
||||
}) as Partial<TokenData>;
|
||||
}
|
||||
@@ -1,12 +1,10 @@
|
||||
import { AppRouter } from "@ibcornelsen/api";
|
||||
import { inferProcedureOutput } from "@trpc/server";
|
||||
import Cookies from "js-cookie";
|
||||
import { client } from "src/trpc"
|
||||
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "./constants";
|
||||
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "./constants.js";
|
||||
import { API, api, inferOutput } from "astro-typesafe-api/client";
|
||||
|
||||
export async function loginClient(email: string, passwort: string): Promise<inferProcedureOutput<AppRouter["v1"]["benutzer"]["getRefreshToken"]> | null> {
|
||||
export async function loginClient(email: string, passwort: string): Promise<inferOutput<API["auth"]["refresh-token"]["GET"]> | null> {
|
||||
try {
|
||||
const response = await client.v1.benutzer.getRefreshToken.query({
|
||||
const response = await api.auth["refresh-token"].GET.fetch({
|
||||
email,
|
||||
passwort
|
||||
})
|
||||
|
||||
81
src/lib/middleware/authorization.ts
Normal file
81
src/lib/middleware/authorization.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { decodeToken } from "#lib/auth/token.js";
|
||||
import { hashPassword } from "#lib/password.js";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { APIError, TypesafeAPIContextWithRequest } from "astro-typesafe-api/server";
|
||||
|
||||
export async function authorizationMiddleware(input: any, context: TypesafeAPIContextWithRequest<any>) {
|
||||
const authorization: string | undefined = context.request.headers.get("Authorization");
|
||||
|
||||
if (!context.request.headers.has("Authorization") || !authorization) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Request is missing an 'Authorization' header."
|
||||
})
|
||||
}
|
||||
|
||||
if (authorization.startsWith("Basic")) {
|
||||
const payload = btoa(authorization.split(" ")[1]).split(":");
|
||||
|
||||
if (payload.length !== 2) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Malformed 'Authorization' header."
|
||||
})
|
||||
}
|
||||
|
||||
const [email, password] = payload;
|
||||
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
email
|
||||
}
|
||||
})
|
||||
|
||||
if (!user || user.passwort !== hashPassword(password)) {
|
||||
throw new APIError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Unknown combination of email and password."
|
||||
})
|
||||
}
|
||||
|
||||
return user;
|
||||
} else if (authorization.startsWith("Bearer")) {
|
||||
const token = authorization.split(" ")[1]
|
||||
|
||||
if (!token) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Malformed 'Authorization' header."
|
||||
})
|
||||
}
|
||||
|
||||
const payload = decodeToken(token)
|
||||
|
||||
if ((payload.exp || 0) < Date.now()) {
|
||||
throw new APIError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Access Token has expired."
|
||||
})
|
||||
}
|
||||
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
uid: payload.uid
|
||||
}
|
||||
})
|
||||
|
||||
if (!user) {
|
||||
throw new APIError({
|
||||
code: "UNAUTHORIZED",
|
||||
message: "Invalid Bearer Token."
|
||||
})
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Invalid authorization method in 'Authorization' header."
|
||||
})
|
||||
}
|
||||
19
src/lib/password.ts
Normal file
19
src/lib/password.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import * as crypto from "crypto";
|
||||
|
||||
export function hashPassword(password: string): string {
|
||||
const salt = crypto.randomBytes(16).toString("hex");
|
||||
const hash = hashWithGivenSalt(password, salt) + salt;
|
||||
return hash;
|
||||
}
|
||||
|
||||
export function hashWithGivenSalt(password: string, salt: string): string {
|
||||
const hash = crypto.scryptSync(password, salt, 32).toString("hex");
|
||||
return hash;
|
||||
}
|
||||
|
||||
export function validatePassword(known: string, unknown: string): boolean {
|
||||
const salt = known.slice(64);
|
||||
const originalPasswordHash = known.slice(0, 64);
|
||||
const currentPasswordHash = hashWithGivenSalt(unknown, salt)
|
||||
return originalPasswordHash == currentPasswordHash;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { PDFElement } from './PDFElement.js';
|
||||
export class Checkbox extends PDFElement {
|
||||
private borderWidth: number = 1;
|
||||
|
||||
constructor(protected _width: number, protected _height: number) {
|
||||
constructor(protected _width: number, protected _height: number, public checked: boolean = false) {
|
||||
super();
|
||||
}
|
||||
|
||||
@@ -22,5 +22,15 @@ export class Checkbox extends PDFElement {
|
||||
borderColor: rgb(0, 0, 0),
|
||||
borderWidth: this.borderWidth
|
||||
});
|
||||
|
||||
if (this.checked) {
|
||||
page.drawSvgPath(`<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M20.285 2l-11.285 11.567-5.286-5.011-3.714 3.716 9 8.728 15-15.285z"/></svg>`, {
|
||||
x: x + this.borderWidth,
|
||||
y: y - this.borderWidth * 1.5,
|
||||
borderColor: rgb(0,0,0),
|
||||
color: rgb(0,0,0),
|
||||
scale: this._width / 24
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ export function xml2pdf(xml: string, fonts: Record<string, PDFFont> & { "default
|
||||
throw new Error("Missing height or width property in Checkbox creation.")
|
||||
}
|
||||
|
||||
const checkbox = new Checkbox(parseFloat(child.attributes.width), parseFloat(child.attributes.height))
|
||||
const checkbox = new Checkbox(parseFloat(child.attributes.width), parseFloat(child.attributes.height), (child.attributes.hasOwnProperty("checked") && child.attributes.checked !== "false") || false)
|
||||
|
||||
parent.addChild(checkbox);
|
||||
} else if (child.tagName === "layout") {
|
||||
|
||||
@@ -1,176 +0,0 @@
|
||||
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
|
||||
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
|
||||
import * as fs from "fs"
|
||||
import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib";
|
||||
import { checkbox, flex, text } from "./elements/index.js";
|
||||
import { xml2pdf } from "./elements/xml2pdf.js";
|
||||
|
||||
/* -------------------------------- Pdf Tools ------------------------------- */
|
||||
|
||||
export async function pdfDatenblatt(ausweis: VerbrauchsausweisWohnenClient) {
|
||||
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("./templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64");
|
||||
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
|
||||
const pages = pdf.getPages()
|
||||
|
||||
// const template = VerbrauchsausweisWohnen2016Template as Template;
|
||||
|
||||
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis);
|
||||
|
||||
const height = pages[0].getHeight()
|
||||
const width = pages[0].getWidth()
|
||||
|
||||
const font = await pdf.embedFont(StandardFonts.Helvetica)
|
||||
const bold = await pdf.embedFont(StandardFonts.HelveticaBold)
|
||||
|
||||
const form = pdf.getForm()
|
||||
form.updateFieldAppearances(font)
|
||||
|
||||
const marginX = 45;
|
||||
const marginY = 150;
|
||||
|
||||
const benutzer: typeof ausweis.benutzer = ausweis.benutzer || {
|
||||
vorname: "Max",
|
||||
name: "Mustermann",
|
||||
adresse: "Musterstraße 123",
|
||||
plz: "12345",
|
||||
ort: "Beispielhausen"
|
||||
};
|
||||
|
||||
const layout = xml2pdf(`<layout height="${pages[0].getHeight()}" width="${pages[0].getWidth()}" marginTop="150" marginLeft="45" marginRight="45">
|
||||
<text size="12" lineHeight="14">${benutzer.vorname} ${benutzer.name}</text>
|
||||
<text size="12" lineHeight="14">${benutzer.adresse}</text>
|
||||
<text size="12" lineHeight="14">${benutzer.plz} ${benutzer.ort}</text>
|
||||
<flex direction="row" justify="space-between" marginTop="55" width="${pages[0].getWidth() - 90}">
|
||||
<text size="12" font="bold">Datenblatt Energieausweis</text>
|
||||
<text size="12">Ausweis ID: ${ausweis.uid}</text>
|
||||
</flex>
|
||||
<text size="12" lineHeight="14" font="bold" marginTop="10">Gebäudedaten</text>
|
||||
<text size="12" lineHeight="14">Adresse: ${ausweis.gebaeude_aufnahme_allgemein.adresse}, ${ausweis.gebaeude_aufnahme_allgemein.plz} ${ausweis.gebaeude_aufnahme_allgemein.ort}</text>
|
||||
|
||||
<flex direction="row" justify="space-between" width="${pages[0].getWidth() - 90}" marginTop="25">
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8"></checkbox>
|
||||
<text size="12">Neubau</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8"></checkbox>
|
||||
<text size="12">Vermietung/Verkauf</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8"></checkbox>
|
||||
<text size="12">Modernisierung</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8"></checkbox>
|
||||
<text size="12">Sonstiges</text>
|
||||
</flex>
|
||||
</flex>
|
||||
|
||||
<flex direction="row" marginTop="25" gap="15">
|
||||
<flex direction="column" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Gebäudetyp:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.gebaeudetyp}</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Wohnfläche:</text>
|
||||
<text size="12" lineHeight="14">DIN Wohnfläche innen ${ausweis.gebaeude_aufnahme_allgemein.flaeche} m²</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Leerstand:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.leerstand || 0}%</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Wohnungen:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.einheiten}</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Dachgeschoss:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.dachgeschoss}</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(pages[0].getWidth() - 90) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Keller:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.keller}</text>
|
||||
</flex>
|
||||
</flex>
|
||||
</flex>
|
||||
</layout>`, {
|
||||
"default": font,
|
||||
bold: bold
|
||||
})
|
||||
|
||||
layout.draw(pages[0], 0, pages[0].getHeight())
|
||||
|
||||
// const containerWidth = width - marginX;
|
||||
|
||||
// const layout = flex([
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Neubau", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// }),
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Vermietung/Verkauf", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// }),
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Modernisierung", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// }),
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Sonstiges", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "space-between",
|
||||
// gap: 15,
|
||||
// x: marginX,
|
||||
// y: height - marginY - 165,
|
||||
// height: 12,
|
||||
// width: containerWidth
|
||||
// })
|
||||
|
||||
// layout.draw(pages[0])
|
||||
|
||||
// pdf.getForm().flatten()
|
||||
|
||||
return pdf.save();
|
||||
}
|
||||
366
src/lib/pdf/pdfDatenblattVerbrauchsausweisWohnen.ts
Normal file
366
src/lib/pdf/pdfDatenblattVerbrauchsausweisWohnen.ts
Normal file
@@ -0,0 +1,366 @@
|
||||
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types.js";
|
||||
import { endEnergieVerbrauchVerbrauchsausweis_2016 } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016.js";
|
||||
import * as fs from "fs"
|
||||
import { PDFDocument, rgb, StandardFonts, TextAlignment } from "pdf-lib";
|
||||
import { checkbox, flex, text } from "./elements/index.js";
|
||||
import { xml2pdf } from "./elements/xml2pdf.js";
|
||||
import moment from "moment";
|
||||
import { Heizungsstatus } from "@ibcornelsen/database/server";
|
||||
|
||||
/* -------------------------------- Pdf Tools ------------------------------- */
|
||||
|
||||
export async function pdfDatenblattVerbrauchsausweisWohnen(ausweis: VerbrauchsausweisWohnenClient) {
|
||||
const VerbrauchsausweisWohnenGEG2024PDF = fs.readFileSync(new URL("./templates/Leerseite_Datenblatt.pdf", import.meta.url), "base64");
|
||||
const pdf = await PDFDocument.load(VerbrauchsausweisWohnenGEG2024PDF)
|
||||
const pages = pdf.getPages()
|
||||
|
||||
// const template = VerbrauchsausweisWohnen2016Template as Template;
|
||||
|
||||
const berechnungen = await endEnergieVerbrauchVerbrauchsausweis_2016(ausweis);
|
||||
|
||||
const height = pages[0].getHeight()
|
||||
const width = pages[0].getWidth()
|
||||
|
||||
const font = await pdf.embedFont(StandardFonts.Helvetica)
|
||||
const bold = await pdf.embedFont(StandardFonts.HelveticaBold)
|
||||
|
||||
const form = pdf.getForm()
|
||||
form.updateFieldAppearances(font)
|
||||
|
||||
const marginX = 60;
|
||||
const marginY = 150;
|
||||
|
||||
const benutzer: typeof ausweis.benutzer = ausweis.benutzer || {
|
||||
vorname: "Max",
|
||||
name: "Mustermann",
|
||||
adresse: "Musterstraße 123",
|
||||
plz: "12345",
|
||||
ort: "Beispielhausen"
|
||||
};
|
||||
|
||||
const translateHeizungsstatus: Record<Heizungsstatus, string> = {
|
||||
BEHEIZT: "beheizt",
|
||||
NICHT_VORHANDEN: "nicht vorhanden",
|
||||
UNBEHEIZT: "unbeheizt"
|
||||
}
|
||||
|
||||
const innerWidth = pages[0].getWidth() - marginX * 2;
|
||||
|
||||
const layout = xml2pdf(`<layout height="${pages[0].getHeight()}" width="${pages[0].getWidth()}" marginTop="150" marginLeft="${marginX}" marginRight="${marginX}">
|
||||
<text size="12" lineHeight="14">${benutzer.vorname} ${benutzer.name}</text>
|
||||
<text size="12" lineHeight="14">${benutzer.adresse}</text>
|
||||
<text size="12" lineHeight="14">${benutzer.plz} ${benutzer.ort}</text>
|
||||
<flex direction="row" justify="space-between" marginTop="55" width="${innerWidth}">
|
||||
<text size="12" font="bold">Datenblatt Energieausweis</text>
|
||||
<text size="12">Ausweis ID: ${ausweis.uid}</text>
|
||||
</flex>
|
||||
<text size="12" lineHeight="14" font="bold" marginTop="10">Gebäudedaten</text>
|
||||
<text size="12" lineHeight="14">Adresse: ${ausweis.gebaeude_aufnahme_allgemein.adresse}, ${ausweis.gebaeude_aufnahme_allgemein.plz} ${ausweis.gebaeude_aufnahme_allgemein.ort}</text>
|
||||
|
||||
<flex direction="row" justify="space-between" width="${innerWidth}" marginTop="25">
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.ausstellgrund === "Neubau"}"></checkbox>
|
||||
<text size="12">Neubau</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.ausstellgrund === "Verkauf" || ausweis.ausstellgrund === "Vermietung"}"></checkbox>
|
||||
<text size="12">Vermietung/Verkauf</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.ausstellgrund === "Modernisierung"}"></checkbox>
|
||||
<text size="12">Modernisierung</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="5" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.ausstellgrund === "Sonstiges"}"></checkbox>
|
||||
<text size="12">Sonstiges</text>
|
||||
</flex>
|
||||
</flex>
|
||||
|
||||
<flex direction="row" marginTop="25" gap="15">
|
||||
<flex direction="column" width="${(innerWidth) / 2 - 7.5}">
|
||||
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Gebäudetyp:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.gebaeudetyp}</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Wohnfläche:</text>
|
||||
<text size="12" lineHeight="14">DIN Wohnfläche innen ${ausweis.gebaeude_aufnahme_allgemein.flaeche} m²</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Leerstand:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.leerstand || 0}%</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Wohnungen:</text>
|
||||
<text size="12" lineHeight="14">${ausweis.gebaeude_aufnahme_allgemein.einheiten}</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" width="${(innerWidth) / 2 - 7.5}">
|
||||
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Dachgeschoss:</text>
|
||||
<text size="12" lineHeight="14">${translateHeizungsstatus[ausweis.gebaeude_aufnahme_allgemein.dachgeschoss || "NICHT_VORHANDEN"]}</text>
|
||||
</flex>
|
||||
<flex direction="row" align="center" justify="space-between" width="${(innerWidth) / 2 - 7.5}">
|
||||
<text size="12" lineHeight="14">Keller:</text>
|
||||
<text size="12" lineHeight="14">${translateHeizungsstatus[ausweis.gebaeude_aufnahme_allgemein.keller || "NICHT_VORHANDEN"]}</text>
|
||||
</flex>
|
||||
</flex>
|
||||
</flex>
|
||||
|
||||
<text size="12" lineHeight="14" font="bold" marginTop="25">Verbrauch</text>
|
||||
|
||||
<flex direction="row" justify="space-between" align="center" width="${(innerWidth)}" marginTop="5">
|
||||
<flex direction="column" gap="4">
|
||||
<text></text>
|
||||
<text></text>
|
||||
<text size="12">Von: ${moment(ausweis.startdatum).format("DD.MM.YYYY")}</text>
|
||||
<text size="12">Von: ${moment(ausweis.startdatum).add("1", "years").format("DD.MM.YYYY")}</text>
|
||||
<text size="12">Von: ${moment(ausweis.startdatum).add("2", "years").format("DD.MM.YYYY")}</text>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<text></text>
|
||||
<text></text>
|
||||
<text size="12">Bis: ${moment(ausweis.startdatum).add("1", "year").format("DD.MM.YYYY")}</text>
|
||||
<text size="12">Bis: ${moment(ausweis.startdatum).add("2", "years").format("DD.MM.YYYY")}</text>
|
||||
<text size="12">Bis: ${moment(ausweis.startdatum).add("3", "years").format("DD.MM.YYYY")}</text>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<text></text>
|
||||
<text size="12" font="bold">${ausweis.gebaeude_aufnahme_allgemein.brennstoff_1}</text>
|
||||
<text size="12">${ausweis.verbrauch_1} ${ausweis.einheit_1}</text>
|
||||
<text size="12">${ausweis.verbrauch_2} ${ausweis.einheit_1}</text>
|
||||
<text size="12">${ausweis.verbrauch_3} ${ausweis.einheit_1}</text>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<text size="12">zusätzliche Heizquelle</text>
|
||||
<text size="12" font="bold">${ausweis.gebaeude_aufnahme_allgemein.brennstoff_2 || ""}</text>
|
||||
<text size="12">${ausweis.verbrauch_4 || ""} ${ausweis.einheit_2 || ""}</text>
|
||||
<text size="12">${ausweis.verbrauch_5 || ""} ${ausweis.einheit_2 || ""}</text>
|
||||
<text size="12">${ausweis.verbrauch_6 || ""} ${ausweis.einheit_2 || ""}</text>
|
||||
</flex>
|
||||
</flex>
|
||||
|
||||
<text size="12" marginTop="5">Warmwasseranteil: ${ausweis.anteil_warmwasser_1}%</text>
|
||||
</layout>`, {
|
||||
"default": font,
|
||||
bold: bold
|
||||
})
|
||||
|
||||
const layoutPage2 = xml2pdf(`<layout height="${pages[1].getHeight()}" width="${pages[1].getWidth()}" marginTop="150" marginLeft="60" marginRight="60">
|
||||
<text size="12" font="bold">Stand der Technik:</text>
|
||||
<text size="12" marginTop="15">Heizungsanlage</text>
|
||||
<flex direction="row" justify="space-between" width="${pages[1].getWidth() - 120}" marginTop="15">
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.zentralheizung || false}"></checkbox>
|
||||
<text size="12">Zentralheizung</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.einzelofen || false}"></checkbox>
|
||||
<text size="12">Einzelöfen</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.durchlauf_erhitzer || false}"></checkbox>
|
||||
<text size="12">Durchlauferhitzer</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.standard_kessel || false}"></checkbox>
|
||||
<text size="12">Standardkessel</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.solarsystem_warmwasser || false}"></checkbox>
|
||||
<text size="12">Solarsystem für Warmwasser</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.waermepumpe || false}"></checkbox>
|
||||
<text size="12">Wärmepumpe</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.niedertemperatur_kessel || false}"></checkbox>
|
||||
<text size="12">Niedertemperaturkessel</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.brennwert_kessel || false}"></checkbox>
|
||||
<text size="12">Brennwertkessel</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.warmwasser_rohre_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Warmwasserrohre gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.heizungsrohre_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Heizungsrohre gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.zirkulation || false}"></checkbox>
|
||||
<text size="12">Zirkulation</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.raum_temperatur_regler || false}"></checkbox>
|
||||
<text size="12">Raumtemperaturregelung</text>
|
||||
</flex>
|
||||
</flex>
|
||||
</flex>
|
||||
<text size="12" marginTop="15">Fenster/Dachfenster/Türen</text>
|
||||
<flex direction="row" justify="space-between" width="${pages[1].getWidth() - 120}" marginTop="15">
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.einfach_verglasung || false}"></checkbox>
|
||||
<text size="12">Einfachglas</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.doppel_verglasung || false}"></checkbox>
|
||||
<text size="12">Doppelverglasung</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.isolier_verglasung || false}"></checkbox>
|
||||
<text size="12">Isolierverglasung</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${false}"></checkbox>
|
||||
<text size="12">Passivhausfenster</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.fenster_dicht || false}"></checkbox>
|
||||
<text size="12">Alle Fenster dicht</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.fenster_teilweise_undicht || false}"></checkbox>
|
||||
<text size="12">Fenster teilweise undicht</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.tueren_undicht || false}"></checkbox>
|
||||
<text size="12">Türen teilweise undicht</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.tueren_dicht || false}"></checkbox>
|
||||
<text size="12">Alle Türen dicht</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.rolllaeden_kaesten_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Rollladenkästen gedämmt</text>
|
||||
</flex>
|
||||
</flex>
|
||||
</flex>
|
||||
<text size="12" marginTop="15">Wärmedämmung</text>
|
||||
<flex direction="row" justify="space-between" width="${pages[1].getWidth() - 120}" marginTop="15">
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.keller_wand_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Kelleraußenwand gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.keller_decke_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Kellerdecke gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.aussenwand_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Außenwand gedämmt</text>
|
||||
</flex>
|
||||
</flex>
|
||||
<flex direction="column" gap="4">
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.dachgeschoss_min_12cm_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Dachgeschoss min. 12cm gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.dachgeschoss_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Dachgeschoss gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.oberste_geschossdecke_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Oberste Geschossdecke gedämmt</text>
|
||||
</flex>
|
||||
<flex direction="row" gap="4" align="center">
|
||||
<checkbox width="8" height="8" checked="${ausweis.gebaeude_aufnahme_allgemein.oberste_geschossdecke_min_12cm_gedaemmt || false}"></checkbox>
|
||||
<text size="12">Oberste Geschossdecke min. 12cm gedämmt</text>
|
||||
</flex>
|
||||
</flex>
|
||||
</flex>
|
||||
</layout>`, {
|
||||
"default": font,
|
||||
bold
|
||||
})
|
||||
|
||||
layout.draw(pages[0], 0, pages[0].getHeight())
|
||||
layoutPage2.draw(pages[1], 0, pages[1].getHeight())
|
||||
|
||||
// const containerWidth = width - marginX;
|
||||
|
||||
// const layout = flex([
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Neubau", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// }),
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Vermietung/Verkauf", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// }),
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Modernisierung", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// }),
|
||||
// flex([
|
||||
// checkbox(8, 8), text("Sonstiges", {
|
||||
// color: rgb(0,0,0),
|
||||
// font,
|
||||
// fontSize: 12
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "center",
|
||||
// gap: 5,
|
||||
// height: 12,
|
||||
// page: pages[0]
|
||||
// })
|
||||
// ], {
|
||||
// align: "center",
|
||||
// justify: "space-between",
|
||||
// gap: 15,
|
||||
// x: marginX,
|
||||
// y: height - marginY - 165,
|
||||
// height: 12,
|
||||
// width: containerWidth
|
||||
// })
|
||||
|
||||
// layout.draw(pages[0])
|
||||
|
||||
// pdf.getForm().flatten()
|
||||
|
||||
return pdf.save();
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { addNotification } from "@ibcornelsen/ui";
|
||||
import { CrossCircled } from "radix-svelte-icons";
|
||||
import {client} from "src/trpc";
|
||||
import {client} from "src/trpc.js";
|
||||
import { fade } from "svelte/transition";
|
||||
|
||||
let passwort: string;
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
<script lang="ts">
|
||||
import PerformanceScore from "#components/Ausweis/PerformanceScore.svelte";
|
||||
import ProgressBar from "#components/Ausweis/Progressbar.svelte";
|
||||
//import Hilfe from "#components/Ausweis/Hilfe.svelte";
|
||||
import { PRICES } from "#lib/constants";
|
||||
import Progressbar from "#components/Ausweis/Progressbar.svelte";
|
||||
import { PRICES } from "#lib/constants.js";
|
||||
|
||||
import Bereich from "#labels/Bereich.svelte";
|
||||
//import HelpLabel from "#labels/HelpLabel.svelte";
|
||||
//import Inputlabel from "#labels/InputLabel.svelte";
|
||||
//import Label from "#components/Label.svelte";
|
||||
import Bereich from "#components/labels/Bereich.svelte";
|
||||
|
||||
import ButtonSpaeterHilfe from "#components/Ausweis/ButtonSpaeterHilfe.svelte";
|
||||
import ButtonWeiterHilfe from "#components/Ausweis/ButtonWeiterHilfe.svelte";
|
||||
@@ -24,13 +20,10 @@
|
||||
import SanierungszustandWaermedammung from "#components/Ausweis/SanierungszustandWaermedammung.svelte";
|
||||
import AusweisPreviewContainer from "#components/Ausweis/AusweisPreviewContainer.svelte";
|
||||
|
||||
//import ZipSearch from "#components/PlzSuche.svelte";
|
||||
|
||||
import {
|
||||
RawNotificationWrapper,
|
||||
RawNotification,
|
||||
notifications,
|
||||
deleteNotification,
|
||||
} from "#components/Notifications/index.js";
|
||||
import { auditHeizungGebaeudeBaujahr } from "#components/Verbrauchsausweis/audits/HeizungGebaeudeBaujahr.js";
|
||||
import { auditHeizungJuengerDreiJahre } from "#components/Verbrauchsausweis/audits/HeizungJuengerDreiJahre.js";
|
||||
@@ -48,38 +41,33 @@
|
||||
import { auditVerbrauchAbweichung } from "#components/Verbrauchsausweis/audits/VerbrauchAbweichung.js";
|
||||
import { auditEndEnergie } from "#components/Verbrauchsausweis/audits/EndEnergie.js";
|
||||
import { auditWohnflaecheGroesserGesamtflaeche } from "#components/Verbrauchsausweis/audits/WohnflaecheGroesserGesamtflaeche.js";
|
||||
//import { Enums } from "@ibcornelsen/database/client"
|
||||
import Overlay from "#components/Overlay.svelte";
|
||||
import AusweisGespeichertModule from "#modules/VerbrauchsausweisWohnen/AusweisGespeichertModule.svelte";
|
||||
import {
|
||||
import type {
|
||||
VerbrauchsausweisWohnenClient,
|
||||
BenutzerClient,
|
||||
UploadedGebaeudeBild,
|
||||
} from "#components/Ausweis/types.js";
|
||||
import { verbrauchsausweisWohnenSpeichern } from "src/client/lib/verbrauchsausweisWohnenSpeichern.js";
|
||||
//import AusweisWeiter from "./AusweisWeiter.svelte";
|
||||
import { Enums } from "@ibcornelsen/database/client";
|
||||
import { OpenInNewWindow } from "radix-svelte-icons";
|
||||
|
||||
// TODO: Vom Server sollte ein volles Objekt kommen, dass alle Subobjekte enthält, weil es sonst zu Problemen führen kann
|
||||
// wenn gebaeude_aufnahme_allgemein oder gebaeude_stammdaten nicht existiert...
|
||||
export let ausweis: VerbrauchsausweisWohnenClient;
|
||||
export let user: BenutzerClient = {} as BenutzerClient;
|
||||
|
||||
export let Energieausweis = "Verbrauchsausweis Wohngebäude";
|
||||
|
||||
let gebaeude_aufnahme_allgemein = ausweis.gebaeude_aufnahme_allgemein || {};
|
||||
let gebaeude =
|
||||
ausweis.gebaeude_aufnahme_allgemein?.gebaeude_stammdaten || {};
|
||||
let aufnahme = ausweis.aufnahme || {};
|
||||
let objekt =
|
||||
ausweis.aufnahme?.objekt || {};
|
||||
let images: (UploadedGebaeudeBild & { base64?: string })[] =
|
||||
ausweis.gebaeude_aufnahme_allgemein?.gebaeude_stammdaten
|
||||
ausweis.aufnahme?.objekt
|
||||
?.gebaeude_bilder || [];
|
||||
|
||||
async function spaeterWeitermachen() {
|
||||
const result = await verbrauchsausweisWohnenSpeichern(
|
||||
ausweis,
|
||||
gebaeude,
|
||||
gebaeude_aufnahme_allgemein,
|
||||
objekt,
|
||||
aufnahme,
|
||||
images,
|
||||
user
|
||||
);
|
||||
@@ -88,8 +76,8 @@
|
||||
// Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
|
||||
// Sonst müsste er alles neu eingeben...
|
||||
ausweis.uid = result.uid;
|
||||
gebaeude.uid = result.gebaeude_uid;
|
||||
gebaeude_aufnahme_allgemein.uid = result.gebaeude_aufnahme_uid;
|
||||
objekt.uid = result.gebaeude_uid;
|
||||
aufnahme.uid = result.gebaeude_aufnahme_uid;
|
||||
window.history.pushState(
|
||||
{},
|
||||
"",
|
||||
@@ -100,35 +88,35 @@
|
||||
}
|
||||
|
||||
function automatischAusfüllen() {
|
||||
gebaeude_aufnahme_allgemein.baujahr_gebaeude = [1962];
|
||||
gebaeude_aufnahme_allgemein.baujahr_heizung = [1952];
|
||||
gebaeude_aufnahme_allgemein.saniert = true;
|
||||
gebaeude_aufnahme_allgemein.einheiten = 1;
|
||||
gebaeude_aufnahme_allgemein.gebaeudetyp = "Einfamilienhaus";
|
||||
gebaeude_aufnahme_allgemein.keller =
|
||||
aufnahme.baujahr_gebaeude = [1962];
|
||||
aufnahme.baujahr_heizung = [1952];
|
||||
aufnahme.saniert = true;
|
||||
aufnahme.einheiten = 1;
|
||||
aufnahme.gebaeudetyp = "Einfamilienhaus";
|
||||
aufnahme.keller =
|
||||
Enums.Heizungsstatus.NICHT_VORHANDEN;
|
||||
gebaeude_aufnahme_allgemein.dachgeschoss =
|
||||
aufnahme.dachgeschoss =
|
||||
Enums.Heizungsstatus.NICHT_VORHANDEN;
|
||||
gebaeude_aufnahme_allgemein.lueftung = "Fensterlüftung";
|
||||
gebaeude_aufnahme_allgemein.kuehlung = "1";
|
||||
aufnahme.lueftung = "Fensterlueftung";
|
||||
aufnahme.kuehlung = "1";
|
||||
ausweis.ausstellgrund = "Vermietung";
|
||||
ausweis.verbrauch_1 = 15000;
|
||||
ausweis.verbrauch_2 = 14000;
|
||||
ausweis.verbrauch_3 = 16000;
|
||||
gebaeude_aufnahme_allgemein.flaeche = 152;
|
||||
gebaeude_aufnahme_allgemein.nutzflaeche = 172;
|
||||
aufnahme.flaeche = 152;
|
||||
aufnahme.nutzflaeche = 172;
|
||||
ausweis.keller_beheizt = true;
|
||||
|
||||
gebaeude_aufnahme_allgemein.brennstoff_1 = "Erdgas H";
|
||||
aufnahme.brennstoff_1 = "Erdgas H";
|
||||
ausweis.einheit_1 = "kWh";
|
||||
ausweis.anteil_warmwasser_1 = 18;
|
||||
ausweis.startdatum = moment("01.01.2021").toDate();
|
||||
gebaeude_aufnahme_allgemein.plz = "21039";
|
||||
gebaeude_aufnahme_allgemein.ort = "Hamburg";
|
||||
gebaeude_aufnahme_allgemein.adresse = "Curslacker Deich 170";
|
||||
gebaeude_aufnahme_allgemein.gebaeudeteil = "Gesamtgebäude";
|
||||
objekt.plz = "21039";
|
||||
objekt.ort = "Hamburg";
|
||||
objekt.adresse = "Curslacker Deich 170";
|
||||
aufnahme.gebaeudeteil = "Gesamtgebäude";
|
||||
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
ausweis = ausweis;
|
||||
}
|
||||
|
||||
@@ -136,8 +124,8 @@
|
||||
if (e && e.preventDefault) e.preventDefault();
|
||||
const result = await verbrauchsausweisWohnenSpeichern(
|
||||
ausweis,
|
||||
gebaeude,
|
||||
gebaeude_aufnahme_allgemein,
|
||||
objekt,
|
||||
aufnahme,
|
||||
images,
|
||||
user
|
||||
);
|
||||
@@ -146,8 +134,8 @@
|
||||
// Falls der Nutzer zurück navigiert, sollte er wieder auf seinen Vorgang kommen.
|
||||
// Sonst müsste er alles neu eingeben...
|
||||
ausweis.uid = result.uid;
|
||||
gebaeude.uid = result.gebaeude_uid;
|
||||
gebaeude_aufnahme_allgemein.uid = result.gebaeude_aufnahme_uid;
|
||||
objekt.uid = result.gebaeude_uid;
|
||||
aufnahme.uid = result.gebaeude_aufnahme_uid;
|
||||
window.history.pushState(
|
||||
{},
|
||||
"",
|
||||
@@ -162,13 +150,13 @@
|
||||
|
||||
$: {
|
||||
if (
|
||||
gebaeude_aufnahme_allgemein.saniert &&
|
||||
gebaeude_aufnahme_allgemein.oberste_geschossdecke_gedaemmt ===
|
||||
aufnahme.saniert &&
|
||||
aufnahme.oberste_geschossdecke_gedaemmt ===
|
||||
undefined &&
|
||||
gebaeude_aufnahme_allgemein.dachgeschoss_gedaemmt === undefined
|
||||
aufnahme.dachgeschoss_gedaemmt === undefined
|
||||
) {
|
||||
gebaeude_aufnahme_allgemein.oberste_geschossdecke_gedaemmt = true;
|
||||
gebaeude_aufnahme_allgemein.dachgeschoss_gedaemmt = true;
|
||||
aufnahme.oberste_geschossdecke_gedaemmt = true;
|
||||
aufnahme.dachgeschoss_gedaemmt = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,8 +186,8 @@
|
||||
<div id="performance-box" class="w-full box relative px-4 order-2 2xl:order-1 self-stretch grid grid-cols-1">
|
||||
<PerformanceScore
|
||||
bind:ausweis
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
bind:gebaeude={objekt}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -223,8 +211,8 @@
|
||||
|
||||
<Bereich bereich="A" title="Prüfung der Ausweisart">
|
||||
<Ausweisart
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude={objekt}
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
bind:ausweis
|
||||
{Energieausweis}
|
||||
/>
|
||||
@@ -235,7 +223,7 @@
|
||||
<Bereich
|
||||
bereich="B"
|
||||
title="Eingabe der Gebäudeadresse - Angaben zu Wohnfläche, Keller und Dachgeschoss"
|
||||
><GebaeudeDaten bind:gebaeude_aufnahme_allgemein /></Bereich
|
||||
><GebaeudeDaten bind:gebaeude_aufnahme_allgemein={aufnahme} /></Bereich
|
||||
>
|
||||
|
||||
<!-- C Eingabe von 3 zusammenhängenden Verbrauchsjahren -->
|
||||
@@ -244,8 +232,8 @@
|
||||
bereich="C"
|
||||
title="Eingabe von 3 zusammenhängenden Verbrauchsjahren"
|
||||
><Verbrauch
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude={objekt}
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
bind:ausweis
|
||||
/></Bereich
|
||||
>
|
||||
@@ -263,7 +251,7 @@
|
||||
<Bereich
|
||||
bereich="E"
|
||||
title="Eingabe von Gebäudeteil, Lüftung, Kühlung und Leerstand"
|
||||
><LueftungundLeerstand bind:gebaeude_aufnahme_allgemein /></Bereich
|
||||
><LueftungundLeerstand bind:gebaeude_aufnahme_allgemein={aufnahme} /></Bereich
|
||||
>
|
||||
|
||||
<!-- F Angaben zur Heizungsanlage -->
|
||||
@@ -271,8 +259,8 @@
|
||||
<Bereich bereich="F" title="Angaben zur Heizunganlage"
|
||||
><SanierungszustandHeizungsanlage
|
||||
bind:images
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude={objekt}
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
bind:ausweis
|
||||
/></Bereich
|
||||
>
|
||||
@@ -282,8 +270,8 @@
|
||||
<Bereich bereich="G" title="Angaben zu Fenster, Dachfenster und Türen"
|
||||
><SanierungszustandFensterTueren
|
||||
bind:images
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude={objekt}
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
bind:ausweis
|
||||
/></Bereich
|
||||
>
|
||||
@@ -292,8 +280,8 @@
|
||||
<Bereich bereich="H" title="Angaben zur Wärmedämmung"
|
||||
><SanierungszustandWaermedammung
|
||||
bind:images
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude={objekt}
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
bind:ausweis
|
||||
/></Bereich
|
||||
>
|
||||
@@ -304,7 +292,7 @@
|
||||
><AusweisPreviewContainer
|
||||
bind:images
|
||||
bind:ausweis
|
||||
bind:gebaeude
|
||||
bind:gebaeude={objekt}
|
||||
/></Bereich
|
||||
>
|
||||
</div>
|
||||
@@ -313,8 +301,8 @@
|
||||
bind:ausweis
|
||||
bind:images
|
||||
bind:user
|
||||
bind:gebaeude
|
||||
bind:gebaeude_aufnahme_allgemein
|
||||
bind:gebaeude={objekt}
|
||||
bind:gebaeude_aufnahme_allgemein={aufnahme}
|
||||
>
|
||||
</ButtonWeiterHilfe>
|
||||
|
||||
@@ -330,7 +318,7 @@
|
||||
</RawNotification>
|
||||
{/each}
|
||||
|
||||
{#if auditBedarfsausweisBenoetigt(ausweis, gebaeude_aufnahme_allgemein)}
|
||||
{#if auditBedarfsausweisBenoetigt(ausweis, aufnahme)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Bedarfsausweis benötigt!",
|
||||
@@ -346,7 +334,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if gebaeude_aufnahme_allgemein.nutzflaeche && gebaeude_aufnahme_allgemein.flaeche && gebaeude_aufnahme_allgemein.flaeche === gebaeude_aufnahme_allgemein.nutzflaeche}
|
||||
{#if aufnahme.nutzflaeche && aufnahme.flaeche && aufnahme.flaeche === aufnahme.nutzflaeche}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -361,7 +349,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if typeof gebaeude_aufnahme_allgemein.einheiten === "number" && gebaeude_aufnahme_allgemein.einheiten < 1}
|
||||
{#if typeof aufnahme.einheiten === "number" && aufnahme.einheiten < 1}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -376,7 +364,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#await auditPlzNichtErkannt(gebaeude_aufnahme_allgemein) then result}
|
||||
{#await auditPlzNichtErkannt(aufnahme) then result}
|
||||
{#if result}
|
||||
<RawNotification
|
||||
notification={{
|
||||
@@ -394,7 +382,7 @@
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#if auditHeizungGebaeudeBaujahr(gebaeude_aufnahme_allgemein)}
|
||||
{#if auditHeizungGebaeudeBaujahr(aufnahme)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -403,7 +391,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.HEIZUNG_GEBAEUDE_BAUJAHR);
|
||||
gebaeude_aufnahme_allgemein = gebaeude_aufnahme_allgemein;
|
||||
aufnahme = aufnahme;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -413,7 +401,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if auditHeizungJuengerDreiJahre(gebaeude_aufnahme_allgemein)}
|
||||
{#if auditHeizungJuengerDreiJahre(aufnahme)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -422,7 +410,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.HEIZUNG_JUENGER_DREI_JAHRE);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -436,7 +424,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if auditZeitraumAktuell(ausweis, gebaeude)}
|
||||
{#if auditZeitraumAktuell(ausweis, objekt)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -445,7 +433,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.ZEITRAUM_AKTUELL);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -458,7 +446,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#await auditKlimaFaktoren(ausweis, gebaeude) then result}
|
||||
{#await auditKlimaFaktoren(ausweis, objekt) then result}
|
||||
{#if result}
|
||||
<RawNotification
|
||||
notification={{
|
||||
@@ -468,7 +456,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.KLIMA_FAKTOREN);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -483,7 +471,7 @@
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#if auditWohnFlaeche(gebaeude_aufnahme_allgemein)}
|
||||
{#if auditWohnFlaeche(aufnahme)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -492,7 +480,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.WOHN_FLAECHE);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -512,7 +500,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.WARM_WASSER);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -522,7 +510,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if auditLeerStand(gebaeude_aufnahme_allgemein)}
|
||||
{#if auditLeerStand(aufnahme)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -531,7 +519,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.LEER_STAND);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -542,7 +530,7 @@
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#if auditVerbrauchAbweichung(ausweis, gebaeude_aufnahme_allgemein).length > 0}
|
||||
{#if auditVerbrauchAbweichung(ausweis, aufnahme).length > 0}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
@@ -551,23 +539,23 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.VERBRAUCH_ABWEICHUNG);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
>
|
||||
Die Abweichung der Verbräuche zwischen Zeitraum {auditVerbrauchAbweichung(
|
||||
ausweis,
|
||||
gebaeude_aufnahme_allgemein
|
||||
aufnahme
|
||||
)[0]} und {auditVerbrauchAbweichung(
|
||||
ausweis,
|
||||
gebaeude_aufnahme_allgemein
|
||||
aufnahme
|
||||
)[1]} beträgt mehr als 30% und sie haben keinen Leerstand angegeben.
|
||||
Sind sie sich sicher, dass das stimmt?
|
||||
</RawNotification>
|
||||
{/if}
|
||||
|
||||
{#await auditEndEnergie(ausweis, gebaeude, gebaeude_aufnahme_allgemein) then result}
|
||||
{#await auditEndEnergie(ausweis, objekt, aufnahme) then result}
|
||||
{#if result}
|
||||
<RawNotification
|
||||
notification={{
|
||||
@@ -577,7 +565,7 @@
|
||||
dismissable: true,
|
||||
onUserDismiss: () => {
|
||||
hidden.add(AuditType.END_ENERGIE);
|
||||
gebaeude = gebaeude;
|
||||
objekt = objekt;
|
||||
},
|
||||
type: "warning",
|
||||
}}
|
||||
@@ -589,7 +577,7 @@
|
||||
{/if}
|
||||
{/await}
|
||||
|
||||
{#if auditWohnflaecheGroesserGesamtflaeche(gebaeude_aufnahme_allgemein)}
|
||||
{#if auditWohnflaecheGroesserGesamtflaeche(aufnahme)}
|
||||
<RawNotification
|
||||
notification={{
|
||||
message: "Plausibilitätsprüfung",
|
||||
|
||||
@@ -3,7 +3,7 @@ layout: ../layouts/Layout.astro
|
||||
title: "Welcher Energieausweis?"
|
||||
---
|
||||
|
||||
import WelcherAusweisWidget from "#widgets/WelcherAusweisWidget.svelte";
|
||||
import WelcherAusweisWidget from "#components/widgets/WelcherAusweisWidget.svelte";
|
||||
import TextboxCardTemplate from "#components/design/content/TextboxCardTemplate.svelte";
|
||||
|
||||
# Welcher Energieausweis ist der richtige?
|
||||
|
||||
46
src/pages/api/aufnahme/[id].ts
Normal file
46
src/pages/api/aufnahme/[id].ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||
|
||||
export const PATCH = defineApiRoute({
|
||||
fetch(input, context) {},
|
||||
});
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
meta: {
|
||||
description: "Gibt eine spezifische Aufnhame eines Objektes des Benutzers zurück.",
|
||||
tags: ["Aufnahme"],
|
||||
headers: {
|
||||
"Authorization": {
|
||||
description: "Ein gültiger Authentifizierungstoken",
|
||||
required: true,
|
||||
allowEmptyValue: false,
|
||||
examples: {
|
||||
Bearer: {
|
||||
value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, context, user) {
|
||||
const { uid } = context.params;
|
||||
|
||||
const aufnahme = await prisma.aufnahme.findUnique({
|
||||
where: {
|
||||
uid,
|
||||
benutzer_id: user.id
|
||||
},
|
||||
});
|
||||
|
||||
if (!aufnahme) {
|
||||
throw new APIError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Aufnahme mit dieser UID existiert nicht oder gehört nicht dem aktuellen Benutzer."
|
||||
})
|
||||
}
|
||||
|
||||
return aufnahme
|
||||
},
|
||||
});
|
||||
0
src/pages/api/aufnahme/index.ts
Normal file
0
src/pages/api/aufnahme/index.ts
Normal file
125
src/pages/api/auth/access-token.ts
Normal file
125
src/pages/api/auth/access-token.ts
Normal file
@@ -0,0 +1,125 @@
|
||||
import { z } from "zod";
|
||||
import moment from "moment";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { TokenType, encodeToken } from "../../../lib/auth/token.js";
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { defineApiRoute } from "astro-typesafe-api/server";
|
||||
|
||||
export const tRPC_V1_BenutzerGetAccessTokenProcedure = defineApiRoute({
|
||||
meta: {
|
||||
description:
|
||||
"Erstellt, basierend auf einem existierenden und gültigen Refresh Tokens, einen neuen Access Token, welcher zur Authentifizierung genutzt werden kann. Der resultierende Access Token ist nur 2 Tage gültig und muss danach neu generiert werden. Diese Funktion gibt ebenfalls einen neuen Refresh Token zurück, der alte wird dadurch invalidiert.",
|
||||
tags: ["Benutzer"],
|
||||
summary: "Access Token anfragen.",
|
||||
},
|
||||
input: z.object({
|
||||
refreshToken: z.string(),
|
||||
}),
|
||||
|
||||
output: z.object({
|
||||
accessToken: z.string(),
|
||||
accessTokenExpiry: z.number(),
|
||||
refreshToken: z.string(),
|
||||
refreshTokenExpiry: z.number(),
|
||||
}),
|
||||
|
||||
async fetch(input, ctx) {
|
||||
/**
|
||||
* Wir benutzen rolling refresh tokens, also löschen wir den alten Token und stellen einen neuen aus,
|
||||
* damit dieser nicht geklaut werden kann.
|
||||
*/
|
||||
const response = await prisma.refreshTokens.findUnique({
|
||||
where: {
|
||||
token: input.refreshToken,
|
||||
},
|
||||
});
|
||||
|
||||
if (!response) {
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Der gegebene refresh token ist nicht gültig.",
|
||||
});
|
||||
}
|
||||
|
||||
if (response.expiry < new Date()) {
|
||||
// Falls der Token abgelaufen ist, müssen wir ihn löschen.
|
||||
await prisma.refreshTokens.delete({
|
||||
where: {
|
||||
id: response.id,
|
||||
},
|
||||
});
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Der gegebene refresh token ist nicht gültig.",
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: Das können wir später implementieren, falls wir das wirklich brauchen.
|
||||
// if (response.ip !== opts.ctx.ip) {
|
||||
// // Falls der Token nicht von der selben IP Adresse kommt, müssen wir ihn löschen.
|
||||
// await prisma.refreshTokens.delete({
|
||||
// where: {
|
||||
// id: response.id
|
||||
// }
|
||||
// })
|
||||
// throw new TRPCError({ code: "BAD_REQUEST", message: "Der gegebene refresh token wurde von einer anderen IP-Adresse ausgestellt, aus Sicherheitsgründen haben wir uns entschieden diesen zu invalidieren." });
|
||||
// }
|
||||
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
id: response.benutzer_id,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
// Falls der Nutzer nicht mehr existiert müssen wir den Refresh Token invalidieren.
|
||||
await prisma.refreshTokens.delete({
|
||||
where: {
|
||||
id: response.id,
|
||||
},
|
||||
});
|
||||
throw new TRPCError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Der gegebene refresh token ist nicht mehr gültig.",
|
||||
});
|
||||
}
|
||||
|
||||
// Wir löschen den alten Token.
|
||||
await prisma.refreshTokens.delete({
|
||||
where: {
|
||||
id: response.id,
|
||||
},
|
||||
});
|
||||
|
||||
const refreshTokenExpiry = moment().add(30, "days");
|
||||
const refreshToken = encodeToken({
|
||||
uid: user.uid,
|
||||
typ: TokenType.Refresh,
|
||||
exp: refreshTokenExpiry.unix(),
|
||||
});
|
||||
|
||||
// Und erstellen einen neuen
|
||||
await prisma.refreshTokens.create({
|
||||
data: {
|
||||
benutzer_id: user.id,
|
||||
expiry: refreshTokenExpiry.toDate(),
|
||||
ip: ctx.clientAddress ?? "",
|
||||
token: refreshToken,
|
||||
},
|
||||
});
|
||||
|
||||
const accessTokenExpiry = moment().add(2, "days").unix();
|
||||
const accessToken = encodeToken({
|
||||
uid: user.uid,
|
||||
typ: TokenType.Access,
|
||||
exp: accessTokenExpiry,
|
||||
});
|
||||
|
||||
return {
|
||||
accessToken,
|
||||
accessTokenExpiry: accessTokenExpiry,
|
||||
refreshToken,
|
||||
refreshTokenExpiry: refreshTokenExpiry.unix(),
|
||||
};
|
||||
},
|
||||
});
|
||||
82
src/pages/api/auth/refresh-token.ts
Normal file
82
src/pages/api/auth/refresh-token.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { z } from "zod";
|
||||
import moment from "moment";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { TokenType, encodeToken } from "../../../lib/auth/token.js";
|
||||
import { hashPassword, validatePassword } from "../../../lib/password.js";
|
||||
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
meta: {
|
||||
description:
|
||||
"Erstellt sowohl einen neuen Refresh Token als auch einen Access Token für den gegebenen Benutzer. Der Refresh Token kann später für die Erstellung neuer Access Token genutzt werden.",
|
||||
tags: ["Benutzer"],
|
||||
summary: "Refresh Token anfragen.",
|
||||
},
|
||||
input: z.object({
|
||||
email: z.string().email(),
|
||||
passwort: z.string().min(8).max(100),
|
||||
}),
|
||||
output: z.object({
|
||||
uid: z.string().uuid(),
|
||||
accessToken: z.string(),
|
||||
refreshToken: z.string(),
|
||||
refreshTokenBase64: z.string(),
|
||||
accessTokenBase64: z.string(),
|
||||
exp: z.number(),
|
||||
}),
|
||||
async fetch(input, ctx) {
|
||||
console.log(input);
|
||||
|
||||
// Falls der Nutzer nicht existiert, wird eine Fehlermeldung zurückgegeben.
|
||||
const user = await prisma.benutzer.findUnique({
|
||||
where: {
|
||||
email: input.email,
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Benutzer konnte nicht gefunden werden.",
|
||||
});
|
||||
}
|
||||
|
||||
// Falls das Passwort nicht stimmt, wird eine Fehlermeldung zurückgegeben.
|
||||
if (!validatePassword(user.passwort, input.passwort)) {
|
||||
throw new APIError({
|
||||
code: "BAD_REQUEST",
|
||||
message: "Benutzer konnte nicht gefunden werden.",
|
||||
});
|
||||
}
|
||||
|
||||
const refreshTokenExpiry = moment().add(30, "days");
|
||||
const accessToken = encodeToken({
|
||||
uid: user.uid,
|
||||
typ: TokenType.Access,
|
||||
exp: moment().add(30, "minutes").valueOf(),
|
||||
});
|
||||
const refreshToken = encodeToken({
|
||||
uid: user.uid,
|
||||
typ: TokenType.Refresh,
|
||||
exp: refreshTokenExpiry.valueOf(),
|
||||
});
|
||||
|
||||
const { id } = await prisma.refreshTokens.create({
|
||||
data: {
|
||||
token: refreshToken,
|
||||
benutzer_id: user.id,
|
||||
ip: ctx.clientAddress ?? "",
|
||||
expiry: refreshTokenExpiry.toDate(),
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
uid: user.uid,
|
||||
accessToken,
|
||||
refreshToken,
|
||||
refreshTokenBase64: Buffer.from(refreshToken).toString("base64"),
|
||||
accessTokenBase64: Buffer.from(accessToken).toString("base64"),
|
||||
exp: refreshTokenExpiry.valueOf(),
|
||||
};
|
||||
},
|
||||
});
|
||||
0
src/pages/api/bedarfsausweis-wohnen/index.ts
Normal file
0
src/pages/api/bedarfsausweis-wohnen/index.ts
Normal file
46
src/pages/api/objekt/[id].ts
Normal file
46
src/pages/api/objekt/[id].ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||
|
||||
export const PATCH = defineApiRoute({
|
||||
fetch(input, context) {},
|
||||
});
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
meta: {
|
||||
description: "Gibt ein spezifisches Gebäude des Benutzers zurück.",
|
||||
tags: ["Gebäude"],
|
||||
headers: {
|
||||
"Authorization": {
|
||||
description: "Ein gültiger Authentifizierungstoken",
|
||||
required: true,
|
||||
allowEmptyValue: false,
|
||||
examples: {
|
||||
Bearer: {
|
||||
value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, context, user) {
|
||||
const { uid } = context.params;
|
||||
|
||||
const objekt = await prisma.objekt.findUnique({
|
||||
where: {
|
||||
uid,
|
||||
benutzer_id: user.id
|
||||
},
|
||||
});
|
||||
|
||||
if (!objekt) {
|
||||
throw new APIError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Objekt mit dieser UID existiert nicht oder gehört nicht dem aktuellen Benutzer."
|
||||
})
|
||||
}
|
||||
|
||||
return objekt
|
||||
},
|
||||
});
|
||||
30
src/pages/api/objekt/index.ts
Normal file
30
src/pages/api/objekt/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
import { ObjektSchema, prisma } from "@ibcornelsen/database/server";
|
||||
import { defineApiRoute } from "astro-typesafe-api/server";
|
||||
import { z } from "zod";
|
||||
|
||||
export const POST = defineApiRoute({
|
||||
fetch(input, context) {
|
||||
|
||||
},
|
||||
})
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
input: z.object({
|
||||
limit: z.number()
|
||||
}),
|
||||
output: z.array(ObjektSchema),
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, context, transfer) {
|
||||
const objekte = await prisma.objekt.findMany({
|
||||
take: input.limit,
|
||||
where: {
|
||||
benutzer: {
|
||||
id: transfer.id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return objekte
|
||||
},
|
||||
})
|
||||
23
src/pages/api/user/self.ts
Normal file
23
src/pages/api/user/self.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
import { BenutzerSchema } from "@ibcornelsen/database/server";
|
||||
import { z } from "zod";
|
||||
import { defineApiRoute } from "astro-typesafe-api/server";
|
||||
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
meta: {
|
||||
description:
|
||||
"Gibt die Daten des momentan eingeloggten Benutzers zurück. Falls der Authorization Key invalid ist wird stattdessen null zurückgegeben.",
|
||||
summary: "Gibt die Daten des eingeloggten Benutzers zurück.",
|
||||
tags: ["Benutzer"],
|
||||
},
|
||||
|
||||
input: z.void(),
|
||||
output: BenutzerSchema.omit({
|
||||
passwort: true,
|
||||
id: true,
|
||||
}).or(z.null()),
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, ctx, transfer) {
|
||||
return transfer;
|
||||
},
|
||||
});
|
||||
0
src/pages/api/verbrauchsausweis-gewerbe/index.ts
Normal file
0
src/pages/api/verbrauchsausweis-gewerbe/index.ts
Normal file
71
src/pages/api/verbrauchsausweis-wohnen/[id].ts
Normal file
71
src/pages/api/verbrauchsausweis-wohnen/[id].ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||
|
||||
export const PATCH = defineApiRoute({
|
||||
fetch(input, context) {},
|
||||
});
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
meta: {
|
||||
description: "Gibt ein spezifisches Gebäude des Benutzers zurück.",
|
||||
tags: ["Gebäude"],
|
||||
headers: {
|
||||
"Authorization": {
|
||||
description: "Ein gültiger Authentifizierungstoken",
|
||||
required: true,
|
||||
allowEmptyValue: false,
|
||||
examples: {
|
||||
Bearer: {
|
||||
value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, context, user) {
|
||||
const { uid } = context.params;
|
||||
|
||||
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
|
||||
where: {
|
||||
uid: input.uid,
|
||||
},
|
||||
include: {
|
||||
benutzer: true,
|
||||
aufnahme: {
|
||||
include: {
|
||||
objekt: {
|
||||
include: {
|
||||
gebaeude_bilder: true
|
||||
},
|
||||
},
|
||||
rechnungen: true,
|
||||
events: {
|
||||
include: {
|
||||
benutzer: {
|
||||
select: {
|
||||
uid: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (!ausweis || (ausweis.benutzer_id !== null && ausweis.benutzer_id !== user.id)) {
|
||||
// Falls wir den Ausweis nicht finden können, werfen wir einen Fehler
|
||||
throw new APIError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Ausweis konnte nicht gefunden werden.",
|
||||
});
|
||||
}
|
||||
|
||||
return ausweis
|
||||
},
|
||||
});
|
||||
71
src/pages/api/verbrauchsausweis-wohnen/index.ts
Normal file
71
src/pages/api/verbrauchsausweis-wohnen/index.ts
Normal file
@@ -0,0 +1,71 @@
|
||||
import { authorizationMiddleware } from "#lib/middleware/authorization.js";
|
||||
import { prisma } from "@ibcornelsen/database/server";
|
||||
import { APIError, defineApiRoute } from "astro-typesafe-api/server";
|
||||
|
||||
export const PATCH = defineApiRoute({
|
||||
fetch(input, context) {},
|
||||
});
|
||||
|
||||
export const GET = defineApiRoute({
|
||||
meta: {
|
||||
description: "Gibt ein spezifisches Gebäude des Benutzers zurück.",
|
||||
tags: ["Gebäude"],
|
||||
headers: {
|
||||
"Authorization": {
|
||||
description: "Ein gültiger Authentifizierungstoken",
|
||||
required: true,
|
||||
allowEmptyValue: false,
|
||||
examples: {
|
||||
Bearer: {
|
||||
value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
middleware: authorizationMiddleware,
|
||||
async fetch(input, context, user) {
|
||||
const { uid } = context.params;
|
||||
|
||||
const ausweis = await prisma.verbrauchsausweisWohnen.findUnique({
|
||||
where: {
|
||||
uid,
|
||||
},
|
||||
include: {
|
||||
benutzer: true,
|
||||
aufnahme: {
|
||||
include: {
|
||||
objekt: {
|
||||
include: {
|
||||
gebaeude_bilder: true
|
||||
},
|
||||
},
|
||||
rechnungen: true,
|
||||
events: {
|
||||
include: {
|
||||
benutzer: {
|
||||
select: {
|
||||
uid: true
|
||||
}
|
||||
}
|
||||
},
|
||||
orderBy: {
|
||||
date: "asc"
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
if (!ausweis || (ausweis.benutzer_id !== null && ausweis.benutzer_id !== user.id)) {
|
||||
// Falls wir den Ausweis nicht finden können, werfen wir einen Fehler
|
||||
throw new APIError({
|
||||
code: "NOT_FOUND",
|
||||
message: "Ausweis konnte nicht gefunden werden.",
|
||||
});
|
||||
}
|
||||
|
||||
return ausweis
|
||||
},
|
||||
});
|
||||
@@ -1,8 +1,9 @@
|
||||
---
|
||||
import { createCaller } from "#lib/caller";
|
||||
import { createCaller } from "../../astro-typesafe-api-caller.js";
|
||||
import UserLayout from "../../layouts/UserLayout.astro";
|
||||
import { validateAccessTokenServer } from "#server/lib/validateAccessToken";
|
||||
import DashboardModule from "#modules/Dashboard/DashboardModule.svelte";
|
||||
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants";
|
||||
|
||||
const accessTokenValid = await validateAccessTokenServer(Astro);
|
||||
|
||||
@@ -12,8 +13,16 @@ if (!accessTokenValid) {
|
||||
|
||||
const caller = createCaller(Astro);
|
||||
|
||||
const user = await caller.v1.benutzer.self(undefined);
|
||||
const gebaeudeArray = await caller.v1.gebaeude.getMany({ limit: 5 });
|
||||
const user = await caller.user.self.GET.fetch(undefined, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
}
|
||||
});
|
||||
const gebaeudeArray = await caller.objekt.GET.fetch({ limit: 5 }, {
|
||||
headers: {
|
||||
"Authorization": `Bearer ${Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value}`
|
||||
}
|
||||
});
|
||||
---
|
||||
|
||||
<UserLayout title="Dashboard">
|
||||
|
||||
@@ -2,23 +2,34 @@
|
||||
import AusweisLayout from "#layouts/AusweisLayoutDaten.astro";
|
||||
import VerbrauchsausweisWohnenModule from "#modules/VerbrauchsausweisWohnen/VerbrauchsausweisWohnenModule.svelte";
|
||||
import { VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
||||
import { createCaller } from "#lib/caller";
|
||||
import { createCaller } from "../../../astro-typesafe-api-caller.js";
|
||||
|
||||
const uid = Astro.url.searchParams.get("uid");
|
||||
let ausweis: VerbrauchsausweisWohnenClient = {
|
||||
gebaeude_aufnahme_allgemein: { gebaeude_stammdaten: {} },
|
||||
aufnahme: { objekt: {} },
|
||||
} as VerbrauchsausweisWohnenClient;
|
||||
|
||||
const caller = createCaller(Astro);
|
||||
const caller = await createCaller(Astro);
|
||||
|
||||
if (uid) {
|
||||
ausweis = await caller.v1.verbrauchsausweisWohnen.get({
|
||||
uid: uid,
|
||||
});
|
||||
try {
|
||||
ausweis = await caller["verbrauchsausweis-wohnen"]._id.GET.fetch(null, {
|
||||
headers: {
|
||||
authorization: "Basic "
|
||||
},
|
||||
params: {
|
||||
id: "123"
|
||||
}
|
||||
});
|
||||
|
||||
if (!ausweis) {
|
||||
// Der Ausweis scheint nicht zu existieren.
|
||||
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
|
||||
if (!ausweis) {
|
||||
// Der Ausweis scheint nicht zu existieren.
|
||||
// Wir leiten auf die generische Ausweisseite ohne UID weiter.
|
||||
return Astro.redirect(
|
||||
"/energieausweis-erstellen/verbrauchsausweis-wohnen"
|
||||
);
|
||||
}
|
||||
} catch(e) {
|
||||
return Astro.redirect(
|
||||
"/energieausweis-erstellen/verbrauchsausweis-wohnen"
|
||||
);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
---
|
||||
import Layout from "#layouts/Layout.astro";
|
||||
import ProduktVergleich from "#content/ProduktVergleich.svelte";
|
||||
import ProduktVergleichGewerbe from "#content/ProduktVergleichGewerbe.svelte";
|
||||
import WelcherAusweisWidget from "#widgets/WelcherAusweisWidget.svelte";
|
||||
import ProduktVergleich from "#components/design/content/ProduktVergleich.svelte";
|
||||
import ProduktVergleichGewerbe from "#components/design/content/ProduktVergleichGewerbe.svelte";
|
||||
import WelcherAusweisWidget from "#components/widgets/WelcherAusweisWidget.svelte";
|
||||
import TextboxCardTemplate from "#components/design/content/TextboxCardTemplate.svelte";
|
||||
|
||||
---
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import { BenutzerClient, VerbrauchsausweisWohnenClient } from "#components/Ausweis/types";
|
||||
import { createCaller } from "#lib/caller";
|
||||
import { pdfDatenblatt } from "#lib/pdf/pdfDatenblatt";
|
||||
import { pdfDatenblattVerbrauchsausweisWohnen } from "#lib/pdf/pdfDatenblattVerbrauchsausweisWohnen";
|
||||
|
||||
const base64 = Astro.url.searchParams.get("base64");
|
||||
let ausweis: VerbrauchsausweisWohnenClient | null = null;
|
||||
@@ -23,7 +23,7 @@ if (base64) {
|
||||
});
|
||||
}
|
||||
|
||||
const pdf = await pdfDatenblatt(ausweis);
|
||||
const pdf = await pdfDatenblattVerbrauchsausweisWohnen(ausweis);
|
||||
|
||||
|
||||
return new Response(pdf, {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
---
|
||||
import Layout from "#layouts/Layout.astro";
|
||||
import WelcherAusweisWidget from "#widgets/WelcherAusweisWidget.svelte";
|
||||
import WelcherAusweisWidget from "#components/widgets/WelcherAusweisWidget.svelte";
|
||||
import TextboxCardTemplate from "#components/design/content/TextboxCardTemplate.svelte";
|
||||
|
||||
---
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
---
|
||||
|
||||
import Layout from "#layouts/WidgetLayout_1.astro";
|
||||
import WelcherAusweisWidget from "#widgets/WelcherAusweisWidget_1.svelte";
|
||||
import WelcherAusweisWidget from "#components/widgets/WelcherAusweisWidget.svelte";
|
||||
|
||||
const { vermittler } = Astro.params;
|
||||
|
||||
|
||||
@@ -27,20 +27,9 @@
|
||||
"#modules/*": ["./src/modules/*"],
|
||||
"#client/*": ["./src/client/*"],
|
||||
"#server/*": ["./src/server/*"],
|
||||
"#style/*": ["./src/style/*"],
|
||||
|
||||
"#footer/*": ["./src/components/design/footer/*"],
|
||||
"#header/*": ["./src/components/design/header/*"],
|
||||
"#content/*": ["./src/components/design/content/*"],
|
||||
"#sidebarCards/*": ["./src/components/design/sidebars/cards/*"],
|
||||
"#sidebarLeft/*": ["./src/components/design/sidebars/left/*"],
|
||||
"#sidebarRight/*": ["./src/components/design/sidebars/right/*"],
|
||||
|
||||
"#ausweise/*": ["./src/pages/energieausweis-erstellen/*"],
|
||||
"#labels/*": ["./src/components/labels/*"],
|
||||
"#widgets/*": ["./src/components/widgets/*"]
|
||||
"#style/*": ["./src/style/*"]
|
||||
},
|
||||
"types": ["cypress", "cypress-file-upload", "bun-types", "svelte"]
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
"include": ["src/**/*", "tests/**/*"]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user