5 Commits

Author SHA1 Message Date
d69e4be6a9 inseret monthly forderungen 2021-02-22 17:16:44 +01:00
59625cac68 fix ci 2021-02-22 16:52:29 +01:00
5a786f6e40 put zahlung 2021-02-22 16:50:10 +01:00
46db3d485a put zahlung 2021-02-22 16:30:48 +01:00
ab44de341d add active mieters request 2021-02-21 11:52:06 +01:00
13 changed files with 146 additions and 117 deletions

37
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,37 @@
stages:
- check
- dockerize
variables:
IMAGE_NAME: $CI_REGISTRY/$CI_PROJECT_PATH
check:
image: registry.hottis.de/dockerized/base-build-env:latest
stage: check
tags:
- hottis
- linux
- docker
rules:
- if: $CI_COMMIT_TAG
script:
- checksemver.py -v
--versionToValidate "$CI_COMMIT_TAG"
--validateMessage
--messageToValidate "$CI_COMMIT_MESSAGE"
dockerize:
image: registry.hottis.de/dockerized/docker-bash:latest
stage: dockerize
tags:
- hottis
- linux
- docker
rules:
- if: $CI_COMMIT_TAG
script:
- docker build --tag $IMAGE_NAME:latest --tag $IMAGE_NAME:$CI_COMMIT_TAG .
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker push $IMAGE_NAME:latest
- docker push $IMAGE_NAME:$CI_COMMIT_TAG

View File

@ -10,10 +10,6 @@ ENV DB_HOST="172.16.10.18"
ENV DB_NAME="hausverwaltung" ENV DB_NAME="hausverwaltung"
ENV DB_USER="hausverwaltung-ui" ENV DB_USER="hausverwaltung-ui"
ENV DB_PASS="test123" ENV DB_PASS="test123"
ENV JWT_ISSUER='de.hottis.hausverwaltung'
ENV JWT_SECRET='streng_geheim'
ENV JWT_LIFETIME_SECONDS=60
ENV JWT_ALGORITHM='HS256'
RUN \ RUN \

View File

@ -5,4 +5,3 @@ export DB_USER="hausverwaltung-ui"
export DB_PASS="test123" export DB_PASS="test123"
export DB_NAME="hausverwaltung" export DB_NAME="hausverwaltung"
export JWT_SECRET='streng_geheim'

View File

@ -1,8 +1,6 @@
from dbpool import getConnection, getMany, getOne from dbpool import getConnection, getMany, getOne
from auth import check_scope
def get_mieters(token_info): def get_mieters():
check_scope(token_info, [ "mieter/read", "wohnung/read", "objekt/read" ])
return getMany(""" return getMany("""
SELECT m.id as id, SELECT m.id as id,
o.id as objekt, o.id as objekt,
@ -23,8 +21,30 @@ SELECT m.id as id,
w.id = m.wohnung w.id = m.wohnung
""", [], "Mieter") """, [], "Mieter")
def get_mieter(id, token_info): def get_mieters_active():
check_scope(token_info, [ "mieter/read", "wohnung/read", "objekt/read" ]) return getMany("""
SELECT m.id as id,
o.id as objekt,
w.id as wohnung,
w.shortname as wohnung_shortname,
o.shortname as objekt_shortname,
COALESCE(m.anrede, '-') as anrede,
COALESCE(m.vorname, '-') as vorname,
m.nachname as nachname,
COALESCE(m.strasse, '-') as strasse,
COALESCE(m.plz, '-') as plz,
COALESCE(m.ort, '-') as ort,
COALESCE(m.telefon, '-') as telefon,
m.einzug as einzug,
COALESCE(m.auszug, '-') as auszug
FROM wohnung w, objekt o, mieter m
WHERE o.id = w.objekt AND
w.id = m.wohnung AND
m.einzug <= curdate() and
(m.auszug is null or m.auszug > curdate())
""", [], "Mieter")
def get_mieter(id=None):
return getOne(""" return getOne("""
SELECT m.id as id, SELECT m.id as id,
o.id as objekt, o.id as objekt,

View File

@ -1,11 +1,8 @@
from dbpool import getConnection, getMany, getOne from dbpool import getConnection, getMany, getOne
from auth import check_scope
def get_objekte(token_info): def get_objekte():
check_scope(token_info, "objekt/read")
return getMany("SELECT id, shortname, flaeche FROM objekt", [], "Objekt") return getMany("SELECT id, shortname, flaeche FROM objekt", [], "Objekt")
def get_objekt(id, token_info): def get_objekt(id=None):
check_scope(token_info, "objekt/read")
return getOne("SELECT id, shortname, flaeche FROM objekt WHERE id = ?", return getOne("SELECT id, shortname, flaeche FROM objekt WHERE id = ?",
(id,), "Objekt") (id,), "Objekt")

View File

@ -1,9 +1,6 @@
from dbpool import getConnection, getOne, getMany from dbpool import getConnection, getOne, getMany
from auth import check_scope
def get_wohnungen():
def get_wohnungen(token_info):
check_scope(token_info, "wohnung/read")
return getMany(""" return getMany("""
SELECT w.id as id, SELECT w.id as id,
w.objekt as objekt, w.objekt as objekt,
@ -14,8 +11,7 @@ SELECT w.id as id,
WHERE o.id = w.objekt WHERE o.id = w.objekt
""", [], "Wohnung") """, [], "Wohnung")
def get_wohnung(id, token_info): def get_wohnung(id=None):
check_scope(token_info, [ "wohnung/read", "objekt/read" ])
return getOne(""" return getOne("""
SELECT w.id as id, SELECT w.id as id,
w.objekt as objekt, w.objekt as objekt,
@ -27,8 +23,7 @@ SELECT w.id as id,
w.id = ? w.id = ?
""", (id, ), "Wohnung") """, (id, ), "Wohnung")
def get_wohnungen_by_objekt(id, token_info): def get_wohnungen_by_objekt(id):
check_scope(token_info, [ "wohnung/read", "objekt/read" ])
return getMany(""" return getMany("""
SELECT w.id as id, SELECT w.id as id,
w.objekt as objekt, w.objekt as objekt,

View File

@ -1,11 +1,9 @@
from dbpool import getConnection, getOne, getMany, putOne from dbpool import getConnection, getOne, getMany, putOne, call
import datetime import datetime
import decimal import decimal
import dateparser import dateparser
from auth import check_scope
def get_zahlungen_by_mieter(mieter_id, token_info): def get_zahlungen_by_mieter(mieter_id):
check_scope(token_info, "zahlung/read")
return getMany(""" return getMany("""
SELECT id, SELECT id,
mieter, mieter,
@ -30,8 +28,7 @@ SELECT id,
""", [ id ], "Zahlung") """, [ id ], "Zahlung")
def get_forderungen_by_mieter(mieter_id, token_info): def get_forderungen_by_mieter(mieter_id):
check_scope(token_info, "forderung/read")
return getMany(""" return getMany("""
SELECT id, SELECT id,
mieter, mieter,
@ -43,8 +40,7 @@ SELECT id,
WHERE mieter = ? WHERE mieter = ?
""", [ mieter_id ], "Forderung") """, [ mieter_id ], "Forderung")
def get_forderung(id, token_info): def get_forderung(id):
check_scope(token_info, "forderung/read")
return getOne(""" return getOne("""
SELECT id, SELECT id,
mieter, mieter,
@ -56,8 +52,7 @@ SELECT id,
WHERE id = ? WHERE id = ?
""", [ id ], "Forderung") """, [ id ], "Forderung")
def get_zahlungforderung_by_mieter_and_year(mieter_id, year, token_info): def get_zahlungforderung_by_mieter_and_year(mieter_id, year):
check_scope(token_info, [ "forderung/read", "zahlung/read", "mieter/read" ])
if year == 0: if year == 0:
year = datetime.datetime.now().year year = datetime.datetime.now().year
start_date = "{}-01-01".format(year) start_date = "{}-01-01".format(year)
@ -77,8 +72,7 @@ WHERE mieter = ? AND
datum_soll BETWEEN ? AND ? datum_soll BETWEEN ? AND ?
""", [mieter_id, start_date, end_date], "ZahlungForderung") """, [mieter_id, start_date, end_date], "ZahlungForderung")
def get_saldo_by_mieter_and_year(mieter_id, year, token_info): def get_saldo_by_mieter_and_year(mieter_id, year):
check_scope(token_info, [ "forderung/read", "zahlung/read", "mieter/read" ])
if year == 0: if year == 0:
year = datetime.datetime.now().year year = datetime.datetime.now().year
start_date = "{}-01-01".format(year) start_date = "{}-01-01".format(year)
@ -112,12 +106,22 @@ WHERE mieter = ? AND
"zahlungen": float(sumZ) "zahlungen": float(sumZ)
} }
def put_zahlung(zahlung, token_info): def put_zahlung(**args):
check_scope(token_info, "zahlung/write") try:
print("Input of put_zahlung: {} {}".format(type(zahlung), zahlung)) body = args["body"]
datum_soll = dateparser.parse(zahlung["datum_soll"], languages=["de"]) datum_soll_raw = body["datum_soll"]
datum_ist = dateparser.parse(zahlung["datum_ist"], languages=["de"]) datum_ist_raw = body["datum_ist"]
return putOne("""
print("Input of put_zahlung: {}".format(body))
datum_soll = dateparser.parse(datum_soll_raw, languages=["de"])
datum_ist = dateparser.parse(datum_ist_raw, languages=["de"])
return putOne("""
INSERT INTO zahlung (datum_soll, datum_ist, mieter, betrag, kommentar) INSERT INTO zahlung (datum_soll, datum_ist, mieter, betrag, kommentar)
VALUES(?, ?, ?, ?, ?) VALUES(?, ?, ?, ?, ?)
""", [ datum_soll, datum_ist, zahlung["mieter"], zahlung["betrag"], zahlung["kommentar"] ], "Zahlung") """, [ datum_soll, datum_ist, body["mieter"], body["betrag"], body["kommentar"] ], "Zahlung")
except KeyError as e:
print("Some parameter missing: {}".format(e))
return str(e), 500
def insertAllForMonth():
return call("insert_monatl_miet_forderung")

44
auth.py
View File

@ -1,44 +0,0 @@
import time
import connexion
from werkzeug.exceptions import Unauthorized, Forbidden
from jose import JWTError, jwt
import os
JWT_SECRET = os.environ['JWT_SECRET']
def decode_token(token):
try:
print("DEBUG decode_token: try to decode")
token_info = jwt.decode(token, JWT_SECRET)
print("DEBUG decode_token: token_info: {}".format(token_info))
return token_info
except JWTError as e:
print("ERROR decode_token: error when decoding token: {}".format(e))
raise Unauthorized()
def check_token(token, key, value):
if (key in token) and ((token[key] == value) or (isinstance(token[key], list) and (value in token[key]))):
return True
print("WARN: check_token: {} -> {} required but not granted".format(key, value))
raise Forbidden()
def check_scope(token, value):
if isinstance(value, list):
for v in value:
check_token(token, "x-scope", v)
else:
check_token(token, "x-scope", value)
def get_secret(user, token_info) -> str:
return '''
You are user_id {user} and the secret is 'wbevuec'.
Decoded token claims: {token_info}.
'''.format(user=user, token_info=token_info)
def _current_timestamp() -> int:
return int(time.time())

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
IMAGE_NAME="registry.hottis.de/hv/hv-service" IMAGE_NAME="registry.hottis.de/hv/hv-service"
VERSION=0.0.3 VERSION=0.0.4
docker build -t ${IMAGE_NAME}:${VERSION} . docker build -t ${IMAGE_NAME}:${VERSION} .
docker push ${IMAGE_NAME}:${VERSION} docker push ${IMAGE_NAME}:${VERSION}

View File

@ -83,6 +83,7 @@ def putOne(stmt, params, objName):
except mariadb.Error as err: except mariadb.Error as err:
dbh.rollback() dbh.rollback()
print("Database error in putOne({}): {}".format(objName, err)) print("Database error in putOne({}): {}".format(objName, err))
return str(err), 500
except Exception as err: except Exception as err:
dbh.rollback() dbh.rollback()
print("Error in putOne({}): {}".format(objName, err)) print("Error in putOne({}): {}".format(objName, err))
@ -94,3 +95,26 @@ def putOne(stmt, params, objName):
if dbh: if dbh:
dbh.close() dbh.close()
def call(procName):
dbh = None
cur = None
try:
dbh = getConnection()
cur = dbh.cursor(dictionary=True)
cur.execute("CALL {}(null)".format(procName))
dbh.commit()
return "{} successfully called {}".format(procName), 202
except mariadb.Error as err:
dbh.rollback()
print("Database error in call {}: {}".format(procName, err))
return str(err), 500
except Exception as err:
dbh.rollback()
print("Some error in call {}: {}".format(procName, err))
return str(err), 500
finally:
print("return connection in call {}".format(procName))
if cur:
cur.close()
if dbh:
dbh.close()

4
run.sh
View File

@ -15,8 +15,4 @@ docker run \
-e DB_USER=$DB_USER \ -e DB_USER=$DB_USER \
-e DB_PASS=$DB_PASS \ -e DB_PASS=$DB_PASS \
-e DB_NAME=$DB_NAME \ -e DB_NAME=$DB_NAME \
-e JWT_ISSUER=$JWT_ISSUER \
-e JWT_SECRET=$JWT_SECRET \
-e JWT_LIFETIME_SECONDS=$JWT_LIFETIME_SECONDS \
-e JWT_ALGORITHM=$JWT_ALGORITHM
${IMAGE_NAME}:${VERSION} ${IMAGE_NAME}:${VERSION}

View File

@ -3,7 +3,7 @@ from flask_cors import CORS
# instantiate the webservice # instantiate the webservice
app = connexion.App(__name__) app = connexion.App(__name__)
app.add_api('openapi.yaml') app.add_api('swagger.yaml')
# CORSify it - otherwise Angular won't accept it # CORSify it - otherwise Angular won't accept it
CORS(app.app) CORS(app.app)

View File

@ -3,9 +3,6 @@ info:
title: Hausverwaltung title: Hausverwaltung
version: "0.1" version: "0.1"
security:
- jwt: []
paths: paths:
/hv/objekte: /hv/objekte:
get: get:
@ -129,9 +126,24 @@ paths:
description: No Mieter available description: No Mieter available
500: 500:
description: Some server error description: Some server error
security: /hv/mieters/active:
- jwt: ['secret'] get:
tags: [ "Mieter" ]
operationId: Mieter.get_mieters_active
summary: Returns all currently active Mieters
responses:
200:
description: Successful response.
content:
'application/json':
schema:
type: array
items:
$ref: '#/components/schemas/Mieter'
404:
description: No Mieter available
500:
description: Some server error
/hv/mieter/{id}: /hv/mieter/{id}:
get: get:
tags: [ "Mieter" ] tags: [ "Mieter" ]
@ -308,8 +320,9 @@ paths:
operationId: ZahlungenForderungen.put_zahlung operationId: ZahlungenForderungen.put_zahlung
summary: Inserts a new Zahlung summary: Inserts a new Zahlung
requestBody: requestBody:
description: Zahlung
content: content:
'application/json': application/json:
schema: schema:
$ref: '#/components/schemas/Zahlung' $ref: '#/components/schemas/Zahlung'
responses: responses:
@ -317,28 +330,20 @@ paths:
description: Zahlung successfully inserted description: Zahlung successfully inserted
500: 500:
description: Some server or database error description: Some server or database error
/secret: /hv/forderung/insertAllForMonth:
get: post:
tags: [ "JWT" ] tags: [ "Forderung" ]
summary: Return secret string operationId: ZahlungenForderungen.insertAllForMonth
operationId: auth.get_secret summary: Insert the Forderungen for the insertAllForMonth
responses: responses:
'200': 202:
description: secret response description: Forderungen successfully inserted
content: 500:
'text/plain': description: Some server or database error
schema:
type: string
components: components:
securitySchemes:
jwt:
type: http
scheme: bearer
bearerFormat: JWT
x-bearerInfoFunc: auth.decode_token
schemas: schemas:
Objekt: Objekt:
description: Objekt type description: Objekt type