Only use one plugin system, load auth and "normal" plugins at once.

* Added Plugin class, where to inheritate from
This commit is contained in:
Ferdinand Thiessen 2020-10-15 21:58:56 +02:00
parent 60c2637784
commit 2c55edf6a8
14 changed files with 428 additions and 497 deletions

View File

@ -6,6 +6,7 @@ from flask.json import JSONEncoder, jsonify
from werkzeug.exceptions import HTTPException from werkzeug.exceptions import HTTPException
from . import logger from . import logger
from .modules import AuthPlugin
from .system.config import config, configure_app from .system.config import config, configure_app
from .system.controller import roleController from .system.controller import roleController
@ -30,19 +31,6 @@ class CustomJSONEncoder(JSONEncoder):
return JSONEncoder.default(self, o) return JSONEncoder.default(self, o)
def __load_auth(app):
for entry_point in pkg_resources.iter_entry_points('flaschengeist.auth'):
logger.debug('Found authentication plugin: %s', entry_point.name)
if entry_point.name == config['FLASCHENGEIST']['AUTH']:
app.config['FG_AUTH_BACKEND'] = entry_point.load()()
app.config['FG_AUTH_BACKEND'].configure(
config[entry_point.name] if config.has_section(entry_point.name) else {})
logger.info('Loaded authentication plugin > %s <', entry_point.name)
break
if not app.config['FG_AUTH_BACKEND']:
logger.error('No authentication plugin configured or authentication plugin not found')
def __load_plugins(app): def __load_plugins(app):
logger.info('Search for plugins') logger.info('Search for plugins')
app.config['FG_PLUGINS'] = {} app.config['FG_PLUGINS'] = {}
@ -50,10 +38,20 @@ def __load_plugins(app):
logger.debug("Found plugin: >{}<".format(entry_point.name)) logger.debug("Found plugin: >{}<".format(entry_point.name))
plugin = None plugin = None
if config.get(entry_point.name, 'enabled', fallback=False): if config.get(entry_point.name, 'enabled', fallback=False):
plugin = entry_point.load()() plugin = entry_point.load()(config[entry_point.name] if config.has_section(entry_point.name) else {})
if plugin.blueprint:
app.register_blueprint(plugin.blueprint) app.register_blueprint(plugin.blueprint)
logger.info("Loaded plugin >{}<".format(entry_point.name)) logger.info("Load plugin >{}<".format(entry_point.name))
if isinstance(plugin, AuthPlugin):
logger.debug('Found authentication plugin: %s', entry_point.name)
if entry_point.name == config['FLASCHENGEIST']['AUTH']:
app.config['FG_AUTH_BACKEND'] = plugin
else:
del plugin
else:
app.config["FG_PLUGINS"][entry_point.name] = plugin app.config["FG_PLUGINS"][entry_point.name] = plugin
if 'FG_AUTH_BACKEND' not in app.config:
logger.error('No authentication plugin configured or authentication plugin not found')
def install_all(): def install_all():
@ -77,7 +75,6 @@ def create_app():
from .system.database import db from .system.database import db
configure_app(app) configure_app(app)
db.init_app(app) db.init_app(app)
__load_auth(app)
__load_plugins(app) __load_plugins(app)
@app.route("/", methods=["GET"]) @app.route("/", methods=["GET"])

View File

@ -12,15 +12,21 @@ HOST =
PASSWORD = PASSWORD =
DATABASE = DATABASE =
[MAIL] [auth_plain]
URL = enabled = true
PORT =
USER = #[mail]
PASSWD = # enabled = true
MAIL = # SERVER =
CRYPT = SSL/STARTLS # PORT =
# USER =
# PASSWORD =
# MAIL =
# SSL or STARTLS
# CRYPT = SSL
#[auth_ldap] #[auth_ldap]
# enabled = true
# URL = # URL =
# PORT = # PORT =
# BINDDN = # BINDDN =

View File

@ -1,5 +1,10 @@
from pyhooks import precall_register
send_message_hook = precall_register("send_message")
class Plugin: class Plugin:
def __init__(self, blueprint, permissions = {}): def __init__(self, config=None, blueprint=None, permissions={}):
self.blueprint = blueprint self.blueprint = blueprint
self.permissions = permissions self.permissions = permissions
@ -10,10 +15,7 @@ class Plugin:
pass pass
class Auth: class AuthPlugin(Plugin):
def configure(self, config):
pass
def login(self, user, pw): def login(self, user, pw):
""" Login routine, MUST BE IMPLEMENTED! """ Login routine, MUST BE IMPLEMENTED!

View File

@ -14,12 +14,12 @@ from flaschengeist.system.decorator import login_required
from flaschengeist.system.controller import accessTokenController, userController from flaschengeist.system.controller import accessTokenController, userController
access_controller = LocalProxy(lambda: accessTokenController.AccessTokenController()) access_controller = LocalProxy(lambda: accessTokenController.AccessTokenController())
auth_bp = Blueprint('auth', __name__) auth_bp = Blueprint('auth', __name__)
def register(): class AuthRoutePlugin(Plugin):
return Plugin(auth_bp) def __init__(self, conf):
super().__init__(blueprint=auth_bp)
################################################# #################################################
# Routes # # Routes #
@ -31,7 +31,6 @@ def register():
# DELETE: logout / delete token # # DELETE: logout / delete token #
################################################# #################################################
@auth_bp.route("/auth", methods=['POST']) @auth_bp.route("/auth", methods=['POST'])
def _create_token(): def _create_token():
""" Login User """ Login User

View File

@ -1,29 +1,26 @@
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError import ssl
from ldap3.utils.hashed import hashed from ldap3.utils.hashed import hashed
from werkzeug.exceptions import BadRequest from ldap3 import SUBTREE, MODIFY_REPLACE, HASHED_SALTED_SHA512
from ldap3.core.exceptions import LDAPPasswordIsMandatoryError, LDAPBindError
import flaschengeist.modules as modules
from flask import current_app as app from flask import current_app as app
from flask_ldapconn import LDAPConn from flask_ldapconn import LDAPConn
from ldap3 import SUBTREE, MODIFY_REPLACE, HASHED_SALTED_SHA512 from werkzeug.exceptions import BadRequest
import ssl
from flaschengeist.modules import AuthPlugin
from flaschengeist.system.models.user import User from flaschengeist.system.models.user import User
from flaschengeist import logger
class AuthLDAP(modules.Auth): class AuthLDAP(AuthPlugin):
_default = { def __init__(self, config):
super().__init__()
defaults = {
'PORT': '389', 'PORT': '389',
'USE_SSL': 'False' 'USE_SSL': 'False'
} }
ldap = None for name in defaults:
dn = None
def configure(self, config):
for name in self._default:
if name not in config: if name not in config:
config[name] = self._default[name] config[name] = defaults[name]
app.config.update( app.config.update(
LDAP_SERVER=config['URL'], LDAP_SERVER=config['URL'],

View File

@ -0,0 +1,43 @@
import smtplib
from email.mime.multipart import MIMEMultipart
from flaschengeist.system.models.user import User
from flaschengeist.system.controller import userController
from flaschengeist.system.controller.messageController import Message
from . import Plugin, send_message_hook
class MailMessagePlugin(Plugin):
def __init__(self, config):
super().__init__()
self.server = config['SERVER']
self.port = config['PORT']
self.user = config['USER']
self.password = config['PASSWORD']
self.crypt = config['CRYPT']
self.mail = config['MAIL']
@send_message_hook
def send_mail(self, msg: Message):
if isinstance(msg.receiver, User):
recipients = [msg.receiver.mail]
else:
recipients = userController.get_user_by_role(msg.receiver)
mail = MIMEMultipart()
mail['From'] = self.mail
mail['To'] = ", ".join(recipients)
mail['Subject'] = msg.subject
msg.attach(msg.message)
if not self.smtp:
self.__connect()
self.smtp.sendmail(self.mail, recipients, msg.as_string())
def __connect(self):
if self.crypt == 'SSL':
self.smtp = smtplib.SMTP_SSL(self.server, self.port)
if self.crypt == 'STARTTLS':
self.smtp = smtplib.SMTP(self.smtpServer, self.port)
self.smtp.starttls()
self.smtp.login(self.user, self.password)

View File

@ -1,16 +1,16 @@
from flask import Blueprint, request, jsonify from flask import Blueprint, request, jsonify
from werkzeug.exceptions import NotFound, BadRequest, Forbidden from werkzeug.exceptions import NotFound, BadRequest
from flaschengeist.modules import Plugin from flaschengeist.modules import Plugin
from flaschengeist.system.decorator import login_required from flaschengeist.system.decorator import login_required
from flaschengeist.system.controller import roleController from flaschengeist.system.controller import roleController
roles_bp = Blueprint("roles", __name__) roles_bp = Blueprint("roles", __name__)
permissions = {}
def register(): class RolesPlugin(Plugin):
return Plugin(roles_bp, permissions) def __init__(self, config):
super().__init__(config, roles_bp)
###################################################### ######################################################
# Routes # # Routes #
@ -23,10 +23,9 @@ def register():
# DELETE: remove role # # DELETE: remove role #
###################################################### ######################################################
@roles_bp.route("/roles", methods=['POST']) @roles_bp.route("/roles", methods=['POST'])
@login_required() @login_required()
def __add_role(): def add_role(self):
data = request.get_json() data = request.get_json()
if not data or "name" not in data: if not data or "name" not in data:
raise BadRequest raise BadRequest
@ -35,24 +34,21 @@ def __add_role():
role = roleController.create_role(data["name"], permissions) role = roleController.create_role(data["name"], permissions)
return jsonify({"ok": "ok", "id": role.id}) return jsonify({"ok": "ok", "id": role.id})
@roles_bp.route("/roles", methods=['GET']) @roles_bp.route("/roles", methods=['GET'])
@login_required() @login_required()
def __list_roles(**kwargs): def list_roles(self, **kwargs):
roles = roleController.get_roles() roles = roleController.get_roles()
return jsonify(roles) return jsonify(roles)
@roles_bp.route("/roles/permissions", methods=['GET']) @roles_bp.route("/roles/permissions", methods=['GET'])
@login_required() @login_required()
def __list_permissions(**kwargs): def list_permissions(self, **kwargs):
permissions = roleController.get_permissions() permissions = roleController.get_permissions()
return jsonify(permissions) return jsonify(permissions)
@roles_bp.route("/roles/<rid>", methods=['GET']) @roles_bp.route("/roles/<rid>", methods=['GET'])
@login_required() @login_required()
def __get_role(rid, **kwargs): def __get_role(self, rid, **kwargs):
role = roleController.get_role(rid) role = roleController.get_role(rid)
if role: if role:
return jsonify({ return jsonify({
@ -62,10 +58,9 @@ def __get_role(rid, **kwargs):
}) })
raise NotFound raise NotFound
@roles_bp.route("/roles/<rid>", methods=['PUT']) @roles_bp.route("/roles/<rid>", methods=['PUT'])
@login_required() @login_required()
def __edit_role(rid, **kwargs): def __edit_role(self, rid, **kwargs):
role = roleController.get_role(rid) role = roleController.get_role(rid)
if not role: if not role:
raise NotFound raise NotFound
@ -78,10 +73,9 @@ def __edit_role(rid, **kwargs):
roleController.update_role(role) roleController.update_role(role)
return jsonify({"ok": "ok"}) return jsonify({"ok": "ok"})
@roles_bp.route("/roles/<rid>", methods=['DELETE']) @roles_bp.route("/roles/<rid>", methods=['DELETE'])
@login_required() @login_required()
def __delete_role(rid, **kwargs): def __delete_role(self, rid, **kwargs):
if not roleController.delete_role(rid): if not roleController.delete_role(rid):
raise NotFound raise NotFound

View File

@ -1,21 +1,20 @@
from dateutil import parser from dateutil import parser
from datetime import datetime, timedelta
from flask import Blueprint, request, jsonify from flask import Blueprint, request, jsonify
from werkzeug.exceptions import BadRequest, NotFound from werkzeug.exceptions import BadRequest, NotFound
from datetime import datetime, timedelta
from flaschengeist.modules import Plugin from flaschengeist.modules import Plugin
from flaschengeist.system.controller import eventController
from flaschengeist.system.database import db from flaschengeist.system.database import db
from flaschengeist.system.decorator import login_required
from flaschengeist.system.models.event import EventKind from flaschengeist.system.models.event import EventKind
from flaschengeist.system.decorator import login_required
from flaschengeist.system.controller import eventController
schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule") schedule_bp = Blueprint("schedule", __name__, url_prefix="/schedule")
permissions = {}
def register(): class SchedulePlugin(Plugin):
return Plugin(schedule_bp, permissions) def __init__(self, config):
super().__init__(blueprint=schedule_bp)
#################################################################################### ####################################################################################
# Routes # # Routes #
@ -38,21 +37,19 @@ def register():
# DELETE: remove user # # DELETE: remove user #
#################################################################################### ####################################################################################
@schedule_bp.route("/events/<int:id>", methods=['GET']) @schedule_bp.route("/events/<int:id>", methods=['GET'])
@login_required() # roles=['schedule_read']) @login_required() # roles=['schedule_read'])
def __get_event(id, **kwargs): def __get_event(self, id, **kwargs):
event = eventController.get_event(id) event = eventController.get_event(id)
if not event: if not event:
raise NotFound raise NotFound
return jsonify(event) return jsonify(event)
@schedule_bp.route("/events", methods=['GET']) @schedule_bp.route("/events", methods=['GET'])
@schedule_bp.route("/events/<int:year>/<int:month>", methods=['GET']) @schedule_bp.route("/events/<int:year>/<int:month>", methods=['GET'])
@schedule_bp.route("/events/<int:year>/<int:month>/<int:day>", methods=['GET']) @schedule_bp.route("/events/<int:year>/<int:month>/<int:day>", methods=['GET'])
@login_required() # roles=['schedule_read']) @login_required() # roles=['schedule_read'])
def __get_events(year=datetime.now().year, month=datetime.now().month, day=None, **kwrags): def __get_events(self, year=datetime.now().year, month=datetime.now().month, day=None, **kwrags):
"""Get Event objects for specified date (or month or year), """Get Event objects for specified date (or month or year),
if nothing set then events for current month are returned if nothing set then events for current month are returned
@ -85,7 +82,7 @@ def __get_events(year=datetime.now().year, month=datetime.now().month, day=None,
@schedule_bp.route("/eventKinds", methods=['POST']) @schedule_bp.route("/eventKinds", methods=['POST'])
@login_required() @login_required()
def __new_event_kind(**kwargs): def __new_event_kind(self, **kwargs):
data = request.get_json() data = request.get_json()
if "name" not in data: if "name" not in data:
raise BadRequest raise BadRequest
@ -95,7 +92,7 @@ def __new_event_kind(**kwargs):
@schedule_bp.route("/slotKinds", methods=["POST"]) @schedule_bp.route("/slotKinds", methods=["POST"])
@login_required() @login_required()
def __new_slot_kind(**kwargs): def __new_slot_kind(self, **kwargs):
data = request.get_json() data = request.get_json()
if not data or "name" not in data: if not data or "name" not in data:
raise BadRequest raise BadRequest
@ -105,7 +102,7 @@ def __new_slot_kind(**kwargs):
@schedule_bp.route("/events", methods=['POST']) @schedule_bp.route("/events", methods=['POST'])
@login_required() @login_required()
def __new_event(**kwargs): def __new_event(self, **kwargs):
data = request.get_json() data = request.get_json()
event = eventController.create_event(begin=parser.isoparse(data["begin"]), event = eventController.create_event(begin=parser.isoparse(data["begin"]),
end=parser.isoparse(data["end"]), end=parser.isoparse(data["end"]),
@ -116,7 +113,7 @@ def __new_event(**kwargs):
@schedule_bp.route("/events/<int:id>", methods=["DELETE"]) @schedule_bp.route("/events/<int:id>", methods=["DELETE"])
@login_required() @login_required()
def __delete_event(id, **kwargs): def __delete_event(self, id, **kwargs):
if not eventController.delete_event(id): if not eventController.delete_event(id):
raise NotFound raise NotFound
db.session.commit() db.session.commit()
@ -125,7 +122,7 @@ def __delete_event(id, **kwargs):
@schedule_bp.route("/eventKinds/<int:id>", methods=["PUT"]) @schedule_bp.route("/eventKinds/<int:id>", methods=["PUT"])
@login_required() @login_required()
def __edit_event_kind(id, **kwargs): def __edit_event_kind(self, id, **kwargs):
data = request.get_json() data = request.get_json()
if not data or "name" not in data: if not data or "name" not in data:
raise BadRequest raise BadRequest
@ -135,7 +132,7 @@ def __edit_event_kind(id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots", methods=["GET"]) @schedule_bp.route("/events/<int:event_id>/slots", methods=["GET"])
@login_required() @login_required()
def __get_slots(event_id, **kwargs): def __get_slots(self, event_id, **kwargs):
event = eventController.get_event(event_id) event = eventController.get_event(event_id)
if not event: if not event:
raise NotFound raise NotFound
@ -144,7 +141,7 @@ def __get_slots(event_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["GET"]) @schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["GET"])
@login_required() @login_required()
def __get_slot(event_id, slot_id, **kwargs): def __get_slot(self, event_id, slot_id, **kwargs):
slot = eventController.get_event_slot(slot_id, event_id) slot = eventController.get_event_slot(slot_id, event_id)
if slot: if slot:
return jsonify(slot) return jsonify(slot)
@ -153,7 +150,7 @@ def __get_slot(event_id, slot_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["DELETE"]) @schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["DELETE"])
@login_required() @login_required()
def __delete_slot(event_id, slot_id, **kwargs): def __delete_slot(self, event_id, slot_id, **kwargs):
if eventController.delete_event_slot(slot_id, event_id): if eventController.delete_event_slot(slot_id, event_id):
return jsonify({"ok": "ok"}) return jsonify({"ok": "ok"})
raise NotFound raise NotFound
@ -161,7 +158,7 @@ def __delete_slot(event_id, slot_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["PUT"]) @schedule_bp.route("/events/<int:event_id>/slots/<int:slot_id>", methods=["PUT"])
@login_required() @login_required()
def __update_slot(event_id, slot_id, **kwargs): def __update_slot(self, event_id, slot_id, **kwargs):
data = request.get_json() data = request.get_json()
if not data: if not data:
raise BadRequest raise BadRequest
@ -175,7 +172,7 @@ def __update_slot(event_id, slot_id, **kwargs):
@schedule_bp.route("/events/<int:event_id>/slots", methods=["POST"]) @schedule_bp.route("/events/<int:event_id>/slots", methods=["POST"])
@login_required() @login_required()
def __add_slot(event_id, **kwargs): def __add_slot(self, event_id, **kwargs):
event = eventController.get_event(event_id) event = eventController.get_event(event_id)
if not event: if not event:
raise NotFound raise NotFound
@ -194,5 +191,5 @@ def __add_slot(event_id, **kwargs):
return jsonify({"ok": "ok"}) return jsonify({"ok": "ok"})
def __edit_event(): def __edit_event(self):
... ...

View File

@ -10,8 +10,9 @@ users_bp = Blueprint("users", __name__)
permissions = {'EDIT_USER': 'edit_user'} permissions = {'EDIT_USER': 'edit_user'}
def register(): class UsersPlugin(Plugin):
return Plugin(users_bp, permissions) def __init__(self, config):
super().__init__(blueprint=users_bp, permissions=permissions)
################################################# #################################################
# Routes # # Routes #
@ -23,34 +24,30 @@ def register():
# DELETE: remove user # # DELETE: remove user #
################################################# #################################################
@users_bp.route("/users", methods=['POST']) @users_bp.route("/users", methods=['POST'])
def __registration(): def __registration(self):
logger.debug("Register new User...") logger.debug("Register new User...")
return jsonify({"ok": "ok... well not implemented"}) return jsonify({"ok": "ok... well not implemented"})
@users_bp.route("/users", methods=['GET']) @users_bp.route("/users", methods=['GET'])
@login_required() @login_required()
def __list_users(**kwargs): def __list_users(self, **kwargs):
logger.debug("Retrieve list of all users") logger.debug("Retrieve list of all users")
users = userController.get_users() users = userController.get_users()
return jsonify(users) return jsonify(users)
@users_bp.route("/users/<uid>", methods=['GET']) @users_bp.route("/users/<uid>", methods=['GET'])
@login_required() @login_required()
def __get_user(uid, **kwargs): def __get_user(self, uid, **kwargs):
logger.debug("Get information of user {{ {} }}".format(uid)) logger.debug("Get information of user {{ {} }}".format(uid))
user = userController.get_user(uid) user = userController.get_user(uid)
if user: if user:
return jsonify(user) return jsonify(user)
raise NotFound raise NotFound
@users_bp.route("/users/<uid>", methods=['PUT']) @users_bp.route("/users/<uid>", methods=['PUT'])
@login_required() @login_required()
def __edit_user(uid, **kwargs): def __edit_user(self, uid, **kwargs):
logger.debug("Modify information of user {{ {} }}".format(uid)) logger.debug("Modify information of user {{ {} }}".format(uid))
user = userController.get_user(uid) user = userController.get_user(uid)
if not user: if not user:

View File

@ -1,119 +0,0 @@
import smtplib
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.header import Header
from geruecht.logger import getDebugLogger
from . import mailConfig
debug = getDebugLogger()
class EmailController():
def __init__(self):
debug.info("init email controller")
self.smtpServer = mailConfig['URL']
self.port = mailConfig['port']
self.user = mailConfig['user']
self.passwd = mailConfig['passwd']
self.crypt = mailConfig['crypt']
self.email = mailConfig['email']
debug.debug("smtpServer is {{ {} }}, port is {{ {} }}, user is {{ {} }}, crypt is {{ {} }}, email is {{ {} }}".format(self.smtpServer, self.port, self.user, self.crypt, self.email))
def __connect__(self):
debug.info('connect to email server')
if self.crypt == 'SSL':
self.smtp = smtplib.SMTP_SSL(self.smtpServer, self.port)
log = self.smtp.ehlo()
debug.debug("ehlo is {{ {} }}".format(log))
if self.crypt == 'STARTTLS':
self.smtp = smtplib.SMTP(self.smtpServer, self.port)
log = self.smtp.ehlo()
debug.debug("ehlo is {{ {} }}".format(log))
log = self.smtp.starttls()
debug.debug("starttles is {{ {} }}".format(log))
log = self.smtp.login(self.user, self.passwd)
debug.debug("login is {{ {} }}".format(log))
def jobTransact(self, user, jobtransact):
debug.info("create email jobtransact {{ {} }}for user {{ {} }}".format(jobtransact, user))
date = '{}.{}.{}'.format(jobtransact['on_date']['day'], jobtransact['on_date']['month'], jobtransact['on_date']['year'])
from_user = '{} {}'.format(jobtransact['from_user']['firstname'], jobtransact['from_user']['lastname'])
job_kind = jobtransact['job_kind']
subject = 'Dienstanfrage am {}'.format(date)
text = MIMEText(
"Hallo {} {},\n"
"{} fragt, ob du am {} den Dienst {} übernehmen willst.\nBeantworte die Anfrage im Userportal von Flaschengeist.".format(user.firstname, user.lastname, from_user, date, job_kind['name']), 'plain')
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
return (subject, text)
def jobInvite(self, user, jobtransact):
debug.info("create email jobtransact {{ {} }}for user {{ {} }}".format(jobtransact, user))
date = '{}.{}.{}'.format(jobtransact['on_date']['day'], jobtransact['on_date']['month'], jobtransact['on_date']['year'])
from_user = '{} {}'.format(jobtransact['from_user']['firstname'], jobtransact['from_user']['lastname'])
subject = 'Diensteinladung am {}'.format(date)
text = MIMEText(
"Hallo {} {},\n"
"{} fragt, ob du am {} mit Dienst haben willst.\nBeantworte die Anfrage im Userportal von Flaschengeist.".format(user.firstname, user.lastname, from_user, date), 'plain')
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
return (subject, text)
def credit(self, user):
debug.info("create email credit for user {{ {} }}".format(user))
subject = Header('Gerücht, bezahle deine Schulden!', 'utf-8')
sum = user.getGeruecht(datetime.now().year).getSchulden()
if sum < 0:
type = 'Schulden'
add = 'Bezahle diese umgehend an den Finanzer.'
else:
type = 'Guthaben'
add = ''
text = MIMEText(
"Hallo {} {},\nDu hast {} im Wert von {:.2f} €. {}\n\nDiese Nachricht wurde automatisch erstellt.".format(
user.firstname, user.lastname, type, abs(sum) / 100, add), 'plain')
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
return (subject, text)
def passwordReset(self, user, data):
debug.info("create email passwort reset for user {{ {} }}".format(user))
subject = Header("Password vergessen")
text = MIMEText(
"Hallo {} {},\nDu hast dein Password vergessen!\nDies wurde nun mit Flaschengeist zurückgesetzt.\nDein neues Passwort lautet:\n{}\n\nBitte ändere es sofort in deinem Flaschengeistprolif in https://flaschengeist.wu5.de.".format(
user.firstname, user.lastname, data['password']
), 'plain'
)
debug.debug("subject is {{ {} }}, text is {{ {} }}".format(subject, text.as_string()))
return (subject, text)
def sendMail(self, user, type='credit', jobtransact=None, **kwargs):
debug.info("send email to user {{ {} }}".format(user))
try:
if user.mail == 'None' or not user.mail:
debug.warning("user {{ {} }} has no email-address".format(user))
raise Exception("no valid Email")
msg = MIMEMultipart()
msg['From'] = self.email
msg['To'] = user.mail
if type == 'credit':
subject, text = self.credit(user)
elif type == 'jobtransact':
subject, text = self.jobTransact(user, jobtransact)
elif type == 'jobinvite':
subject, text = self.jobInvite(user, jobtransact)
elif type == 'passwordReset':
subject, text = self.passwordReset(user, kwargs)
else:
raise Exception("Fail to send Email. No type is set. user={}, type={} , jobtransact={}".format(user, type, jobtransact))
msg['Subject'] = subject
msg.attach(text)
debug.debug("send email {{ {} }} to user {{ {} }}".format(msg.as_string(), user))
self.__connect__()
self.smtp.sendmail(self.email, user.mail, msg.as_string())
return {'error': False, 'user': {'userId': user.uid, 'firstname': user.firstname, 'lastname': user.lastname}}
except Exception:
debug.warning("exception in send email", exc_info=True)
return {'error': True, 'user': {'userId': user.uid, 'firstname': user.firstname, 'lastname': user.lastname}}

View File

@ -1,10 +1,9 @@
from werkzeug.exceptions import BadRequest, NotFound from werkzeug.exceptions import BadRequest, NotFound
from flaschengeist.system.models.event import EventKind, Event, EventSlot, JobSlot, JobKind
from sqlalchemy.exc import IntegrityError from sqlalchemy.exc import IntegrityError
from flaschengeist import logger from flaschengeist import logger
from flaschengeist.system.database import db from flaschengeist.system.database import db
from flaschengeist.system.models.event import EventKind, Event, EventSlot, JobSlot, JobKind
def get_event(id): def get_event(id):

View File

@ -0,0 +1,14 @@
from flaschengeist.system.models.user import User, Role
from pyhooks import Hook
class Message:
def __init__(self, receiver: User or Role, message: str, subject: str):
self.message = message
self.subject = subject
self.receiver = receiver
@Hook
def send_message(message: Message):
pass

View File

@ -1,6 +1,6 @@
from flask import current_app from flask import current_app
from flaschengeist.system.models.user import User from flaschengeist.system.models.user import User, Role
from flaschengeist.system.database import db from flaschengeist.system.database import db
from flaschengeist import logger from flaschengeist import logger
@ -44,5 +44,9 @@ def get_users():
return User.query.all() return User.query.all()
def get_user_by_role(role: Role):
return User.query.join(User.roles).filter_by(role_id=role.id).all()
def get_user(uid): def get_user(uid):
return User.query.filter(User.uid == uid).one_or_none() return User.query.filter(User.uid == uid).one_or_none()

View File

@ -18,17 +18,18 @@ setup(
"flask_cors", "flask_cors",
"werkzeug", "werkzeug",
"bjoern", "bjoern",
"python-dateutil" "python-dateutil",
"pyhooks"
], ],
extras_require={"ldap": ["flask_ldapconn", "ldap3"]}, extras_require={"ldap": ["flask_ldapconn", "ldap3"]},
entry_points={ entry_points={
"flaschengeist.plugin": [ "flaschengeist.plugin": [
"auth = flaschengeist.modules.auth:register", "auth = flaschengeist.modules.auth:AuthRoutePlugin",
"users = flaschengeist.modules.users:register", "users = flaschengeist.modules.users:UsersPlugin",
"roles = flaschengeist.modules.roles:register", "roles = flaschengeist.modules.roles:RolesPlugin",
"schedule = flaschengeist.modules.schedule:register", "schedule = flaschengeist.modules.schedule:SchedulePlugin",
], "mail = flaschengeist.modules.message_mail:MailMessagePlugin",
"flaschengeist.auth": [
"auth_plain = flaschengeist.modules.auth_plain:AuthPlain", "auth_plain = flaschengeist.modules.auth_plain:AuthPlain",
"auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]", "auth_ldap = flaschengeist.modules.auth_ldap:AuthLDAP [ldap]",
], ],