Merge branch 'dev' into UMBE

This commit is contained in:
Robert Jagtiani
2025-07-08 01:06:23 +02:00
28 changed files with 1033 additions and 156 deletions

View File

@@ -8,6 +8,8 @@ on:
jobs: jobs:
merge: merge:
runs-on: ubuntu-latest runs-on: ubuntu-latest
outputs:
reason: ${{ steps.check.outputs.reason }}
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -28,9 +30,15 @@ jobs:
id: check id: check
run: | run: |
git fetch origin git fetch origin
if [ $(git rev-list --count origin/staging..origin/main) -gt 0 ]; then COUNT=$(git rev-list --count origin/staging..origin/main)
if [ "$COUNT" -gt 0 ]; then
echo "reason=ok" >> $GITHUB_OUTPUT
echo "❌ Staging is behind main and requires manual merging." echo "❌ Staging is behind main and requires manual merging."
exit 1 exit 1
elif [ "$COUNT" -eq 0 ]; then
echo "reason=identical" >> $GITHUB_OUTPUT
echo "✅ Staging and main are identical. Nothing to do."
exit 42
fi fi
- name: Create PR from staging to main - name: Create PR from staging to main
@@ -53,7 +61,7 @@ jobs:
notify_failure: notify_failure:
needs: merge needs: merge
if: failure() if: failure() && needs.merge.outputs.reason != 'identical'
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Send Discord notification on failure - name: Send Discord notification on failure
@@ -62,15 +70,3 @@ jobs:
-X POST \ -X POST \
-d "{\"content\": \"🚨 Auto-Merge fehlgeschlagen! Bitte manuell prüfen: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}" \ -d "{\"content\": \"🚨 Auto-Merge fehlgeschlagen! Bitte manuell prüfen: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}\"}" \
${{ secrets.DISCORD_WEBHOOK_URL }} ${{ secrets.DISCORD_WEBHOOK_URL }}
notify_success:
needs: merge
if: success()
runs-on: ubuntu-latest
steps:
- name: Send Discord notification on success
run: |
curl -H "Content-Type: application/json" \
-X POST \
-d "{\"content\": \"✅ Auto-Merge ausgeführt! Ergebnis jetzt auf [GitHub](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}) und [online-energieausweis.org](https://online-energieausweis.org) einsehen.\"}" \
${{ secrets.DISCORD_WEBHOOK_URL }}

31
.github/workflows/prevent-wrong-pr.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: PR Rules Enforcement
on:
pull_request:
branches:
- main
- staging
jobs:
check-pr:
runs-on: ubuntu-latest
name: Validate Pull Request Sources
steps:
- name: Prevent dev merges
run: |
echo "${{ github.head_ref }}";
echo "${{ github.base_ref }}";
if [[ "${{ github.head_ref }}" == "dev" ]]; then
echo "ERROR: Merging 'dev' into '${{ github.base_ref }}' is forbidden!"
exit 1
fi
- name: Allow only staging into main
if: github.base_ref == 'main'
run: |
echo "${{ github.head_ref }}";
echo "${{ github.base_ref }}";
if [[ "${{ github.head_ref }}" != "staging" ]]; then
echo "ERROR: Only 'staging' branch is allowed to merge into 'main'. Current: '${{ github.head_ref }}'"
exit 1
fi

View File

@@ -10,7 +10,7 @@ PERSISTENT_DIR := $(HOME)/persistent/$(APP_NAME)
BACKUP_FILENAME := $(HOME)/backups/$(shell date +"%Y-%m-%d_%H-%M-%S").sql.gz BACKUP_FILENAME := $(HOME)/backups/$(shell date +"%Y-%m-%d_%H-%M-%S").sql.gz
online-energieausweis: online-energieausweis:
bun run dev --host NODE_ENV="development" bun run dev --host
dev: database online-energieausweis dev: database online-energieausweis
@@ -30,6 +30,7 @@ run-database: stop-database
docker volume create $(DB_VOLUME) docker volume create $(DB_VOLUME)
docker build -t $(DB_CONTAINER_NAME) . docker build -t $(DB_CONTAINER_NAME) .
docker run -d --name $(DB_CONTAINER_NAME) \ docker run -d --name $(DB_CONTAINER_NAME) \
--restart=always \
-e POSTGRES_USER=$(DB_USER) \ -e POSTGRES_USER=$(DB_USER) \
-e POSTGRES_PASSWORD=$(DB_PASSWORD) \ -e POSTGRES_PASSWORD=$(DB_PASSWORD) \
-p $(DB_PORT):5432 \ -p $(DB_PORT):5432 \
@@ -71,4 +72,4 @@ prod: install-dependencies prisma-studio backup-database-cronjob update-dwd-klim
backup-database-cronjob: backup-database-cronjob:
- pm2 delete daily-db-backup - pm2 delete daily-db-backup
pm2 start bash --name "daily-db-backup" --cron "0 0 * * *" -- backup-database.bash pm2 start bash --name "daily-db-backup" --no-autorestart --cron "0 0 * * *" -- backup-database.bash

View File

@@ -19,7 +19,11 @@ echo "Uploaded $FILE_NAME"
docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE docker exec -t online-energieausweis-database-1 pg_dumpall -c -U main | brotli --best > $FILE_NAME_COMPLETE
<<<<<<< HEAD
aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-3.ionoscloud.com --storage-class STANDARD aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3-eu-central-3.ionoscloud.com --storage-class STANDARD
=======
aws s3 cp $FILE_NAME_COMPLETE s3://ibc-db-backup/ --profile ionos --endpoint-url https://s3.eu-central-3.ionoscloud.com --storage-class STANDARD
>>>>>>> dev
echo "Uploaded $FILE_NAME_COMPLETE" echo "Uploaded $FILE_NAME_COMPLETE"

View File

@@ -2,6 +2,7 @@ version: '3'
services: services:
database: database:
build: ./ build: ./
restart: always
env_file: env_file:
- .env - .env
ports: ports:

View File

@@ -41,19 +41,19 @@ model BedarfsausweisWohnen {
volumen Float? volumen Float?
dicht Boolean? dicht Boolean?
fenster_flaeche_1 Float? fenster_flaeche_1 Float?
fenster_art_1 String? fenster_art_1 Float?
fenster_flaeche_2 Float? fenster_flaeche_2 Float?
fenster_art_2 String? fenster_art_2 Float?
dachfenster_flaeche Float? dachfenster_flaeche Float?
dachfenster_art String? dachfenster_art Float?
haustuer_flaeche Float? haustuer_flaeche Float?
haustuer_art String? haustuer_art Float?
dach_bauart String? @db.VarChar dach_bauart String? @db.VarChar
decke_bauart String? @db.VarChar decke_bauart String? @db.VarChar
dach_daemmung String? dach_daemmung Float?
decke_daemmung String? decke_daemmung Float?
aussenwand_daemmung String? aussenwand_daemmung Float?
boden_daemmung String? boden_daemmung Float?
aussenwand_bauart String? @db.VarChar aussenwand_bauart String? @db.VarChar
boden_bauart String? @db.VarChar boden_bauart String? @db.VarChar
warmwasser_verteilung String? @db.VarChar warmwasser_verteilung String? @db.VarChar

View File

@@ -2,7 +2,7 @@
# === Configuration === # === Configuration ===
BUCKET_NAME="ibc-db-backup" BUCKET_NAME="ibc-db-backup"
ENDPOINT_URL="https://s3-eu-central-1.ionoscloud.com" ENDPOINT_URL="https://s3.eu-central-3.ionoscloud.com"
LOCAL_DOWNLOAD_DIR="./" # Where to save the file LOCAL_DOWNLOAD_DIR="./" # Where to save the file
# === Get latest file from IONOS S3 bucket === # === Get latest file from IONOS S3 bucket ===

View File

@@ -5,6 +5,7 @@ export const createCaller = createCallerFactory({
"klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"), "klimafaktoren": await import("../src/pages/api/klimafaktoren.ts"),
"postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"), "postleitzahlen": await import("../src/pages/api/postleitzahlen.ts"),
"unterlage": await import("../src/pages/api/unterlage.ts"), "unterlage": await import("../src/pages/api/unterlage.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"), "admin/ausstellen": await import("../src/pages/api/admin/ausstellen.ts"),
"admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"), "admin/bedarfsausweis-ausstellen": await import("../src/pages/api/admin/bedarfsausweis-ausstellen.ts"),
"admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"), "admin/bestellbestaetigung": await import("../src/pages/api/admin/bestellbestaetigung.ts"),
@@ -12,7 +13,6 @@ export const createCaller = createCallerFactory({
"admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"), "admin/nicht-ausstellen": await import("../src/pages/api/admin/nicht-ausstellen.ts"),
"admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"), "admin/registriernummer": await import("../src/pages/api/admin/registriernummer.ts"),
"admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"), "admin/stornieren": await import("../src/pages/api/admin/stornieren.ts"),
"aufnahme": await import("../src/pages/api/aufnahme/index.ts"),
"ausweise": await import("../src/pages/api/ausweise/index.ts"), "ausweise": await import("../src/pages/api/ausweise/index.ts"),
"auth/access-token": await import("../src/pages/api/auth/access-token.ts"), "auth/access-token": await import("../src/pages/api/auth/access-token.ts"),
"auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"), "auth/passwort-vergessen": await import("../src/pages/api/auth/passwort-vergessen.ts"),
@@ -31,7 +31,6 @@ export const createCaller = createCallerFactory({
"rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"), "rechnung/anfordern": await import("../src/pages/api/rechnung/anfordern.ts"),
"rechnung": await import("../src/pages/api/rechnung/index.ts"), "rechnung": await import("../src/pages/api/rechnung/index.ts"),
"ticket": await import("../src/pages/api/ticket/index.ts"), "ticket": await import("../src/pages/api/ticket/index.ts"),
"user": await import("../src/pages/api/user/index.ts"),
"user/self": await import("../src/pages/api/user/self.ts"), "user/self": await import("../src/pages/api/user/self.ts"),
"verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"), "verbrauchsausweis-gewerbe/[id]": await import("../src/pages/api/verbrauchsausweis-gewerbe/[id].ts"),
"verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"), "verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"),

15
src/client/lib/lesen.ts Normal file
View File

@@ -0,0 +1,15 @@
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Benutzer } from "#lib/client/prisma.js";
import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie";
export async function benutzerLesen(benutzerId: string): Promise<Benutzer> {
const benutzer = await api.user.GET.fetch({ id: benutzerId }
, {
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
});
return benutzer[0];
}

View File

@@ -1,5 +1,5 @@
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"; import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { Aufnahme, Objekt } from "#lib/client/prisma.js"; import { Aufnahme, Benutzer, Objekt } from "#lib/client/prisma.js";
import { api } from "astro-typesafe-api/client"; import { api } from "astro-typesafe-api/client";
import Cookies from "js-cookie"; import Cookies from "js-cookie";
@@ -162,3 +162,31 @@ export async function objektSpeichern(objekt: Objekt & { id?: string }): Promise
return id; return id;
} }
} }
export async function benutzerSpeichern(benutzer: Partial<Benutzer>): Promise<string> {
const completeBenutzer: Benutzer = {
id: benutzer.id,
name: benutzer.name ?? null,
email: benutzer.email,
passwort: "",
adresse: benutzer.adresse ?? null,
anrede: benutzer.anrede ?? null,
firma: benutzer.firma ?? null,
vorname: benutzer.vorname ?? null,
ort: benutzer.ort ?? null,
plz: benutzer.plz ?? null,
profilbild: benutzer.profilbild ?? null,
telefon: benutzer.telefon ?? null,
updated_at: new Date(),
verified: benutzer.verified ?? false,
};
await api.user.POST.fetch(completeBenutzer
, {
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`
}
});
return benutzer.id;
}

View File

@@ -0,0 +1,109 @@
<script lang="ts">
import { BedarfsausweisWohnen, Enums, Rechnung, VerbrauchsausweisGewerbe, VerbrauchsausweisWohnen } from "#lib/server/prisma.js";
import moment from "moment";
import { format } from "sharp";
export let bestellungen: (Rechnung & {
verbrauchsausweis_wohnen: VerbrauchsausweisWohnen | null,
verbrauchsausweis_gewerbe: VerbrauchsausweisGewerbe | null,
bedarfsausweis_wohnen: BedarfsausweisWohnen | null,
})[];
export let provisionen: Record<Enums.Ausweisart, number>;
export let partnerCodeErstesMal: Date;
const bestellungenNachMonat: Record<string, (typeof bestellungen)> = {};
for (const bestellung of bestellungen) {
const monat = moment(bestellung.created_at).format("Y-m");
if (monat in bestellungenNachMonat) {
bestellungenNachMonat[monat].push(bestellung)
} else {
bestellungenNachMonat[monat] = [bestellung]
}
}
// Wir brauchen alle Monate zwischen dem ersten Mal, dass der partner_code benutzt wurde bis zum heutigen Zeitpunkt.
const months: Record<string, string> = {
"01": "Januar", "02": "Februar", "03": "März", "04": "April",
"05": "Mai", "06": "Juni", "07": "Juli", "08": "August",
"09": "September", "10": "Oktober", "11": "November", "12": "Dezember"
};
function getMonthlyPeriods(minTime?: Date): moment.Moment[] {
const min = minTime ? moment(minTime) : moment();
const start = min.clone().startOf('month');
const end = moment().add(1, 'month').startOf('month');
const monthsArray: moment.Moment[] = [];
const current = start.clone();
while (current.isBefore(end)) {
monthsArray.push(current.clone());
current.add(1, 'month');
}
return monthsArray.reverse(); // Most recent month first
}
const periods = getMonthlyPeriods(partnerCodeErstesMal)
</script>
{#each periods as dt}
{@const jahrMonat = dt.format("Y-m")}
{#if jahrMonat in bestellungenNachMonat && bestellungenNachMonat[jahrMonat].length > 0}
<!-- Echo dropdown foreach month. -->
{@const provisionMonat = bestellungenNachMonat[jahrMonat].reduce((acc, bestellung) => {
if (bestellung.verbrauchsausweis_wohnen) {
return acc + provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen];
}
if (bestellung.bedarfsausweis_wohnen) {
return acc + provisionen[Enums.Ausweisart.BedarfsausweisWohnen];
}
if (bestellung.verbrauchsausweis_gewerbe) {
return acc + provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe];
}
return acc;
}) * 1.19}
<div onclick="$(this).nextUntil('.dropdown_month').filter('table').toggle(); $('#betrag_gesamt').html('Abrechnungsbetrag $month_name: <b>$provision_month €</b>')" class='dropdown_month'>
<p>$month_name $year_name - Klicke, um Tabelle anzuzeigen</p>
<a target='_blank' rel='noreferrer noopener' href='/user/abrechnung/pdf.php?month={dt.format("m")}&year={dt.format("Y")}'>PDF Ansehen</a>
</div>
<table id='QTT' style='margin-top: 0 !important; display:none;'>
<thead>
<tr>
<td style='text-align:center;'>ID</td>
<td style='text-align:center;'>DATUM</td>
<td style='width:11em;text-align:center;'>GEBÄUDEADRESSE </td>
<td style='width:11em;text-align:center;'>PLZ </td>
<td style='width:11em;text-align:center;'>ORT </td>
<td style='text-align:center;'>AUSWEIS</td>
<td style='width:5em;text-align:center;'>BETRAG NETTO</td>
</tr>
</thead>
<tbody>
{#each bestellungenNachMonat[jahrMonat] as bestellung}
{@const provisionBestellung = bestellung.verbrauchsausweis_wohnen ? provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen] : bestellung.verbrauchsausweis_gewerbe ? provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe] : provisionen[Enums.Ausweisart.BedarfsausweisWohnen]}
<tr>
<td style='width:1em;text-align:center;'>{bestellung.id}</td>
<td style='width:9em;text-align:center;font-weight:bold;'>{moment(bestellung.created_at).format("Y/m/d")}</td>
<td style='width:8em;text-align:left;'>{bestellung["objekt_strasse"]}</td>
<td style='width:5em;text-align:center;'>{bestellung["objekt_plz"]}</td>
<td style='width:6em;text-align:left;'>{bestellung["objekt_ort"]}</td>
<td style='width:3em;text-align:center;'>{bestellung['ausweisart']}</td>
<td style='width:8em;text-align:right;'>{provisionBestellung}</td>
</tr>
{/each}
</table>
{/if}
{/each}
<!-- foreach ($period as $dt) {
$year_month = $dt->format("Y-m");
$month_name = $months[$dt->format("m")];
if ((new DateTime(date("m/d/Y", strtotime($EEtimestamp))))->format("d") - (new DateTime(date("m/d/Y", strtotime($SStimestamp))))->format("d") == 1) {
$Pall = $dt->format("d/m/Y") . ' bis ' . (new DateTime($today))->format("d/m/Y");
} -->
<!-- } -->

View File

@@ -257,6 +257,12 @@
let bedarfsausweisFileInput: HTMLInputElement; let bedarfsausweisFileInput: HTMLInputElement;
let bedarfsausweisAdditionalInput: HTMLInputElement; let bedarfsausweisAdditionalInput: HTMLInputElement;
let dropdownOpen = false;
function toggleDropdown() {
dropdownOpen = !dropdownOpen;
}
</script> </script>
<div class="relative bg-base-200 border border-base-300 rounded-lg p-4 mx-2"> <div class="relative bg-base-200 border border-base-300 rounded-lg p-4 mx-2">
@@ -273,30 +279,41 @@
{/if} {/if}
<div class="card-body"> <div class="card-body">
<div <div
class="flex justify-end mb-2 dropdown dropdown-bottom absolute top-4 right-4" class="mb-2 dropdown dropdown-bottom absolute top-4 right-4 bg-base-100"
> >
<button class="rounded-full p-2.5 hover:bg-base-100"> <button class="rounded-full p-2.5 hover:bg-base-100" on:click={toggleDropdown}>
<DotsVertical size={15} /> <DotsVertical size={15} />
</button> </button>
</div>
{#if dropdownOpen}
<ul <ul
tabindex="-1" tabindex="-1"
class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-64 gap-2" class="z-[1] menu p-2 shadow bg-base-100 rounded-box w-64 gap-2 border"
> >
<li> <!-- <div>
<button on:click={ausweisStornieren} <button on:click={ausweisStornieren} class="flex items-center gap-2" disabled
><CrossCircled size={15} />Ausweis Stornieren</button ><CrossCircled size={15} />Stornieren</button
> >
</li> </div>
<li> <div>
<button><Pencil2 size={15} /> Als Vorlage benutzen</button> <button class="flex items-center gap-2" disabled
</li> ><Pencil2 size={15} /> Als Vorlage</button>
<li> </div>
<button on:click={() => hilfeModal.showModal()} <div>
<button on:click={() => hilfeModal.showModal()} class="flex items-center gap-2" disabled
><QuestionMarkCircled size={15} /> Hilfe Erhalten</button ><QuestionMarkCircled size={15} /> Hilfe Erhalten</button
> >
</li> </div> -->
</ul> {#if ausweis.bestellt && rechnung}
<div>
<a href="/dashboard/rechnung/aendern?rechnungid={rechnung.id}"><button> Adresse ändern</button
></a>
</div> </div>
{/if}
</ul>
{/if}
<div class="flex flex-row flex-wrap items-center gap-2"> <div class="flex flex-row flex-wrap items-center gap-2">
{#if ausweis.ausgestellt} {#if ausweis.ausgestellt}
<span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span> <span class="bg-green-600 px-2 py-0.5 text-sm font-semibold rounded-lg text-white">Ausgestellt</span>
@@ -341,9 +358,6 @@
<div class="w-full border rounded-lg my-2"> <div class="w-full border rounded-lg my-2">
<div class="bg-green-600 h-4 rounded-lg" class:bg-red-600={progress == 33} class:bg-primary={progress == 66} style="width: {progress}%;"></div> <div class="bg-green-600 h-4 rounded-lg" class:bg-red-600={progress == 33} class:bg-primary={progress == 66} style="width: {progress}%;"></div>
</div> </div>
<span class="text-sm font-semibold text-base-content"
>{progress}%</span
>
</div> </div>
{#await calculations then calculations} {#await calculations then calculations}
<div class="flex flex-col mb-4"> <div class="flex flex-col mb-4">

View File

@@ -70,6 +70,7 @@
</div> </div>
</div> </div>
{/if} {/if}
<a href="/dashboard/abrechnung" class="button ">Conversions</a>
</div> </div>
<hr class="border-gray-600" /> <hr class="border-gray-600" />

View File

@@ -1,9 +1,27 @@
import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js"; import { API_ACCESS_TOKEN_COOKIE_NAME } from "#lib/constants.js";
import { checkAuthorizationHeader, checkAuthorizationHeaderNoThrow } from "#lib/middleware/authorization.js"; import { checkAuthorizationHeader, checkAuthorizationHeaderNoThrow } from "#lib/middleware/authorization.js";
import { AstroGlobal } from "astro"; import { AstroGlobal } from "astro";
import { Enums } from "#lib/client/prisma.js";
import { prisma } from "#lib/server/prisma.js";
export function getCurrentUser(Astro: AstroGlobal) { export function getCurrentUser(Astro: AstroGlobal) {
const accessToken = Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value; const accessToken = Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value;
return checkAuthorizationHeaderNoThrow(`Bearer ${accessToken}`) return checkAuthorizationHeaderNoThrow(`Bearer ${accessToken}`)
} }
export async function getOtherUser(Astro: AstroGlobal, userId : string) {
const accessToken = Astro.cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)?.value;
let currentUser = await checkAuthorizationHeaderNoThrow(`Bearer ${accessToken}`)
if (currentUser?.rolle == Enums.BenutzerRolle.ADMIN) {
const user = await prisma.benutzer.findUnique({
where: {
id: userId
}
})
return user;
}
return null;
}

View File

@@ -32,8 +32,12 @@
import { getMaximumDevitationInPercent } from "#client/lib/helpers.js"; import { getMaximumDevitationInPercent } from "#client/lib/helpers.js";
import { endEnergieVerbrauchVerbrauchsausweis_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016_Client.js"; import { endEnergieVerbrauchVerbrauchsausweis_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisWohnen/VerbrauchsausweisWohnen_2016_Client.js";
import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016_Client.js"; import { endEnergieVerbrauchVerbrauchsausweisGewerbe_2016_Client } from "#lib/Berechnungen/VerbrauchsausweisGewerbe/VerbrauchsausweisGewerbe_2016_Client.js";
import { benutzerSpeichern } from "#client/lib/speichern.js";
import { benutzerLesen } from "#client/lib/lesen.js";
import { exclude } from "#lib/exclude.js";
export let user: Partial<BenutzerClient>; export let user: Partial<BenutzerClient>;
export let impersonatedUser: Partial<BenutzerClient> | null = null;
export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe | BedarfsausweisWohnen; export let ausweis: VerbrauchsausweisWohnenClient | VerbrauchsausweisGewerbe | BedarfsausweisWohnen;
export let aufnahme: AufnahmeClient; export let aufnahme: AufnahmeClient;
export let objekt: ObjektClient; export let objekt: ObjektClient;
@@ -42,9 +46,8 @@
export let rechnung: RechnungClient | null = null; export let rechnung: RechnungClient | null = null;
export let ausweisart: Enums.Ausweisart; export let ausweisart: Enums.Ausweisart;
export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal; export let aktiveBezahlmethode: Bezahlmethoden = Enums.Bezahlmethoden.paypal;
export let partner_code: string; export let partner_code: string;
export let nurRechnungsadresseUpdate: Boolean | null = false;
let email: string, vorname: string, name: string, empfaenger: string, strasse: string, plz: string, ort: string, zusatzzeile: string, telefon: string; let email: string, vorname: string, name: string, empfaenger: string, strasse: string, plz: string, ort: string, zusatzzeile: string, telefon: string;
@@ -59,9 +62,22 @@
ort = rechnung?.ort || localStorage.getItem("kundendaten.ort") || user.ort || ""; ort = rechnung?.ort || localStorage.getItem("kundendaten.ort") || user.ort || "";
zusatzzeile = rechnung?.zusatzzeile || localStorage.getItem("kundendaten.zusatzzeile") || "" zusatzzeile = rechnung?.zusatzzeile || localStorage.getItem("kundendaten.zusatzzeile") || ""
telefon = rechnung?.telefon || localStorage.getItem("kundendaten.telefon") || user.telefon || ""; telefon = rechnung?.telefon || localStorage.getItem("kundendaten.telefon") || user.telefon || "";
} else if (impersonatedUser) {
vorname = impersonatedUser.vorname || "";
name = impersonatedUser.name || "";
telefon = impersonatedUser.telefon || "";
email = impersonatedUser.email || "";
if (rechnung){
empfaenger = rechnung?.empfaenger || "";
strasse = rechnung?.strasse || "";
plz = rechnung?.plz || "";
ort = rechnung?.ort || "";
zusatzzeile = rechnung?.zusatzzeile || "";
email = rechnung?.email || "";
}
} }
let abweichende_versand_adresse = JSON.parse(localStorage.getItem("kundendaten.abweichende_versand_adresse") || "false") let abweichende_versand_adresse = rechnung?.abweichende_versand_adresse ?? JSON.parse(localStorage.getItem("kundendaten.abweichende_versand_adresse") || "false")
let versand_email: string | undefined, let versand_email: string | undefined,
versand_zusatzzeile: string | undefined, versand_zusatzzeile: string | undefined,
@@ -69,16 +85,13 @@
versand_strasse: string | undefined, versand_strasse: string | undefined,
versand_plz: string | undefined, versand_plz: string | undefined,
versand_ort: string | undefined; versand_ort: string | undefined;
$: {
if (!abweichende_versand_adresse) { versand_email = "";//Todo Datenbankfeld fehlt noch
versand_email = email versand_zusatzzeile = rechnung?.versand_zusatzzeile ?? zusatzzeile;
versand_zusatzzeile = zusatzzeile versand_empfaenger = rechnung?.versand_empfaenger ?? empfaenger;
versand_empfaenger = empfaenger versand_strasse = rechnung?.versand_strasse ?? strasse;
versand_strasse = strasse versand_plz = rechnung?.versand_plz ?? plz;
versand_plz = plz versand_ort = rechnung?.versand_ort ?? ort;
versand_ort = ort
}
}
$: { $: {
// Wir speichern jede Änderung an den Kundendaten im localStorage ab. // Wir speichern jede Änderung an den Kundendaten im localStorage ab.
@@ -199,6 +212,12 @@
} }
try { try {
const merged_versand_empfaenger = versand_empfaenger || empfaenger;
const merged_versand_strasse = versand_strasse || strasse;
const merged_versand_plz = versand_plz || plz;
const merged_versand_ort = versand_ort || ort;
const merged_versand_zusatzzeile = versand_zusatzzeile || zusatzzeile;
const { id } = await api.rechnung.anfordern.PUT.fetch( const { id } = await api.rechnung.anfordern.PUT.fetch(
{ {
email: email, email: email,
@@ -206,10 +225,11 @@
strasse: strasse, strasse: strasse,
plz: plz, plz: plz,
ort: ort, ort: ort,
versand_empfaenger: versand_empfaenger, versand_empfaenger: merged_versand_empfaenger,
versand_strasse: versand_strasse, versand_strasse: merged_versand_strasse,
versand_plz: versand_plz, versand_plz: merged_versand_plz,
versand_ort: versand_ort, versand_ort: merged_versand_ort,
versand_zusatzzeile: merged_versand_zusatzzeile,
telefon: telefon, telefon: telefon,
nachweis_id: result.nachweis_id nachweis_id: result.nachweis_id
}, },
@@ -233,7 +253,7 @@
} }
} }
async function speichern() { async function speichern(authuser = null) {
loginAction = speichern; loginAction = speichern;
if (!await validateAccessTokenClient()) { if (!await validateAccessTokenClient()) {
loginOverlayHidden = false; loginOverlayHidden = false;
@@ -249,6 +269,62 @@
} else { } else {
result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart) result = await ausweisSpeichern(ausweis, objekt, aufnahme, bilder, unterlagen, ausweisart)
} }
if (authuser) {
user = await benutzerLesen(authuser.id);
}
let resultUser: Awaited<ReturnType<typeof benutzerSpeichern>> | Awaited<ReturnType<typeof benutzerSpeichern>> | null = null;
const { passwort, ...baseUser } = impersonatedUser ?? user;
const benutzerObjekt = {
...baseUser,
name,
vorname,
telefon
};
resultUser = await benutzerSpeichern(benutzerObjekt);
let id: string, checkout_url: string | undefined;
if (rechnung) {
const merged_versand_empfaenger = versand_empfaenger || empfaenger;
const merged_versand_strasse = versand_strasse || strasse;
const merged_versand_plz = versand_plz || plz;
const merged_versand_ort = versand_ort || ort;
const merged_versand_zusatzzeile = versand_zusatzzeile || zusatzzeile;
const result = await api.rechnung._id.PATCH.fetch({
bezahlmethode: aktiveBezahlmethode,
abweichende_versand_adresse: abweichende_versand_adresse,
empfaenger,
strasse,
plz,
ort,
telefon,
email,
zusatzzeile,
versand_empfaenger: merged_versand_empfaenger,
versand_strasse: merged_versand_strasse,
versand_plz: merged_versand_plz,
versand_ort: merged_versand_ort,
versand_zusatzzeile: merged_versand_zusatzzeile
}, {
params: {
id: rechnung.id
},
headers: {
Authorization: `Bearer ${Cookies.get(API_ACCESS_TOKEN_COOKIE_NAME)}`,
},
});
id = result.id;
checkout_url = result.checkout_url;
}
} catch(e) { } catch(e) {
addNotification({ addNotification({
dismissable: true, dismissable: true,
@@ -269,7 +345,7 @@
} }
} }
async function bestellen() { async function bestellen(authuser = null) {
if (!form.checkValidity()) { if (!form.checkValidity()) {
addNotification({ addNotification({
dismissable: true, dismissable: true,
@@ -312,6 +388,22 @@
} }
} }
if (authuser) {
user = await benutzerLesen(authuser.id);
}
let resultUser: Awaited<ReturnType<typeof benutzerSpeichern>> | Awaited<ReturnType<typeof benutzerSpeichern>> | null = null;
const { passwort, ...baseUser } = impersonatedUser ?? user;
const benutzerObjekt = {
...baseUser,
name,
vorname,
telefon
};
resultUser = await benutzerSpeichern(benutzerObjekt);
if (rechnung && rechnung.status === "paid") { if (rechnung && rechnung.status === "paid") {
window.location.href = "/dashboard" window.location.href = "/dashboard"
return; return;
@@ -320,6 +412,12 @@
try { try {
let id: string, checkout_url: string | undefined; let id: string, checkout_url: string | undefined;
const merged_versand_empfaenger = versand_empfaenger || empfaenger;
const merged_versand_strasse = versand_strasse || strasse;
const merged_versand_plz = versand_plz || plz;
const merged_versand_ort = versand_ort || ort;
const merged_versand_zusatzzeile = versand_zusatzzeile || zusatzzeile;
if (rechnung) { if (rechnung) {
const result = await api.rechnung._id.PATCH.fetch({ const result = await api.rechnung._id.PATCH.fetch({
bezahlmethode: aktiveBezahlmethode, bezahlmethode: aktiveBezahlmethode,
@@ -328,12 +426,13 @@
strasse: strasse, strasse: strasse,
plz: plz, plz: plz,
ort: ort, ort: ort,
versand_empfaenger: versand_empfaenger,
versand_strasse: versand_strasse,
versand_plz: versand_plz,
versand_ort: versand_ort,
telefon: telefon, telefon: telefon,
versand_zusatzzeile: versand_zusatzzeile zusatzzeile: zusatzzeile,
versand_empfaenger: merged_versand_empfaenger,
versand_strasse: merged_versand_strasse,
versand_plz: merged_versand_plz,
versand_ort: merged_versand_ort,
versand_zusatzzeile: merged_versand_zusatzzeile
}, { }, {
params: { params: {
id: rechnung.id id: rechnung.id
@@ -358,13 +457,16 @@
strasse: strasse, strasse: strasse,
plz: plz, plz: plz,
ort: ort, ort: ort,
versand_empfaenger: versand_empfaenger, zusatzzeile: zusatzzeile,
versand_strasse: versand_strasse, versand_empfaenger: merged_versand_empfaenger,
versand_plz: versand_plz, versand_strasse: merged_versand_strasse,
versand_ort: versand_ort, versand_plz: merged_versand_plz,
versand_ort: merged_versand_ort,
versand_zusatzzeile: merged_versand_zusatzzeile,
telefon: telefon, telefon: telefon,
ausweis_id: ausweis.id, ausweis_id: ausweis.id,
partner_code partner_code,
abweichende_versand_adresse: abweichende_versand_adresse
}, },
{ {
headers: { headers: {
@@ -404,6 +506,7 @@
let form: HTMLFormElement; let form: HTMLFormElement;
</script> </script>
{#if !nurRechnungsadresseUpdate}
<div <div
id="skala" id="skala"
class="bg-white grid grid-cols-1 gap-x-8 gap-y-4 px-0 sm:p-4 class="bg-white grid grid-cols-1 gap-x-8 gap-y-4 px-0 sm:p-4
@@ -434,7 +537,7 @@
<Progressbar active={1} {ausweisart} ausweistyp={ausweis.ausweistyp} anliegen={"Energieausweis erstellen"} /> <Progressbar active={1} {ausweisart} ausweistyp={ausweis.ausweistyp} anliegen={"Energieausweis erstellen"} />
{/if} {/if}
</div> </div>
{/if}
<form id="formInput-2" bind:this={form}> <form id="formInput-2" bind:this={form}>
<div id="formular-box" class="formular-boxen ring-0"> <div id="formular-box" class="formular-boxen ring-0">
@@ -702,7 +805,6 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
<input <input
name="versand_ort" name="versand_ort"
type="text" type="text"
readonly
required required
bind:value={versand_ort} bind:value={versand_ort}
/> />
@@ -739,7 +841,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
</div> </div>
<!-- E-mail --> <!-- E-mail -->
<!-- Versand Email wird derzeit nicht verwendet
<div class="input-standard order-12 md:order-12 xl:order-12"> <div class="input-standard order-12 md:order-12 xl:order-12">
<InputLabel title="E-mail *"></InputLabel> <InputLabel title="E-mail *"></InputLabel>
@@ -756,7 +858,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
</HelpLabel> </HelpLabel>
</div> </div>
</div> </div>
-->
<!-- Telefon <!-- Telefon
<div class="input-standard order-[13] md:order-[13] xl:order-[13]"> <div class="input-standard order-[13] md:order-[13] xl:order-[13]">
@@ -780,7 +882,7 @@ xl:grid-cols-3 xl:gap-x-8 xl:gap-y-8
</Bereich </Bereich
> >
{#if !gegAnfrage} {#if !gegAnfrage && !nurRechnungsadresseUpdate}
<Bereich bereich="3" title="Bezahlmethode"> <Bereich bereich="3" title="Bezahlmethode">
<div <div
id="bezahlung" id="bezahlung"
@@ -891,7 +993,7 @@ grid-cols-3 sm:grid-cols-5 justify-around justify-items-center items-center"
{/if} {/if}
<!-- Falls wir es mit einem Ausweis zu tun haben und der Nutzer keine Hilfe bestellt hat dann zeigen wir eine Box mit sachen an die vielleicht unklar sind. --> <!-- Falls wir es mit einem Ausweis zu tun haben und der Nutzer keine Hilfe bestellt hat dann zeigen wir eine Box mit sachen an die vielleicht unklar sind. -->
{#if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) && (ausweis.ausweistyp === Enums.AusweisTyp.Standard || ausweis.ausweistyp === Enums.AusweisTyp.standardXL)} {#if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen || ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe || ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) && (ausweis.ausweistyp === Enums.AusweisTyp.Standard || ausweis.ausweistyp === Enums.AusweisTyp.standardXL) && (!nurRechnungsadresseUpdate)}
<div class="grid grid-cols-1 sm:grid-cols-1 gap-x-6 my-6"> <div class="grid grid-cols-1 sm:grid-cols-1 gap-x-6 my-6">
<div class="pruefpunkte bereich-box bg-white"> <div class="pruefpunkte bereich-box bg-white">
<h3>Bitte untenstehende Punkte bestätigen. Bitte gehen Sie gegebenenfalls zurück zum Formular und überprüfen bzw. korrigieren Ihre Eingaben.</h3> <h3>Bitte untenstehende Punkte bestätigen. Bitte gehen Sie gegebenenfalls zurück zum Formular und überprüfen bzw. korrigieren Ihre Eingaben.</h3>
@@ -1072,15 +1174,16 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
<button class="order-2 button" type="button" on:click={speichern}>Speichern</button> <button class="order-2 button" type="button" on:click={() => speichern()}>Speichern</button>
{#if !nurRechnungsadresseUpdate}
{#if rechnung && rechnung.status === "paid"} {#if rechnung && rechnung.status === "paid"}
<!-- Von einer GEG Anfrage sollte man sowieso nicht noch mal auf die Kundendaten Seite gelangen, also brauchen wir das hier nicht. --> <!-- Von einer GEG Anfrage sollte man sowieso nicht noch mal auf die Kundendaten Seite gelangen, also brauchen wir das hier nicht. -->
<button <button
class="order-1 sm:order-2 button cursor-pointer" class="order-1 sm:order-2 button cursor-pointer"
data-cy="bestellen" data-cy="bestellen"
type="button" type="button"
on:click={bestellen}>Absenden</button on:click={() => bestellen()}>Absenden</button
> >
{:else} {:else}
{#if gegAnfrage} {#if gegAnfrage}
@@ -1095,10 +1198,11 @@ sm:grid-cols-[min-content_min-content_min-content] sm:justify-self-end sm:mt-8"
class="order-1 sm:order-2 button cursor-pointer" class="order-1 sm:order-2 button cursor-pointer"
data-cy="bestellen" data-cy="bestellen"
type="button" type="button"
on:click={bestellen}>Kostenpflichtig bestellen</button on:click={() => bestellen()}>Kostenpflichtig bestellen</button
> >
{/if} {/if}
{/if} {/if}
{/if}
{#if user.rolle === Enums.BenutzerRolle.ADMIN} {#if user.rolle === Enums.BenutzerRolle.ADMIN}
<button class="button text-sm" on:click={() => { <button class="button text-sm" on:click={() => {

View File

@@ -17,7 +17,6 @@ import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { z } from "astro:content"; import { z } from "astro:content";
import { transport } from "#lib/mail.js"; import { transport } from "#lib/mail.js";
import {Attachment} from "nodemailer/lib/mailer/index.js"; import {Attachment} from "nodemailer/lib/mailer/index.js";
import { BASE_URI } from "#lib/constants.js";
import { getAnsichtsausweis, getDatenblatt, getAushang } from "#lib/server/ausweis.js"; import { getAnsichtsausweis, getDatenblatt, getAushang } from "#lib/server/ausweis.js";
import { PutObjectCommand } from "@aws-sdk/client-s3"; import { PutObjectCommand } from "@aws-sdk/client-s3";
import { s3Client } from "#lib/s3.js"; import { s3Client } from "#lib/s3.js";
@@ -34,7 +33,6 @@ import {
getVerbrauchsausweisWohnenKomplett, getVerbrauchsausweisWohnenKomplett,
} from "#lib/server/db.js"; } from "#lib/server/db.js";
import { PDFDocument } from "pdf-lib"; import { PDFDocument } from "pdf-lib";
import * as fs from 'fs';
export const GET = defineApiRoute({ export const GET = defineApiRoute({
input: z.object({ input: z.object({

View File

@@ -197,7 +197,7 @@ export const POST = defineApiRoute({
let filename: string; let filename: string;
if (type === "Ausweis") { if (type === "Ausweis") {
filename = `ID_${ausweis.id}_Ausweis.pdf` filename = `ID_${ausweis.id}_Energieausweis.pdf`
} else { } else {
filename = `ID_${ausweis.id}_${name}`; filename = `ID_${ausweis.id}_${name}`;
} }
@@ -212,7 +212,7 @@ export const POST = defineApiRoute({
const command = new PutObjectCommand({ const command = new PutObjectCommand({
Bucket: "ibc-pdfs", Bucket: "ibc-pdfs",
Key: name, Key: filename,
Body: buffer, Body: buffer,
ACL: "private", ACL: "private",
}); });

View File

@@ -62,6 +62,7 @@ export const GET = defineApiRoute({
exp: refreshTokenExpiry.valueOf(), exp: refreshTokenExpiry.valueOf(),
}); });
console.log("Creating refresh token for user ID:", user.id);
const { id } = await prisma.refreshTokens.create({ const { id } = await prisma.refreshTokens.create({
data: { data: {
token: refreshToken, token: refreshToken,

View File

@@ -16,12 +16,14 @@ export const PATCH = defineApiRoute({
strasse: true, strasse: true,
telefon: true, telefon: true,
empfaenger: true, empfaenger: true,
zusatzzeile: true,
versand_empfaenger: true, versand_empfaenger: true,
versand_ort: true, versand_ort: true,
versand_plz: true, versand_plz: true,
versand_strasse: true, versand_strasse: true,
versand_zusatzzeile: true, versand_zusatzzeile: true,
abweichende_versand_adresse: true abweichende_versand_adresse: true,
email: true
}), }),
output: z.object({ output: z.object({
checkout_url: z.string().optional(), checkout_url: z.string().optional(),
@@ -31,7 +33,9 @@ export const PATCH = defineApiRoute({
headers: authorizationHeaders, headers: authorizationHeaders,
async fetch(input, context, user) { async fetch(input, context, user) {
// Wir holen uns die Rechnung // Wir holen uns die Rechnung
const rechnung = await prisma.rechnung.findUnique({ let rechnung;
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
rechnung = await prisma.rechnung.findUnique({
where: { where: {
id: context.params.id, id: context.params.id,
benutzer: { benutzer: {
@@ -47,6 +51,21 @@ export const PATCH = defineApiRoute({
verbrauchsausweis_wohnen: true verbrauchsausweis_wohnen: true
} }
}) })
} else {
rechnung = await prisma.rechnung.findUnique({
where: {
id: context.params.id
},
include: {
bedarfsausweis_gewerbe: true,
bedarfsausweis_wohnen: true,
geg_nachweis_gewerbe: true,
geg_nachweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true
}
})
}
if (!rechnung) { if (!rechnung) {
throw new APIError({ throw new APIError({
@@ -66,12 +85,14 @@ export const PATCH = defineApiRoute({
strasse: input.strasse, strasse: input.strasse,
telefon: input.telefon, telefon: input.telefon,
empfaenger: input.empfaenger, empfaenger: input.empfaenger,
zusatzzeile: input.zusatzzeile,
versand_empfaenger: input.versand_empfaenger, versand_empfaenger: input.versand_empfaenger,
versand_ort: input.versand_ort, versand_ort: input.versand_ort,
versand_plz: input.versand_plz, versand_plz: input.versand_plz,
versand_strasse: input.versand_strasse, versand_strasse: input.versand_strasse,
versand_zusatzzeile: input.versand_zusatzzeile, versand_zusatzzeile: input.versand_zusatzzeile,
abweichende_versand_adresse: input.abweichende_versand_adresse, abweichende_versand_adresse: input.abweichende_versand_adresse,
email: input.email
} }
}) })

View File

@@ -5,18 +5,17 @@ import { adminMiddleware, authorizationMiddleware } from "#lib/middleware/author
import { hashPassword } from "#lib/password.js"; import { hashPassword } from "#lib/password.js";
import { createLexOfficeCustomer } from "#lib/server/lexoffice.js"; import { createLexOfficeCustomer } from "#lib/server/lexoffice.js";
import { sendRegisterMail } from "#lib/server/mail/registrierung.js"; import { sendRegisterMail } from "#lib/server/mail/registrierung.js";
import { prisma } from "#lib/server/prisma.js"; import { Benutzer, prisma } from "#lib/server/prisma.js";
import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server";
import { BenutzerSchema } from "src/generated/zod/benutzer.js"; import { BenutzerSchema } from "src/generated/zod/benutzer.js";
import { z } from "zod"; import { z } from "zod";
import { Enums } from "#lib/client/prisma.js";
export const POST = defineApiRoute({ export const POST = defineApiRoute({
input: BenutzerSchema.omit({ input: BenutzerSchema.omit({
id: true,
lex_office_id: true, lex_office_id: true,
rolle: true, rolle: true,
created_at: true, created_at: true
updated_at: true
}), }),
middleware: authorizationMiddleware, middleware: authorizationMiddleware,
async fetch(input, context, user) { async fetch(input, context, user) {
@@ -24,24 +23,36 @@ export const POST = defineApiRoute({
// TODO: Email wurde geändert, neue Bestätigunsmail schicken. // TODO: Email wurde geändert, neue Bestätigunsmail schicken.
} }
const updateData: any = {};
updateData.id = user.id;
if (input.adresse) updateData.adresse = input.adresse;
if (input.anrede) updateData.anrede = input.anrede;
if (input.email) updateData.email = input.email;
if (input.firma) updateData.firma = input.firma;
if (input.name) updateData.name = input.name;
if (input.vorname) updateData.vorname = input.vorname;
if (input.ort) updateData.ort = input.ort;
if (input.passwort.length != 0) updateData.passwort = hashPassword(input.passwort);
if (input.plz) updateData.plz = input.plz;
if (input.profilbild) updateData.profilbild = input.profilbild;
if (input.telefon) updateData.telefon = input.telefon;
if (input.verified) updateData.telefon = input.verified;
//Only Admin can update other users
if (user.rolle == Enums.BenutzerRolle.ADMIN && input.id != user.id) {
updateData.id = input.id;
} else if(user.rolle != Enums.BenutzerRolle.ADMIN && input.id != user.id){
return;
}
await prisma.benutzer.update({ await prisma.benutzer.update({
where: { where: {
id: user.id id: updateData.id
}, },
data: { data: updateData
adresse: input.adresse, });
anrede: input.anrede,
email: input.email,
firma: input.firma,
name: input.name,
vorname: input.vorname,
ort: input.ort,
passwort: hashPassword(input.passwort),
plz: input.plz,
profilbild: input.profilbild,
telefon: input.telefon,
}
})
}, },
}) })
@@ -53,9 +64,14 @@ export const GET = defineApiRoute({
email: z.string() email: z.string()
})), })),
output: z.array(BenutzerSchema), output: z.array(BenutzerSchema),
middleware: adminMiddleware, middleware: authorizationMiddleware,
async fetch(input, context, admin) { async fetch(input, context, admin) {
if ("id" in input) { if ("id" in input) {
//Only Admin can read other users
if (admin.rolle != Enums.BenutzerRolle.ADMIN && input.id != admin.id) {
return;
}
const user = await prisma.benutzer.findUnique({ const user = await prisma.benutzer.findUnique({
where: { where: {
id: input.id id: input.id
@@ -68,6 +84,11 @@ export const GET = defineApiRoute({
return [user]; return [user];
} else { } else {
//Only admin can read many users
if (admin.rolle != Enums.BenutzerRolle.ADMIN ) {
return;
}
const users = await prisma.benutzer.findMany({ const users = await prisma.benutzer.findMany({
where: { where: {
email: { email: {

View File

@@ -0,0 +1,334 @@
---
import AbrechungTable from "#components/Abrechnung/AbrechungTable.svelte";
import { Enums, prisma } from "#lib/server/prisma";
import { getCurrentUser } from "#lib/server/user";
import moment from "moment";
const start = moment(Astro.url.searchParams.get("start"))
const end = moment(Astro.url.searchParams.get("end"))
let startdatum = start.toDate();
let enddatum = end.toDate();
const benutzer = await getCurrentUser(Astro)
if (!benutzer) {
return Astro.redirect("/404")
}
const provisionen={
[Enums.Ausweisart.VerbrauchsausweisWohnen]: 10,
[Enums.Ausweisart.BedarfsausweisWohnen]: 10,
[Enums.Ausweisart.VerbrauchsausweisGewerbe]: 10,
}
// $kommission = db()->one("SELECT abr_va, abr_ba, abr_vanw FROM users WHERE resellercode = :resellercode", ["resellercode" => $resellercode]);
// Select every entry from database where user was involved.
let bestellungen;
if (start.isValid() && end.isValid()) {
bestellungen = await prisma.rechnung.findMany({
where: {
partner_code: "immowelt",
OR: [{
verbrauchsausweis_gewerbe: {
ausgestellt: true
}
},
{
bedarfsausweis_wohnen: {
ausgestellt: true
}
},
{
verbrauchsausweis_wohnen: {
ausgestellt: true
}
}],
AND: [{
created_at: {
gte: startdatum
},
}, {
created_at: {
lte: enddatum
},
}]
},
orderBy: {
created_at: "desc"
},
include: {
bedarfsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true
}
});
} else {
bestellungen = await prisma.rechnung.findMany({
where: {
partner_code: "immowelt",
OR: [{
verbrauchsausweis_gewerbe: {
ausgestellt: true
}
},
{
bedarfsausweis_wohnen: {
ausgestellt: true
}
},
{
verbrauchsausweis_wohnen: {
ausgestellt: true
}
}]
},
orderBy: {
created_at: "desc"
},
include: {
bedarfsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
verbrauchsausweis_wohnen: true
}
});
}
// Wann wurde der partner_code zum ersten mal benutzt?
const partnerCodeErstesMal = (await prisma.rechnung.findFirst({
select: {
created_at: true
},
where: {
partner_code: "immowelt",
OR: [{
verbrauchsausweis_gewerbe: {
ausgestellt: true
}
},
{
bedarfsausweis_wohnen: {
ausgestellt: true
}
},
{
verbrauchsausweis_wohnen: {
ausgestellt: true
}
}],
created_at: {
gte: moment().set("year", 2020).set("dayOfYear", 1).toDate()
}
},
orderBy: {
created_at: "asc"
}
}))?.created_at
let provision = 0;
const ausweisarten: string[] = [];
for (const bestellung of bestellungen) {
if (bestellung.verbrauchsausweis_wohnen) {
ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisWohnen)
provision += provisionen[Enums.Ausweisart.VerbrauchsausweisWohnen]
}
if (bestellung.bedarfsausweis_wohnen) {
ausweisarten.push(Enums.Ausweisart.BedarfsausweisWohnen)
provision += provisionen[Enums.Ausweisart.BedarfsausweisWohnen]
}
if (bestellung.verbrauchsausweis_gewerbe) {
ausweisarten.push(Enums.Ausweisart.VerbrauchsausweisGewerbe)
provision += provisionen[Enums.Ausweisart.VerbrauchsausweisGewerbe]
}
}
---
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Reporting | online-energieausweis.org</title>
<meta charset="utf-8">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script type="text/javascript" src="https://cdn.jsdelivr.net/jquery/latest/jquery.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/momentjs/latest/moment.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.min.js"></script>
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/daterangepicker/daterangepicker.css" />
<link rel="stylesheet" href="./main.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.3/umd/popper.min.js" integrity="sha384-ZMP7rVo3mIykV+2+9J3UJ46jBk0WLaUAdn689aCwoqbBJiSnjAK/l8WvCWPIPm49" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js" integrity="sha384-ChfqqxuZUCnJSK3+MXmPNIyE6ZbWh2IMqE241rYiqJxyMiZ6OW/JmZQ5stwEULTy" crossorigin="anonymous"></script>
</head>
<style>
body {
font-family: arial;
}
#inputwrap {
position: fixed;
top: 0;
left: 10%;
width: 70%;
padding-top: 10px;
padding-bottom: 10px;
background: #fff;
}
#cal {
margin-right: 10px !important;
}
#demo {
width: 76%;
display: inline-block;
}
table tr,
td {
border: 0.1em solid #000;
padding: 0;
margin: 0;
}
#QTT {
border-collapse: collapse;
width: 70%;
margin-top: 8em;
margin-left: 10%;
table-layout: auto;
}
#QTT thead td {
background: #ff7d26;
font-weight: bold;
}
#QTT tr:nth-child(even) {
background-color: #f2f2f2;
}
#QTT td {
padding: 0.4em 0.4em 0.4em 0.4em;
text-align: right;
}
#logo1 {
display: inline-block;
margin-right: 1em;
margin-top: -3px;
}
#logo2 {
width: 18%;
margin-bottom: 0.5em;
float: right;
padding-top: -1px;
margin-right: -5px;
}
</style>
<div id='inputwrap' class='form-group' >
<div style='display:flex; justify-content: space-between; align-items:center;'>
<img id='logo1' src='https://widget.ib-cornelsen.de/OEA_WIDGETS/img/IBC-logo.png' alt='IBCornelsen' />
<h5 style='margin-top: 10px;'><b>Erziehlte Conversions von {benutzer.email}</b></h5>
</div>
<input type='text' id='demo' class='form-control' name='demo' value='' placeholder='Bitte Zeitraum auswählen' />
</div>
<AbrechungTable bestellungen={bestellungen} {provisionen} {partnerCodeErstesMal}></AbrechungTable>
<div id="total" class="footer">
<div class="inner">
<div>
<p id="betrag_gesamt">Abrechnungsbetrag gesamt: <b>{provision} €</b></p>
</div>
<a target='_blank' rel='noreferrer noopener' href=`/user/abrechnung/pdf.php?month=${moment().subtract(1, "month").get("month")}&year=${moment().subtract(1, "month").get("year")}`>PDF für letzten Monat generieren.</a>
</div>
</div>
<script type="text/javascript">
$('#demo').daterangepicker({
"showDropdowns": true,
"minYear": 2019,
ranges: {
'Heute': [moment(), moment()],
'Gestern': [moment().subtract(1, 'days'), moment().subtract(1, 'days')],
'letzte 7 Tage': [moment().subtract(6, 'days'), moment()],
'letzte 30 Tage': [moment().subtract(29, 'days'), moment()],
'dieser Monat': [moment().startOf('month'), moment().endOf('month')],
'letzter Monat': [moment().subtract(1, 'month').startOf('month'), moment().subtract(1, 'month').endOf('month')]
},
"locale": {
"format": "DD/MM/YYYY",
"separator": " - ",
"applyLabel": "Übernehmen",
"cancelLabel": "Abrechen",
"fromLabel": "Von",
"toLabel": "Bis",
"customRangeLabel": "Benutzerdefiniert",
"weekLabel": "W",
"daysOfWeek": [
"So",
"Mo",
"Di",
"Mi",
"Do",
"Fr",
"Sa"
],
"monthNames": [
"Januar",
"Februar",
"März",
"April",
"Mai",
"Juni",
"Juli",
"August",
"September",
"Oktober",
"November",
"Dezember"
],
"firstDay": 1
},
"autoUpdateInput": false,
"alwaysShowCalendars": true,
"startDate": "<?php echo $day_start_display; ?>",
"endDate": "<?php echo $day_end_display; ?>",
"minDate": "01/10/2019"
}, function(start, end, label) {
var Pstart = start.format('MM/DD/YYYY');
var Pend = end.format('MM/DD/YYYY');
$("#start").val(Pstart);
$("#end").val(Pend);
$('#FO').submit();
});
// $("#demo").val(`Conversions im Zeitraum: <?php echo $Pall; ?>`);
</script>
<body>
<form id='FO' method='GET' action='index.php'>
<input type="hidden" id="start" name="start" value='' />
<input type="hidden" id="end" name="end" value='' />
</form>
<script>
</script>
</body>
</html>

View File

@@ -0,0 +1,108 @@
---
import { encodeToken } from "#lib/auth/token";
import { TokenType } from "#lib/auth/types";
import { API_ACCESS_TOKEN_COOKIE_NAME, API_REFRESH_TOKEN_COOKIE_NAME } from "#lib/constants";
import { Enums, prisma } from "#lib/server/prisma";
import moment from "moment";
import { createCaller } from "src/astro-typesafe-api-caller";
import KundendatenModule from "#modules/KundendatenModule.svelte";
import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro";
import { getCurrentUser, getOtherUser } from "#lib/server/user";
import { getAusweisartFromId } from "#components/Ausweis/types";
import { getAufnahme, getBedarfsausweisWohnen, getBilder, getObjekt, getRechnung, getUnterlagen, getVerbrauchsausweisGewerbe, getVerbrauchsausweisWohnen } from "#lib/server/db";
import { BenutzerClient } from "#components/Ausweis/types.js";
function getExistingAusweis(rechnung) {
if (rechnung.verbrauchsausweis_wohnen) {
return rechnung.verbrauchsausweis_wohnen;
}
if (rechnung.verbrauchsausweis_gewerbe) {
return rechnung.verbrauchsausweis_gewerbe;
}
if (rechnung.bedarfsausweis_wohnen) {
return rechnung.bedarfsausweis_wohnen ;
}
if (rechnung.bedarfsausweis_gewerbe) {
return rechnung.bedarfsausweis_gewerbe;
}
if (rechnung.geg_nachweis_gewerbe) {
return rechnung.geg_nachweis_gewerbe;
}
if (rechnung.geg_nachweis_wohnen) {
return rechnung.geg_nachweis_wohnen;
}
return null;
}
const user = await getCurrentUser(Astro);
if (!user) {
return Astro.redirect("/auth/login")
}
const rechnungid = Astro.url.searchParams.get("rechnungid")
if (!rechnungid) {
return Astro.redirect("/404")
}
let rechnung;
//Only Admin can read foreign invoices
if (user.rolle !== Enums.BenutzerRolle.ADMIN) {
rechnung = await prisma.rechnung.findUnique({
where: {
id: rechnungid,
benutzer_id: user.id
},
include: {
verbrauchsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
bedarfsausweis_wohnen: true,
bedarfsausweis_gewerbe: true,
geg_nachweis_gewerbe: true,
geg_nachweis_wohnen: true
}
})
} else {
rechnung = await prisma.rechnung.findUnique({
where: {
id: rechnungid,
},
include: {
verbrauchsausweis_wohnen: true,
verbrauchsausweis_gewerbe: true,
bedarfsausweis_wohnen: true,
bedarfsausweis_gewerbe: true,
geg_nachweis_gewerbe: true,
geg_nachweis_wohnen: true
}
})
}
if (!rechnung) {
return Astro.redirect("/404")
}
const ausweis = getExistingAusweis(rechnung);
const ausweisart = getAusweisartFromId(ausweis.id)
let aufnahme, objekt, bilder, unterlagen, partner_code;
aufnahme = await getAufnahme(ausweis.aufnahme_id)
objekt = await getObjekt(aufnahme?.objekt_id)
bilder = await getBilder(ausweis.aufnahme_id)
unterlagen = await getUnterlagen(ausweis.aufnahme_id)
let impersonatedUser: Partial<BenutzerClient> | null = null;
if (user){
if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){
impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {}
}
}
---
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
<KundendatenModule {user} {impersonatedUser} {ausweis} {objekt} {aufnahme} {bilder} {rechnung} {ausweisart} {unterlagen} {partner_code} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} nurRechnungsadresseUpdate={true} client:only ></KundendatenModule>
</AusweisLayout>

View File

@@ -3,10 +3,11 @@ import { getAusweisartFromId } from "#components/Ausweis/types";
import AusweisLayoutPruefung from "#layouts/AusweisLayoutPruefung.astro"; import AusweisLayoutPruefung from "#layouts/AusweisLayoutPruefung.astro";
import { getPrismaAusweisAdapter } from "#lib/server/ausweis"; import { getPrismaAusweisAdapter } from "#lib/server/ausweis";
import { Enums } from "#lib/server/prisma"; import { Enums } from "#lib/server/prisma";
import { getCurrentUser } from "#lib/server/user"; import { getCurrentUser, getOtherUser } from "#lib/server/user";
import KundendatenModule from "#modules/KundendatenModule.svelte"; import KundendatenModule from "#modules/KundendatenModule.svelte";
import { PaymentStatus } from "@mollie/api-client"; import { PaymentStatus } from "@mollie/api-client";
import { AusweisTyp } from "src/generated/enums"; import { AusweisTyp } from "src/generated/enums";
import { BenutzerClient } from "#components/Ausweis/types.js";
const uid = Astro.url.searchParams.get("uid") const uid = Astro.url.searchParams.get("uid")
@@ -45,8 +46,16 @@ if (!ausweis) {
if (ausweis.rechnung.status === PaymentStatus.paid) { if (ausweis.rechnung.status === PaymentStatus.paid) {
return Astro.redirect("/dashboard") return Astro.redirect("/dashboard")
} }
let impersonatedUser: Partial<BenutzerClient> | null = null;
if (user){
if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){
impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {}
}
}
--- ---
<AusweisLayoutPruefung title="Energieausweis Bezahlung"> <AusweisLayoutPruefung title="Energieausweis Bezahlung">
<KundendatenModule {user} {ausweis} objekt={ausweis.aufnahme.objekt} rechnung={ausweis.rechnung} aufnahme={ausweis.aufnahme} bilder={ausweis.aufnahme.bilder} {ausweisart} ausweistyp={AusweisTyp.Standard} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:only></KundendatenModule> <KundendatenModule {user} {impersonatedUser} {ausweis} objekt={ausweis.aufnahme.objekt} rechnung={ausweis.rechnung} aufnahme={ausweis.aufnahme} bilder={ausweis.aufnahme.bilder} {ausweisart} ausweistyp={AusweisTyp.Standard} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:only></KundendatenModule>
</AusweisLayoutPruefung> </AusweisLayoutPruefung>

View File

@@ -0,0 +1,19 @@
---
import { getHeapSnapshot } from "v8";
import * as fs from "fs";
// Create a named heap snapshot
const snapshotStream = getHeapSnapshot();
const fileName = `heap-${Date.now()}.heapsnapshot`;
const fileStream = fs.createWriteStream(fileName);
snapshotStream.pipe(fileStream);
fileStream.on("finish", () => {
console.log(`Heap snapshot saved to ${fileName}`);
});
fileStream.on("error", (err) => {
console.error("Error writing heap snapshot:", err);
});
---

View File

@@ -3,9 +3,10 @@
import KundendatenModule from "#modules/KundendatenModule.svelte"; import KundendatenModule from "#modules/KundendatenModule.svelte";
import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro"; import AusweisLayout from "#layouts/AusweisLayoutPruefung.astro";
import { Enums } from "#lib/client/prisma"; import { Enums } from "#lib/client/prisma";
import { getCurrentUser } from "#lib/server/user"; import { getCurrentUser, getOtherUser } from "#lib/server/user";
import { getAusweisartFromId } from "#components/Ausweis/types"; import { getAusweisartFromId } from "#components/Ausweis/types";
import { getAufnahme, getBedarfsausweisWohnen, getBilder, getObjekt, getRechnung, getUnterlagen, getVerbrauchsausweisGewerbe, getVerbrauchsausweisWohnen } from "#lib/server/db"; import { getAufnahme, getBedarfsausweisWohnen, getBilder, getObjekt, getRechnung, getUnterlagen, getVerbrauchsausweisGewerbe, getVerbrauchsausweisWohnen } from "#lib/server/db";
import { BenutzerClient } from "#components/Ausweis/types.js";
// Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde. // Man sollte nur auf diese Seite kommen, wenn ein Ausweis bereits vorliegt und in der Datenbank abgespeichert wurde.
@@ -70,9 +71,16 @@ if (!params.has("ausweis") || !params.has("aufnahme") || !params.has("objekt") |
} }
} }
let impersonatedUser: Partial<BenutzerClient> | null = null;
if (user){
if (user.id !== ausweis.benutzer_id && ausweis.benutzer_id !== undefined){
impersonatedUser = await getOtherUser(Astro, ausweis.benutzer_id) || {}
}
}
--- ---
<AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen"> <AusweisLayout title="Kundendaten Aufnehmen - IBCornelsen">
<KundendatenModule {user} {ausweis} {objekt} {aufnahme} {bilder} {rechnung} {ausweisart} {unterlagen} {partner_code} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:only ></KundendatenModule> <KundendatenModule {user} {impersonatedUser} {ausweis} {objekt} {aufnahme} {bilder} {rechnung} {ausweisart} {unterlagen} {partner_code} aktiveBezahlmethode={Enums.Bezahlmethoden.paypal} client:only ></KundendatenModule>
</AusweisLayout> </AusweisLayout>

View File

@@ -45,14 +45,23 @@ export const GET: APIRoute = async (Astro) => {
user = await getCurrentUser(Astro) user = await getCurrentUser(Astro)
let pdf: Uint8Array<ArrayBufferLike> | null = null; let pdf: Uint8Array<ArrayBufferLike> | null = null;
if (ausweis.ausgestellt) {
if (/[A-Z]{2}[0-9]{8}/.test(ausweis.id)) { if (/[A-Z]{2}[0-9]{8}/.test(ausweis.id)) {
const id = ausweis.id.match(/[A-Z]{2}([0-9]{8})/) as RegExpMatchArray const id = ausweis.id.match(/[A-Z]{2}([0-9]{8})/) as RegExpMatchArray
// Dieser Ausweis wurde mit der alten Version erstellt, das PDF sollte bereits existieren. // Dieser Ausweis wurde mit der alten Version erstellt, das PDF sollte bereits existieren.
pdf = await getS3File("ibc-pdfs", `ID_${id[1]}_Energieausweis.pdf`) pdf = await getS3File("ibc-pdfs", `ID_${id[1]}_Energieausweis.pdf`)
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) { } else {
pdf = await getS3File("ibc-pdfs", `ID_${ausweis.id}_Energieausweis.pdf`)
}
} else {
if (ausweisart === Enums.Ausweisart.VerbrauchsausweisWohnen) {
pdf = await pdfVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt); pdf = await pdfVerbrauchsausweisWohnen(ausweis as VerbrauchsausweisWohnenClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt);
} else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) { } else if (ausweisart === Enums.Ausweisart.VerbrauchsausweisGewerbe) {
pdf = await pdfVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt); pdf = await pdfVerbrauchsausweisGewerbe(ausweis as VerbrauchsausweisGewerbeClient, aufnahme, objekt, bilder, user, !ausweis.ausgestellt);
} else if (ausweisart === Enums.Ausweisart.BedarfsausweisWohnen) {
//todo
}
} }
return new Response(pdf, { return new Response(pdf, {

View File

@@ -9,6 +9,22 @@ DB_NAME="main"
TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S")
FILE_NAME="backup-$TIMESTAMP.sql.br" FILE_NAME="backup-$TIMESTAMP.sql.br"
# Wir holen uns den parameter --skip-backup, um zu entscheiden, ob wir ein Backup machen wollen
SKIP_BACKUP=false
while [[ $# -gt 0 ]]; do
case $1 in
--skip-backup)
SKIP_BACKUP=true
shift # Remove the argument from the list
;;
*)
echo "Unbekannter Parameter: $1"
exit 1
;;
esac
done
REQUIRED_CONFIRMATION='Ja, ich möchte alle Daten unwiderruflich löschen.' REQUIRED_CONFIRMATION='Ja, ich möchte alle Daten unwiderruflich löschen.'
echo "⚠️ WARNUNG: Diese Aktion wird alle Tabellen und Einträge in der Datenbank vollständig löschen!" echo "⚠️ WARNUNG: Diese Aktion wird alle Tabellen und Einträge in der Datenbank vollständig löschen!"
@@ -21,9 +37,11 @@ if [[ "$USER_CONFIRMATION" != "$REQUIRED_CONFIRMATION" ]]; then
exit 1 exit 1
fi fi
if [[ "$SKIP_BACKUP" == false ]]; then
echo "📦 Backup wird erstellt..." echo "📦 Backup wird erstellt..."
docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli > "$FILE_NAME" docker exec -t "$CONTAINER_NAME" pg_dumpall -c -U "$DB_USER" | brotli > "$FILE_NAME"
echo "✅ Backup abgeschlossen: $FILE_NAME" echo "✅ Backup abgeschlossen: $FILE_NAME"
fi
echo "🧨 Alle Daten aus allen Tabellen werden gelöscht..." echo "🧨 Alle Daten aus allen Tabellen werden gelöscht..."
@@ -34,6 +52,7 @@ DECLARE
r RECORD; r RECORD;
sql TEXT := ''; sql TEXT := '';
BEGIN BEGIN
-- Truncate all tables
FOR r IN FOR r IN
SELECT tablename SELECT tablename
FROM pg_tables FROM pg_tables
@@ -42,6 +61,15 @@ BEGIN
sql := sql || FORMAT('TRUNCATE TABLE public.%I CASCADE;', r.tablename); sql := sql || FORMAT('TRUNCATE TABLE public.%I CASCADE;', r.tablename);
END LOOP; END LOOP;
-- Drop all sequences
FOR r IN
SELECT sequence_name
FROM information_schema.sequences
WHERE sequence_schema = 'public'
LOOP
sql := sql || FORMAT('DROP SEQUENCE IF EXISTS public.%I CASCADE;', r.sequence_name);
END LOOP;
EXECUTE sql; EXECUTE sql;
END END
$$; $$;