Initial Commit für das Grundgerüst der Anwendung, bestehend aus der Dev-Container Konfiguration, der Docker und docker-Compose Definitionen sowie der Verzeichnisse App_Server für die Backend-Programme sowie Client für die browserseitigen GUI-Komponenten

This commit is contained in:
gg committed 2026-08-17 16:10:11 +02:00
1 parent 10549934ea
commit 1ba78992a6
63 files changed
+5410

No files matched your search

+258
View File
@@ -0,0 +1,258 @@
import sqlite3
from typing import List
from sqlalchemy.engine import Engine
from sqlalchemy import ForeignKey, event
from sqlalchemy import Column, Integer, String, DateTime
import datetime, decimal
from db import dbauth
SYS_ADMIN = "SysAdmin"
APP_ADMIN = "AppAdmin"
APP_USER = "User"
APP_DOZENT = "Doz"
BINDKEY = 'auth'
#c = Connection()
def columns2dict(record, excludefields=[]):
if not isinstance(excludefields, list):
excludefields = []
attribs = dict()
if hasattr(record, '__table__'):
if hasattr(record.__table__, 'columns'):
for col in record.__table__.columns:
if col.name in excludefields:
continue
value = getattr(record, col.name)
if isinstance(value, datetime.date):
value = value.isoformat()
if isinstance(value, decimal.Decimal):
value = "{0:.2f}".format(value)
attribs[col.name] = value
return attribs
@event.listens_for(Engine, "connect")
def set_sqlite_pragma(dbapi_connection, connection_record):
# Dieser Trigger darf nur bei einer Sqlite-Verbindung zünden.
# Bei einer VErbindugn zum MS SQL-Server darf er nicht ausgelöst werden
if isinstance(dbapi_connection, sqlite3.Connection):
cursor = dbapi_connection.cursor()
cursor.execute("PRAGMA foreign_keys=ON")
cursor.close()
class Systeminfo(dbauth.Model):
__tablename__ = 'systeminfo'
__bind_key__ = BINDKEY
id = Column(Integer, primary_key=True)
version = Column(String(20), nullable=False)
lastupdate = Column(DateTime, nullable=True)
initialinstall = Column(DateTime, nullable=True)
# diese Tabelle enthält für alle Apps diejenigen Rollen, die in der App notwendig sind
# Da die Rollen nur einmal in der Tabelle "Role" definiert sind und mehrere Apps die gleichen
# Rollen haben können, handelt es sich im eine "many-to-many"-Relation, die in dieser
# Hilfstabelle verwaltet werden
apps_roles = dbauth.Table(
'apps_roles',
Column('appid', Integer, ForeignKey('applications.id'), primary_key=True),
Column('roleid', Integer, ForeignKey('roles.id'), primary_key=True),
bind_key=BINDKEY
)
# diese Tabelle enthält für alle Apps, in denen der User eine Rolle hat, die Rollen,
# die der User in der jeweiligen App hat.
# Da die Rollen nur einmal in der Tabelle "Role" definiert sind und verschiedene einem User
# zugeordnete Apps die gleichen Rollen haben können, handelt es sich im eine
# "many-to-many"-Relation, die in dieser Hilfstabelle verwaltet werden
userapps_roles = dbauth.Table(
'userapps_roles',
Column('userappid', Integer, ForeignKey('userapps.id'), primary_key=True),
Column('roleid', Integer, ForeignKey('roles.id'), primary_key=True),
bind_key=BINDKEY
)
class Role(dbauth.Model):
__tablename__ = 'roles'
__bind_key__ = BINDKEY
id = Column(Integer, primary_key=True)
roleid = Column(String(80), index=True, unique=True, nullable=False, default=None)
name = Column(String(80), nullable=False, default=None)
level = Column(Integer, default=0)
beschreibung = Column(String(800))
def to_dict(self):
if self.level is None:
self.level = 0
return columns2dict(self)
# Die Tabelle "UserApp" enthält für jeden User für jede App, in der der User eine Rolle hat,
# einen Datensatz.
class Userapp(dbauth.Model):
__tablename__ = 'userapps'
__bind_key__ = BINDKEY
id = Column(Integer, primary_key=True)
userid = Column(ForeignKey('users.id'), index=True)
appid = Column(ForeignKey('applications.id'))
userapp_roles = dbauth.relationship('Role', secondary=userapps_roles, lazy='subquery', order_by="asc(Role.roleid)")
application = dbauth.relationship('Application', uselist=False)
def get_role(self, roleid: str) -> Role:
"""
Die Methode gibt die Rolle aus der userapp zurück, die mit der roleid (nicht id) angegeben wurde.
Gibt es keine Rolle mit der übergebenen roleid, wird 'None' zurückgegeben
- roleid: str
- die roleid (nicht id) der Rollue, die gesucht wird
"""
for role in self.userapp_roles:
if role.id == roleid:
return role
return None
def to_dict(self, withrelations=True):
result = columns2dict(self)
result["userapp_roles"] = []
if withrelations:
for userapprole in self.userapp_roles:
result["userapp_roles"].append(userapprole.to_dict())
return result
class User(dbauth.Model):
__tablename__ = 'users'
__bind_key__ = BINDKEY
id = Column(Integer, primary_key=True)
userid = Column(String(80), index=True, unique=True, nullable=False, default='')
username = Column(String(80), nullable=False)
password = Column(String(40), nullable=False)
email = Column(String(120))
telefon = Column(String(800))
# Jeder User kann mehrere "User-Apps" haben. Dies sind die Apps, in denen dem User Rollen
# zugewiesen wurden. Es handelt sich um eine "one-to-many"-Relation, da ein User zwar mehrere
# User-Apps haben kann, jede User-App aber genau einem User gehört
userapps = dbauth.relationship('Userapp')
def get_userapp(self, appid:str) -> Userapp:
"""
Die Funktion liefert die userapp mit Hilfe der appid (nicht der id) zurück.
Wenn der User keine userapp für die Application hat, wird 'None' zurückgegeben
- appid: string
- Der Kurzname der Application (nicht die id)
"""
for userapp in self.userapps:
app = userapp.application
if app.appid == appid:
return userapp
return None
def get_userapp_by_id(self, id:int) -> Userapp:
"""
Die Funktion liefert die userapp mit Hilfe der id (nicht der appid) zurück
- appid: int
- die interne Record-ID der Application (nicht die userid)
"""
for userapp in self.userapps:
app = userapp.application
if app.id == id:
return userapp
return None
def get_userapproles(self, appid:str) -> List[Role]:
"""
Die Funktion liefert die roles zurück, die der User in der durch die appid (nicht id) bestimmten Application hat
- appid: str
- Der Kurzname der Application
"""
userapp: Userapp = self.get_userapp(appid)
if userapp is not None:
return userapp.userapp_roles
else:
return []
def has_roles(self, roleids: List[str]) -> bool:
"""
Die Funktion liefert 'True' zurück, falls der User in irgendeiner Application eine der Rollen hat, deren roleids
übergeben wurden, ansonsten 'False'
- roleids: List[str]
- eine Liste mit roleids (nicht ids)
"""
for userapp in self.userapps:
for role in userapp.userapp_roles:
if role.roleid in roleids:
return True
return False
def is_SysAdmin(self) -> bool:
"""
die Methode liefert 'True' zurück, wenn der User in irgendeiner Anwendung SysAdmin ist
"""
return self.has_roles([SYS_ADMIN])
def __repr__(self):
return '<User %r>' % self.username
def to_dict(self, withrelations=False):
result = columns2dict(self, excludefields=['password'])
result['userapps'] = []
if withrelations:
for userapp in self.userapps:
result['userapps'].append(userapp.to_dict())
return result
def to_relationaldict(self):
return self.to_dict(withrelations=True)
def has_permission(self, appid:str, allowed_roles: List[str]):
"""
Gibt an, ob der User in einer bestimmten Anwendung eine der gewünschten Rollen hat
- appid: string
- Die appid (nicht id) der gewünschten Application
- allowed_roles: List[str]
- Eine Liste mit den roleids (nicht ids) der erlaubten Rollen
"""
userapp = self.get_userapp(appid)
if userapp is not None:
rolleerlaubt = any([role.roleid in allowed_roles for role in userapp.userapp_roles])
if rolleerlaubt:
return True
return False
# Die nachfolgenden Properties werden für flask_login benötigt
@property
def is_authenticated(self):
return True
@property
def is_active(self):
return True
@property
def is_anonymous(self):
return False
def get_id(self):
return self.userid
class Application(dbauth.Model):
__tablename__ = 'applications'
__bind_key__ = BINDKEY
id = Column(Integer, primary_key=True)
appid = Column(String(80), index=True, unique=True, nullable=False, default=None)
name = Column(String(80), nullable=False, default=None)
minversion = Column(String(20))
beschreibung = Column(String(800))
roles = dbauth.relationship('Role', secondary=apps_roles, lazy='subquery', order_by="asc(Role.roleid)")
def to_dict(self, withrelations=True):
result = columns2dict(self)
result['roles'] = []
for role in self.roles:
result['roles'].append(role.to_dict())
return result
print("########## auth/model importiert")