From 6f3ddedd9671956f90dd7df839fcdf1bdf7f8fda Mon Sep 17 00:00:00 2001 From: Moritz Utcke Date: Fri, 24 Jan 2025 14:04:58 +0700 Subject: [PATCH] OpenAPI Generierung verbessert --- openapi.json | 1522 ++++++++++++++++- .../3c319927-d226-4c84-8650-11bcc3d90670.webp | Bin 51548 -> 0 bytes src/astro-typesafe-api-caller.ts | 2 +- src/components/Ausweis/types.ts | 15 +- src/lib/constants.ts | 33 +- src/lib/middleware/authorization.ts | 5 + src/pages/api/aufnahme/[uid].ts | 4 +- src/pages/api/aufnahme/index.ts | 7 +- src/pages/api/auth/access-token.ts | 1 - src/pages/api/auth/refresh-token.ts | 3 +- src/pages/api/objekt/index.ts | 3 +- src/pages/api/ticket.ts | 3 +- src/pages/api/user/index.ts | 3 +- .../api/verbrauchsausweis-wohnen/[uid].ts | 8 +- .../api/verbrauchsausweis-wohnen/index.ts | 12 +- 15 files changed, 1595 insertions(+), 26 deletions(-) delete mode 100644 persistent/images/3c319927-d226-4c84-8650-11bcc3d90670.webp diff --git a/openapi.json b/openapi.json index d69505c3..de8cae85 100644 --- a/openapi.json +++ b/openapi.json @@ -1 +1,1521 @@ -{"openapi":"3.0.3","info":{"title":"Title","version":"1.0.0","description":""},"paths":{"klimafaktoren":{"get":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"plz":{"type":"string","minLength":4,"maxLength":5},"startdatum":{"type":"string","format":"date-time"},"enddatum":{"type":"string","format":"date-time"},"genauigkeit":{"type":"string","enum":["months","years"]}},"required":["plz","startdatum","enddatum","genauigkeit"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"month":{"type":"number"},"year":{"type":"number"},"klimafaktor":{"type":"number"}},"required":["month","year","klimafaktor"],"additionalProperties":false}}}}}}}},"postleitzahlen":{"get":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"plz":{"type":"string","minLength":1,"maxLength":5},"limit":{"type":"integer","maximum":50,"minimum":1,"default":10}},"required":["plz"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"plz":{"type":"string","minLength":4,"maxLength":5},"stadt":{"type":"string"},"bundesland":{"type":"string"},"landkreis":{"type":"string"},"lat":{"type":"number"},"lon":{"type":"number"}},"required":["plz","stadt","bundesland","landkreis","lat","lon"],"additionalProperties":false}}}}}}}},"index":{"put":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"latitude":{"type":"number","nullable":true},"longitude":{"type":"number","nullable":true},"plz":{"type":"string","nullable":true,"description":"Postleitzahl des Gebäudes"},"ort":{"type":"string","nullable":true,"description":"Ort des Gebäudes"},"adresse":{"type":"string","nullable":true,"description":"Adresse (Straße und Hausnummer) des Gebäudes"}},"required":["latitude","longitude","plz","ort","adresse"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string","format":"uuid"}},"required":["uid"],"additionalProperties":false}}}}}}},"[uid]":{"patch":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"ausweisart":{"type":"string","enum":["VerbrauchsausweisWohnen","VerbrauchsausweisGewerbe","BedarfsausweisWohnen","BedarfsausweisGewerbe"],"description":"Art des korrespondierenden Ausweises, wie z.B. VerbrauchsausweisWohnen","nullable":true},"gebaeudetyp":{"type":"string","nullable":true,"description":"Art des Gebäudes und seiner primären Nutzungsart"},"gebaeudeteil":{"type":"string","nullable":true,"description":"Betrachteter Teil des Gebäudes, z.B. Gesamtgebäude, Wohnteil, Gewerbeteil"},"baujahr_gebaeude":{"type":"array","items":{"type":"integer"},"description":"Alle Jahre in denen das Gebäude konstruiert oder grundlegend verändert wurde"},"baujahr_heizung":{"type":"array","items":{"type":"integer"},"description":"Alle Jahre in denen die Heizung eingebaut oder grundlegend verändert wurde"},"baujahr_klima":{"type":"array","items":{"type":"integer"},"description":"Alle Jahre in denen die Klimaanlage eingebaut oder grundlegend verändert wurde"},"einheiten":{"type":"integer","description":"Anzahl der (Wohn)Einheiten im Gebäude","nullable":true},"flaeche":{"type":"integer","description":"Wohnfläche bei Wohngebäuden, Nutzfläche bei Gewerbegebäuden","nullable":true},"nutzflaeche":{"type":"integer","description":"(energetische) Nutzfläche des Gebäudes. Bei Gewerbegebäuden entspricht Sie der Nutzfläche","nullable":true},"saniert":{"type":"boolean","nullable":true,"description":"Falls das Gebäude energetisch saniert ist, sollte dieser Wert auf true stehen"},"keller":{"type":"string","enum":["BEHEIZT","UNBEHEIZT","NICHT_VORHANDEN"],"description":"Ob ein Keller vorhanden, beheizt oder unbeheizt ist","nullable":true},"dachgeschoss":{"type":"string","enum":["BEHEIZT","UNBEHEIZT","NICHT_VORHANDEN"],"description":"Ob ein Dachgeschoss vorhanden, beheizt oder unbeheizt ist","nullable":true},"lueftung":{"type":"string","enum":["Fensterlueftung","Schachtlueftung","LueftungsanlageMitWaermerueckgewinnung","LueftungsanlageOhneWaermerueckgewinnung"],"description":"Art der Gebäudelüftung","nullable":true},"kuehlung":{"type":"string","nullable":true,"description":"Art der Gebäudekühlung"},"leerstand":{"type":"integer","description":"Prozentualer Leerstand des Gebäudes in einem durchschnittlichen Jahr","nullable":true},"alternative_heizung":{"type":"boolean","nullable":true,"description":"Falls der Heizungsverbrauch alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen"},"alternative_warmwasser":{"type":"boolean","nullable":true,"description":"Falls der Warmwasserverbrauch alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen"},"alternative_lueftung":{"type":"boolean","nullable":true,"description":"Falls die Lüftung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen"},"alternative_kuehlung":{"type":"boolean","nullable":true,"description":"Falls die Kühlung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen"},"brennstoff_1":{"type":"string","nullable":true,"description":"Genutzer Brennstoff der primären Energiequelle"},"brennstoff_2":{"type":"string","nullable":true,"description":"Genutzer Brennstoff der sekundären Energiequelle"},"storniert":{"type":"boolean","nullable":true,"description":"Falls der Ausweis storniert wurde, sollte dieser Wert auf true stehen"},"erledigt":{"type":"boolean","nullable":true,"description":"Falls der Ausweis erledigt ist, sollte dieser Wert auf true stehen"},"bestellt":{"type":"boolean","nullable":true,"description":"Falls der Ausweis bestellt wurde, sollte dieser Wert auf true stehen"},"zurueckgestellt":{"type":"boolean","nullable":true,"description":"Falls der Ausweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen"},"prueftext":{"type":"string","nullable":true,"description":"Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung"},"boxpruefung":{"type":"boolean","nullable":true},"energieeffizienzklasse":{"type":"string","nullable":true,"description":"Die aus der Berechnung hervorgehende Energieeffizienzklasse des Gebäudes"},"erstellungsdatum":{"type":"string","format":"date-time","description":"Datum an dem der Kunde den Ausweis erstellt hat","nullable":true},"ausstellungsdatum":{"type":"string","format":"date-time","description":"Datum an dem der Aussteller den Ausweis ausgestellt hat","nullable":true},"zentralheizung":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über eine Zentralbeheizung verfügt, sollte dieser Wert auf true stehen"},"solarsystem_warmwasser":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über ein Solarsystem für Warmwasser verfügt, sollte dieser Wert auf true stehen"},"warmwasser_rohre_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die Warmwasserrohre des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen"},"niedertemperatur_kessel":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über einen Niedertemperaturkessel verfügt, sollte dieser Wert auf true stehen"},"brennwert_kessel":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über einen Brennwertkessel verfügt, sollte dieser Wert auf true stehen"},"heizungsrohre_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die Heizungsrohre des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen"},"standard_kessel":{"type":"boolean","nullable":true},"waermepumpe":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über eine Wärmepumpe verfügt, sollte dieser Wert auf true stehen"},"raum_temperatur_regler":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über einen Raumtemperaturregler verfügt, sollte dieser Wert auf true stehen"},"photovoltaik":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über eine Photovoltaikanlage verfügt, sollte dieser Wert auf true stehen"},"durchlauf_erhitzer":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über einen Durchlauferhitzer verfügt, sollte dieser Wert auf true stehen"},"einzelofen":{"type":"boolean","nullable":true},"zirkulation":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über eine Zirkulationspumpe verfügt, sollte dieser Wert auf true stehen"},"einfach_verglasung":{"type":"boolean","nullable":true,"description":"Falls die Fenster des Gebäudes einfach gedämmt sind, sollte dieser Wert auf true stehen"},"dreifach_verglasung":{"type":"boolean","nullable":true,"description":"Falls die Fenster des Gebäudes dreifach gedämmt sind, sollte dieser Wert auf true stehen"},"fenster_teilweise_undicht":{"type":"boolean","nullable":true,"description":"Falls die Fenster des Gebäudes teilweise undicht sind, sollte dieser Wert auf true stehen"},"doppel_verglasung":{"type":"boolean","nullable":true,"description":"Falls die Fenster des Gebäudes doppelt gedämmt sind, sollte dieser Wert auf true stehen"},"fenster_dicht":{"type":"boolean","nullable":true,"description":"Falls die Fenster des Gebäudes dicht sind, sollte dieser Wert auf true stehen"},"rolllaeden_kaesten_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls das Gebäude über gedämmte Rolllädenkästen verfügt, sollte dieser Wert auf true stehen"},"isolier_verglasung":{"type":"boolean","nullable":true,"description":"Falls die Fenster des Gebäudes isolier Verglasung haben, sollte dieser Wert auf true stehen"},"tueren_undicht":{"type":"boolean","nullable":true,"description":"Falls die Türen des Gebäudes undicht sind, sollte dieser Wert auf true stehen"},"tueren_dicht":{"type":"boolean","nullable":true,"description":"Falls die Türen des Gebäudes dicht sind, sollte dieser Wert auf true stehen"},"dachgeschoss_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls das Dachgeschoss des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen"},"keller_decke_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die Kellerdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen"},"keller_wand_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die Kellerwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen"},"aussenwand_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die Außenwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen"},"oberste_geschossdecke_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die oberste Geschossdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen"},"aussenwand_min_12cm_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die Außenwände des Gebäudes mindestens 12cm gedämmt sind, sollte dieser Wert auf true stehen"},"dachgeschoss_min_12cm_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls das Dachgeschoss des Gebäudes mindestens 12cm gedämmt ist, sollte dieser Wert auf true stehen"},"oberste_geschossdecke_min_12cm_gedaemmt":{"type":"boolean","nullable":true,"description":"Falls die oberste Geschossdecke des Gebäudes mindestens 12cm gedämmt ist, sollte dieser Wert auf true stehen"}},"required":["ausweisart","gebaeudetyp","gebaeudeteil","baujahr_gebaeude","baujahr_heizung","baujahr_klima","einheiten","flaeche","nutzflaeche","saniert","keller","dachgeschoss","lueftung","kuehlung","leerstand","alternative_heizung","alternative_warmwasser","alternative_lueftung","alternative_kuehlung","brennstoff_1","brennstoff_2","storniert","erledigt","bestellt","zurueckgestellt","prueftext","boxpruefung","energieeffizienzklasse","erstellungsdatum","ausstellungsdatum","zentralheizung","solarsystem_warmwasser","warmwasser_rohre_gedaemmt","niedertemperatur_kessel","brennwert_kessel","heizungsrohre_gedaemmt","standard_kessel","waermepumpe","raum_temperatur_regler","photovoltaik","durchlauf_erhitzer","einzelofen","zirkulation","einfach_verglasung","dreifach_verglasung","fenster_teilweise_undicht","doppel_verglasung","fenster_dicht","rolllaeden_kaesten_gedaemmt","isolier_verglasung","tueren_undicht","tueren_dicht","dachgeschoss_gedaemmt","keller_decke_gedaemmt","keller_wand_gedaemmt","aussenwand_gedaemmt","oberste_geschossdecke_gedaemmt","aussenwand_min_12cm_gedaemmt","dachgeschoss_min_12cm_gedaemmt","oberste_geschossdecke_min_12cm_gedaemmt"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{}}}}}}},"ticket":{"put":{"description":"Erstellt ein neues Support Ticket und weist den Ersteller diesem zu, falls ein Authorization Header mitgegeben wurde.","tags":["Tickets"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"titel":{"type":"string"},"beschreibung":{"type":"string"},"metadata":{"anyOf":[{"anyOf":[{"type":"string"},{"type":"number"},{"type":"boolean"}]},{"type":"array","items":{"$ref":"#/properties/metadata"}},{"type":"object","additionalProperties":{"$ref":"#/properties/metadata"}}]},"email":{"type":"string"}},"required":["titel","beschreibung","metadata","email"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string","format":"uuid"}},"required":["uid"],"additionalProperties":false}}}}}}},"access-token":{"get":{"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"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"refreshToken":{"type":"string"}},"required":["refreshToken"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"accessToken":{"type":"string"},"accessTokenExpiry":{"type":"number"},"refreshToken":{"type":"string"},"refreshTokenExpiry":{"type":"number"}},"required":["accessToken","accessTokenExpiry","refreshToken","refreshTokenExpiry"],"additionalProperties":false}}}}}}},"refresh-token":{"get":{"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"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"passwort":{"type":"string","minLength":8,"maxLength":100}},"required":["email","passwort"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string","format":"uuid"},"accessToken":{"type":"string"},"refreshToken":{"type":"string"},"refreshTokenBase64":{"type":"string"},"accessTokenBase64":{"type":"string"},"exp":{"type":"number"}},"required":["uid","accessToken","refreshToken","refreshTokenBase64","accessTokenBase64","exp"],"additionalProperties":false}}}}}}},"self":{"get":{"description":"Gibt die Daten des momentan eingeloggten Benutzers zurück. Falls der Authorization Key invalid ist wird stattdessen null zurückgegeben.","tags":["Benutzer"],"requestBody":{"required":true,"content":{"application/json":{"schema":{}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"uid":{"type":"string"},"name":{"type":"string","nullable":true},"vorname":{"type":"string","nullable":true},"email":{"type":"string"},"profilbild":{"type":"string","nullable":true},"plz":{"type":"string","nullable":true},"ort":{"type":"string","nullable":true},"adresse":{"type":"string","nullable":true},"telefon":{"type":"string","nullable":true},"anrede":{"type":"string","nullable":true},"rolle":{"type":"string","enum":["USER","ADMIN"]}},"required":["uid","name","vorname","email","profilbild","plz","ort","adresse","telefon","anrede","rolle"],"additionalProperties":false},{"enum":["null"],"nullable":true}]}}}}}}},"bilder":{"put":{"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"kategorie":{"type":"string","enum":["Heizung","Fenster","Gebaeude","Daemmung"]},"base64":{"type":"string"}},"required":["kategorie","base64"],"additionalProperties":false}}}},"parameters":[],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string","description":"Die UID des Bildes."}},"required":["uid"],"additionalProperties":false}}}}}}}}} \ No newline at end of file +{ + "openapi": "3.0.3", + "info": { "title": "Title", "version": "1.0.0", "description": "" }, + "paths": { + "/klimafaktoren": { + "get": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "plz": { + "type": "string", + "minLength": 4, + "maxLength": 5 + }, + "startdatum": { + "type": "string", + "format": "date-time" + }, + "enddatum": { + "type": "string", + "format": "date-time" + }, + "genauigkeit": { + "type": "string", + "enum": ["months", "years"] + } + }, + "required": [ + "plz", + "startdatum", + "enddatum", + "genauigkeit" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "month": { "type": "number" }, + "year": { "type": "number" }, + "klimafaktor": { "type": "number" } + }, + "required": [ + "month", + "year", + "klimafaktor" + ], + "additionalProperties": false + } + } + } + } + } + } + } + }, + "/postleitzahlen": { + "get": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "plz": { + "type": "string", + "minLength": 1, + "maxLength": 5 + }, + "limit": { + "type": "integer", + "maximum": 50, + "minimum": 1, + "default": 10 + } + }, + "required": ["plz"], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "object", + "properties": { + "plz": { + "type": "string", + "minLength": 4, + "maxLength": 5 + }, + "stadt": { "type": "string" }, + "bundesland": { "type": "string" }, + "landkreis": { "type": "string" }, + "lat": { "type": "number" }, + "lon": { "type": "number" } + }, + "required": [ + "plz", + "stadt", + "bundesland", + "landkreis", + "lat", + "lon" + ], + "additionalProperties": false + } + } + } + } + } + } + } + }, + "/verbrauchsausweis-wohnen/": { + "patch": { + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { "application/json": { "schema": {} } } + } + } + } + }, + "/verbrauchsausweis-wohnen/{uid}": { + "patch": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ausstellgrund": { + "type": "string", + "enum": [ + "Neubau", + "Vermietung", + "Verkauf", + "Modernisierung", + "Sonstiges" + ], + "description": "Ausstellgrund wie z.B. Vermietung oder Verkauf", + "nullable": true + }, + "registriernummer": { + "type": "string", + "nullable": true, + "description": "Die Registriernummer des Ausweises" + }, + "zusaetzliche_heizquelle": { + "type": "boolean", + "nullable": true, + "description": "Falls eine sekundäre Heizquelle existiert, sollte dieser Wert auf true stehen" + }, + "einheit_1": { + "type": "string", + "nullable": true, + "description": "Einheit des Energieträgers der primären Heizquelle" + }, + "einheit_2": { + "type": "string", + "nullable": true, + "description": "Einheit des Energieträgers der sekundären Heizquelle" + }, + "startdatum": { + "type": "string", + "format": "date-time", + "nullable": true + }, + "verbrauch_1": { + "type": "integer", + "description": "Energieverbrauch der primären Heizquelle im ersten der drei Verbrauchsjahre", + "nullable": true + }, + "verbrauch_2": { + "type": "integer", + "description": "Energieverbrauch der primären Heizquelle im zweiten der drei Verbrauchsjahre", + "nullable": true + }, + "verbrauch_3": { + "type": "integer", + "description": "Energieverbrauch der primären Heizquelle im letzten der drei Verbrauchsjahre", + "nullable": true + }, + "verbrauch_4": { + "type": "integer", + "description": "Energieverbrauch der sekund̈́ären Heizquelle im ersten der drei Verbrauchsjahre", + "nullable": true + }, + "verbrauch_5": { + "type": "integer", + "description": "Energieverbrauch der sekund̈́ären Heizquelle im zweiten der drei Verbrauchsjahre", + "nullable": true + }, + "verbrauch_6": { + "type": "integer", + "description": "Energieverbrauch der sekund̈́ären Heizquelle im letzten der drei Verbrauchsjahre", + "nullable": true + }, + "warmwasser_enthalten": { + "type": "boolean", + "nullable": true, + "description": "Falls Warmwasser im Verbrauchswert enthalten ist, sollte dieser Wert auf true stehen" + }, + "warmwasser_anteil_bekannt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Warmwasser Anteil am Verbrauch bekannt ist, sollte dieser Wert auf true stehen" + }, + "wird_gekuehlt": { + "type": "boolean", + "nullable": true, + "description": "Falls Kühlung im Verbrauch enthalten ist, sollte dieser Wert auf true stehen" + }, + "keller_beheizt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Keller des Gebäudes beheizt wird, sollte dieser Wert auf true stehen" + }, + "faktorKeller": { + "type": "number", + "nullable": true, + "description": "Der Faktor mit dem die Wohnfläche erhöht wird wenn die beheizte Gesamtfläche (energetische Nutzfläche) unbekannt ist." + }, + "alternative_heizung": { + "type": "boolean", + "nullable": true, + "description": "Falls der Heizungsverbrauch alternative Energieversorgungssysteme beinhaltet, sollte dieser Wert auf true stehen." + }, + "alternative_warmwasser": { + "type": "boolean", + "nullable": true, + "description": "Falls der Warmwasserverbrauch alternative Energieversorgungssysteme (z.B. Solarsystem, Wärmepumpe, etc.) beinhaltet, sollte dieser Wert auf true stehen." + }, + "alternative_lueftung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Lüftung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen." + }, + "alternative_kuehlung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kühlung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen." + }, + "anteil_warmwasser_1": { + "type": "number", + "nullable": true, + "description": "Anteil des Warmwassers am Gesamtverbrauch der primären Energiequelle in Prozent" + }, + "anteil_warmwasser_2": { + "type": "number", + "nullable": true, + "description": "Anteil des Warmwassers am Gesamtverbrauch der sekundären Energiequelle in Prozent" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "uid", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "Authorization", + "schema": { "type": "string" }, + "required": true, + "in": "header" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { "application/json": { "schema": {} } } + } + } + } + }, + "/aufnahme/": { + "put": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "aufnahme": { + "type": "object", + "properties": { + "ausweisart": { + "type": "string", + "enum": [ + "VerbrauchsausweisWohnen", + "VerbrauchsausweisGewerbe", + "BedarfsausweisWohnen", + "BedarfsausweisGewerbe" + ], + "description": "Art des korrespondierenden Ausweises, wie z.B. VerbrauchsausweisWohnen", + "nullable": true + }, + "gebaeudetyp": { + "type": "string", + "nullable": true, + "description": "Art des Gebäudes und seiner primären Nutzungsart" + }, + "gebaeudeteil": { + "type": "string", + "nullable": true, + "description": "Betrachteter Teil des Gebäudes, z.B. Gesamtgebäude, Wohnteil, Gewerbeteil" + }, + "baujahr_gebaeude": { + "type": "array", + "items": { "type": "integer" }, + "description": "Alle Jahre in denen das Gebäude konstruiert oder grundlegend verändert wurde" + }, + "baujahr_heizung": { + "type": "array", + "items": { "type": "integer" }, + "description": "Alle Jahre in denen die Heizung eingebaut oder grundlegend verändert wurde" + }, + "baujahr_klima": { + "type": "array", + "items": { + "type": "integer", + "exclusiveMinimum": true, + "minimum": 0 + }, + "nullable": true + }, + "einheiten": { + "type": "integer", + "description": "Anzahl der (Wohn)Einheiten im Gebäude", + "nullable": true + }, + "flaeche": { + "type": "integer", + "description": "Wohnfläche bei Wohngebäuden, Nutzfläche bei Gewerbegebäuden", + "nullable": true + }, + "nutzflaeche": { + "type": "integer", + "description": "(energetische) Nutzfläche des Gebäudes. Bei Gewerbegebäuden entspricht Sie der Nutzfläche", + "nullable": true + }, + "saniert": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude energetisch saniert ist, sollte dieser Wert auf true stehen" + }, + "keller": { + "type": "string", + "enum": [ + "BEHEIZT", + "UNBEHEIZT", + "NICHT_VORHANDEN" + ], + "description": "Ob ein Keller vorhanden, beheizt oder unbeheizt ist", + "nullable": true + }, + "dachgeschoss": { + "type": "string", + "enum": [ + "BEHEIZT", + "UNBEHEIZT", + "NICHT_VORHANDEN" + ], + "description": "Ob ein Dachgeschoss vorhanden, beheizt oder unbeheizt ist", + "nullable": true + }, + "lueftung": { + "type": "string", + "enum": [ + "Fensterlueftung", + "Schachtlueftung", + "LueftungsanlageMitWaermerueckgewinnung", + "LueftungsanlageOhneWaermerueckgewinnung" + ], + "description": "Art der Gebäudelüftung", + "nullable": true + }, + "kuehlung": { + "type": "string", + "nullable": true, + "description": "Art der Gebäudekühlung" + }, + "leerstand": { + "type": "integer", + "description": "Prozentualer Leerstand des Gebäudes in einem durchschnittlichen Jahr", + "nullable": true + }, + "alternative_heizung": { + "type": "boolean", + "nullable": true, + "description": "Falls der Heizungsverbrauch alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "alternative_warmwasser": { + "type": "boolean", + "nullable": true, + "description": "Falls der Warmwasserverbrauch alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "alternative_lueftung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Lüftung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "alternative_kuehlung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kühlung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "brennstoff_1": { + "type": "string", + "nullable": true, + "description": "Genutzer Brennstoff der primären Energiequelle" + }, + "brennstoff_2": { + "type": "string", + "nullable": true, + "description": "Genutzer Brennstoff der sekundären Energiequelle" + }, + "storniert": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis storniert wurde, sollte dieser Wert auf true stehen" + }, + "erledigt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis erledigt ist, sollte dieser Wert auf true stehen" + }, + "bestellt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis bestellt wurde, sollte dieser Wert auf true stehen" + }, + "zurueckgestellt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen" + }, + "prueftext": { + "type": "string", + "nullable": true, + "description": "Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung" + }, + "boxpruefung": { + "type": "boolean", + "nullable": true + }, + "energieeffizienzklasse": { + "type": "string", + "nullable": true, + "description": "Die aus der Berechnung hervorgehende Energieeffizienzklasse des Gebäudes" + }, + "erstellungsdatum": { + "type": "string", + "format": "date-time", + "description": "Datum an dem der Kunde den Ausweis erstellt hat", + "nullable": true + }, + "ausstellungsdatum": { + "type": "string", + "format": "date-time", + "description": "Datum an dem der Aussteller den Ausweis ausgestellt hat", + "nullable": true + }, + "zentralheizung": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Zentralbeheizung verfügt, sollte dieser Wert auf true stehen" + }, + "solarsystem_warmwasser": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über ein Solarsystem für Warmwasser verfügt, sollte dieser Wert auf true stehen" + }, + "warmwasser_rohre_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Warmwasserrohre des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "niedertemperatur_kessel": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Niedertemperaturkessel verfügt, sollte dieser Wert auf true stehen" + }, + "brennwert_kessel": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Brennwertkessel verfügt, sollte dieser Wert auf true stehen" + }, + "heizungsrohre_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Heizungsrohre des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "standard_kessel": { + "type": "boolean", + "nullable": true + }, + "waermepumpe": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Wärmepumpe verfügt, sollte dieser Wert auf true stehen" + }, + "raum_temperatur_regler": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Raumtemperaturregler verfügt, sollte dieser Wert auf true stehen" + }, + "photovoltaik": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Photovoltaikanlage verfügt, sollte dieser Wert auf true stehen" + }, + "durchlauf_erhitzer": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Durchlauferhitzer verfügt, sollte dieser Wert auf true stehen" + }, + "einzelofen": { + "type": "boolean", + "nullable": true + }, + "zirkulation": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Zirkulationspumpe verfügt, sollte dieser Wert auf true stehen" + }, + "einfach_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes einfach gedämmt sind, sollte dieser Wert auf true stehen" + }, + "dreifach_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes dreifach gedämmt sind, sollte dieser Wert auf true stehen" + }, + "fenster_teilweise_undicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes teilweise undicht sind, sollte dieser Wert auf true stehen" + }, + "doppel_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes doppelt gedämmt sind, sollte dieser Wert auf true stehen" + }, + "fenster_dicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes dicht sind, sollte dieser Wert auf true stehen" + }, + "rolllaeden_kaesten_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über gedämmte Rolllädenkästen verfügt, sollte dieser Wert auf true stehen" + }, + "isolier_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes isolier Verglasung haben, sollte dieser Wert auf true stehen" + }, + "tueren_undicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Türen des Gebäudes undicht sind, sollte dieser Wert auf true stehen" + }, + "tueren_dicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Türen des Gebäudes dicht sind, sollte dieser Wert auf true stehen" + }, + "dachgeschoss_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls das Dachgeschoss des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen" + }, + "keller_decke_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kellerdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen" + }, + "keller_wand_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kellerwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "aussenwand_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Außenwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "oberste_geschossdecke_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die oberste Geschossdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen" + }, + "aussenwand_min_12cm_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Außenwände des Gebäudes mindestens 12cm gedämmt sind, sollte dieser Wert auf true stehen" + }, + "dachgeschoss_min_12cm_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls das Dachgeschoss des Gebäudes mindestens 12cm gedämmt ist, sollte dieser Wert auf true stehen" + }, + "oberste_geschossdecke_min_12cm_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die oberste Geschossdecke des Gebäudes mindestens 12cm gedämmt ist, sollte dieser Wert auf true stehen" + } + }, + "required": [ + "baujahr_gebaeude", + "baujahr_heizung" + ], + "additionalProperties": false + }, + "uid_objekt": { "type": "string" } + }, + "required": ["aufnahme", "uid_objekt"], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { "type": "string" } + }, + "required": ["uid"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/aufnahme/{uid}": { + "patch": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "ausweisart": { + "type": "string", + "enum": [ + "VerbrauchsausweisWohnen", + "VerbrauchsausweisGewerbe", + "BedarfsausweisWohnen", + "BedarfsausweisGewerbe" + ], + "description": "Art des korrespondierenden Ausweises, wie z.B. VerbrauchsausweisWohnen", + "nullable": true + }, + "gebaeudetyp": { + "type": "string", + "nullable": true, + "description": "Art des Gebäudes und seiner primären Nutzungsart" + }, + "gebaeudeteil": { + "type": "string", + "nullable": true, + "description": "Betrachteter Teil des Gebäudes, z.B. Gesamtgebäude, Wohnteil, Gewerbeteil" + }, + "baujahr_gebaeude": { + "type": "array", + "items": { "type": "integer" }, + "description": "Alle Jahre in denen das Gebäude konstruiert oder grundlegend verändert wurde" + }, + "baujahr_heizung": { + "type": "array", + "items": { "type": "integer" }, + "description": "Alle Jahre in denen die Heizung eingebaut oder grundlegend verändert wurde" + }, + "baujahr_klima": { + "type": "array", + "items": { "type": "integer" }, + "description": "Alle Jahre in denen die Klimaanlage eingebaut oder grundlegend verändert wurde" + }, + "einheiten": { + "type": "integer", + "description": "Anzahl der (Wohn)Einheiten im Gebäude", + "nullable": true + }, + "flaeche": { + "type": "integer", + "description": "Wohnfläche bei Wohngebäuden, Nutzfläche bei Gewerbegebäuden", + "nullable": true + }, + "nutzflaeche": { + "type": "integer", + "description": "(energetische) Nutzfläche des Gebäudes. Bei Gewerbegebäuden entspricht Sie der Nutzfläche", + "nullable": true + }, + "saniert": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude energetisch saniert ist, sollte dieser Wert auf true stehen" + }, + "keller": { + "type": "string", + "enum": [ + "BEHEIZT", + "UNBEHEIZT", + "NICHT_VORHANDEN" + ], + "description": "Ob ein Keller vorhanden, beheizt oder unbeheizt ist", + "nullable": true + }, + "dachgeschoss": { + "type": "string", + "enum": [ + "BEHEIZT", + "UNBEHEIZT", + "NICHT_VORHANDEN" + ], + "description": "Ob ein Dachgeschoss vorhanden, beheizt oder unbeheizt ist", + "nullable": true + }, + "lueftung": { + "type": "string", + "enum": [ + "Fensterlueftung", + "Schachtlueftung", + "LueftungsanlageMitWaermerueckgewinnung", + "LueftungsanlageOhneWaermerueckgewinnung" + ], + "description": "Art der Gebäudelüftung", + "nullable": true + }, + "kuehlung": { + "type": "string", + "nullable": true, + "description": "Art der Gebäudekühlung" + }, + "leerstand": { + "type": "integer", + "description": "Prozentualer Leerstand des Gebäudes in einem durchschnittlichen Jahr", + "nullable": true + }, + "alternative_heizung": { + "type": "boolean", + "nullable": true, + "description": "Falls der Heizungsverbrauch alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "alternative_warmwasser": { + "type": "boolean", + "nullable": true, + "description": "Falls der Warmwasserverbrauch alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "alternative_lueftung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Lüftung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "alternative_kuehlung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kühlung alternative Energieversorgungssysteme beinhaltet sollte dieser Wert auf true stehen" + }, + "brennstoff_1": { + "type": "string", + "nullable": true, + "description": "Genutzer Brennstoff der primären Energiequelle" + }, + "brennstoff_2": { + "type": "string", + "nullable": true, + "description": "Genutzer Brennstoff der sekundären Energiequelle" + }, + "storniert": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis storniert wurde, sollte dieser Wert auf true stehen" + }, + "erledigt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis erledigt ist, sollte dieser Wert auf true stehen" + }, + "bestellt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis bestellt wurde, sollte dieser Wert auf true stehen" + }, + "zurueckgestellt": { + "type": "boolean", + "nullable": true, + "description": "Falls der Ausweis vom Aussteller zurückgestellt wurde, sollte dieser Wert auf true stehen" + }, + "prueftext": { + "type": "string", + "nullable": true, + "description": "Durch den Kunden hinzugefügte Anmerkung zur Vorabprüfung" + }, + "boxpruefung": { + "type": "boolean", + "nullable": true + }, + "energieeffizienzklasse": { + "type": "string", + "nullable": true, + "description": "Die aus der Berechnung hervorgehende Energieeffizienzklasse des Gebäudes" + }, + "erstellungsdatum": { + "type": "string", + "format": "date-time", + "description": "Datum an dem der Kunde den Ausweis erstellt hat", + "nullable": true + }, + "ausstellungsdatum": { + "type": "string", + "format": "date-time", + "description": "Datum an dem der Aussteller den Ausweis ausgestellt hat", + "nullable": true + }, + "zentralheizung": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Zentralbeheizung verfügt, sollte dieser Wert auf true stehen" + }, + "solarsystem_warmwasser": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über ein Solarsystem für Warmwasser verfügt, sollte dieser Wert auf true stehen" + }, + "warmwasser_rohre_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Warmwasserrohre des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "niedertemperatur_kessel": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Niedertemperaturkessel verfügt, sollte dieser Wert auf true stehen" + }, + "brennwert_kessel": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Brennwertkessel verfügt, sollte dieser Wert auf true stehen" + }, + "heizungsrohre_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Heizungsrohre des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "standard_kessel": { + "type": "boolean", + "nullable": true + }, + "waermepumpe": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Wärmepumpe verfügt, sollte dieser Wert auf true stehen" + }, + "raum_temperatur_regler": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Raumtemperaturregler verfügt, sollte dieser Wert auf true stehen" + }, + "photovoltaik": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Photovoltaikanlage verfügt, sollte dieser Wert auf true stehen" + }, + "durchlauf_erhitzer": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über einen Durchlauferhitzer verfügt, sollte dieser Wert auf true stehen" + }, + "einzelofen": { + "type": "boolean", + "nullable": true + }, + "zirkulation": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über eine Zirkulationspumpe verfügt, sollte dieser Wert auf true stehen" + }, + "einfach_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes einfach gedämmt sind, sollte dieser Wert auf true stehen" + }, + "dreifach_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes dreifach gedämmt sind, sollte dieser Wert auf true stehen" + }, + "fenster_teilweise_undicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes teilweise undicht sind, sollte dieser Wert auf true stehen" + }, + "doppel_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes doppelt gedämmt sind, sollte dieser Wert auf true stehen" + }, + "fenster_dicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes dicht sind, sollte dieser Wert auf true stehen" + }, + "rolllaeden_kaesten_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls das Gebäude über gedämmte Rolllädenkästen verfügt, sollte dieser Wert auf true stehen" + }, + "isolier_verglasung": { + "type": "boolean", + "nullable": true, + "description": "Falls die Fenster des Gebäudes isolier Verglasung haben, sollte dieser Wert auf true stehen" + }, + "tueren_undicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Türen des Gebäudes undicht sind, sollte dieser Wert auf true stehen" + }, + "tueren_dicht": { + "type": "boolean", + "nullable": true, + "description": "Falls die Türen des Gebäudes dicht sind, sollte dieser Wert auf true stehen" + }, + "dachgeschoss_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls das Dachgeschoss des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen" + }, + "keller_decke_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kellerdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen" + }, + "keller_wand_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Kellerwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "aussenwand_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Außenwände des Gebäudes gedämmt sind, sollte dieser Wert auf true stehen" + }, + "oberste_geschossdecke_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die oberste Geschossdecke des Gebäudes gedämmt ist, sollte dieser Wert auf true stehen" + }, + "aussenwand_min_12cm_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die Außenwände des Gebäudes mindestens 12cm gedämmt sind, sollte dieser Wert auf true stehen" + }, + "dachgeschoss_min_12cm_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls das Dachgeschoss des Gebäudes mindestens 12cm gedämmt ist, sollte dieser Wert auf true stehen" + }, + "oberste_geschossdecke_min_12cm_gedaemmt": { + "type": "boolean", + "nullable": true, + "description": "Falls die oberste Geschossdecke des Gebäudes mindestens 12cm gedämmt ist, sollte dieser Wert auf true stehen" + } + }, + "required": [ + "baujahr_gebaeude", + "baujahr_heizung", + "baujahr_klima" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "uid", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { "application/json": { "schema": {} } } + } + } + } + }, + "/ticket": { + "put": { + "description": "Erstellt ein neues Support Ticket und weist den Ersteller diesem zu, falls ein Authorization Header mitgegeben wurde.", + "tags": ["Tickets"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "titel": { "type": "string" }, + "beschreibung": { "type": "string" }, + "metadata": { + "anyOf": [ + { + "anyOf": [ + { "type": "string" }, + { "type": "number" }, + { "type": "boolean" } + ] + }, + { + "type": "array", + "items": { + "$ref": "#/properties/metadata" + } + }, + { + "type": "object", + "additionalProperties": { + "$ref": "#/properties/metadata" + } + } + ] + }, + "email": { "type": "string" } + }, + "required": [ + "titel", + "beschreibung", + "metadata", + "email" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { "type": "string" } + }, + "required": ["uid"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/auth/access-token": { + "get": { + "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"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "refreshToken": { "type": "string" } + }, + "required": ["refreshToken"], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "accessToken": { "type": "string" }, + "accessTokenExpiry": { + "type": "number" + }, + "refreshToken": { "type": "string" }, + "refreshTokenExpiry": { + "type": "number" + } + }, + "required": [ + "accessToken", + "accessTokenExpiry", + "refreshToken", + "refreshTokenExpiry" + ], + "additionalProperties": false + } + } + } + } + } + } + }, + "/auth/refresh-token": { + "get": { + "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"], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email" + }, + "passwort": { + "type": "string", + "minLength": 8, + "maxLength": 100 + } + }, + "required": ["email", "passwort"], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { "type": "string" }, + "accessToken": { "type": "string" }, + "refreshToken": { "type": "string" }, + "refreshTokenBase64": { + "type": "string" + }, + "accessTokenBase64": { + "type": "string" + }, + "exp": { "type": "number" } + }, + "required": [ + "uid", + "accessToken", + "refreshToken", + "refreshTokenBase64", + "accessTokenBase64", + "exp" + ], + "additionalProperties": false + } + } + } + } + } + } + }, + "/user/self": { + "get": { + "description": "Gibt die Daten des momentan eingeloggten Benutzers zurück. Falls der Authorization Key invalid ist wird stattdessen null zurückgegeben.", + "tags": ["Benutzer"], + "requestBody": { + "required": true, + "content": { "application/json": { "schema": {} } } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "uid": { "type": "string" }, + "name": { + "type": "string", + "nullable": true + }, + "vorname": { + "type": "string", + "nullable": true + }, + "email": { "type": "string" }, + "profilbild": { + "type": "string", + "nullable": true + }, + "plz": { + "type": "string", + "nullable": true + }, + "ort": { + "type": "string", + "nullable": true + }, + "adresse": { + "type": "string", + "nullable": true + }, + "telefon": { + "type": "string", + "nullable": true + }, + "anrede": { + "type": "string", + "nullable": true + }, + "rolle": { + "type": "string", + "enum": ["USER", "ADMIN"] + } + }, + "required": [ + "uid", + "email", + "rolle" + ], + "additionalProperties": false + }, + { "enum": ["null"], "nullable": true } + ] + } + } + } + } + } + } + }, + "/user/": { + "put": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email" + }, + "passwort": { + "type": "string", + "minLength": 6 + }, + "vorname": { "type": "string" }, + "name": { "type": "string" } + }, + "required": [ + "email", + "passwort", + "vorname", + "name" + ], + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { "type": "string" } + }, + "required": ["uid"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/objekt/{uid}/bilder": { + "put": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "kategorie": { + "type": "string", + "enum": [ + "Heizung", + "Fenster", + "Gebaeude", + "Daemmung" + ] + }, + "base64": { "type": "string" } + }, + "required": ["kategorie", "base64"], + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "uid", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { + "type": "string", + "description": "Die UID des Bildes." + } + }, + "required": ["uid"], + "additionalProperties": false + } + } + } + } + } + } + }, + "/objekt/{uid}/": { + "patch": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "latitude": { + "type": "number", + "nullable": true + }, + "longitude": { + "type": "number", + "nullable": true + }, + "plz": { + "type": "string", + "nullable": true, + "description": "Postleitzahl des Gebäudes" + }, + "ort": { + "type": "string", + "nullable": true, + "description": "Ort des Gebäudes" + }, + "adresse": { + "type": "string", + "nullable": true, + "description": "Adresse (Straße und Hausnummer) des Gebäudes" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [ + { + "name": "uid", + "in": "path", + "required": true, + "schema": { "type": "string" } + }, + { + "name": "Authorization", + "schema": { "type": "string" }, + "required": true, + "in": "header" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { "application/json": { "schema": {} } } + } + } + } + }, + "/objekt/": { + "put": { + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "latitude": { + "type": "number", + "nullable": true + }, + "longitude": { + "type": "number", + "nullable": true + }, + "plz": { + "type": "string", + "nullable": true, + "description": "Postleitzahl des Gebäudes" + }, + "ort": { + "type": "string", + "nullable": true, + "description": "Ort des Gebäudes" + }, + "adresse": { + "type": "string", + "nullable": true, + "description": "Adresse (Straße und Hausnummer) des Gebäudes" + } + }, + "additionalProperties": false + } + } + } + }, + "parameters": [], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "uid": { "type": "string" } + }, + "required": ["uid"], + "additionalProperties": false + } + } + } + } + } + } + } + }, + "servers": [{ "url": "awd" }] +} diff --git a/persistent/images/3c319927-d226-4c84-8650-11bcc3d90670.webp b/persistent/images/3c319927-d226-4c84-8650-11bcc3d90670.webp deleted file mode 100644 index 68fcce0a6fbe9c97297125d0a93171b1d4c4a16f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 51548 zcmeFYXIL9qvo0!+BRCBY+2jl}*nkB_fDj^xV2m-zLMCVU#s+K?2N1$04hSKH z5IKtU84MW7LnxNrdgxNyD!&Soxr2R?e_Xa+Vl06x|Km*6YloGv{C0N`GJK43$=U#x9x zf4TbOUswDkb8_~5{nzyZ#6M`G4S@U;F%}AAhc+1%KuL zS6hG4Up>Cz;$>-Ze!h0T^8tJTV1OY&@2}r~{{5T~`2c|04ghfRkAE+F{s{o6iv|Gh zjs1I>@Sgy{?I-}Cw(sA|{vDIoPCicmR^6rZ<4-SN0su@b0C3X=0Jz%^0IXmD(KeMv3u&}bQ&Zjtan*i?~3zq@`(SJ>Fl2XwriIGKb>B@@Br`=+l7m47tX!_`2RAe z%NPE##Q#Z`FZ^`z(v_>%SkA>pKLdWcaPg;07cXDA^cP*Z2>46NcKQC5JMzChFn79o z*ZcQmb_Kn>iqAsefsJb%&!>eIeKtAYq_inH=T~xxh(3C30ZE-XuZ#D*k&EXo{fDOh zs_Pt-bD=ofdHGNOgD(DCS1$a-cJcll`AfguHNX6TUEzwio>Rry7~samb49j`Yye%r z!C$8KH~o#k-w6DTz~2b`jlkas{Efih2>gw}-w6Ew76A@mT~uXvg5o>G`dr0jgWC}v zN$Jn-|323LgJC|_988KZAB~9F5#XV?ixv;exAnTHoB@0$l{JEYXe;mtBnb~zMCIlx zr8s`V1h$R&^HBXI`Gp0YKP&dkS6Ge`%hU{>fShX)nW zOalV2mT9A5FPeAxgI25Ej|zR$uvT1BU?WRSCF2REqr=ELUc#jC3~u^IU!V5QC22rbFfAhSVROKBx{Z*d*E~E5H?ms}Gf45u6ZSRHv))tsV0{eL-V=3c(Y~ zbNWMZsc%x|+k0=+4$-5zKkE}}Wve`V#yiC6E;~E2ZH&yRdfJ~x$+4)#vPSFWjc)7k zx$>Ma(y5lKdeGNGqv!#ALLH!tzty(?W!$V zpTv+d917EHY}1<%0*?PN?!sA4c{=35s`~|`u;tcg>-4-T@klP_2HaVim<17uMpi|? zL%zuP;&Vls?o|1eYL+Xzq)^pv1AOIaiD6BRbN7`!Iem;bKYmnTuqIn`t+iStJ$i3s zN3C0oTUjKAh^9#N8mY%O885%hm}%BgI0Gcswf7x=L8)#@AdeoU1OCbh{kPHGFo|bn z{%WNB)0={PRa4ypakh9=n3{vl;-l9ub9e3Kp&6$lRyo;P9}cU>b8Km?`Ep{$%1%J4 zy99!EqT3IRSEov-u1yb|0TkCxBlA!`Z5t~@VJF}ZWNB>MX9w`t?$V;}cL~Hx$#K@+ z2r0CI?aw%G2X?p5z14F_XO2chMf6J@*uk!_5^phQ20g9AMO81sx;HfIac_}ik?tl=ZFYu%1eeF`{jI2EneOxK1^=q=n^7(8BR<`0-b$}Hv5w$|Y~bW@U7AVdJlZP5ht?_^a`3UHR1*(9WX^Y) zM)Nin5q*dRTT4lcM5wxaG-r9PfnTo;HgdiT7MQk=_-$y`cCuM+dMN>17HIl&T9^e0 zWXjv!y`amt+m}g>Dc%%7`${3_DEl4CVq6xP5wbKGDb(tB07D z+%MnDv8o6QTa4cBSi#J(U4@5v`e#HE^x2FYQ;J{En!4;BF!oO7SY{@3qD?;DF|H&K zJk|Ftvt6#hWfMCTblLGB6HCE)u@kj>(PJ{%(Pck(EU`~W8OO4h-Z#z7OwCa51VMe; z+YcA`zxm{-g0wa_Yh}qXn?awG`?20EZRTG@>taW}o?E!DA8Z@gD!AkHSLs`emWDZu zfXd2dyq;t9DkH%HKO5>t*PDOXrSg1^sJk~#zp*m-uT<)PgQZ{3V*wdGH0j=c(mHP0 zt1f&+$n$A!VBofRhiith?!`N3*;h)v=qR-FtBIZ2%wdmkFXYS&wE^s23vSjiZp!h~~W=cU09URsY(|QnnHPPKk zXO+8!<}TL&m7CeP+@p@jJ|=zkkrs|EregQ=k__wyk7X{D9w774G3BEv2zAfEcrU0D zy?1_(29GxK>52||&+|uds?TfVS1vjoyz^cr>*T1aiS(hj(OO2gwKcq+(dXOUnRN|L zOJP!99OpuA*6bWRt;@Ju(G$Ov-CP>XhJ`CYvv$XFav0;5 z!Q`@;qD)%#i;*4yU0L^``4o3`zwq9!(K7%Sw13BPmqfA+i3Wz^ys~CZn9P=*YII%B z{CA(_;-#5|)RL^)GAO~`sH!m|&F?@s1t@D7m16%eeNMlAe=@*;-lMNFe-O-2m1*Ru zjPvQ`Bv+(0mcA-o=8fs&5B((YoirL8vpc2vv6v)J@^O!FdK}0>x;sb(dl;F+cf&ys zmxE#pTFJKl4`w9_(Noxy-Y11m0GEILZ!n+pMS;Q(_d4vxfi9G{=KIYb>^0Jfb!i5v zcqOE7BXD+6Z)peiZZy9Rr%Ys=+#(U8!*ys=L)dtqzA$Cl_2uX-2lE1K%a3T99vEyP3}oo+=Rh3P$Mztiizp&+S**;{He z9pWrns7R4_ho@Xlt*Sd#%42>=R8jKHc`9cxvgl=4Z*DUhRnbP$b{`?!28Eqs?0JhL znT)nVRXUC@!t;=qt!b*isK1ykppa#@Z)OLdOQv{4$T4lbfM+(y+ypMS~(B$%4Ql z3#UXha>g?WH(lkc3RB_gs~h9dqC4ApMp2vr-PbI1Uu*+d3;tWoMWjiubrk3pYZOyX3Y*h!Bw+J8>eeJm2B~`!;U5QQ2RIQUpIciG(8b{wf zce9d)G}xHAw`UcOBdPEUeOStSwkf-gcL4Y3SBk41TS7Jq&OAmn!9!Km+j*wAhhmnnz}e$Ibmib zc|o#m-csZmjDnY588Q?ob7?5!QtDMd2$B;#5vqvJv5RIg*>2mvv$Guz&hpt_3@(Aj zw~E{k%<~LT*~B?StAVq4!EY8i?*@6^#8#ALdDDBk-W@^0BurU^r*b%-ZZBGSwu4NE z9>)%sm92zNit&_Z`Es$$-dh=5-&BGl{520iX27=Fcj6b`wSGYm3Vof*WVV;GF+p{G zx9oyf-<0QpO|PdN3%BApq(Y-FYhx}~nNM`hE^Iy&2Pvyp^>Hy=gO#Rkyz~tk`E?a9 zz7BF^kJYclrdr{ zvZwgbj?E`{t-p9lnj;55ALXs&0RsuMy}< z{TOvqDou1&_r`3MX|bYGVfnD{csK5Q=RyZpw~gG5k@flamch`$I%1<;%CSOUjB$S@ zVQlzgN(!*xS!o4`)qB&wj|7W&5qZ>HU%v>?~WqWcHuMcvWD6yG#8?1D&co@cc3 z8DMSU^keJzjbFQaO#I#=PM)GOSCA3ct{eT|4+$chZ$>O*^18{%op-HNcl~YCU;G)x z)dOyW=60KLwAQ%mI*p=kW(@&jJJl5LG>!h0@YmEc!1sxvEpYaw)UZKsV427n;DpT_ zyfmHwDp}?(6YfWV&M{n4ym1TA!i-(tydjEYSf45=AE0? zis&J%<;$G$$Pj*U z!|_!UYEXOZT9O9NotNLBta(%qAt+LJ2JmK#g^RGVN(CHcz2mh8Sta`YN$YiqUbu(J zJ(2Evr|p6{s4on%&zISBOfy882O;F@{`sl8CIJ@aOY}t3tq;5=t-ewRrLl0%9~fEx zL@VS}v4ed$sFZX2vuM~=0(^$LEQlFpT4dVh30(IO}9yPpBlU}fPT{NASpoB5=a zsk*PT+i(p(S8(7G)!OIDr;#UY)y|W>|!gDycIAcA;Ln+ zZNz^HbljDDr#zgk=Izwej@1SZM1M)+@pu?oG@FMGcex!Z0j6oz=Y!`*L%)*LecXl{ zQ_%*NLL$hVzOWWrxUoyX)Q?SiS9+|@Ewykw9h zcjGr{>3iL!DqUPELC*djdV^~TD^LapakjeUvTK@XF67tH{o+Ke0gJd!MY8bejnq8< z^(GDhDUqrz4SDh_=~v|NO`^~audNjX!;>7Jjw52Sa57|dsEW0N{)|*yQyr1w+H+MB zwY0Z{aLc&n?SEU zLMrI7rA~TCQM<3f^vi<5J`U#Aiv1&3<`_0&#~PLar|vRj?PJ(Re~cFK_tMnx>&@eh z1ufFuk}08WS~>5lTRG=@m;C4=Tk8S5#j%k`k?2!Iq^0cH&GBtA(*cvCBCc-yg5Md(|`!+%XD0dh+ew~$Y$PLRANY0wd406;PF`q8N za4cTtQ;#@mXWAP(DAwuyYkdD-4AvXfaQsML0~%bY!PIZMN9W?CrkeOaJ?uJuI8aGg z*+oNen$iAh)O1PmQhfT6>#n&=+4mu;QY<^6CdAxl!w{vMa_*WL&Ibi#%TXPEa#A1f z)DqKNzWrl@M-8trn`dMn^TF}}4&i{|8F-CjQ6tF}yP*c|_rM)*-$pDQWp)X)Wcz1F zm9AGyMsTb*fgFOfm{TOF#Yb)-B}#-4RGvd>aZwj9un;2>U!vT?j1NLFR>sblsEgVFofbH29&SN;(tN^yFCFlS$ zgj9c?oMc1E{^m})S+L1nQ0J+MSZbyAxea!j9CRwX8{Mo)i!Uvj4=|d^jy4h4<4{ zl-P~DwIE+KKwsEP=nAW+FX&#hlN@&x+?2JCBNRE4TPT!6^WhZi*OKSDx*o0Jp z^H$fJl#yOnmloMj7%bm|jK#yYXt>e|yD$g-6SORr)F5b=Vk;W8Ua}1G7tyD@MZTE* zNGeFB+iV*PJD@)flM(ZM2GjL}=r$$19+EMPS2wcGxdUW6mFN^pAwIxfZO0t|>xZVYwpPJOm8t!`)5>dD_A!}or5o;4{dKF%5G+{sFVOCTsG-KD;K_CVQ z4e=;18YlosQrt?%nchCHBa`DvJ9bxU(48~1RV@;SP-VE{=6#uLBLzq?U8nC*AR)Z4 z{dU>|(ZpPkat7X1s+dHQQ)hc85au{CZeR=9+kBnTVZC#nNOE8QfS`}lhLoB*RXL4O z&DsaPd&vY)4R8GxWusT_&f8^9Kc`%zr*%X4dCXn=b-KQ{Ri|`Ge_rVs?)b2^r>cpV z1(#vik#AbWg%M`u$c*4b3>f3Fg|plOfqf7?btv0IE76R0$qdJ6S86r8WuW3dJ9*3H z-$o}_XIO>1NNYgl1GHQR=_G^`pwOG}q=Y%I+rvNbo_H52;3USi_${&8^$ehp1=~uB z{ymDjnJU(-@j;iK(|5>8MT2v;-WvCn-}~o(akyWAWG;U4!Kw}_9A0=Pw`Xw*48Mp~ z9#(MtMf&n4MqSH5ruC6WOfD4dVPdh962!yvYdSXHvUn5J%z2#I#dwB8Pg%^LUi40~ z5v!wSL%g&{j>R1=nqf(&zXUlRx5k~)ob`_y>$iIJ{n8D3rJhvaLA?cq zSucja?#XRl3^qtD2giGukgVUL6e?P~>KqljOYq>b*oY;)ARwZO(R<3z#ge3) zEF)s_dR+=^M{p5qbYRHM?&~VPZFbzei>yeS*$;`xebmzIWh;#DI3~*SuC5U=*z(~Un`;{yil{C%NI&uQPy9cV?0WnL3j+0OG;7i}^ zJnH-y&y5s{axK}*;qF>;zF%0a#xOlbet2LHI3H=(?C{<3QpnAlqCH^8jqSM+L-E3| z+JTUU>BHo`01E;_tSW{i)lfh>e4ol2&J%gv9c9UGS*N2(4Hhk4LcOkaAA=Q~0S?^a z2lf-Ez)4Ms&T<_rD>Em+O!7Wx)KH2A-e5mfJ+aLMsZ5_+D8pLcqWFAb)-t#sl4;9t z1KUWD@<>k8hy_Q3+?uLsDP5pJ(NdfgZOu)KsdzaK<7i&y6moFj+{3pUx7Mn49QSl3 zqtrBY6RVZF6EKZfB%wD}mHR0e4dmoWl4bogETrLe7Fx7%?NgsemYBD(LSdTzX%1$S z-dS}95a^QE@X5X%I?UZ3@fdD|__!oPaE0qFPm0}RGV5E`D{ew_UZ8HuH@c8J3UeE2 z{Entj?=Vw;gAucMLT#A{YG$(%rn>og+(Y@kyQ@ZxgG!LSfM)COv$m_NuuM`K!??q8 zOJ>h}u~i5kgQ$}e{@7{a2&<4c_3TqJ(!7rmk+OWwP2NFsi?>dUR|u-h`w=%qQ!Qo zZeG*{Xhx9djl9rI&pQ(#sQ-2G|BkupzH$Z_tz+Bl8B9!e6(7USHWH?>g1LcGn7dHE(&ppiq<@^RO9ETP#NVl>t4;N63kG_xR zc_K`L+=+voz4kiqQ;JIwc;ZM(4^YRocMvghlb$jL{oTI^>bFSAc9$)_&X#ln4%bOQ zF+`m`bKYbuY)AmP%V{YX z5o%VCMbsrL6E#Yc<_$=r7GIo9dV#a*ePnp|C;V&J^;~~*$Wfnqdz|@+dHQji1u0+~ z71#z&oDywqP5vD=uH8(IW15p6P7E{@9JqoYsZ+OP)bCaYb$Z4!3Wyd_`G;cZTl240 z!qYag>RV%rz-3o8C1s!unTR#9J&Rr|MH=IX4|~f^^>7!b*VdU;Y>C%0kVC{p0R3IR zPxb}rkl${z20-hxgP#X-G*WZ7?eClcd^6{KgG@~QDVz0L%!%!6w7WrqnqJnOs5?NH z>HCptl)5ZzyvTST*gMJ3$6?T)XE#jVU-NoM-FYGvxn%w}3nMn*ghA7G{XsqKMHYqfhZ^TcXJ=R19h`o2JP?lIfIr?kMAt zHdK*on>P1qqcrzAEn6>oMUl1kxICR%BW++xk%)L=jCnQoXq3)kW7k$P*We|DOn+G( ze)CT|i7|@^w}Xf-OIsf_!d5ohQ=@*VRn`_6VdL7o5s+U@(^vOO6iiDB4Lp9jkeEGd zWFGNC#zbFmb4iX%9Omwy~_Mx|`0)D>q~ zdtPzxybDqUV&@Y%3(B^?k>VMaXn_i!Z|Nhr8mA5jo}6r%)Rbi1qgJyi23Oc0?VZ(S zb9-&NYU`1pSwxuSPt%_}G1VDTUNvGF^c%MwvkA@lxGrRM7kQvKueWR)j{0-F*m*Ki zDFlTI$DvdVFQC2o={2?$4YA%RhIw4KTzfUP*h4i9D*-N|x`4uGMoxNY5!~orx<*ge zpf*dh5D1O!^t!u{)i`@kOj8HhS!Lc@_B>5Hp8Yg4;XKG%z$i0?9xV~H>$kTeTdR1VEgqh%N zZ0LH3G48l`2B01t-`J~>dnF**1HtArbbnh;_b3K;J@)fsYo1;e|?Frg={LH12= z=NI8wZrS;KN{{!clJfZ#w`{afoAic;~NvS4rJYkInP z=98P@8lB7FW{kTN0z5Nc(%@v26^s$v(8<^}J>|zyqHmfe=4zW@_%&{~wJxVDZx|LH z{jzI?3Dq6M4dHnLH71_SH;<iN#vl=Ft9+1id+_F|y+!{F&?keglo>{bZyY%KY7BkCCGgO>tjFhL z=SL@Bf;R7?JXY2{$b9r=0XK`7UPMpr@ZA?tHL#;Yg^EGeFENH-cd&xF8$#`$FK*tZB| zVy9?9uA?W>u?ZbR*X-!&Lb5q9(ajpAQ4*b6Eh5ngA10uTkYNAxN-2pW z41R>z*eNIiWVQ?Z0pnLry0Dnx9X)Kqa>rbd0ad=nc0F$f^ zt{{tUrA-YbS4-?4WK6)b<_g1d9}`_2M7L<7IN6-kY@{dUy$>cgjk4!U~YiNP_-`}b5-J|2{Ypuyj2knsQ#$GOhROtRzKj8<~m-9g2u6IO2p#AHXm$j+k7A90q zXKrv7zj{|MHyIYl2FzD*%vD+L7#tuU?vD$`@Ra za25Ro{eFhkX94NcF#ND8?OlAhAj4&v_Y;^1!C@*lTA1$JkzxlST=Y(tH(Ba-zTw)~ zk$E#uw1%-5MS2T#eFz=sdTHuIa89%n?2|tBJF`@y%!;=j^@g6xl(0bj?yoLNL{TT6 zHL;DLx?6&Tw}x~U# zwyTf2WxjX88_v`3nJwdV9o77d1gZz@Jnd=6<5)PQi0|LYu-f)D^3E->b!+L0De-I? zu8V3N5^3oFzQ_ZwmPa72X|0pTYoQ^pZB*-rEd{084tcE7Q!rfVly8f&1a~l|^7B_u ztx}Lw*{6HErB($h1l&=Fc-MUJ0*~j<6ls27*Q77-w?}I8TgR3DV`zw7re{x%NS7^< zifHbUc$p@ll$*KMdwN4<>(o>fZTx=caO?|OFpx)OGZ;c4BdBjZrHQ72b6oblOTrAT zaRO;AsqiUMWZJEQ(4y~N_#~yG(@NnxWklMZHMYPi#$dJBI6eH6X0eR{BMNQuQi7vf ze&Gk%U%#Iq>9g`p|L317?E0>iwu}-ZLg3zR?9REc~~o(0aLv zorsqA+q#=qyIK*%+?(#o4XbYCQw6gLNKp=TYeIi#Cuk+Ok97&ITWk3yGtMqKrBAVM zVd#3;%dy#n-lh9!H-&2G8K7;xvABxW$J#sY*i>8N^whB8wb)MvnO1cJmQpHNFneuq zc(Y0F%O*a?5DJ4k1KjZqqb%6N!gT~27+Zffs6R-F3r`F^X(kdr?))q{s3a(ZQSKYF z={*^3M7uG@ya{=#+d z7QcqnNZR#~@NK=pR*zkCg*)m5Imly-x;w?$8o`j0kYk;n*nsTu5U6}Z%EPQ?HZsae z?4{bbkl2EX#_#!)Frfzp>Go5&NNIEZ?{)>p^0EosnCZ@NV=5}(bFz`V$$~V&R!Pzh zbcbG)p;R{RVUDP12twvs7!huTfRkR9e>E|%F;B||dB~*`nO(^Z;YKkyPYugF&T(%w zZDwm;$}s8|93&VSqB=g(g4HmA6mE)dyL__h6BzW99MfLk6sE(I0$E!6r&taNBi~YX zjWICBoq(Yw90+6G_lZDt=ElCG1q2EV-bdiwWmByQDk(4*tyx6rEyq!%1?M93KzXyY z$5m+q#=K>@a`S!*+2ju~e7*vZ9b=wjd4ho=Vr9r-a5YzVSNryF%@$vRQ^U&-(Xv&T z{-NrF{`#0;bk!nd%kZ*Guy27Qsdu%;Hg3$ZPoRgd^56_W!#l`1*QUDbbQ%u*F(!)! zF``^qL^DL#H>OnQpE^7o#`fhZD9rStBRHQr%e{1Y{RKD}Fz*7lfq#0y&jLPh&?phj?g44(W1gFKnzep+hV6K1K>?%S)NfH4!(U@%Oh8NH!8 zGhN$o(6HI57z&)(AB+p4}h+ z!A&hPT{kd`@SfnDfP<;UrDL3bkU^j9L-J?4qmSjBJUa zG@E&#bOUhPk*{V)=O5FuR}yq9+nU(1+>xA~Yjo)v!5q%;Yh|ulidVl-3DYLxql4gV z%RzsU59;CS4?}A(NEx~SBqiRKHgd%#($zqt&9BP|e%(dV`%V0V{6Ty9_&aQGmf4$c z$llwmYxPyckuOJ0(k{z++M1)ZdSK+`P{hsixFP)hwTABFlIPgFNBFbDgGYKD?kwi-Vy+itat2@p*4NP} zbK1p>ORiSbR!&Kk zHN9ohoN0<*Ul9kHcK*mbTw%)eo@vPXVjn#b8r4AR8dlQ)f zDP0g4w7eK8*(e?D?`;u(t zVP(`|9N!KjW_XZf+Eu3q&T4RP)u$%qvF8M+xQJZ0O+nOtG4Eq2YtzT+43Bh37$tQ_ zM!e|%(3kxWHNTd={YPfA4nlbt_lhpnSOT<3DR1)W!hLR#chm#AgqAR|HoRg*?DsRk z#=C3g7WsL_Q~H*~qG1=l?Kk@o4J@f%t#8yEpZ;jRl9*ZmrpH4)s9lLAN43Y@a8t9q zf~BGL8rDDZ;0Cf_WTPD8RSl>&iUBf`WN82)SY%hLI_uk(&1MN;&Rsidwb9)T60j_6 zujgr`Bn-2)uTM7F?DCR|^G~oE6TD-PCZ^_I5!qIdL;X?blWOmhFohzA@prMlj^^d5 z#z5Kf^aj(Lvg*Dq$fWk=&mU&1B(xJFK43uRX!0#c!R99;^-O`z@|5P7HYufo>dM=BV@3y-f_lhMi`g} z#Z>jqH;A+72AaQ+d13`gnAD^UCv+Z0^P+}$4;o`F9lF(Pw|0Dz;8de=%@5}FwJjMK z+tkxR8|3SKtb$iuW0$9Bkp3DV$qMxcD1MH~058QH z)i+m7JlnB-y%^R}u#9}AyvhS*!)nHbY=KH#$m^9<7yc8@(JqHLF^bMn+Kg0&VFI)K zqw5H5Y(FbqOY;ye{6~=TkbPa~#|7_%O5atAjfW|>^2u!9mv-oMaK>O`qQKH6RTnGj z2;L_ztNDCFVw9~`J6F4--VFQTMv0nZbUu9Z4I>uSBK;|$cziAZxt@R6%{eqA-U$r- zN^kPlx^A;uWiW_&;$D$G^fY|F!M!YV;zY+)%zc#?8WL41$MA(w!+O)yikMC-vkP0H znSBY_nJ%ZGJIjb-++-)#FePmv4HjK)49a7K(bNPLCQN> zNkfSSCCX^{t;U$bEFE8|y1^P{-7TImC?2S9-jcUgtS^Ixa+4xYjOP+sBZjS})mmLM z3K07avrmy(rQ#%ILTcm(C*@olU%5;Tx1L^Bn_y3(R$ppN6^*h#y3QZ*aVJA*9qwun z)DF`Xn-88CYRt1W%bkqVBvDdK3J$a8oApgXhtiZssAU`@CW@K9mF}Ft>p*nqKm+=?gC_hF+EexoM4PTmMPvlpiV-(jt;MTrSY@J5_wyKq(s(&ntt1y3#d z9tBL^iO-nAuDvqKauqLiAh_a^^@AoIyx$Do3^G($edGKzTFsyUn=T8_O*!2#u!vF2 znWyrVkGzz0_FxdLUk9h8qrR^mWo*%Vozu7mv^N*cKO1rfO9A-EM8T(G>5Gi^7`SZWxlrM}Q3H{K_(U^Gx!$^j}uN2#lbPgmj z%dGlu>z@H`PJV+Dyl+X2xSaw1X_kJ>FF`1#I(|5mqaG41#m8V8H81j0dY?2aB(!{T zLbzfFV$q1pM#wuGo#Mk(0%NMa@q=#Q)gH1y!mi^~`nNd0sT+1>Y#!-a#yF{a6u)gZ zW98=svr;IcA)M+v(#I4ftmNta>^B>OVuyh3RfCw;z&k{pI94+-5*%(vY&s0Slj~xh z_zNm*YQ-fGMi$Cy$b-%|xj{)$Vb%!zRwU(zACF9do5e;~;iv-5=C?LjQ07ESQSHoW zOuGI_-unIn;@2d5N}wz{csRP+MWfQ}%|wHiu+L#{jpnEZwA8F_kv`COC}eQB+k&yk zsEf&n;PK4gKd3Cnkdk}4`&ugeH(z@;q59E@F<+pXT%DS)>J$ukvucT1j)JfG>o|V1 zHz-;3fVeZwal`z+AM|%jWptDBwH|#~*$LGLby-%{S4X*aLj$PI^O4ld&=RjYN149j z`*&!|8eFwib@gwu)k~a8bMVxucXKXXBb3a{S?BI4+Po$)OR>QCDcT)N#og42*!9QP z@YF1f_IM$E{@ZptE?zwCHP<#}Z>CctQ}V+ydUFDQ{2P@V0yJj$*=25Q!Hr;`qoC+#-V?Dgy2<+C9)P_uQ7 zNysezI5F})4pf>R=-M9^d>cJ5QR<0U|@{F!@PTK^0B?Ttju5P=a(mzsxTlK z{jS>)aYwEOeAd%TeYqlJ+BZpAyIR^yOX=$L8GD;IaHsXDD<&w_)$xI-lImq@9#|2r zPQi10B;CHHc~Ba)s-rgI^r}dzdWHys%+Qk(udz5`7pNnqHsf6%E{f3mfRyV0fx%Le3({%_<#$Qc-ciXO`LkFma*4wp1W^{`M zvN-2R)MS6fFV1ssX;e6+CXOt0Kl;?6~=uVW$DqNz(wIRz5 zZOAMBgNqrRVM&h?m$}l(s;M4RrZraVZoRQNE-goAfbb78&e019PbspkS(FI69i*})|NNNzl=ppjJ^_Er6Nz2PnehsTz z>`O0U$KCdhPfBaX%4?0FtF@W5YdIA7s$YTz;TyKcKN0fh(Lp5CHRN%oud0gIsCd(Q z%Nby5FBLTEODfb9?Y_R8QRf%FgE&Z;&{aP2J5G=iiS-xmelrr4;uyN4;{KaHPFkn4 z=}uVBF#uN#-yr2k8A5-1e1@=n?AUWqt z^GDii*>^m3$E1$r_dRZvUn=^)<(nJw$5A>zU)AgGxv&0gh+y_R zy6pRyCl5SS>d+joSKJqd@!EwFzA!sND#Z%;j)66JEko&but@E z^D_~73&(zoQ`V3=0*8opdC#e?sI?1jiOf{1=nY)`kpaaz0!t?dz@r9fXk1t^7R80l zwOT?YJ*gNXFx;x~u=@G@Np-T%diq@Jqby7t8`@{tekAf`Qi4{E_+exNkP<=&bafH* zbq4xSvjTv!uP~d!OeJwY-Jul8rmdSWUnRoXM4P&Qqwn?6`+29%Wc2oT?v6!g;V=nw8)Lx zgZMGV;ip+S4w3i;sWR-*$0Fy9JBKLTbEN_lyG!&EwTMwKi;ls8!eMcy(|pd`+OuZ$ zcvuW!0feSwz{+>}KzQ9x(|os0s6!qUI@!n~QO9kMU-{^itLzpdGiV2P+Tq(3G~8t4 zDV~KP+xBvRj|QGbHP!ix4yy>OdE}QBbn>cR8Tse<5%2tb@aI{Z;$4g{!qmr(Ao{6i zIpA(JPP`|GhvZs7sRo(K(@Kvr#)eaBZt6ht)0<4&<-|^|Pos(zGLv$HV%h?KPA8g9 z>Ti8n5VN!@$YGZP?u{n!KE8ac`e#Y()XbrlwCjXOf!B2u8~E z){RxD;IK_3pFj-v_Ezxg%%DBizA2hC6T_e5=)bASN*p3Ym)M6?2PAGD^(_*!RX(g- zCRsw!C7oH%H_&>h;Pgy*N!UYwTfxekcMYS~+)q+1aO}fgOTPLcPR8jAF+K8gDV5}# zT|G^XUz8a38c4J_PB_&wIO3fczfEucf{DK0wszq0lSLI2-h}!JXAp;&fE1)p1d+P( zrd`VXqx~#pg&fYOvbXc?<3G|1(hV1Xvw^%OaAap{NVN0exk+s9G+T)+r34~ml2_j1 zttA)wbDiV|L;v`I>zyTvlIuHCur3FwLObUQf1+Kl{jRiWMzuiXou!IvPD2IL?nauk zGIaR7Z{ACdttFb4#0A`+HZG3D_f}>d+%H_Ji^g zN9)Md{!_B{hsCVh0W~~zcd5#cGZH+K&CkRWn}WIl~gIKFYVk0MCarKw{VdQ$mLRxf{~f*rty>R1n+p5XeE4~Gpw;KS73 zN&h8`FL|CC68^Y0otr(eAgg?&zn{9ZKj4+ku`YQKkn|;KSQgDf8t(d>Pz=(JU`eiq zAAr9v&=*F`DIK3%80i*ep(2{GiKdk+EmuO6klwZPMtn z@9OK`VM}M?O6;hWwMeu)kkgono)V=VNeDp#BNpp7O_5otJe6aZx)b42 zyq2IWu=&LKTZs0fd0<`7;YDz0Ta^9FlwR1FZsQ?8(Hq`a;J#5^cb-|RF_Q4rDeGyq zPsr>z*7&2XOK5rOQUVW1DHABY-av3j^?^&M>+kGmd@bxJPPox%L<*vfxixIEZLRe- zei>&KWrt*_(9Jtma+zf@%Z$Kd`yzu{zK1x9jcKW-dIWhs*Z}7(g(sz^+EoMrb;#w# z!*3_8mt$VQv>tp%#2hx&zA*Pe%tM5U$2V@{Rf-J}&|2k+nQn1B?&PFS(LhtD@SZeC zm%rz0*UQcCNEu_-xd#o+bD>+J<#y@sv?+|c<~Ww>jl+WK9xff`m5OukcfBv837WL;4+hG2oR_X4O}dfy0p5I87e;^L6m)Z&M?OA4>^h2zV^@ z`HwTe-51Iplk~`&&f5x`oq>fpHV(Bp2|Yd3^G76JpaxMS!Ap%9>9*NJ1>?n*dpNj+ z@;i=AS6%*)nNc!3zk3A7&GM7*TcOZO>i(PJkTlc4S2>o=I=KhAK1|$nAT2Vs8C`EX zRQ>-j_MSm)W=p>>d-eq5Y)mkDkIC64XU2E{BN<^Nk&|tbMG`rOJvPB64xnI=fB_+d zkO32gh+{CwLWn591c3=6=bU|XZ`C>H-F5GM&;6veYE?Z|kLp>yR(JpV*8>P|CxCuU z&W-g1H)~f>*zX%P0;kgYhc74LfIgr`auzgoao)kyL5RHg% zi*$>y#I{Ilhm;%h+B8+)rnfUYE=20%Ar?QLn{%b&oLdsq<(MzAmY0elJz28`V)%QY zfCdr`9P6SJP z?$4Q%@X(pDpY6<0BZg^K$=f%#ZC2ghAju_Rf8# zr3X?w!VsN_0j~eQxVwL7d^#0%k(kp{QcdlwFyd`TDTG}nkDYq{L0FjxRq%0iP@e}} zRX}lvY)0NXj+?b}1fy@e)(bLwWlatQY_gw{Gx=bmY*M+QH#F=GpCskPK-X_Rw5gDcm3@^fZ)Xy~+2S-vO zFJFUz7Z!2!1Kmg+jijlyz07n(?f6%u*gr_Be*{KOe{ltr)z8fXczg!)sx7vX!W{~M&%B^y|69Ewx;R)^QoZyFj^af9NDGwmq ziB!D$kXStmu0(d3;NNY^!8#fJ(YTCXl?33MN> zEM0Sa7i>)sY}XvO8>~s)o*X*qQZ=;ME7`f826c_|Q<1o#!FpnAa{z194FHzXd>@Ss zKVMujCx~2(B^DOd%K>*n9?DnH+XS+7hcpvM{9;*xFQU{>afRRLf=)YrH*Mbz`Qs+( z7u(_Wzk-UpoF~VtjIkQ{ff^=htaulH)A}<1=pyMrZj(~zvx|?s=6H2~1OQ3EgKzi_ zcUTjvc_Fv5dRQI)+mecFaZ$+Z{tG&F))*#DbvZ#yqJO-Ktb-kR~cKln{8gwxwhq zoVFvin59z23_ZBV_Mk|jon%Y0j}@OUwQ76{ErEJ>ga*^Z?^28Wo;FqZC2O^NP-;r> zzPs6M%lN{l=Yyfe2-sldx80Iyv5SU_C#j>Yj9&oY(uvP*Il|jR33^`Aj(G*U5Y*Xa z#KY0?&dUDl31lCuggTnJ-?y259c`gCzEX7VG8$GXhRxoyyGZUTv}w za?gu9E#I;5+NK^E$c(F0lZ2u?P~^|mXBLcC^2`eHsnUYA+&GyG)-9LTx=SGf$R7*t zcsA*VG0I76%9vJ3MnNJ~UrjUi*PL||Yg#HaKyndcH%?oADe2%ii}izxL6@bK$an|{ zC!{XMa?J4~FODmSx-0^>l#?LnU!3RJ`F^jR{_&SJhwd{weZgcGGCy%fs0?yutNlhF zBbhWcxRSi{piQpX^|f9U>ioUJ@ku-Eni%g;h_X*g$PP_FOHOkewMDETfUGz2nZt{X z{*~fTe3PqG;;zK%+Q>naEx&d36=sr{*haXduaB`6H1M5?FFIRwk=_%!LKYCS+g#dc z_=u~1x|tNCBE=8!QuA;_P4;z7R|QRfX%;qmpbT8JUQba@tVL;lF>wSx8EhoJQHpB3 zU*-P*^UoUxJt@)HHezhE`KITHip?38H4@&33I@ljO)|$aZ^=`03{34jE1rhNjz2Wb zOXJyBuUm_=t7wB$WHPxqf(=4Gtq|!0weN9u{5y>YSYxu{N${1BPg(b-zsd(G6Pocg zi&)z(FU3Dg2^j!KjaoSQ@7gH}OL`1+NwDtJ)tXc`V4I{yz@^VlZ>%*H`lwe55dvXb z%2*v45syY=i9XhU7h@tPddS)e$>kl+(5GKW-0Oi(*7KWp8Ya#+#T z@J71G4ksCSNpEK#_p8lmWvU$#K5slDy?|Q{;la1$uXSmpwVasUJ6_oSqTR<= zigh9=8ciOUg>U@BrmikA`mlglrV^=Zb=I&S&VIey$AJhX6!G2bu@4OO?4)3`F(USft%Cn z_458i;P|w=Ltdh@1L3Q=)kTnm3b;^UiqkPmQLFbmmw!Qthc0OYWi3@huxQxMW9{jm z*B(gMi3}H&nW-Fu7oBTbfO|AUgvn!bd<4=&*;e;Jr*v8^u^?a1h!|>dbvg;V)Hk(Q zowPkSJR|-XZjq@WNTZ8w&RX7E>CNk3d?zO#s=gY8b*B{GpTSw)icem(L?T_e-O@&s z3Y*Dk!Z9Cx#IQs06r2qL_md#?UTl1Ou3pq%^L$DyU4Q$%&t%u9d1NT16fg6>Pk-|K zaAn!Afj?~dn5SE*!_Vy@wjl5l`JJnIHL9xiCwiyN%nE*{>S$nA+jAnMu9;}AB^2_p zHK69`_}ji1*PG<)F127x;a$f!6uwpdh}}K+!FKc<)El;5cXpYSY5|u zEy&8s!b8%jVh)Gi`9ajNuOu&N8cq|oQCL5~bOu=Yh{1^xSMLxWozyeCt}L1>Wl#OV z#sayaBb99JIS}saAJ7SGoD96{aOTp-!EP1Z@9s9x7-sF=(aQAT%|l3>Q=tp*=elQ` z=3*a3QH^t~9yI09~3xP9kRS?!BPP4tG)d~U_-j$5Mg`O$tSh{FDhv_AiIdES{M zt4uxT@K~eM07n?NiEd3~8c~*z=CN@(1J=ZYq8WwB!t(zLXw}5sRQt3XNXFM!AOE{x!at1u zc2I0gPE)T?m1`WU5{rML#6FS!O|1V?(6@~KPD9kR24utJm0POKVO`t-Ikg1TSKSng z>~(!+d>d!VTa3b+bjRP* zo>y9jcT_1!PJT)n12O$w++bhMblR8wnX?9_E%EQdg?xHAZdlOqjz=7lj^^Gh-rRb@ zyC?Y=%6uW_Yatq{`~%*K5E^O|mrGsur~jeu5CDJ{4ATAKYs`rNcltS2g0V!@6{uS> zHLo8V5sklPO$-kqHP(aVwibi(`1B0SQr9j}**3QktwVb$<3@#$p;wSZ`Ix%m;?_GE z_Nx(8v--72f$&uxg*TE4%g(2~TV&&L^ZQoTi0a{@DsZtm+B&x=(9x4-ow3<=7j}x> zBt#|*dG_JL6GlM}yDjC64=AcA31t!8vjYe%r}KWpVmKDOCzw*TwWbJg7TB%)!en|Y zu#9y>W!?{UIUMh;-Qze>k4uLAPVP789S1Nc-(U>(S!CSX;?w4kWnW09qFUNLdC4=6 z+EO#6m!&yQ)9~snQ;QSTx+3gz^k7JNQ)0iQfRe@$K0RA0Djzq=pIl!M;b}i zbioeu5{_)y3DP{WMtZlq5~a`Q(87|jzZl8bkZ$wcPd8pfVM@m+A0`sz!I*;%+Fqf^ zs;%n+VnY%S3WtP;7Q|RfDb^R7On#xu&t!@oemfqvtE%#@-|`obCn=gLY3>fcP`_XqhZw0NAeF6Cg~usb69_F z*^VGhE1k2y2PPY_tDJjVw+`4+&rN)6)dzG{3zD#>a#PjqbE}ARIa8;$a(znVdAnNF zUbYa9c!e22w9J#6SI86e*>j)q?zb?I*6^ORN#ge`2srDux0hC5pLtb_lk+TbU!1bp z^59%aN+8e;FAGT~PSH)&N$ukNI##bR+EmVM+Ara7T1n|bDBd_X+Le3weQQZR^9cA! zQDeN_2%G9J2PiI?olC(BG_3fd*T;I%qkh&()`Mw#ax(AQQb2O}(>q5upW(P=>-&Mo zl8=RolNaguU``0P?VokSn-{sxENE%D4N?xAIwNn_aoP}euEp6eI0pw~kxIPH-V8E0 z9zu=HTIH+s_g>x?PH!Py;QY3WM+Fu$i`1J#&7MJ@x2Ve*kvzgZTuJYQpTI_zp~aX? zBgI;l=yfSX%a;pN!CJ6mYeB392GDkx=3Zz`5p+I$J5D17o43v{QR+pHqVK26RbrGA z04S_Xa?+vZ3uX8puj@rL2LZty-Q31&DOK4I)?^yGex0SqK1@#)^7kjuBwRu#{JCE` z2mDPfbC`4*N$>`P%bPcSWuwddlEIEKSDz&}r4eKpV3RH19@j`@{j1%=ouBN%-zK2N zGduonw=Q$V^<9s>qus^G0*wRHV;kT|;sS?OXt1(-$ zP+MeV@m`&qV%T`>HRGx(DfkNj-~HX$o`MH83z&G+6_|Fnx9dAXVP+6u5r`ZtvW99o+ zNg8*3bD2x({|u!o&~l&KBo4hzDdAd;t)h_b^V#%JN&#s4k|lhTKg4FeN{nHg~!{`n2w#Y1J+$4gEMH z_~m}p&ynG+P0bOdr%EZbO5fY4rhPXgIOn){#Yc1F$l_E8^b|g+(1|^LYW~7+m`FW) zHquUyaM)t?qw484`-_h4^_Vn~3c$v$gMBZi50&BJs7SH#2grXhAe)r)A}rwY{28OCB35 zGd_Dw%Ct-sK@XAEC)QEuN;XoeRuQr7V^h)7RNOP7tnlLb+cru^L^RsT={WaBY;f%- zRkeD2*%TSk^k-B$z2;+8=q4NdEW_NST@b{!jN)W({;h%9=R!;dw)$^7KB-a1PCEA{$uRU5SCyEEQ^`UWh%}41Y4$ zQ#~4Cevdb3EEnY>gJM)@c2^wq$`0Bi3NC>o=zT(ivjC7-<|H4m{Ru7?mSP}mS&Mgr z3#q?E*v4&~zOS3S8Wme7JLq}GrN0U!hv9i!~^rO zyd$U0pbi%8==d})k1;!D&{gUjk*Kt);-lnF{eqawV-= zno1!Pr;H2TkY)P%{xdA87V8b1S%}uIoD3IvWuJ^@Lp=-xrB3Z-5KAfedkM0T=8b&D3 zI?vt2PT9l;ot}8DWQ#sKGtq%$!`Evk4FaXGQTtxzpJ}6mE7MX^+K|L2rzdd{7f*zB zs2l1d_9}epHy59}q)((N?SKp|se-U`SXEo|~TSj!yyg_#F+!Uel3 zXvnL#anB!mb!U+bjGWS=l*;QAmN4{~sv?dR`)S&gb6VGuuFLiyJjjJXCvur9dd@PB zOtz}=B^J9-yh};2(pNZwQi>Qm<1K6TVsk}wkoXMZ`d%G_fp4`5@!8;yp zNe;D(_*?ZHgJ^g8Nho1zRRwAJ`S7bMiP}0p?*tbNkJFu&4`xv{K#h0B84x2R2MO z`9Y9*sFvHOyNoz>-D5S&6Os4^p`(44{?!A9VTF9XPt!wy z$av3Q_dn6N+t9IW)5rztJ|;f*pzqYRVUcMTKlu&b1!)B>ud| zu-ad|2!Jh*21gQIKzLXitk2n@u7;y?_7739RXIo3zPQLEhPExeKFZ#*ve_F_KQdTk?Q0<+Gkc%KuY@6xXoLH zurrUX+6TFM3wbMq&w04kJiCzPZhgcnDqdT(6ZO#d`G+r@P~n*7fIywcBIV;m$yPbyVEK2|?HAWg^j zZT_`{3iVWZP3By+vHot(nr>C|vE(HIwPqF7E z>$JfI(=p`|7Ls!MZO649Fs&tkZQtR;-P{yIz&I3*gY7Wjdm)kV8mXp0ph|Gnc zH>=s1st1nk7H{7!kMZkTL^rokY_TuVyR%v&`S2^-6@6se>6uSdIhu5nN$X{_;Bm)I z5h<8|1JN&P13v+ourR_pcr=vXyo7xn#!3i)k@w8uSp6Q?fgvkSHT{oMkQ5}J92|wQ z+T#e}LpGM=Yh&tRbHeLGR9BNi=2(+=2GL7HnnLWp0nqNF?{3#BPVC^bZACP+={LH$ zm0gG)_&uG*!GQFuRX4z8v)UEa4O-`y38T4=g-@F6{Iu(}XItE~vm^K2HFPM!J;i~T zHzX?Wt(tM^==s7f-W&KmU;`J9?vie{xUb=$?=D!7Z(A z$NgV9n4?ILGmo9*-1);&vi*7b4Y2m-LhI&x#biHr0VFVDP|(k4wu{jGH4CTM^*rT$ z59*GOeO%&2lz)l=YW*#W+f0>~%&Lsk8g}=kZ<5FTgQF@bphVlNewt0F6ee~DROb>V zq2W5mGR`=LOXnBh72fSZW1}QI>u`spNQ!Tva@_Bj$T0zCdR3i|F2!kJ80)~v-Uqo> zf7xl3R}VQ8HE!-mx8>&W!47B|Qv1L6*EMCt4V0C&XgffhbxT)OZ%ueA1jI~qK$osZ zZPCATH8!Y4;1tSt8IQV4mSlVGAa#O9N^>Uc<0Q{GCZv&>AZ4n7LozhcGK8uHXK+i~ zXn95Lm5zw5_k_Z#oTo6wYcVDwZ$8 z^EZAP7Cq+#7;;DCo5)~z!P9pf$zHGoAjzaaNq zp8I)2-L95b@SR^J<%t#eEWj{_y9q1Jk?ph4NP^6*1X1P$35awyh?6~8{muobDp?&__s69mJm(9BoJ(4TIt}`tF`acI zBM<_da=V$L-Zg6u;dJUdSFV;2vmxEV`aU6(9l6?!=ogn8j=O1}xHT+u#fw6@M7%>SBN{asz5AiPU-~!( zW;D*A?N)r}vVCOWjSc$X_d?+OKp%Yh_LIwLt4DvZb^T?jd-ZUI>?gnnWrcP*3u7ac zAmy+J%86{=fcpW(-zmdlLGRM2!)V1#msP>35e&Nl&ne0-2cnENfA=}^AMZ$RJ!(p{ zY|cQqoqyfiRh%=_zym-@xl-YgS{d=5Zmpf(iL%CSf?wYI5fY-3{Rk)WgPs^JdGq?Xb=f0F#+LhS9As>Yt zOO;R1!nV6d@yQ3`ER3;GH{NVujY5IL>b?GYy5F|F7Mj_P5hXutAvZi7bLDMD;|Ch_ zRMaE|f}WMs;1U84)>((OHk)%s9i
6!9(F3rBK&7)=SDMv6#%wFZ%DmsYbR=-2< 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 diff --git a/src/astro-typesafe-api-caller.ts b/src/astro-typesafe-api-caller.ts index 704b51a5..41cafcbe 100644 --- a/src/astro-typesafe-api-caller.ts +++ b/src/astro-typesafe-api-caller.ts @@ -10,9 +10,9 @@ export const createCaller = createCallerFactory({ "auth/refresh-token": await import("../src/pages/api/auth/refresh-token.ts"), "bedarfsausweis-wohnen": await import("../src/pages/api/bedarfsausweis-wohnen/index.ts"), "objekt": await import("../src/pages/api/objekt/index.ts"), + "verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"), "user": await import("../src/pages/api/user/index.ts"), "user/self": await import("../src/pages/api/user/self.ts"), - "verbrauchsausweis-gewerbe": await import("../src/pages/api/verbrauchsausweis-gewerbe/index.ts"), "verbrauchsausweis-wohnen/[uid]": await import("../src/pages/api/verbrauchsausweis-wohnen/[uid].ts"), "verbrauchsausweis-wohnen": await import("../src/pages/api/verbrauchsausweis-wohnen/index.ts"), "objekt/[uid]/bilder": await import("../src/pages/api/objekt/[uid]/bilder.ts"), diff --git a/src/components/Ausweis/types.ts b/src/components/Ausweis/types.ts index 345a2836..ac3194d4 100644 --- a/src/components/Ausweis/types.ts +++ b/src/components/Ausweis/types.ts @@ -1,3 +1,4 @@ +import { VALID_UUID_PREFIXES } from "#lib/constants.js"; import { Aufnahme, BedarfsausweisWohnen, @@ -103,4 +104,16 @@ export type OptionalNullable = T extends object ? { [K in keyof PickNullable]?: OptionalNullable } & { [K in keyof PickNotNullable]: OptionalNullable -} : T; \ No newline at end of file +} : T; + +export const UUidWithPrefix = z.string().refine((value) => { + const prefixedUUidRegex = /^([0-9a-z]+)-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i + + const match = value.match(prefixedUUidRegex) + + if (match && match[1] in VALID_UUID_PREFIXES) { + return true; + } + + return false; +}) \ No newline at end of file diff --git a/src/lib/constants.ts b/src/lib/constants.ts index f50a2fb6..a1dfbefb 100644 --- a/src/lib/constants.ts +++ b/src/lib/constants.ts @@ -4,6 +4,22 @@ export const API_ACCESS_TOKEN_COOKIE_NAME = "accessToken"; export const API_REFRESH_TOKEN_COOKIE_NAME = "refreshToken"; export const API_UID_COOKIE_NAME = "uid"; +export enum VALID_UUID_PREFIXES { + "auf" = "Aufnahme", + "obj" = "Objekt", + "vaw" = "Verbrauchsausweis Wohnen", + "vag" = "Verbrauchsausweis Gewerbe", + "baw" = "Bedarfsausweis Wohnen", + "bag" = "Bedarfsausweis Gewerbe", + "usr" = "User", + "ant" = "Anteilshaber", + "evt" = "Event", + "img" = "Bild", + "inv" = "Rechnung", + "tkt" = "Ticket", + "pln" = "Gebäude Plan", +} + /** * Ein Objekt welches alle definierten Preise für unsere Basisprodukte enthält. */ @@ -12,15 +28,18 @@ export const PRICES: Record = { BedarfsausweisWohnen: [135, 145, 290], VerbrauchsausweisWohnen: [65, 75, 180], VerbrauchsausweisGewerbe: [95, 115, 360], - BedarfsausweisGewerbe: [500, 0, 0] + BedarfsausweisGewerbe: [500, 0, 0], }; -export const SERVICES: Record> = { +export const SERVICES: Record< + Enums.Ausweisart, + Record +> = { BedarfsausweisWohnen: { Qualitaetsdruck: 9, Aushang: 10, SameDay: 29, - Telefonberatung: 30, + Telefonberatung: 30, }, VerbrauchsausweisWohnen: { Qualitaetsdruck: 9, @@ -34,4 +53,10 @@ export const SERVICES: Record> = SameDay: 29, Telefonberatung: 25, }, - }; + BedarfsausweisGewerbe: { + Aushang: 0, + Qualitaetsdruck: 0, + SameDay: 0, + Telefonberatung: 0, + }, +}; diff --git a/src/lib/middleware/authorization.ts b/src/lib/middleware/authorization.ts index 322162ad..2b2df868 100644 --- a/src/lib/middleware/authorization.ts +++ b/src/lib/middleware/authorization.ts @@ -2,6 +2,7 @@ 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"; +import { z } from "zod"; export async function authorizationMiddleware(input: any, context: TypesafeAPIContextWithRequest) { const authorization: string | undefined = context.request.headers.get("Authorization"); @@ -86,4 +87,8 @@ export async function maybeAuthorizationMiddleware(input: any, ctx: TypesafeAPIC } catch(e) { return null; } +} + +export const authorizationHeaders = { + Authorization: z.string() } \ No newline at end of file diff --git a/src/pages/api/aufnahme/[uid].ts b/src/pages/api/aufnahme/[uid].ts index e22bb302..f2f3bed4 100644 --- a/src/pages/api/aufnahme/[uid].ts +++ b/src/pages/api/aufnahme/[uid].ts @@ -1,4 +1,4 @@ -import { AufnahmeClient, OptionalNullable, ZodOverlap } from "#components/Ausweis/types.js"; +import { AufnahmeClient, OptionalNullable, UUidWithPrefix, ZodOverlap } from "#components/Ausweis/types.js"; import { exclude } from "#lib/exclude.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { AufnahmeSchema, prisma } from "@ibcornelsen/database/server"; @@ -62,7 +62,7 @@ export const GET = defineApiRoute({ objekt_id: true, benutzer_id: true }).merge(z.object({ - uid_objekt: z.string().uuid() + uid_objekt: UUidWithPrefix }))), middleware: authorizationMiddleware, async fetch(input, context, user) { diff --git a/src/pages/api/aufnahme/index.ts b/src/pages/api/aufnahme/index.ts index 000c90f8..789da870 100644 --- a/src/pages/api/aufnahme/index.ts +++ b/src/pages/api/aufnahme/index.ts @@ -1,3 +1,4 @@ +import { UUidWithPrefix } from "#components/Ausweis/types.js" import { authorizationMiddleware } from "#lib/middleware/authorization.js" import { AufnahmeSchema, ObjektSchema, prisma } from "@ibcornelsen/database/server" import { APIError, defineApiRoute } from "astro-typesafe-api/server" @@ -11,12 +12,12 @@ export const PUT = defineApiRoute({ benutzer_id: true, objekt_id: true, }).merge(z.object({ - baujahr_klima: z.array(z.number().int().positive()).nullish() + baujahr_klima: z.array(z.number().int().positive()).optional() })), - uid_objekt: z.string().uuid() + uid_objekt: UUidWithPrefix }), output: z.object({ - uid: z.string().uuid() + uid: UUidWithPrefix }), middleware: authorizationMiddleware, async fetch(input, context, user) { diff --git a/src/pages/api/auth/access-token.ts b/src/pages/api/auth/access-token.ts index a7313a77..bff9220f 100644 --- a/src/pages/api/auth/access-token.ts +++ b/src/pages/api/auth/access-token.ts @@ -16,7 +16,6 @@ export const GET = defineApiRoute({ input: z.object({ refreshToken: z.string(), }), - output: z.object({ accessToken: z.string(), accessTokenExpiry: z.number(), diff --git a/src/pages/api/auth/refresh-token.ts b/src/pages/api/auth/refresh-token.ts index 7616f46f..3e754e13 100644 --- a/src/pages/api/auth/refresh-token.ts +++ b/src/pages/api/auth/refresh-token.ts @@ -5,6 +5,7 @@ import { encodeToken } from "../../../lib/auth/token.js"; import { validatePassword } from "../../../lib/password.js"; import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { TokenType } from "#lib/auth/types.js"; +import { UUidWithPrefix } from "#components/Ausweis/types.js"; export const GET = defineApiRoute({ meta: { @@ -18,7 +19,7 @@ export const GET = defineApiRoute({ passwort: z.string().min(8).max(100), }), output: z.object({ - uid: z.string().uuid(), + uid: UUidWithPrefix, accessToken: z.string(), refreshToken: z.string(), refreshTokenBase64: z.string(), diff --git a/src/pages/api/objekt/index.ts b/src/pages/api/objekt/index.ts index 8a22344e..4d241001 100644 --- a/src/pages/api/objekt/index.ts +++ b/src/pages/api/objekt/index.ts @@ -1,3 +1,4 @@ +import { UUidWithPrefix } from "#components/Ausweis/types.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { ObjektSchema, prisma } from "@ibcornelsen/database/server"; import { defineApiRoute } from "astro-typesafe-api/server"; @@ -10,7 +11,7 @@ export const PUT = defineApiRoute({ benutzer_id: true }), output: z.object({ - uid: z.string().uuid() + uid: UUidWithPrefix }), middleware: authorizationMiddleware, async fetch(input, context, user) { diff --git a/src/pages/api/ticket.ts b/src/pages/api/ticket.ts index 5a999a18..30266906 100644 --- a/src/pages/api/ticket.ts +++ b/src/pages/api/ticket.ts @@ -2,6 +2,7 @@ import { z } from "zod"; import { TicketsSchema, prisma } from "@ibcornelsen/database/server"; import { defineApiRoute } from "astro-typesafe-api/server"; import { maybeAuthorizationMiddleware } from "#lib/middleware/authorization.js"; +import { UUidWithPrefix } from "#components/Ausweis/types.js"; export const PUT = defineApiRoute({ meta: { @@ -23,7 +24,7 @@ export const PUT = defineApiRoute({ updated_at: true, }), output: z.object({ - uid: z.string().uuid(), + uid: UUidWithPrefix, }), middleware: maybeAuthorizationMiddleware, async fetch(input, ctx, user) { diff --git a/src/pages/api/user/index.ts b/src/pages/api/user/index.ts index 958b9b25..10ed09c1 100644 --- a/src/pages/api/user/index.ts +++ b/src/pages/api/user/index.ts @@ -1,3 +1,4 @@ +import { UUidWithPrefix } from "#components/Ausweis/types.js"; import { hashPassword } from "#lib/password.js"; import { prisma } from "@ibcornelsen/database/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server"; @@ -11,7 +12,7 @@ export const PUT = defineApiRoute({ name: z.string() }), output: z.object({ - uid: z.string().uuid() + uid: UUidWithPrefix }), async fetch(input) { const user = await prisma.benutzer.findUnique({ diff --git a/src/pages/api/verbrauchsausweis-wohnen/[uid].ts b/src/pages/api/verbrauchsausweis-wohnen/[uid].ts index 388349a6..21cb5c32 100644 --- a/src/pages/api/verbrauchsausweis-wohnen/[uid].ts +++ b/src/pages/api/verbrauchsausweis-wohnen/[uid].ts @@ -1,4 +1,4 @@ -import { OptionalNullable, VerbrauchsausweisWohnenClient, ZodOverlap } from "#components/Ausweis/types.js"; +import { OptionalNullable, UUidWithPrefix, VerbrauchsausweisWohnenClient, ZodOverlap } from "#components/Ausweis/types.js"; import { exclude } from "#lib/exclude.js"; import { authorizationMiddleware } from "#lib/middleware/authorization.js"; import { prisma, VerbrauchsausweisWohnenSchema } from "@ibcornelsen/database/server"; @@ -61,9 +61,9 @@ export const GET = defineApiRoute({ } }, output: ZodOverlap>(VerbrauchsausweisWohnenSchema.merge(z.object({ - uid_aufnahme: z.string().uuid(), - uid_objekt: z.string().uuid(), - uid_benutzer: z.string().uuid().optional() + uid_aufnahme: UUidWithPrefix, + uid_objekt: UUidWithPrefix, + uid_benutzer: UUidWithPrefix.optional() })).omit({ id: true, aufnahme_id: true, diff --git a/src/pages/api/verbrauchsausweis-wohnen/index.ts b/src/pages/api/verbrauchsausweis-wohnen/index.ts index c7ebd158..4d384540 100644 --- a/src/pages/api/verbrauchsausweis-wohnen/index.ts +++ b/src/pages/api/verbrauchsausweis-wohnen/index.ts @@ -1,4 +1,5 @@ -import { authorizationMiddleware } from "#lib/middleware/authorization.js"; +import { UUidWithPrefix } from "#components/Ausweis/types.js"; +import { authorizationHeaders, authorizationMiddleware } from "#lib/middleware/authorization.js"; import { prisma, VerbrauchsausweisWohnenSchema } from "@ibcornelsen/database/server"; import { APIError, defineApiRoute } from "astro-typesafe-api/server"; import { z } from "zod"; @@ -21,13 +22,14 @@ export const PUT = defineApiRoute({ uid: true, aufnahme_id: true }), - uid_aufnahme: z.string().uuid() + uid_aufnahme: UUidWithPrefix }), output: z.object({ - uid: z.string().uuid(), - objekt_uid: z.string().uuid(), - aufnahme_uid: z.string().uuid(), + uid: UUidWithPrefix, + objekt_uid: UUidWithPrefix, + aufnahme_uid: UUidWithPrefix, }), + headers: authorizationHeaders, middleware: authorizationMiddleware, async fetch(input, ctx, user) { const aufnahme = await prisma.aufnahme.findUnique({