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:
1 parent
10549934ea
commit
1ba78992a6
63 files changed
+5410
No files matched your search
@@ -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")
|
||||
Reference in new issue
Block a user