Added modules for authentification.
* Added base class for auth plugins * Provide plain_auth (using password authentification) * Provide module for login and logout handling
This commit is contained in:
parent
187dc40730
commit
a000ccfb1c
|
@ -19,6 +19,11 @@ with (_modpath/'logging.yml').open(mode='rb') as file:
|
|||
config = yaml.safe_load(file.read())
|
||||
dictConfig(config)
|
||||
|
||||
import logging
|
||||
from werkzeug.local import LocalProxy
|
||||
logger = LocalProxy(lambda: logging.getLogger(__name__))
|
||||
|
||||
|
||||
def create_app():
|
||||
app = Flask(__name__)
|
||||
CORS(app)
|
||||
|
|
|
@ -37,11 +37,6 @@ handlers:
|
|||
encoding: utf8
|
||||
|
||||
loggers:
|
||||
debug_logger:
|
||||
level: DEBUG
|
||||
handlers: [console, debug]
|
||||
propagate: no
|
||||
|
||||
credit_logger:
|
||||
level: INFO
|
||||
handlers: [credit]
|
||||
|
@ -52,6 +47,9 @@ loggers:
|
|||
handlers: [jobs]
|
||||
propagate: no
|
||||
|
||||
werkzeug:
|
||||
level: WARNING
|
||||
|
||||
root:
|
||||
level: INFO
|
||||
level: DEBUG
|
||||
handlers: [console, debug]
|
|
@ -0,0 +1,29 @@
|
|||
class Auth():
|
||||
def login(self, user, pw):
|
||||
"""
|
||||
user User class containing at least the uid
|
||||
pw given password
|
||||
|
||||
HAS TO BE IMPLEMENTED!
|
||||
|
||||
should return False if not found or invalid credentials
|
||||
should return True if success
|
||||
"""
|
||||
return False
|
||||
|
||||
def updateUser(self, user):
|
||||
"""
|
||||
user User class
|
||||
|
||||
If backend is using external data, then update this user instance with external data
|
||||
"""
|
||||
pass
|
||||
|
||||
def modifyUser(self, user):
|
||||
"""
|
||||
user User class
|
||||
|
||||
If backend is using (writeable) external data, then update the external database with the user provided.
|
||||
"""
|
||||
pass
|
||||
|
|
@ -0,0 +1,77 @@
|
|||
#############################################
|
||||
# Plugin: Auth #
|
||||
# Functionality: Allow management of #
|
||||
# authentification, login, logout, etc #
|
||||
#############################################
|
||||
|
||||
from flask import Blueprint, current_app, request, jsonify
|
||||
from werkzeug.local import LocalProxy
|
||||
|
||||
from flaschengeist.system.decorator import login_required
|
||||
from flaschengeist.system.exceptions import PermissionDenied
|
||||
from flaschengeist.system.controller import mainController as mc
|
||||
import flaschengeist.system.controller.accesTokenController as ac
|
||||
|
||||
logger = LocalProxy(lambda: current_app.logger)
|
||||
accesTokenController = LocalProxy(lambda: ac.AccesTokenController())
|
||||
|
||||
auth_bp = Blueprint('auth', __name__)
|
||||
|
||||
def register():
|
||||
return auth_bp
|
||||
|
||||
############################################
|
||||
## Routes ##
|
||||
############################################
|
||||
|
||||
@auth_bp.route("/logout", methods=['GET'])
|
||||
@login_required()
|
||||
def _logout(**kwargs):
|
||||
try:
|
||||
logger.debug("logout user")
|
||||
accToken = kwargs['accToken']
|
||||
logger.debug("accesstoken is {{ {} }}".format(accToken))
|
||||
logger.debug("delete accesstoken")
|
||||
accesTokenController.deleteAccessToken(accToken)
|
||||
logger.info("return ok logout user")
|
||||
return jsonify({"ok": "ok"})
|
||||
except Exception as err:
|
||||
logger.warning("exception in logout user.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@auth_bp.route("/login", methods=['POST'])
|
||||
def _login():
|
||||
""" Login User
|
||||
|
||||
Nothing to say.
|
||||
Login in User and create an AccessToken for the User.
|
||||
|
||||
Returns:
|
||||
A JSON-File with createt Token or Errors
|
||||
"""
|
||||
logger.debug("Start log in.")
|
||||
data = request.get_json()
|
||||
logger.info(request)
|
||||
username = data['username']
|
||||
password = data['password']
|
||||
logger.debug("username is {{ {} }}".format(username))
|
||||
try:
|
||||
logger.debug("search {{ {} }} in database".format(username))
|
||||
mainController = mc.MainController()
|
||||
user = mainController.loginUser(username, password)
|
||||
logger.debug("user is {{ {} }}".format(user))
|
||||
token = accesTokenController.createAccesToken(user, user_agent=request.user_agent)
|
||||
logger.debug("accesstoken is {{ {} }}".format(token))
|
||||
logger.debug("validate accesstoken")
|
||||
dic = user.toJSON()
|
||||
dic["token"] = token
|
||||
logger.info("User {{ {} }} success login.".format(username))
|
||||
logger.debug("return login {{ {} }}".format(dic))
|
||||
return jsonify(dic)
|
||||
except PermissionDenied as err:
|
||||
logger.debug("permission denied exception in login", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 401
|
||||
except Exception as err:
|
||||
logger.error("exception in login.", exc_info=True)
|
||||
return jsonify({"error": "permission denied"}), 401
|
|
@ -0,0 +1,24 @@
|
|||
import hashlib, binascii, os
|
||||
import flaschengeist.modules as modules
|
||||
|
||||
class AuthPlain(modules.Auth):
|
||||
def login(self, user, password):
|
||||
if not user:
|
||||
return False
|
||||
if 'password' in user.attributes:
|
||||
return self.__verify_password(user.attributes['password'].value, password)
|
||||
return False
|
||||
|
||||
def __hash_password(self, password):
|
||||
salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
|
||||
pwdhash = hashlib.pbkdf2_hmac('sha3-512', password.encode('utf-8'), salt, 100000)
|
||||
pwdhash = binascii.hexlify(pwdhash)
|
||||
return (salt + pwdhash).decode('ascii')
|
||||
|
||||
def __verify_password(self, stored_password, provided_password):
|
||||
salt = stored_password[:64]
|
||||
stored_password = stored_password[64:]
|
||||
pwdhash = hashlib.pbkdf2_hmac('sha3-512', provided_password.encode('utf-8'),
|
||||
salt.encode('ascii'), 100000)
|
||||
pwdhash = binascii.hexlify(pwdhash).decode('ascii')
|
||||
return pwdhash == stored_password
|
|
@ -1,56 +0,0 @@
|
|||
#######################################
|
||||
# Plugin: Users #
|
||||
# Functionality: Allow management #
|
||||
# of users, login, logout, etc #
|
||||
#######################################
|
||||
|
||||
from flask import Blueprint
|
||||
from flaschengeist.app import app
|
||||
|
||||
def register():
|
||||
return Blueprint('user', __name__)
|
||||
|
||||
#######################################
|
||||
## Routes ##
|
||||
#######################################
|
||||
#dummy
|
||||
@app.route("/")
|
||||
def _dummy():
|
||||
return 'Noch funktioniert hier mal überhaupt nichts!'
|
||||
|
||||
@app.route("/login", methods=['POST'])
|
||||
def _login():
|
||||
""" Login User
|
||||
|
||||
Nothing to say.
|
||||
Login in User and create an AccessToken for the User.
|
||||
|
||||
Returns:
|
||||
A JSON-File with createt Token or Errors
|
||||
"""
|
||||
debug.info("Start log in.")
|
||||
data = request.get_json()
|
||||
username = data['username']
|
||||
password = data['password']
|
||||
debug.debug("username is {{ {} }}".format(username))
|
||||
try:
|
||||
user_agent = request.user_agent
|
||||
debug.info("search {{ {} }} in database".format(username))
|
||||
user = mainController.loginUser(username, password)
|
||||
debug.debug("user is {{ {} }}".format(user))
|
||||
token = accesTokenController.createAccesToken(user, user_agent=user_agent)
|
||||
debug.debug("accesstoken is {{ {} }}".format(token))
|
||||
debug.info("validate accesstoken")
|
||||
dic = accesTokenController.validateAccessToken(
|
||||
token, [USER, EXTERN]).user.toJSON()
|
||||
dic["token"] = token
|
||||
dic["accessToken"] = token
|
||||
debug.info("User {{ {} }} success login.".format(username))
|
||||
debug.info("return login {{ {} }}".format(dic))
|
||||
return jsonify(dic)
|
||||
except PermissionDenied as err:
|
||||
debug.warning("permission denied exception in logout", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 401
|
||||
except Exception as err:
|
||||
debug.warning("exception in logout.", exc_info=True)
|
||||
return jsonify({"error": "permission denied"}), 401
|
|
@ -1,216 +0,0 @@
|
|||
from geruecht import app
|
||||
from geruecht.logger import getDebugLogger
|
||||
from geruecht.decorator import login_required
|
||||
from geruecht.exceptions import PermissionDenied
|
||||
import geruecht.controller.accesTokenController as ac
|
||||
import geruecht.controller.mainController as mc
|
||||
from geruecht.model import MONEY, BAR, USER, GASTRO, VORSTAND, EXTERN
|
||||
from flask import request, jsonify
|
||||
|
||||
accesTokenController = ac.AccesTokenController()
|
||||
mainController = mc.MainController()
|
||||
|
||||
debug = getDebugLogger()
|
||||
|
||||
@app.route("/valid", methods=['POST'])
|
||||
@login_required(bar=True)
|
||||
def _valid(**kwargs):
|
||||
debug.info('/valid')
|
||||
try:
|
||||
accToken = kwargs['accToken']
|
||||
data = request.get_json()
|
||||
mainController.validateUser(accToken.user.uid, data['password'])
|
||||
debug.debug('return {{ "ok": "ok" }}')
|
||||
return jsonify({"ok": "ok"})
|
||||
except Exception as err:
|
||||
debug.warning("exception in valide.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
@app.route("/pricelist", methods=['GET'])
|
||||
def _getPricelist():
|
||||
try:
|
||||
debug.info("get pricelist")
|
||||
retVal = mainController.getPricelist()
|
||||
debug.info("return pricelist {{ {} }}".format(retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.warning("exception in get pricelist.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route('/drinkTypes', methods=['GET'])
|
||||
def getTypes():
|
||||
try:
|
||||
debug.info("get drinktypes")
|
||||
retVal = mainController.getAllDrinkTypes()
|
||||
debug.info("return drinktypes {{ {} }}".format(retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.warning("exception in get drinktypes.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route('/getAllStatus', methods=['GET'])
|
||||
@login_required(groups=[USER, MONEY, GASTRO, BAR, VORSTAND], bar=True)
|
||||
def _getAllStatus(**kwargs):
|
||||
try:
|
||||
debug.info("get all status for users")
|
||||
retVal = mainController.getAllStatus()
|
||||
debug.info("return all status for users {{ {} }}".format(retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.warning("exception in get all status for users.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route('/getStatus', methods=['POST'])
|
||||
@login_required(groups=[USER, MONEY, GASTRO, BAR, VORSTAND], bar=True)
|
||||
def _getStatus(**kwargs):
|
||||
try:
|
||||
debug.info("get status from user")
|
||||
data = request.get_json()
|
||||
name = data['name']
|
||||
debug.info("get status from user {{ {} }}".format(name))
|
||||
retVal = mainController.getStatus(name)
|
||||
debug.info(
|
||||
"return status from user {{ {} }} : {{ {} }}".format(name, retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.warning("exception in get status from user.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route('/getUsers', methods=['GET'])
|
||||
@login_required(groups=[USER], bar=True)
|
||||
def _getUsers(**kwargs):
|
||||
try:
|
||||
extern = True
|
||||
if 'extern' in request.args:
|
||||
extern = not bool(int(request.args['extern']))
|
||||
debug.info("get all users from database")
|
||||
users = mainController.getAllUsersfromDB(extern=extern)
|
||||
debug.debug("users are {{ {} }}".format(users))
|
||||
retVal = [user.toJSON() for user in users]
|
||||
debug.info("return all users from database {{ {} }}".format(retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.warning(
|
||||
"exception in get all users from database.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route("/getLifeTime", methods=['GET'])
|
||||
@login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True)
|
||||
def _getLifeTime(**kwargs):
|
||||
try:
|
||||
debug.info("get lifetime of accesstoken")
|
||||
if 'accToken' in kwargs:
|
||||
accToken = kwargs['accToken']
|
||||
debug.debug("accessToken is {{ {} }}".format(accToken))
|
||||
retVal = {"value": accToken.lifetime,
|
||||
"group": accToken.user.toJSON()['group'],
|
||||
"lock_bar": accToken.lock_bar}
|
||||
debug.info(
|
||||
"return get lifetime from accesstoken {{ {} }}".format(retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.info("exception in get lifetime of accesstoken.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route("/saveLifeTime", methods=['POST'])
|
||||
@login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True)
|
||||
def _saveLifeTime(**kwargs):
|
||||
try:
|
||||
debug.info("save lifetime for accessToken")
|
||||
if 'accToken' in kwargs:
|
||||
accToken = kwargs['accToken']
|
||||
debug.debug("accessToken is {{ {} }}".format(accToken))
|
||||
data = request.get_json()
|
||||
lifetime = data['value']
|
||||
debug.debug("lifetime is {{ {} }}".format(lifetime))
|
||||
debug.info("set lifetime {{ {} }} to accesstoken {{ {} }}".format(
|
||||
lifetime, accToken))
|
||||
accToken.lifetime = lifetime
|
||||
debug.info("update accesstoken timestamp")
|
||||
accToken = accesTokenController.updateAccessToken(accToken)
|
||||
accToken = accesTokenController.validateAccessToken(accToken.token, [USER, EXTERN])
|
||||
retVal = {"value": accToken.lifetime,
|
||||
"group": accToken.user.toJSON()['group']}
|
||||
debug.info(
|
||||
"return save lifetime for accessToken {{ {} }}".format(retVal))
|
||||
return jsonify(retVal)
|
||||
except Exception as err:
|
||||
debug.warning(
|
||||
"exception in save lifetime for accesstoken.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
@app.route("/passwordReset", methods=['POST'])
|
||||
def _passwordReset():
|
||||
try:
|
||||
debug.info('password reset')
|
||||
data = request.get_json()
|
||||
mail = mainController.resetPassword(data)
|
||||
index = mail.find('@')
|
||||
for i in range(index):
|
||||
if i == 0:
|
||||
continue
|
||||
mail = mail.replace(mail[i], "*", 1)
|
||||
return jsonify({"ok": "ok", "mail": mail})
|
||||
except Exception as err:
|
||||
debug.warning("excetpion in password reset", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 409
|
||||
|
||||
@app.route("/logout", methods=['GET'])
|
||||
@login_required(groups=[MONEY, GASTRO, VORSTAND, EXTERN, USER], bar=True)
|
||||
def _logout(**kwargs):
|
||||
try:
|
||||
debug.info("logout user")
|
||||
if 'accToken' in kwargs:
|
||||
accToken = kwargs['accToken']
|
||||
debug.debug("accesstoken is {{ {} }}".format(accToken))
|
||||
debug.info("delete accesstoken")
|
||||
accesTokenController.deleteAccessToken(accToken)
|
||||
debug.info("return ok logout user")
|
||||
return jsonify({"ok": "ok"})
|
||||
except Exception as err:
|
||||
debug.warning("exception in logout user.", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 500
|
||||
|
||||
|
||||
@app.route("/login", methods=['POST'])
|
||||
def _login():
|
||||
""" Login User
|
||||
|
||||
Nothing to say.
|
||||
Login in User and create an AccessToken for the User.
|
||||
|
||||
Returns:
|
||||
A JSON-File with createt Token or Errors
|
||||
"""
|
||||
debug.info("Start log in.")
|
||||
data = request.get_json()
|
||||
username = data['username']
|
||||
password = data['password']
|
||||
debug.debug("username is {{ {} }}".format(username))
|
||||
try:
|
||||
user_agent = request.user_agent
|
||||
debug.info("search {{ {} }} in database".format(username))
|
||||
user = mainController.loginUser(username, password)
|
||||
debug.debug("user is {{ {} }}".format(user))
|
||||
token = accesTokenController.createAccesToken(user, user_agent=user_agent)
|
||||
debug.debug("accesstoken is {{ {} }}".format(token))
|
||||
debug.info("validate accesstoken")
|
||||
dic = accesTokenController.validateAccessToken(
|
||||
token, [USER, EXTERN]).user.toJSON()
|
||||
dic["token"] = token
|
||||
dic["accessToken"] = token
|
||||
debug.info("User {{ {} }} success login.".format(username))
|
||||
debug.info("return login {{ {} }}".format(dic))
|
||||
return jsonify(dic)
|
||||
except PermissionDenied as err:
|
||||
debug.warning("permission denied exception in logout", exc_info=True)
|
||||
return jsonify({"error": str(err)}), 401
|
||||
except Exception as err:
|
||||
debug.warning("exception in logout.", exc_info=True)
|
||||
return jsonify({"error": "permission denied"}), 401
|
|
@ -1,244 +0,0 @@
|
|||
from geruecht.logger import getDebugLogger
|
||||
from geruecht.model.creditList import CreditList, create_empty_data
|
||||
from datetime import datetime
|
||||
|
||||
debug = getDebugLogger()
|
||||
|
||||
|
||||
class User():
|
||||
""" Database Object for User
|
||||
|
||||
Table for all safed User
|
||||
|
||||
Attributes:
|
||||
id: Id in Database as Primary Key.
|
||||
userID: ID for the User maybe to Link?
|
||||
username: Username of the User to Login
|
||||
firstname: Firstname of the User
|
||||
Lastname: Lastname of the User
|
||||
group: Which group is the User? moneymaster, gastro, user or bar?
|
||||
password: salted hashed password for the User.
|
||||
"""
|
||||
def __init__(self, data):
|
||||
debug.info("init user")
|
||||
if 'id' in data:
|
||||
self.id = int(data['id'])
|
||||
self.uid = data['uid']
|
||||
self.dn = data['dn']
|
||||
self.firstname = data['firstname']
|
||||
self.lastname = data['lastname']
|
||||
self.group = data['gruppe']
|
||||
self.last_seen = None
|
||||
if 'last_seen' in data:
|
||||
self.last_seen = data['last_seen']
|
||||
if 'statusgroup' in data:
|
||||
self.statusgroup = data['statusgroup']
|
||||
else:
|
||||
self.statusgroup = None
|
||||
if 'voting' in data:
|
||||
self.voting = data['voting']
|
||||
else:
|
||||
self.voting = None
|
||||
if 'mail' in data:
|
||||
self.mail = data['mail']
|
||||
else:
|
||||
self.mail = ''
|
||||
if 'lockLimit' in data:
|
||||
self.limit = int(data['lockLimit'])
|
||||
else:
|
||||
self.limit = 4200
|
||||
if 'locked' in data:
|
||||
self.locked = bool(data['locked'])
|
||||
else:
|
||||
self.locked = False
|
||||
if 'autoLock' in data:
|
||||
self.autoLock = bool(data['autoLock'])
|
||||
else:
|
||||
self.autoLock = True
|
||||
if type(data['gruppe']) == list:
|
||||
self.group = data['gruppe']
|
||||
elif type(data['gruppe']) == str:
|
||||
self.group = data['gruppe'].split(',')
|
||||
if 'creditLists' in data:
|
||||
self.geruechte = data['creditLists']
|
||||
if 'workgroups' in data:
|
||||
self.workgroups = data['workgroups']
|
||||
else:
|
||||
self.workgroups = None
|
||||
self.password = ''
|
||||
debug.debug("user is {{ {} }}".format(self))
|
||||
|
||||
def updateData(self, data):
|
||||
debug.info("update data of user")
|
||||
if 'dn' in data:
|
||||
self.dn = data['dn']
|
||||
if 'firstname' in data:
|
||||
self.firstname = data['firstname']
|
||||
if 'lastname' in data:
|
||||
self.lastname = data['lastname']
|
||||
if 'gruppe' in data:
|
||||
self.group = data['gruppe']
|
||||
if 'lockLimit' in data:
|
||||
self.limit = int(data['lockLimit'])
|
||||
if 'locked' in data:
|
||||
self.locked = bool(data['locked'])
|
||||
if 'autoLock' in data:
|
||||
self.autoLock = bool(data['autoLock'])
|
||||
if 'mail' in data:
|
||||
self.mail = data['mail']
|
||||
if 'statusgorup' in data:
|
||||
self.statusgroup = data['statusgroup']
|
||||
if 'voting' in data:
|
||||
self.voting = data['voting']
|
||||
if 'workgroups' in data:
|
||||
self.workgroups = data['workgroups']
|
||||
else:
|
||||
self.workgroups = None
|
||||
|
||||
def initGeruechte(self, creditLists):
|
||||
if type(creditLists) == list:
|
||||
self.geruechte = creditLists
|
||||
|
||||
def createGeruecht(self, amount=0, year=datetime.now().year):
|
||||
""" Create Geruecht
|
||||
|
||||
This function create a geruecht for the user for an year.
|
||||
By default is amount zero and year the actual year.
|
||||
|
||||
Args:
|
||||
amount: is the last_schulden of the geruecht
|
||||
year: is the year of the geruecht
|
||||
|
||||
Returns:
|
||||
the created geruecht
|
||||
"""
|
||||
debug.info("create creditlist for user {{ {} }} in year {{ {} }}".format(self, year))
|
||||
data = create_empty_data()
|
||||
data['user_id'] = self.id
|
||||
data['last_schulden'] = amount
|
||||
data['year_date'] = year
|
||||
credit = CreditList(data)
|
||||
self.geruechte.append(credit)
|
||||
debug.debug("creditlist is {{ {} }}".format(credit))
|
||||
return credit
|
||||
|
||||
def getGeruecht(self, year=datetime.now().year):
|
||||
""" Get Geruecht
|
||||
|
||||
This function returns the geruecht of an year.
|
||||
By default is the year the actual year.
|
||||
|
||||
Args:
|
||||
year: the year of the geruecht
|
||||
|
||||
Returns:
|
||||
the geruecht of the year
|
||||
"""
|
||||
debug.info("get creditlist from user on year {{ {} }}".format(year))
|
||||
for geruecht in self.geruechte:
|
||||
if geruecht.year == year:
|
||||
debug.debug("creditlist is {{ {} }} for user {{ {} }}".format(geruecht, self))
|
||||
return geruecht
|
||||
debug.debug("no creditlist found for user {{ {} }}".format(self))
|
||||
geruecht = self.createGeruecht(year=year)
|
||||
|
||||
return self.getGeruecht(year=year)
|
||||
|
||||
def addAmount(self, amount, year=datetime.now().year, month=datetime.now().month):
|
||||
""" Add Amount
|
||||
|
||||
This function add an amount to a geruecht with an spezified year and month to the user.
|
||||
By default the year is the actual year.
|
||||
By default the month is the actual month.
|
||||
|
||||
Args:
|
||||
year: year of the geruecht
|
||||
month: month for the amount
|
||||
|
||||
Returns:
|
||||
double (credit, amount)
|
||||
"""
|
||||
debug.info("add amount to user {{ {} }} in year {{ {} }} and month {{ {} }}".format(self, year, month))
|
||||
geruecht = self.getGeruecht(year=year)
|
||||
retVal = geruecht.addAmount(amount, month=month)
|
||||
|
||||
return retVal
|
||||
|
||||
def addCredit(self, credit, year=datetime.now().year, month=datetime.now().month):
|
||||
""" Add Credit
|
||||
|
||||
This function add an credit to a geruecht with an spezified year and month to the user.
|
||||
By default the year is the actual year.
|
||||
By default the month is the actual month.
|
||||
|
||||
Args:
|
||||
year: year of the geruecht
|
||||
month: month for the amount
|
||||
|
||||
Returns:
|
||||
double (credit, amount)
|
||||
"""
|
||||
debug.info("add credit to user {{ {} }} in year {{ {} }} and month {{ {} }}".format(self, year, month))
|
||||
geruecht = self.getGeruecht(year=year)
|
||||
retVal = geruecht.addCredit(credit, month=month)
|
||||
|
||||
return retVal
|
||||
|
||||
def updateGeruecht(self):
|
||||
""" Update list of geruechte
|
||||
|
||||
This function iterate through the geruechte, which sorted by year and update the last_schulden of the geruecht.
|
||||
"""
|
||||
debug.info("update all creditlists ")
|
||||
self.geruechte.sort(key=self.sortYear)
|
||||
|
||||
for index, geruecht in enumerate(self.geruechte):
|
||||
if index == 0 or index == len(self.geruechte) - 1:
|
||||
geruecht.last_schulden = 0
|
||||
if index != 0:
|
||||
geruecht.last_schulden = (self.geruechte[index - 1].getSchulden() * -1)
|
||||
|
||||
return self.geruechte
|
||||
|
||||
def sortYear(self, geruecht):
|
||||
""" Sort Year
|
||||
|
||||
This function is only an helperfunction to sort the list of geruechte by years.
|
||||
It only returns the year of the geruecht.
|
||||
|
||||
Args:
|
||||
geruecht: geruecht which year you want
|
||||
|
||||
Returns:
|
||||
int year of the geruecht
|
||||
"""
|
||||
return geruecht.year
|
||||
|
||||
def toJSON(self):
|
||||
""" Create Dic to dump in JSON
|
||||
|
||||
Returns:
|
||||
A Dic with static Attributes.
|
||||
"""
|
||||
dic = {
|
||||
"id": self.id,
|
||||
"userId": self.uid,
|
||||
"uid": self.uid,
|
||||
"dn": self.dn,
|
||||
"firstname": self.firstname,
|
||||
"lastname": self.lastname,
|
||||
"group": self.group,
|
||||
"username": self.uid,
|
||||
"locked": self.locked,
|
||||
"autoLock": self.autoLock,
|
||||
"limit": self.limit,
|
||||
"mail": self.mail,
|
||||
"statusgroup": self.statusgroup,
|
||||
"voting": self.voting,
|
||||
"workgroups": self.workgroups
|
||||
}
|
||||
return dic
|
||||
|
||||
def __repr__(self):
|
||||
return "User({}, {}, {})".format(self.uid, self.dn, self.group)
|
||||
|
|
@ -1,12 +1,8 @@
|
|||
from ..logger import getDebugLogger
|
||||
from ..configparser import ConifgParser
|
||||
from flaschengeist import _modpath
|
||||
import os
|
||||
|
||||
config = ConifgParser(_modpath/'config.yml')
|
||||
|
||||
LOGGER = getDebugLogger()
|
||||
|
||||
class Singleton(type):
|
||||
_instances = {}
|
||||
def __call__(cls, *args, **kwargs):
|
||||
|
|
|
@ -1,17 +1,13 @@
|
|||
from geruecht.model.accessToken import AccessToken
|
||||
import geruecht.controller as gc
|
||||
import geruecht.controller.mainController as mc
|
||||
import geruecht.controller.databaseController as dc
|
||||
from geruecht.model import BAR
|
||||
from ..models.accessToken import AccessToken
|
||||
from flaschengeist.system.database import db
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
import hashlib
|
||||
import secrets
|
||||
from . import Singleton
|
||||
from geruecht.logger import getDebugLogger
|
||||
from flask import Blueprint, request, jsonify
|
||||
import logging
|
||||
|
||||
debug = getDebugLogger()
|
||||
|
||||
mainController = mc.MainController()
|
||||
db = dc.DatabaseController()
|
||||
logger = logging.getLogger("flaschenpost")
|
||||
|
||||
class AccesTokenController(metaclass=Singleton):
|
||||
""" Control all createt AccesToken
|
||||
|
@ -30,22 +26,8 @@ class AccesTokenController(metaclass=Singleton):
|
|||
|
||||
Initialize Thread and set tokenList empty.
|
||||
"""
|
||||
debug.info("init accesstoken controller")
|
||||
self.lifetime = gc.accConfig
|
||||
|
||||
def checkBar(self, user):
|
||||
debug.info("check if user {{ {} }} is baruser".format(user))
|
||||
if (mainController.checkBarUser(user)):
|
||||
if BAR not in user.group:
|
||||
debug.debug("append bar to user {{ {} }}".format(user))
|
||||
user.group.append(BAR)
|
||||
return True
|
||||
else:
|
||||
while BAR in user.group:
|
||||
debug.debug("delete bar from user {{ {} }}".format(user))
|
||||
user.group.remove(BAR)
|
||||
return False
|
||||
debug.debug("user {{ {} }} groups are {{ {} }}".format(user, user.group))
|
||||
logger.debug("init accesstoken controller")
|
||||
self.lifetime = lifetime
|
||||
|
||||
def validateAccessToken(self, token, group):
|
||||
""" Verify Accestoken
|
||||
|
@ -59,27 +41,27 @@ class AccesTokenController(metaclass=Singleton):
|
|||
Returns:
|
||||
An the AccesToken for this given Token or False.
|
||||
"""
|
||||
debug.info("check token {{ {} }} is valid")
|
||||
for accToken in db.getAccessTokens():
|
||||
debug.debug("accesstoken is {}".format(accToken))
|
||||
logger.debug("check token {{ {} }} is valid".format(token))
|
||||
for accToken in AccessToken.query.filter_by(token=token):
|
||||
endTime = accToken.timestamp + timedelta(seconds=accToken.lifetime)
|
||||
now = datetime.now()
|
||||
debug.debug("now is {{ {} }}, endtime is {{ {} }}".format(now, endTime))
|
||||
now = datetime.utcnow()
|
||||
logger.debug("now is {{ {} }}, endtime is {{ {} }}".format(now, endTime))
|
||||
if now <= endTime:
|
||||
debug.debug("check if token {{ {} }} is same as {{ {} }}".format(token, accToken))
|
||||
logger.debug("check if token {{ {} }} is same as {{ {} }}".format(token, accToken))
|
||||
if accToken == token:
|
||||
if not self.checkBar(accToken.user):
|
||||
accToken.lock_bar = False
|
||||
debug.debug("check if accestoken {{ {} }} has group {{ {} }}".format(accToken, group))
|
||||
if self.isSameGroup(accToken, group):
|
||||
accToken.updateTimestamp()
|
||||
db.updateAccessToken(accToken)
|
||||
debug.debug("found accesstoken {{ {} }} with token: {{ {} }} and group: {{ {} }}".format(accToken, token, group))
|
||||
return accToken
|
||||
# if not self.checkBar(accToken.user):
|
||||
# accToken.lock_bar = False
|
||||
# logger.debug("check if accestoken {{ {} }} has group {{ {} }}".format(accToken, group))
|
||||
# if self.isSameGroup(accToken, group):
|
||||
accToken.updateTimestamp()
|
||||
db.session.commit()
|
||||
# logger.debug("found accesstoken {{ {} }} with token: {{ {} }} and group: {{ {} }}".format(accToken, token, group))
|
||||
return accToken
|
||||
else:
|
||||
debug.debug("accesstoken is {{ {} }} out of date".format(accToken))
|
||||
db.deleteAccessToken(accToken)
|
||||
debug.debug("no valid accesstoken with token: {{ {} }} and group: {{ {} }}".format(token, group))
|
||||
logger.debug("accesstoken is {{ {} }} out of date".format(accToken))
|
||||
db.session.delete(accToken)
|
||||
db.session.commit()
|
||||
logger.debug("no valid accesstoken with token: {{ {} }} and group: {{ {} }}".format(token, group))
|
||||
return False
|
||||
|
||||
def createAccesToken(self, user, user_agent=None):
|
||||
|
@ -93,12 +75,13 @@ class AccesTokenController(metaclass=Singleton):
|
|||
Returns:
|
||||
A created Token for User
|
||||
"""
|
||||
debug.info("creat accesstoken")
|
||||
now = datetime.ctime(datetime.now())
|
||||
token = hashlib.md5((now + user.dn).encode('utf-8')).hexdigest()
|
||||
self.checkBar(user)
|
||||
accToken = db.createAccessToken(user, token, self.lifetime, datetime.now(), lock_bar=False, user_agent=user_agent)
|
||||
debug.debug("accesstoken is {{ {} }}".format(accToken))
|
||||
logger.debug("creat accesstoken")
|
||||
token = secrets.token_hex(16)
|
||||
accToken = AccessToken(token=token, user=user, lifetime=self.lifetime, browser=user_agent.browser, platform=user_agent.platform)
|
||||
db.session.add(accToken)
|
||||
db.session.commit()
|
||||
|
||||
logger.debug("accesstoken is {{ {} }}".format(accToken))
|
||||
return token
|
||||
|
||||
def isSameGroup(self, accToken, groups):
|
||||
|
@ -122,7 +105,9 @@ class AccesTokenController(metaclass=Singleton):
|
|||
return db.getAccessTokensFromUser(user)
|
||||
|
||||
def deleteAccessToken(self, accToken):
|
||||
db.deleteAccessToken(accToken)
|
||||
db.session.delete(accToken)
|
||||
db.session.commit()
|
||||
#AccessToken.query.filter_by(token=accToken).delete()
|
||||
|
||||
def updateAccessToken(self, accToken):
|
||||
accToken.updateTimestamp()
|
||||
|
|
|
@ -1,44 +1,37 @@
|
|||
from .. import Singleton, mailConfig
|
||||
import geruecht.controller.databaseController as dc
|
||||
import geruecht.controller.ldapController as lc
|
||||
import geruecht.controller.emailController as ec
|
||||
from geruecht.model.user import User
|
||||
from ...models.user import User
|
||||
from datetime import datetime, timedelta
|
||||
from geruecht.logger import getDebugLogger
|
||||
from ..mainController import mainJobKindController, mainCreditListController, mainPricelistController, mainUserController, mainWorkerController, mainWorkgroupController, mainJobInviteController, mainJobRequestController, mainRegistrationController, mainPasswordReset
|
||||
from . import mainUserController
|
||||
from ...database import db
|
||||
from flask import current_app
|
||||
from werkzeug.local import LocalProxy
|
||||
logger = LocalProxy(lambda: current_app.logger)
|
||||
|
||||
db = dc.DatabaseController()
|
||||
ldap = lc.LDAPController()
|
||||
emailController = ec.EmailController()
|
||||
|
||||
debug = getDebugLogger()
|
||||
|
||||
|
||||
class MainController(mainJobKindController.Base,
|
||||
mainCreditListController.Base,
|
||||
mainPricelistController.Base,
|
||||
class MainController(#mainJobKindController.Base,
|
||||
#mainCreditListController.Base,
|
||||
#mainPricelistController.Base,
|
||||
mainUserController.Base,
|
||||
mainWorkerController.Base,
|
||||
mainWorkgroupController.Base,
|
||||
mainJobInviteController.Base,
|
||||
mainJobRequestController.Base,
|
||||
mainRegistrationController.Base,
|
||||
mainPasswordReset.Base,
|
||||
#mainWorkerController.Base,
|
||||
#mainWorkgroupController.Base,
|
||||
#mainJobInviteController.Base,
|
||||
#mainJobRequestController.Base,
|
||||
#mainRegistrationController.Base,
|
||||
#mainPasswordReset.Base,
|
||||
metaclass=Singleton):
|
||||
|
||||
def __init__(self):
|
||||
debug.debug("init UserController")
|
||||
logger.debug("init UserController")
|
||||
pass
|
||||
|
||||
def setLockedDay(self, date, locked, hard=False):
|
||||
debug.info(
|
||||
logger.info(
|
||||
"set day locked on {{ {} }} with state {{ {} }}".format(date, locked))
|
||||
retVal = db.setLockedDay(date.date(), locked, hard)
|
||||
debug.debug("seted day locked is {{ {} }}".format(retVal))
|
||||
logger.debug("seted day locked is {{ {} }}".format(retVal))
|
||||
return retVal
|
||||
|
||||
def getLockedDays(self, from_date, to_date):
|
||||
debug.info("get locked days from {{ {} }} to {{ {} }}".format(
|
||||
logger.info("get locked days from {{ {} }} to {{ {} }}".format(
|
||||
from_date.date(), to_date.date()))
|
||||
oneDay = timedelta(1)
|
||||
delta = to_date.date() - from_date.date()
|
||||
|
@ -48,11 +41,11 @@ class MainController(mainJobKindController.Base,
|
|||
startdate += oneDay
|
||||
lockday = self.getLockedDay(startdate)
|
||||
retVal.append(lockday)
|
||||
debug.debug("lock days are {{ {} }}".format(retVal))
|
||||
logger.debug("lock days are {{ {} }}".format(retVal))
|
||||
return retVal
|
||||
|
||||
def getLockedDaysFromList(self, date_list):
|
||||
debug.info("get locked days from list {{ {} }}".format(date_list))
|
||||
logger.info("get locked days from list {{ {} }}".format(date_list))
|
||||
retVal = []
|
||||
for on_date in date_list:
|
||||
day = datetime(on_date['on_date']['year'], on_date['on_date']['month'], on_date['on_date']['day'], 12)
|
||||
|
@ -60,22 +53,22 @@ class MainController(mainJobKindController.Base,
|
|||
return retVal
|
||||
|
||||
def getLockedDay(self, date):
|
||||
debug.info("get locked day on {{ {} }}".format(date))
|
||||
logger.info("get locked day on {{ {} }}".format(date))
|
||||
now = datetime.now()
|
||||
debug.debug("now is {{ {} }}".format(now))
|
||||
logger.debug("now is {{ {} }}".format(now))
|
||||
oldMonth = False
|
||||
debug.debug("check if date old month or current month")
|
||||
logger.debug("check if date old month or current month")
|
||||
for i in range(1, 8):
|
||||
if datetime(now.year, now.month, i).weekday() == 2:
|
||||
if now.day < i:
|
||||
oldMonth = True
|
||||
break
|
||||
debug.debug("oldMonth is {{ {} }}".format(oldMonth))
|
||||
logger.debug("oldMonth is {{ {} }}".format(oldMonth))
|
||||
lockedYear = now.year
|
||||
lockedMonth = now.month if now.month < now.month else now.month - \
|
||||
1 if oldMonth else now.month
|
||||
endDay = 1
|
||||
debug.debug("calculate end day of month")
|
||||
logger.debug("calculate end day of month")
|
||||
lockedYear = lockedYear if lockedMonth != 12 else (lockedYear + 1)
|
||||
lockedMonth = (lockedMonth + 1) if lockedMonth != 12 else 1
|
||||
for i in range(1, 8):
|
||||
|
@ -86,33 +79,33 @@ class MainController(mainJobKindController.Base,
|
|||
|
||||
monthLockedEndDate = datetime(
|
||||
lockedYear, lockedMonth, endDay) - timedelta(1)
|
||||
debug.debug("get lock day from database")
|
||||
logger.debug("get lock day from database")
|
||||
retVal = db.getLockedDay(date.date())
|
||||
if not retVal:
|
||||
debug.debug(
|
||||
logger.debug(
|
||||
"lock day not exists, retVal is {{ {} }}".format(retVal))
|
||||
if date.date() <= monthLockedEndDate.date():
|
||||
debug.debug("lock day {{ {} }}".format(date.date()))
|
||||
logger.debug("lock day {{ {} }}".format(date.date()))
|
||||
self.setLockedDay(date, True)
|
||||
retVal = db.getLockedDay(date.date())
|
||||
else:
|
||||
retVal = {"daydate": date.date(), "locked": False}
|
||||
debug.debug("locked day is {{ {} }}".format(retVal))
|
||||
logger.debug("locked day is {{ {} }}".format(retVal))
|
||||
return retVal
|
||||
|
||||
def __updateDataFromLDAP(self, user):
|
||||
debug.info("update data from ldap for user {{ {} }}".format(user))
|
||||
logger.info("update data from ldap for user {{ {} }}".format(user))
|
||||
groups = ldap.getGroup(user.uid)
|
||||
debug.debug("ldap gorups are {{ {} }}".format(groups))
|
||||
logger.debug("ldap gorups are {{ {} }}".format(groups))
|
||||
user_data = ldap.getUserData(user.uid)
|
||||
debug.debug("ldap data is {{ {} }}".format(user_data))
|
||||
logger.debug("ldap data is {{ {} }}".format(user_data))
|
||||
user_data['gruppe'] = groups
|
||||
user_data['group'] = groups
|
||||
user.updateData(user_data)
|
||||
db.updateUser(user)
|
||||
|
||||
def checkBarUser(self, user):
|
||||
debug.info("check if user {{ {} }} is baruser")
|
||||
logger.info("check if user {{ {} }} is baruser")
|
||||
date = datetime.now()
|
||||
zero = date.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
end = zero + timedelta(hours=12)
|
||||
|
@ -121,22 +114,22 @@ class MainController(mainJobKindController.Base,
|
|||
if date > zero and end > date:
|
||||
startdatetime = startdatetime - timedelta(days=1)
|
||||
enddatetime = startdatetime + timedelta(days=1)
|
||||
debug.debug("startdatetime is {{ {} }} and enddatetime is {{ {} }}".format(
|
||||
logger.debug("startdatetime is {{ {} }} and enddatetime is {{ {} }}".format(
|
||||
startdatetime, end))
|
||||
result = False
|
||||
if date >= startdatetime and date < enddatetime:
|
||||
result = db.getWorker(user, startdatetime)
|
||||
debug.debug("worker is {{ {} }}".format(result))
|
||||
logger.debug("worker is {{ {} }}".format(result))
|
||||
return True if result else False
|
||||
|
||||
def sendMail(self, username):
|
||||
debug.info("send mail to user {{ {} }}".format(username))
|
||||
logger.info("send mail to user {{ {} }}".format(username))
|
||||
if type(username) == User:
|
||||
user = username
|
||||
if type(username) == str:
|
||||
user = db.getUser(username)
|
||||
retVal = emailController.sendMail(user)
|
||||
debug.debug("send mail is {{ {} }}".format(retVal))
|
||||
logger.debug("send mail is {{ {} }}".format(retVal))
|
||||
return retVal
|
||||
|
||||
def sendAllMail(self):
|
||||
|
|
|
@ -1,14 +1,10 @@
|
|||
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError
|
||||
from flaschengeist.system.exceptions import UsernameExistLDAP, LDAPExcetpion, PermissionDenied
|
||||
from flaschengeist.system.models.user import User
|
||||
from flaschengeist.system.database import db
|
||||
|
||||
from geruecht.exceptions import UsernameExistLDAP, LDAPExcetpion, PermissionDenied
|
||||
import geruecht.controller.databaseController as dc
|
||||
import geruecht.controller.ldapController as lc
|
||||
from geruecht.logger import getDebugLogger
|
||||
from geruecht.model.user import User
|
||||
|
||||
db = dc.DatabaseController()
|
||||
ldap = lc.LDAPController()
|
||||
debug = getDebugLogger()
|
||||
from flask import Blueprint, current_app
|
||||
from werkzeug.local import LocalProxy
|
||||
logger = LocalProxy(lambda: current_app.logger)
|
||||
|
||||
class Base:
|
||||
def getAllStatus(self):
|
||||
|
@ -167,13 +163,14 @@ class Base:
|
|||
ldap.login(username, password)
|
||||
|
||||
def loginUser(self, username, password):
|
||||
debug.info("login user {{ {} }}".format(username))
|
||||
try:
|
||||
user = self.getUser(username)
|
||||
debug.debug("user is {{ {} }}".format(user))
|
||||
user.password = password
|
||||
ldap.login(username, password)
|
||||
return user
|
||||
except PermissionDenied as err:
|
||||
debug.debug("permission is denied", exc_info=True)
|
||||
raise err
|
||||
logger.info("login user {{ {} }}".format(username))
|
||||
user = User.query.filter_by(uid=username).first()
|
||||
if user is None:
|
||||
user = User(uid=username)
|
||||
for backend in current_app.config['FG_AUTH_BACKENDS']:
|
||||
b = backend()
|
||||
if b.login(user, password):
|
||||
db.session.add(user)
|
||||
db.session.commit()
|
||||
return user
|
||||
raise PermissionDenied()
|
||||
|
|
|
@ -1,35 +1,29 @@
|
|||
from functools import wraps
|
||||
from flask import current_app
|
||||
from werkzeug.local import LocalProxy
|
||||
logger = LocalProxy(lambda: current_app.logger)
|
||||
|
||||
from flask import current_app, request, jsonify
|
||||
from flaschengeist import logger
|
||||
|
||||
def login_required(**kwargs):
|
||||
import geruecht.controller.accesTokenController as ac
|
||||
from geruecht.model import BAR, USER, MONEY, GASTRO, VORSTAND, EXTERN
|
||||
from flask import request, jsonify
|
||||
accessController = ac.AccesTokenController()
|
||||
groups = [USER, BAR, GASTRO, MONEY, VORSTAND, EXTERN]
|
||||
bar = False
|
||||
if "groups" in kwargs:
|
||||
groups = kwargs["groups"]
|
||||
if "bar" in kwargs:
|
||||
bar = kwargs["bar"]
|
||||
logger.debug("groups are {{ {} }}".format(groups))
|
||||
from .controller.accesTokenController import AccesTokenController
|
||||
accessController = AccesTokenController()
|
||||
#if "groups" in kwargs:
|
||||
# groups = kwargs["groups"]
|
||||
#if "bar" in kwargs:
|
||||
# bar = kwargs["bar"]
|
||||
#logger.debug("groups are {{ {} }}".format(groups))
|
||||
|
||||
def real_decorator(func):
|
||||
@wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
token = request.headers.get('Token')
|
||||
logger.debug("token is {{ {} }}".format(token))
|
||||
accToken = accessController.validateAccessToken(token, groups)
|
||||
accToken = accessController.validateAccessToken(token, None)
|
||||
logger.debug("accToken is {{ {} }}".format(accToken))
|
||||
kwargs['accToken'] = accToken
|
||||
if accToken:
|
||||
logger.debug("token {{ {} }} is valid".format(token))
|
||||
if accToken.lock_bar and not bar:
|
||||
return jsonify({"error": "error",
|
||||
"message": "permission forbidden"}), 403
|
||||
# if accToken.lock_bar and not bar:
|
||||
# return jsonify({"error": "error",
|
||||
# "message": "permission forbidden"}), 403
|
||||
return func(*args, **kwargs)
|
||||
else:
|
||||
logger.warning("token {{ {} }} is not valid".format(token))
|
||||
|
|
|
@ -52,7 +52,7 @@ class AccessToken(db.Model):
|
|||
return dic
|
||||
|
||||
def __eq__(self, token):
|
||||
return True if self.token == token else False
|
||||
return self.token == token
|
||||
|
||||
def __sub__(self, other):
|
||||
return other - self.timestamp
|
||||
|
|
|
@ -48,6 +48,16 @@ class User(db.Model):
|
|||
if 'displayname' in data:
|
||||
self.displayname = data['displayname']
|
||||
|
||||
def toJSON(self):
|
||||
return {
|
||||
"uid": self.uid,
|
||||
"displayname": self.displayname,
|
||||
"firstname": self.firstname,
|
||||
"lastname": self.lastname,
|
||||
"mail": self.mail,
|
||||
"groups": self.groups
|
||||
}
|
||||
|
||||
|
||||
class UserAttribute(db.Model):
|
||||
__tablename__ = 'userAttribute'
|
||||
|
|
2
setup.py
2
setup.py
|
@ -13,7 +13,7 @@ setup(
|
|||
install_requires=['Flask >= 1.1', 'PyYAML>=5.3.1', 'sqlalchemy>=1.3', "flask_sqlalchemy", "flask_ldapconn", "flask_cors"],
|
||||
entry_points = {
|
||||
'flaschengeist.plugin': [
|
||||
'user = flaschengeist.modules.user:register'
|
||||
'auth = flaschengeist.modules.auth:register'
|
||||
],
|
||||
'flaschengeist.auth': [
|
||||
'plain_auth = flaschengeist.modules.auth_plain:AuthPlain'
|
||||
|
|
Loading…
Reference in New Issue